
    i(H                       d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	 ddl
mZmZmZ ddlZ eej                  j!                  dd            Z ee      ej&                  vr"ej&                  j)                  d ee             dd	lmZ  G d
 d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Zy)u  
tests/test_session_monitor.py

SessionMonitor 단위 테스트 (TDD - RED 단계)

테스트 항목:
- 초기 상태: total_tokens=0, level="normal"
- update()로 토큰 누적 → 70% 도달 시 level="warning"
- update()로 토큰 누적 → 85% 도달 시 level="critical"
- 임계값 커스텀 설정 테스트
- reset() 후 상태 초기화 확인
- 콜백 등록 + 호출 확인
- CLI --status 테스트 (mock으로)
    )annotationsN)Path)Any)	MagicMock	mock_openpatchWORKSPACE_ROOTz/home/jay/workspace)SessionMonitorc                  :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
TestInitialStateu3   SessionMonitor 초기 상태가 올바른지 확인c                L    t               }|j                         }|d   dk(  sJ y )Nlimit@ r
   get_usage_statusselfmonitorstatuss      K/home/jay/workspace/.worktrees/task-2116-dev1/tests/test_session_monitor.pytest_default_context_limitz+TestInitialState.test_default_context_limit)   s*     "))+g')))    c                L    t               }|j                         }|d   dk(  sJ y )Ntotal_tokensr   r   r   s      r   test_initial_total_tokens_zeroz/TestInitialState.test_initial_total_tokens_zero.   s+     "))+n%***r   c                L    t               }|j                         }|d   dk(  sJ y )Nlevelnormalr   r   s      r   test_initial_level_normalz*TestInitialState.test_initial_level_normal3   s*     "))+g(***r   c                L    t               }|j                         }|d   dk(  sJ y )N	usage_pct        r   r   s      r   test_initial_usage_pct_zeroz,TestInitialState.test_initial_usage_pct_zero8   s+     "))+k"c)))r   c                P    t        d      }|j                         }|d   dk(  sJ y )N順 context_limitr   r   r   s      r   test_custom_context_limitz*TestInitialState.test_custom_context_limit=   s,     w7))+g')))r   c                z    t        dd      }|j                  ddd       |j                         }|d   dk(  sJ y )	Nr%   g333333?)r'   warning_pct`  r   input_tokensoutput_tokensr   warningr
   updater   r   s      r   test_custom_warning_pctz(TestInitialState.test_custom_warning_pctB   s?     wDICD))+g)+++r   c                z    t        dd      }|j                  ddd       |j                         }|d   dk(  sJ y )	Nr%   g?)r'   critical_pcti_ r   r,   r   criticalr0   r   s      r   test_custom_critical_pctz)TestInitialState.test_custom_critical_pctI   s?     wTJCD))+g*,,,r   N)__name__
__module____qualname____doc__r   r   r   r#   r(   r2   r6    r   r   r   r   &   s(    =*
+
+
*
*
,-r   r   c                  L    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zy)
TestUpdateuP   update()가 올바르게 토큰을 누적하고 레벨을 반환하는지 확인c                V    t        ddd      }|j                  ddd      }|dk(  sJ y )	Nr   ffffff?333333?r'   r*   r4   r%   ip  r,   r   r
   r1   r   r   r   s      r   (test_update_returns_normal_below_warningz3TestUpdate.test_update_returns_normal_below_warningY   s2     wDW[\&QR   r   c                V    t        ddd      }|j                  ddd      }|dk(  sJ y )	Nr   r?   r@   rA   r%   i@  r,   r/   rB   rC   s      r   $test_update_returns_warning_at_70pctz/TestUpdate.test_update_returns_warning_at_70pct_   2     wDW[\&QR	!!!r   c                V    t        ddd      }|j                  ddd      }|dk(  sJ y )	Nr   r?   r@   rA   r%   P  r,   r/   rB   rC   s      r   -test_update_returns_warning_between_70_and_85z8TestUpdate.test_update_returns_warning_between_70_and_85e   rG   r   c                R    t        d      }|j                  ddd      }|dk(  sJ y )Nr   r&   r%   ip r,   r5   rB   rC   s      r   %test_update_returns_critical_at_85pctz0TestUpdate.test_update_returns_critical_at_85pctk   s-     w7&QR
"""r   c                    t        d      }|j                  ddd       |j                  ddd       |j                         }|d   d	k(  sJ y )
Nr   r&   rI   i'  r,   0u  i  r   is r0   r   s      r   test_update_accumulates_tokensz)TestUpdate.test_update_accumulates_tokensq   sO     w7HIGH))+n%///r   c                x    t        d      }|j                  ddd       |j                         }|d   dk(  sJ y )Nr   r&   rN   i N  r,   r   rI   r0   r   s      r   (test_update_uses_input_and_output_tokensz3TestUpdate.test_update_uses_input_and_output_tokensx   s>     w7HI))+n%///r   c                v    t        d      }|j                  ddi       |j                         }|d   dk(  sJ y )Nr   r&   r-   rI   r   r0   r   s      r   "test_update_with_only_input_tokensz-TestUpdate.test_update_with_only_input_tokens~   s>     w7/0))+n%///r   c                v    t        d      }|j                  ddi       |j                         }|d   dk(  sJ y )Nr   r&   r.   rN   r   r0   r   s      r   #test_update_with_only_output_tokensz.TestUpdate.test_update_with_only_output_tokens   s>     w701))+n%///r   c                L    t        d      }|j                  i       }|dk(  sJ y )Nr   r&   r   rB   rC   s      r   #test_update_empty_dict_stays_normalz.TestUpdate.test_update_empty_dict_stays_normal   s(     w7r"   r   c                    t        d      }|j                  ddd       |j                         }|d   t        j                  d      k(  sJ y )Nr   r&   r%   rI   r,   r!   g     R@)r
   r1   r   pytestapproxr   s      r   test_usage_pct_calculationz%TestUpdate.test_usage_pct_calculation   sG     w7&IJ))+k"fmmD&9999r   N)r7   r8   r9   r:   rD   rF   rJ   rL   rO   rQ   rS   rU   rW   r[   r;   r   r   r=   r=   V   s7    Z!""#0000!
:r   r=   c                  (    e Zd ZdZd Zd Zd Zd Zy)TestGetUsageStatusu@   get_usage_status()가 올바른 형식을 반환하는지 확인c                h    t               }|j                         }d|v sJ d|v sJ d|v sJ d|v sJ y )Nr   r   r!   r   r   r   s      r   test_returns_required_keysz-TestGetUsageStatus.test_returns_required_keys   sP     "))+'''&   f$$$&   r   c                |    t        ddd      }|j                  ddd       |j                         }|d   d	k(  sJ y )
Nr   r?   r@   rA   " r   r,   r   r/   r0   r   s      r   test_level_warning_in_statusz/TestGetUsageStatus.test_level_warning_in_status   sB     wDW[\!DE))+g)+++r   c                x    t        d      }|j                  ddd       |j                         }|d   dk(  sJ y )Nr   r&    r   r,   r   r5   r0   r   s      r   test_level_critical_in_statusz0TestGetUsageStatus.test_level_critical_in_status   s=     w7!DE))+g*,,,r   c                    t        d      }|j                  ddd       |j                         }t        |d   t              sJ y )Nr   r&   rI   r   r,   r!   )r
   r1   r   
isinstancefloatr   s      r   test_usage_pct_is_floatz*TestGetUsageStatus.test_usage_pct_is_float   s@     w7CD))+&-u555r   N)r7   r8   r9   r:   r_   rb   re   ri   r;   r   r   r]   r]      s    J!,-6r   r]   c                  4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)		TestResetuE   reset()이 올바르게 토큰 카운터를 초기화하는지 확인c                    t        d      }|j                  ddd       |j                          |j                         }|d   dk(  sJ y )Nr   r&   r%   rI   r,   r   r   r
   r1   resetr   r   s      r   test_reset_clears_tokensz"TestReset.test_reset_clears_tokens   sG     w7&IJ))+n%***r   c                    t        d      }|j                  ddd       |j                          |j                         }|d   dk(  sJ y )Nr   r&   rd   r   r,   r   r   rm   r   s      r   test_reset_level_returns_normalz)TestReset.test_reset_level_returns_normal   sF     w7!DE))+g(***r   c                    t        d      }|j                  ddd       |j                  d       |j                         }|d   dk(  sJ y )	Nr   r&   rd   r   r,   rI   	new_totalr   rm   r   s      r   test_reset_with_new_totalz#TestReset.test_reset_with_new_total   sL     w7!DE'))+n%///r   c                    t        d      }|j                  ddd       |j                  d       |j                         }|d   d	k(  sJ y )
Nr   r&   rd   r   r,   rI   rs   r   r   rm   r   s      r   'test_reset_with_new_total_updates_levelz1TestReset.test_reset_with_new_total_updates_level   sK     w7!DE'))+g(***r   c                x    t        ddd      }|j                  d       |j                         }|d   dk(  sJ y )	Nr   r?   r@   rA   I rs   r   r/   )r
   rn   r   r   s      r   !test_reset_with_new_total_warningz+TestReset.test_reset_with_new_total_warning   s?     wDW[\())+g)+++r   c                    t        d      }|j                  ddd       |j                          |j                         }|d   dk(  sJ y )Nr   r&   r%   rI   r,   r!   r"   rm   r   s      r   test_reset_usage_pct_zeroz#TestReset.test_reset_usage_pct_zero   sG     w7&IJ))+k"c)))r   N)
r7   r8   r9   r:   ro   rq   ru   rw   rz   r|   r;   r   r   rk   rk      s#    O++0+,*r   rk   c                  @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestCallbacksuF   콜백 등록 및 자동 호출이 올바르게 동작하는지 확인c                    t        ddd      }t               }|j                  d|       |j                  ddd       |j	                          y 	Nr   r?   r@   rA   r/   ra   r   r,   r
   r   register_callbackr1   assert_called_oncer   r   callbacks      r   %test_register_warning_callback_calledz3TestCallbacks.test_register_warning_callback_called   sE     wDW[\;!!)X6!DE##%r   c                    t        d      }t               }|j                  d|       |j                  ddd       |j	                          y )Nr   r&   r5   rd   r   r,   r   r   s      r   &test_register_critical_callback_calledz4TestCallbacks.test_register_critical_callback_called   s@     w7;!!*h7!DE##%r   c                    t        d      }t               }|j                  d|       |j                  ddd       |j	                          y )Nr   r&   r/   i r   r,   )r
   r   r   r1   assert_not_calledr   s      r   0test_warning_callback_not_called_below_thresholdz>TestCallbacks.test_warning_callback_not_called_below_threshold  s@     w7;!!)X6!DE""$r   c                    t        ddd      }t               }t               }|j                  d|       |j                  d|       |j                  ddd	       |j	                          |j                          y )
Nr   r?   r@   rA   r/   r5   ry   r   r,   r
   r   r   r1   r   r   r   r   
warning_cbcritical_cbs       r   ,test_critical_callback_not_called_at_warningz:TestCallbacks.test_critical_callback_not_called_at_warning  sh     wDW[\[
k!!)Z8!!*k:!DE%%'%%'r   c                    t        ddd      }g |j                  dfd       |j                  ddd	       t              d
k(  sJ dd   v sJ dd   v sJ y )Nr   r?   r@   rA   r/   c                &    j                  |       S )N)append)sreceiveds    r   <lambda>zBTestCallbacks.test_callback_receives_status_dict.<locals>.<lambda>  s    xq7I r   ra   r   r,      r   r   )r
   r   r1   len)r   r   r   s     @r   "test_callback_receives_status_dictz0TestCallbacks.test_callback_receives_status_dict  so     wDW[\!!!)-IJ!DE8}!!!!,,,(1+%%%r   c                    t        ddd      }t               }t               }|j                  d|       |j                  d|       |j                  ddd       |j	                          |j	                          y r   r   )r   r   cb1cb2s       r   "test_multiple_callbacks_same_levelz0TestCallbacks.test_multiple_callbacks_same_level!  sh     wDW[\kk!!)S1!!)S1!DE  r   c                    t        ddd      }t               }|j                  d|       |j                  ddd       |j                  d	dd       |j	                          y
)uS   warning에서 한 번만 호출되고, 이미 warning 상태에서 재호출 안됨r   r?   r@   rA   r/   ra   r   r,   i  Nr   r   s      r   -test_callback_called_only_on_level_transitionz;TestCallbacks.test_callback_called_only_on_level_transition+  sV     wDW[\;!!)X6!DEBC##%r   c                `   t        ddd      }t               }t               }|j                  d|       |j                  d|       |j                  ddd	       |j	                          |j                          |j                  d
dd	       |j	                          |j	                          y)u>   warning에서 critical로 전환 시 critical 콜백만 호출r   r?   r@   rA   r/   r5   ra   r   r,   rN   Nr   r   s       r   1test_critical_callback_on_transition_from_warningz?TestCallbacks.test_critical_callback_on_transition_from_warning6  s     wDW[\[
k!!)Z8!!*k:!DE%%'%%'CD%%'&&(r   N)r7   r8   r9   r:   r   r   r   r   r   r   r   r   r;   r   r   r~   r~      s-    P&&%	(&!	&)r   r~   c                  (    e Zd ZdZd Zd Zd Zd Zy)TestCLIStatusu?   CLI --status 모드가 올바른 JSON을 출력하는지 확인c           	        ddddddii}ddddddd	d
dii}|dz  }|dz  }|j                  t        j                  |             |j                  t        j                  |             ddlm}  |t        |      t        |            }d|v sJ t        |d         dk(  sJ |d   d   }|d   dk(  sJ |d   dk(  sJ |d   d	k(  sJ |d   dk(  sJ d|v sJ d|v sJ y)uN   mock으로 task-timers.json과 token-ledger.json을 제공하고 출력 검증tasksz
task-100.1z	dev6-teamrunningtask_idteam_idr   abc123i8 r+   ra   
   )
session_idr   r-   r.   r   message_counttask-timers.jsontoken-ledger.jsonr   get_active_sessions_statustimers_pathledger_pathsessionsr   r   r   r   r   r   r!   r   N
write_textjsondumpsutils.session_monitorr   strr   	r   tmp_pathtask_timers_datatoken_ledger_datar   r   r   resultsessions	            r   test_cli_status_output_formatz+TestCLIStatus.test_cli_status_output_formatO  sU    +*'
 "**$*%+$+%'	
 !33!44tzz*:;<tzz*;<=D+K(K(

 V###6*%&!+++$Q'y!\111y![000~&'111w7***g%%%'!!!r   c                n   ddddddii}ddddiii}|dz  }|d	z  }|j                  t        j                  |             |j                  t        j                  |             d
dlm}  |t        |      t        |            }|d   d
   }|d   dk(  sJ |d   t        j                  d      k(  sJ y)uM   55% 토큰 사용 시 warning 레벨 반환 (기본 임계값 50%/65% 기준)r   z
task-200.1	dev1-teamr   r   r   i r   r   r   r   r   r   r   r/   r!   g     K@N)r   r   r   r   r   r   rY   rZ   r   s	            r   test_cli_status_warning_levelz+TestCLIStatus.test_cli_status_warning_level}  s     +*'
 "G
 !33!44tzz*:;<tzz*;<=D+K(K(
 $Q'w9,,,{#v}}T'::::r   c                   ddddddii}di i}|dz  }|dz  }|j                  t        j                  |             |j                  t        j                  |             dd	lm}  |t        |      t        |      
      }|d   g k(  sJ y)u8   실행 중인 태스크가 없으면 빈 sessions 반환r   z
task-300.1r   	completedr   r   r   r   r   r   r   N)r   r   r   r   r   r   r   r   r   r   r   r   r   r   s           r    test_cli_status_no_running_tasksz.TestCLIStatus.test_cli_status_no_running_tasks  s     +*)
 %bM!33!44tzz*:;<tzz*;<=D+K(K(
 j!R'''r   c                n   ddddddii}di i}|dz  }|dz  }|j                  t        j                  |             |j                  t        j                  |             dd	lm}  |t        |      t        |      
      }t        |d         dk(  sJ |d   d   d   dk(  sJ |d   d   d   dk(  sJ y)uD   running 태스크가 token-ledger에 없으면 0 토큰으로 표시r   z
task-400.1z	dev2-teamr   r   r   r   r   r   r   r   r   r   r   r   Nr   r   s           r   "test_cli_status_task_not_in_ledgerz0TestCLIStatus.test_cli_status_task_not_in_ledger  s     +*'
 %bM!33!44tzz*:;<tzz*;<=D+K(K(
 6*%&!+++j!!$^4999j!!$W-999r   N)r7   r8   r9   r:   r   r   r   r   r;   r   r   r   r   L  s    I,"\ ;D(4:r   r   )r:   
__future__r   r   ossyspathlibr   typingr   unittest.mockr   r   r   rY   environget
_WORKSPACEr   pathinsertr   r
   r   r=   r]   rk   r~   r   r;   r   r   <module>r      s    #  	 
   5 5 "**..!13HIJ
z?#(("HHOOAs:' 0(- (-`=: =:J6 6F,* ,*hR) R)tG: G:r   