
    iMk                        d Z ddl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 ej                  j                  dd        G d dej                        Z G d	 d
ej                        Z G d dej                        Z G d dej                        Z G d dej                        Z G d dej                        Zedk(  r ej,                  d       yy)uT  
dispatch.py 수정사항 테스트
테스터: 아르고스

테스트 대상 변경 사항:
1. dispatch()에 task-timer 자동 시작 추가 (generate_task_id() 직후 subprocess 호출)
2. _cleanup_reserved() → _cleanup_task()로 이름 변경 및 확장 (reserved + running 정리)
3. dispatch 실패 시 _cleanup_task(task_id) 호출
    N)datetime)Path)	MagicMockcallpatchz/home/jay/workspacec                   D    e Zd ZdZd Zd ZddZd ZddZd Z	d Z
d	 Zy
)TestDispatchAutoTimeru8   dispatch() 실행 시 task-timer 자동 시작 테스트c                    t        j                         | _        t        | j                  j                        | _        | j
                  dz  j                  d       | j
                  dz  dz  j                  d       | j
                  dz  dz  | _        | j                  j                  t        j                  di i      d       | j
                  dz  dz  | _        y	)
u<   각 테스트 전 임시 디렉토리 및 공통 mock 설정memoryTparentstaskstask-timers.jsonutf-8encodingtask-timer.pyNtempfileTemporaryDirectorytmp_dirr   nametmp_pathmkdir
timer_file
write_textjsondumpstask_timer_pathselfs    Z/home/jay/workspace/.worktrees/task-2116-dev1/teams/dev1/tests/test_dispatch_auto_timer.pysetUpzTestDispatchAutoTimer.setUp   s    224T\\../ 
	!(((6		!G	+2242@ --(25GG""4::wm#<w"O  $}}x7/I    c                 8    | j                   j                          y Nr   cleanupr    s    r"   tearDownzTestDispatchAutoTimer.tearDown*       r$   c                 n    t               }d|_        t        j                  ddi      |_        d|_        |S )u@   성공하는 subprocess.run mock 반환 (cokacdir 응답 포함)r   
session_idsess-001 r   
returncoder   r   stdoutstderr)r!   task_idmock_results      r"   _make_subprocess_successz.TestDispatchAutoTimer._make_subprocess_success-   s5    k!"!ZZz(BCr$   c                 D    t               }d|_        d|_        d|_        |S )u'   실패하는 subprocess.run mock 반환   r.   u   cokacdir 연결 실패)r   r0   r1   r2   )r!   r4   s     r"   _make_subprocess_failz+TestDispatchAutoTimer._make_subprocess_fail5   s'    k!"5r$   c           
          t        d| j                        t        d| j                        t        dddd      t        dd      t        d	|
      t        dd
      t        d|      g}|S )u=   dispatch() 실행을 위한 공통 패치 컨텍스트 반환dispatch.WORKSPACEdispatch.TASK_TIMERdispatch.BOT_KEYStest-key-dev1test-key-anudev1anudispatch.CHAT_ID
1234567890dispatch.generate_task_idreturn_valuedispatch.build_prompt   테스트 프롬프트dispatch.subprocess.runside_effect)r   r   r   )r!   subprocess_side_effectsr3   patchess       r"   _patch_dispatch_envz)TestDispatchAutoTimer._patch_dispatch_env=   sp     &6')=)=>%'WX$l3-GD)8PQ+9PQ
 r$   c                     d fd}ddl }t        d j                        5  t        d j                        5  t        ddd	d
      5  t        dd      5  t        d      5  t        dd      5  t        d|      5  |j                  dd      }ddd       ddd       ddd       ddd       ddd       ddd       ddd        j	                  d   d        j	                  |d          t        j                   j                  j                               }|d   j                        } j                  | d        j	                  |d   dd d|d           y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)uQ  
        테스트 1: dispatch() 실행 후 task-timers.json에서 해당 task가 running 상태인지 확인.

        task-timer start 호출 시 task-timers.json에 status=running으로 기록되어야 한다.
        실제 task-timer.py 실행 없이, subprocess.run이 호출되면 수동으로 timer_file을 업데이트.
        task-1.1c                 T   d| v rt        j                        dj                  d | D              v rt        j                  j
                  j                               }dddt        j                         j                         d|d   <   j
                  j                  t        j                  |      d	
       t               }d|_        t        j                  ddi      |_        d|_        |S t               }d|_        t        j                  ddi      |_        d|_        |S )Nstart c              3   2   K   | ]  }t        |        y wr&   str.0cs     r"   	<genexpr>z~TestDispatchAutoTimer.test_task_running_status_in_timer_file_after_dispatch.<locals>.subprocess_side_effect.<locals>.<genexpr>U   s     G\STAG\   	dev1-team   테스트 작업runningr3   team_iddescriptionstatus
start_timer   r   r   r   rb   startedr.   r,   r-   )rV   r   joinr   loadsr   	read_textr   now	isoformatr   r   r   r0   r1   r2   )cmdkwargs
timer_datamockr!   r3   s       r"   subprocess_side_effectzkTestDispatchAutoTimer.test_task_running_status_in_timer_file_after_dispatch.<locals>.subprocess_side_effectT   s    #~#d&:&:";sxxG\X[G\?\"\!ZZ(A(A(CD
&*#5'"*,,.":":"<0
7#G, **4::j+AG*T {"#"jj(I)>?  !{"#"jj,
)CD r$   r   Nr:   r;   r<   r=   r>   r?   rB   rC   rD   rE   rG   rH   rI   rJ   r\   r]   rb   
dispatchedr3   r   u(   가 task-timers.json에 존재해야 함r^   u   dispatch 후 u.   의 상태는 'running'이어야 함, 실제: )dispatchr   r   r   assertEqualr   rf   r   rg   getassertIsNotNone)r!   rn   rp   resultrl   
task_entryr3   s   `     @r"   5test_task_running_status_in_timer_file_after_dispatchzKTestDispatchAutoTimer.test_task_running_status_in_timer_file_after_dispatchJ   s    	2 	 &6
	H')=)=>
	H %'WX
	H $l3	
	H
 -GD
	H )8PQ
	H +9OP
	H &&{4FGF
	H 
	H 
	H 
	H 
	H 
	H 
	H 	)<8	*G4 ZZ 9 9 ;<
(,,W5
ZG94\)]^x G9$RS]^fSgRhi	
)
	H 
	H 
	H 
	H 
	H 
	H 
	H 
	H 
	H 
	H 
	H 
	H 
	H 
	Hs   F6F*FF	'F5E:E.E:F&F	.F6F*>F6.E73E::F?FFF	FFF'#F**F3	/F66F?c                    d}d}g fd}ddl }t        d| j                        5  t        d| j                        5  t        dd	d
d      5  t        dd      5  t        d|      5  t        dd      5  t        d|      5  |j                  d|       ddd       ddd       ddd       ddd       ddd       ddd       ddd       D cg c]!  }d|v st	        | j                        |v s |# }}| j                  t        |      dd       |d   }| j                  d|       | j                  t	        | j                        |       | j                  d|       | j                  ||       | j                  d|       | j                  d|       | j                  d|       |j                  d      }||dz      }	|dd t        |      dkD  rdndz   }
| j                  |	|
d|	d|
       y# 1 sw Y   cxY w# 1 sw Y   hxY w# 1 sw Y   mxY w# 1 sw Y   rxY w# 1 sw Y   wxY w# 1 sw Y   |xY w# 1 sw Y   xY wc c}w ) u
  
        테스트 2: task-timer.py start가 올바른 인자로 호출되는지 확인.

        dispatch()는 generate_task_id() 직후 다음 명령을 실행해야 한다:
        python3 <TASK_TIMER> start <task_id> --team <team_id> --desc <short_desc>
        ztask-2.1u    테스트 작업 설명입니다c                     j                  t        d | D                     t               }d|_        t	        j
                  ddi      |_        d|_        |S )Nc              3   2   K   | ]  }t        |        y wr&   rU   rW   s     r"   rZ   zuTestDispatchAutoTimer.test_task_timer_start_called_with_correct_args.<locals>.capturing_subprocess.<locals>.<genexpr>   s     &;!s1v&;r[   r   r,   zsess-002r.   )appendlistr   r0   r   r   r1   r2   )rj   rk   rm   call_args_lists      r"   capturing_subprocesszbTestDispatchAutoTimer.test_task_timer_start_called_with_correct_args.<locals>.capturing_subprocess   sK    !!$&;s&;";<;DDO**lJ%?@DKDKKr$   r   Nr:   r;   r<   r=   r>   r?   rB   rC   rD   rE   rG   rH   rI   rJ   r\   rR   !   task-timer start 호출이 없음python3z--teamz--descr7   <   z...r.   u#   --desc 값이 올바르지 않음: z != )
rp   r   r   r   rV   assertGreaterlenassertInindexrq   )r!   r3   	task_descr}   rp   rY   timer_calls
timer_calldesc_idxactual_descexpected_descr|   s              @r"   .test_task_timer_start_called_with_correct_argszDTestDispatchAutoTimer.test_task_timer_start_called_with_correct_args   sS    6		 	 &6
	6')=)=>
	6 %'WX
	6 $l3	
	6
 -GD
	6 )8PQ
	6 +9MN
	6 k95
	6 
	6 
	6 
	6 
	6 
	6 
	6 #1dQGqLSI]I]E^bcEcqdd3{+Q0ST ^
i,c$../<gz*gz*h
+k:.h
+ ##H- A.!#23y>B3F%BOm7Z[fZiimn{m~5  	A=
	6 
	6 
	6 
	6 
	6 
	6 
	6 
	6 
	6 
	6 
	6 
	6 
	6 
	6 es   IH:H-H 	)H7HG9H H(H 	0H-8H: I	II6I9H>HHHHH 	 H*%H--H72H::I	?IIc                     d}g  fd}ddl }t        d j                        5  t        d j                        5  t        ddd	d
      5  t        dd      5  t        d|      5  t        dd      5  t        d|      5  |j                  dd       ddd       ddd       ddd       ddd       ddd       ddd       ddd        j	                  dd        j	                  dd       j                  d      }j                  d      } j                  ||d| d| d       y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)u   
        테스트 2 추가: task-timer start가 cokacdir --cron보다 먼저 호출되는지 순서 확인.

        코드 구조상 timer_cmd 실행이 cokacdir cmd 실행보다 먼저여야 한다.
        ztask-3.1c                    dj                  d | D              }t        j                        |v rd|v rj                  d       nJd|v rd|v rd|vrj                  d       n,t        j                        |v rd|v rj                  d	       t	               }d
|_        t        j                  ddi      |_        d|_	        |S )NrS   c              3   2   K   | ]  }t        |        y wr&   rU   rW   s     r"   rZ   zqTestDispatchAutoTimer.test_task_timer_start_called_before_cokacdir.<locals>.ordered_subprocess.<locals>.<genexpr>        3!s1v3r[   rR   timer_startcokacdir--cronlogcokacdir_cron	timer_logr   r,   zsess-003r.   )
re   rV   r   rz   r   r0   r   r   r1   r2   )rj   rk   cmd_strrm   
call_orderr!   s       r"   ordered_subprocessz^TestDispatchAutoTimer.test_task_timer_start_called_before_cokacdir.<locals>.ordered_subprocess   s    hh3s33G4''(G378J!!-0w&8w+>5PWCW!!/2T))*g5%7:J!!+.;DDO**lJ%?@DKDKKr$   r   Nr:   r;   r<   r=   r>   r?   rB   rC   rD   rE   rG   rH   rI   rJ   r\   u   순서 확인 테스트r   r~   r   u    cokacdir --cron 호출이 없음ztask-timer start(u   )가 cokacdir --cron(u"   )보다 먼저 호출되어야 함)rp   r   r   r   r   r   
assertLess)r!   r3   r   rp   	timer_idxcokacdir_idxr   s   `     @r"   ,test_task_timer_start_called_before_cokacdirzBTestDispatchAutoTimer.test_task_timer_start_called_before_cokacdir   s    
	 	 &6
	F')=)=>
	F %'WX
	F $l3	
	F
 -GD
	F )8PQ
	F +9KL
	F k+DE
	F 
	F 
	F 
	F 
	F 
	F 
	F 	mZ1TUoz3UV$$]3	!''8	{*?~Mop	
#
	F 
	F 
	F 
	F 
	F 
	F 
	F 
	F 
	F 
	F 
	F 
	F 
	F 
	Fs   E;E/E#E	)E7D?D3D? E(E	0E#8E/ E;3D<8D??EEEE	E E##E,(E//E8	4E;;FN)rP   )__name__
__module____qualname____doc__r#   r)   r5   r8   rN   rv   r   r    r$   r"   r	   r	      s1    BJ =
~4Al.
r$   r	   c                   X    e Zd ZdZd Zd ZdefdZdefdZd Z	d	 Z
d
 Zd Zd Zd Zy)TestCleanupTasku'   _cleanup_task() 함수 동작 테스트c                     t        j                         | _        t        | j                  j                        | _        | j
                  dz  j                  d       | j
                  dz  dz  | _        y Nr   Tr   r   r   r   r   r   r   r   r   r   r    s    r"   r#   zTestCleanupTask.setUp   X    224T\\../		!(((6--(25GGr$   c                 8    | j                   j                          y r&   r'   r    s    r"   r)   zTestCleanupTask.tearDown   r*   r$   r   c                 n    | j                   j                  t        j                  d|idd      d       y)u4   task-timers.json에 지정된 tasks 데이터 작성r   F   ensure_asciiindentr   r   N)r   r   r   r   )r!   r   s     r"   _write_timer_filez!TestCleanupTask._write_timer_file   s-    ""4::w.>U[\#]ho"pr$   returnc                     t        j                  | j                  j                  d            }|j	                  di       S )u4   task-timers.json 읽어서 tasks 딕셔너리 반환r   r   r   r   rf   r   rg   rr   )r!   datas     r"   _read_timer_filez TestCleanupTask._read_timer_file   s3    zz$//33W3EFxx$$r$   c                 B   d}| j                  |dt        j                         j                         di       ddl}t        d| j                        5  |j                  |       ddd       | j                         }| j                  ||d| d       y# 1 sw Y   1xY w)	u   
        테스트 3: _cleanup_task()가 reserved 상태 엔트리를 삭제하는지 확인.

        task-timers.json에 reserved 상태의 task가 있을 때
        _cleanup_task()를 호출하면 해당 task가 삭제되어야 한다.
        z	task-10.1reservedrb   reserved_atr   Nr:   u   reserved 상태의 +   가 _cleanup_task() 후 삭제되어야 함
r   r   rh   ri   rp   r   r   _cleanup_taskr   assertNotInr!   r3   rp   r   s       r"   (test_cleanup_task_deletes_reserved_entryz8TestCleanupTask.test_cleanup_task_deletes_reserved_entry  s     Jx||~OgOgOi)jkl'7 	,""7+	, %%'%+>wiGr)st		, 	,s   BBc           	      H   d}| j                  ||dddt        j                         j                         di       ddl}t        d| j                        5  |j                  |       ddd       | j                         }| j                  ||d	| d
       y# 1 sw Y   1xY w)u  
        테스트 4: _cleanup_task()가 running 상태 엔트리를 삭제하는지 확인.

        task-timer 자동 시작 도입으로 dispatch 실패 시 이미 running 상태일 수 있음.
        _cleanup_task()는 running 상태도 삭제 대상이어야 한다.
        z	task-11.1r\   u   실패한 작업r^   r_   r   Nr:   u   running 상태의 r   r   r   s       r"   'test_cleanup_task_deletes_running_entryz7TestCleanupTask.test_cleanup_task_deletes_running_entry  s     &*#5'"*,,.":":"<
	
 	'7 	,""7+	, %%'%+=gYFq)rs		, 	,s   BB!c                 B   d}|ddddddd}| j                  ||i       d	d
l}t        d| j                        5  |j	                  |       d
d
d
       | j                         }| j                  ||d| d       | j                  ||   d   dd       y
# 1 sw Y   JxY w)u  
        테스트 5: _cleanup_task()가 completed 상태는 건너뛰는지 확인.

        completed 상태는 정상 종료된 작업이므로 삭제하면 안 된다.
        _cleanup_task() 호출 후에도 completed 엔트리가 그대로 남아있어야 한다.
        z	task-12.1r\   u   완료된 작업	completed2026-03-04T10:00:00z2026-03-04T11:00:00i  )r3   r`   ra   rb   rc   end_timeduration_secondsr   Nr:   u   completed 상태의 u1   는 _cleanup_task() 후에도 남아있어야 함rb   u;   completed 엔트리의 상태가 변경되어서는 안 됨)r   rp   r   r   r   r   r   rq   )r!   r3   completed_entryrp   r   s        r"   'test_cleanup_task_skips_completed_entryz7TestCleanupTask.test_cleanup_task_skips_completed_entry3  s     "-!/- $
 	9:'7 	,""7+	, %%'gu(<WIEv&wxw1;@}~	, 	,s   BBc                    d}| j                   dz  dz  j                  d       | j                  j                  t	        j
                  d|dt        j                         j                         dii      d	       | j                   dz  d
z  }d }ddl	}t        d| j                         5  t        d|      5  t        dddd      5  t        dd      5  t        d|      5  t        dd      5  t        d      5 }t        d|      5  |j                  dd      }ddd       ddd       ddd       ddd       ddd       ddd       ddd       ddd       | j                  d   d        j                  |       y# 1 sw Y   hxY w# 1 sw Y   lxY w# 1 sw Y   pxY w# 1 sw Y   txY w# 1 sw Y   xxY w# 1 sw Y   |xY w# 1 sw Y   xY w# 1 sw Y   xY w)!u   
        테스트 3+: cokacdir --cron 실패 시 _cleanup_task()가 호출되는지 확인.

        dispatch()에서 cokacdir 호출이 실패(returncode != 0)하면
        _cleanup_task(task_id)를 호출해야 한다.
        	task-20.1r   r   Tr   r   r   r   r   r   c                     dj                  d | D              }t               }d|v rd|v rd|_        d|_        d|_        |S d|_        t        j                  d	d
i      |_        d|_        |S )NrS   c              3   2   K   | ]  }t        |        y wr&   rU   rW   s     r"   rZ   zoTestCleanupTask.test_cleanup_task_called_on_dispatch_failure.<locals>.subprocess_side_effect.<locals>.<genexpr>a  r   r[   r   r   r7   r.      연결 실패r   rb   okre   r   r0   r1   r2   r   r   rj   rk   r   rm   s       r"   rn   z\TestCleanupTask.test_cleanup_task_called_on_dispatch_failure.<locals>.subprocess_side_effect`  sr    hh3s33G;DW$W)<"# -
 K #$"jj(D)9: Kr$   r   Nr:   r;   r<   r=   r>   r?   rB   rC   rD   rE   rG   rH   dispatch._cleanup_taskrI   rJ   r\   u   실패할 작업rb   error)r   r   r   r   r   r   r   rh   ri   rp   r   rq   assert_called_once_with)r!   r3   r   rn   rp   mock_cleanuprt   s          r"   ,test_cleanup_task_called_on_dispatch_failurez<TestCleanupTask.test_cleanup_task_called_on_dispatch_failureO  s     
	!G	+2242@""JJ'jQYQ]Q]Q_QiQiQk+l!mno 	# 	
 --(2_D	 	 &6	H'9	H %'WX	H $l3		H
 -GD	H )8PQ	H *+	H 0<+9OP	H &&{4FGF	H 	H 	H 	H 	H 	H 	H 	H 	)73 	,,W5#	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	Hs   +G8GGF5	#F)1F=FFF&F.F)6F5	>GGGF
FFFF&"F))F2.F5	5F>:GG
GG	GG"c           	         d}d}| j                  |dt        j                         j                         d||dt        j                         j                         di       ddl}t        d	| j                        5  |j                  |       ddd       | j                         }| j                  ||| d
       | j                  ||| d       y# 1 sw Y   FxY w)uj   
        _cleanup_task()가 지정된 task만 삭제하고 다른 task는 보존하는지 확인.
        z	task-30.1z	task-30.2r   r   r^   )r3   rb   rc   r   Nr:   u   가 삭제되어야 함u   는 삭제되지 않아야 함)r   r   rh   ri   rp   r   r   r   r   r   r   )r!   	target_idother_idrp   r   s        r"   *test_cleanup_task_only_deletes_target_taskz:TestCleanupTask.test_cleanup_task_only_deletes_target_task  s      	jAYAYA[\''"*,,.":":"<		
 	'7 	.""9-	. %%'Ei[8O+PQh(3Q'RS	. 	.s   ;CCc                     | j                  i        ddl}	 t        d| j                        5  |j	                  d       ddd       y# 1 sw Y   yxY w# t
        $ r}| j                  d|        Y d}~yd}~ww xY w)u}   
        _cleanup_task()에 존재하지 않는 task_id를 전달해도 예외 없이 정상 종료되어야 한다.
        r   Nr:   ztask-nonexistent-999.1u.   _cleanup_task()가 예외를 발생시켰음: )r   rp   r   r   r   	Exceptionfail)r!   rp   es      r"   +test_cleanup_task_nonexistent_task_no_errorz;TestCleanupTask.test_cleanup_task_nonexistent_task_no_error  sz     	r"	L+T]]; A&&'?@A A A 	LIIFqcJKK	Ls3   A AA AA A 	A;A66A;N)r   r   r   r   r#   r)   dictr   r   r   r   r   r   r   r   r   r$   r"   r   r      sN    1Hqt q%$ %
u$t8826hT6Lr$   r   c                   X    e Zd ZdZd Zd ZdededefdZdede	fdZ
d	 Zd
 Zd Zd Zy)TestCleanupTaskStatusCoverageu.   _cleanup_task() 상태별 동작 종합 확인c                     t        j                         | _        t        | j                  j                        | _        | j
                  dz  j                  d       | j
                  dz  dz  | _        y r   r   r    s    r"   r#   z#TestCleanupTaskStatusCoverage.setUp  r   r$   c                 8    | j                   j                          y r&   r'   r    s    r"   r)   z&TestCleanupTaskStatusCoverage.tearDown  r*   r$   r3   rb   r   c                 F   ||d}|dk(  r&t        j                         j                         |d<   n9|dv r&t        j                         j                         |d<   n|dk(  r
d|d<   d|d	<   | j                  j	                  t        j                  d
||iidd      d       |S )uI   지정 상태의 task를 timer_file에 기록하고 task 데이터 반환)r3   rb   r   r   )r^   stalerc   r   z2026-03-04T09:00:00r   r   r   Fr   r   r   r   )r   rh   ri   r   r   r   r   )r!   r3   rb   ru   s       r"   _setup_taskz)TestCleanupTaskStatusCoverage._setup_task  s    !(F;
Z(0(@(@(BJ}%++'/||~'?'?'AJ|${"'<J|$%:Jz"""JJ':!67eTUVah 	# 	
 r$   c                     t        j                  | j                  j                  d            }||j	                  di       v S )Nr   r   r   r   )r!   r3   r   s      r"   _task_existsz*TestCleanupTaskStatusCoverage._task_exists  s8    zz$//33W3EF$((7B///r$   c                     d}| j                  |d       ddl}t        d| j                        5  |j	                  |       ddd       | j                  | j                  |      d       y# 1 sw Y   +xY w)u   reserved 상태 → 삭제z
task-100.1r   r   Nr:   u&   reserved 상태는 삭제되어야 함r   rp   r   r   r   assertFalser   r!   r3   rp   s      r"   test_reserved_is_deletedz6TestCleanupTaskStatusCoverage.test_reserved_is_deleted  sh    *-'7 	,""7+	,**735]^	, 	,   A++A4c                     d}| j                  |d       ddl}t        d| j                        5  |j	                  |       ddd       | j                  | j                  |      d       y# 1 sw Y   +xY w)u   running 상태 → 삭제z
task-101.1r^   r   Nr:   u%   running 상태는 삭제되어야 함r   r   s      r"   test_running_is_deletedz5TestCleanupTaskStatusCoverage.test_running_is_deleted  sh    ),'7 	,""7+	,**735\]	, 	,r   c                     d}| j                  |d       ddl}t        d| j                        5  |j	                  |       ddd       | j                  | j                  |      d       y# 1 sw Y   +xY w)u   completed 상태 → 보존z
task-102.1r   r   Nr:   u'   completed 상태는 보존되어야 함r   rp   r   r   r   
assertTruer   r   s      r"   test_completed_is_preservedz9TestCleanupTaskStatusCoverage.test_completed_is_preserved  sf    +.'7 	,""7+	,))'24]^	, 	,r   c                     d}| j                  |d       ddl}t        d| j                        5  |j	                  |       ddd       | j                  | j                  |      d       y# 1 sw Y   +xY w)u.   stale 상태 → 보존 (정리 대상 아님)z
task-103.1r   r   Nr:   u#   stale 상태는 보존되어야 함r   r   s      r"   test_stale_is_preservedz5TestCleanupTaskStatusCoverage.test_stale_is_preserved  sf    '*'7 	,""7+	,))'24YZ	, 	,r   N)r   r   r   r   r#   r)   rV   r   r   boolr   r   r   r   r   r   r$   r"   r   r     sU    8H3    0C 0D 0_^_[r$   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestCleanupUsesTimerTaskIduD   _cleanup_task가 timer_task_id (= task_id)로 호출되는지 확인c                    t        j                         | _        t        | j                  j                        | _        | j
                  dz  j                  d       | j
                  dz  dz  j                  d       | j
                  dz  dz  | _        | j                  j                  t        j                  di i      d       | j
                  dz  dz  | _        y 	Nr   Tr   r   r   r   r   r   r   r    s    r"   r#   z TestCleanupUsesTimerTaskId.setUp      224T\\../		!(((6		!G	+2242@--(25GG""4::wm#<w"O#}}x7/Ir$   c                 8    | j                   j                          y r&   r'   r    s    r"   r)   z#TestCleanupUsesTimerTaskId.tearDown  r*   r$   c                    d}d}d }ddl }t        d| j                        5  t        d| j                        5  t        ddd	d
      5  t        dd      5  t        d|      5  t        dd      5  t        d      5 }t        d|      5  |j                  dd      }ddd       ddd       ddd       ddd       ddd       ddd       ddd       ddd       | j	                  d   d       j                  |       y# 1 sw Y   hxY w# 1 sw Y   lxY w# 1 sw Y   pxY w# 1 sw Y   txY w# 1 sw Y   xxY w# 1 sw Y   |xY w# 1 sw Y   xY w# 1 sw Y   xY w)u\   task_id에 점이 없는 경우(task-20), _cleanup_task가 task-20으로 호출되어야 함ztask-20c                     dj                  d | D              }t               }d|v rd|v rd|_        d|_        d|_        |S d|_        t        j                  d	d
i      |_        d|_        |S )NrS   c              3   2   K   | ]  }t        |        y wr&   rU   rW   s     r"   rZ   z}TestCleanupUsesTimerTaskId.test_cleanup_uses_timer_task_id_not_raw_task_id.<locals>.subprocess_side_effect.<locals>.<genexpr>  r   r[   r   r   r7   r.   r   r   rb   r   r   r   s       r"   rn   zjTestCleanupUsesTimerTaskId.test_cleanup_uses_timer_task_id_not_raw_task_id.<locals>.subprocess_side_effect  r    hh3s33G;DW$W)<"# -
 K #$"jj(D)9: Kr$   r   Nr:   r;   r<   r=   r>   r?   rB   rC   rD   rE   rG   rH   r   rI   rJ   r\      실패 테스트rb   r   rp   r   r   r   rq   r   )r!   r3   expected_timer_task_idrn   rp   r   rt   s          r"   /test_cleanup_uses_timer_task_id_not_raw_task_idzJTestCleanupUsesTimerTaskId.test_cleanup_uses_timer_task_id_not_raw_task_id  s   !*	 	 &6	H')=)=>	H %'WX	H $l3		H
 -GD	H )8PQ	H *+	H 0<+9OP	H &&{4FGF	H 	H 	H 	H 	H 	H 	H 	H 	)73,,-CD	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	Hs   EE	ED6	$D*2D>DDD'D/D*7D6	?EEEDDDDD'#D**D3/D6	6D?;EEEE	EE#c                    d}d }ddl }t        d| j                        5  t        d| j                        5  t        ddd	d
      5  t        dd      5  t        d|      5  t        dd      5  t        d      5 }t        d|      5  |j                  dd      }ddd       ddd       ddd       ddd       ddd       ddd       ddd       ddd       | j	                  d   d       j                  |       y# 1 sw Y   hxY w# 1 sw Y   lxY w# 1 sw Y   pxY w# 1 sw Y   txY w# 1 sw Y   xxY w# 1 sw Y   |xY w# 1 sw Y   xY w# 1 sw Y   xY w)uP   task_id에 점이 있는 경우(task-20.1), _cleanup_task도 task-20.1로 호출r   c                     dj                  d | D              }t               }d|v rd|v rd|_        d|_        d|_        |S d|_        t        j                  d	d
i      |_        d|_        |S )NrS   c              3   2   K   | ]  }t        |        y wr&   rU   rW   s     r"   rZ   zsTestCleanupUsesTimerTaskId.test_cleanup_with_dotted_task_id_same.<locals>.subprocess_side_effect.<locals>.<genexpr>/  r   r[   r   r   r7   r.   r   r   rb   r   r   r   s       r"   rn   z`TestCleanupUsesTimerTaskId.test_cleanup_with_dotted_task_id_same.<locals>.subprocess_side_effect.  r   r$   r   Nr:   r;   r<   r=   r>   r?   rB   rC   rD   rE   rG   rH   r   rI   rJ   r\   r   rb   r   r  r!   r3   rn   rp   r   rt   s         r"   %test_cleanup_with_dotted_task_id_samez@TestCleanupUsesTimerTaskId.test_cleanup_with_dotted_task_id_same*  s   	 	 &6	H')=)=>	H %'WX	H $l3		H
 -GD	H )8PQ	H *+	H 0<+9OP	H &&{4FGF	H 	H 	H 	H 	H 	H 	H 	H 	)73,,W5	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	H 	Hs   EEE D4	"D(0D<D
DD%D-D(5D4	=E EED	DDDD%!D((D1-D4	4D=9E  E	EE	EE!N)r   r   r   r   r#   r)   r  r  r   r$   r"   r   r     s    NJ"EH!6r$   r   c                   "    e Zd ZdZd Zd Zd Zy)TestCleanupOnBotIdMissingu>   bot_id 미할당 시에도 _cleanup_task 호출 확인 (Fix 2)c                    t        j                         | _        t        | j                  j                        | _        | j
                  dz  j                  d       | j
                  dz  dz  j                  d       | j
                  dz  dz  | _        | j                  j                  t        j                  di i      d       | j
                  dz  dz  | _        y r   r   r    s    r"   r#   zTestCleanupOnBotIdMissing.setUpQ  r   r$   c                 8    | j                   j                          y r&   r'   r    s    r"   r)   z"TestCleanupOnBotIdMissing.tearDownZ  r*   r$   c                 6   d}d }ddl }t        d| j                        5  t        d| j                        5  t        ddd	i      5  t        d
ddi      5  t        dd      5  t        d|      5  t        dd      5  t        d      5 }t        d|      5  |j                  dd      }ddd       ddd       ddd       ddd       ddd       ddd       ddd       ddd       ddd       | j	                  d   d       | j                  d|d          j                  |       y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY w)uO   TEAM_BOT에 매핑이 있지만 BOT_KEYS에 없는 경우 cleanup 호출 확인z	task-50.1c                 n    t               }d|_        t        j                  ddi      |_        d|_        |S )Nr   rb   r   r.   r/   )rj   rk   rm   s      r"   rn   ziTestCleanupOnBotIdMissing.test_cleanup_called_when_bot_id_not_in_bot_keys.<locals>.subprocess_side_effecta  s1    ;DDO**h%56DKDKKr$   r   Nr:   r;   r<   rA   r>   zdispatch.TEAM_BOTr\   r@   rB   rC   rD   rE   rG   rH   r   rI   rJ   u   bot_id 없는 테스트rb   r   u   봇이 없습니다message)rp   r   r   r   rq   r   r   r  s         r"   /test_cleanup_called_when_bot_id_not_in_bot_keyszITestCleanupOnBotIdMissing.test_cleanup_called_when_bot_id_not_in_bot_keys]  s   	 	 &6	O')=)=>	O %~'>?	O %V'<=		O
 $l3	O -GD	O )8PQ	O *+	O 0<+9OP	O &&{4MNF	O 	O 	O 	O 	O 	O 	O 	O 	O 	)73+VI->?,,W5!	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	O 	Os   FFE7E+	"E0E>E
D;D/+D;3E;EEE+	E7F#F/D84D;;E EEEEEE($E+	+E40E77F <FF	FFN)r   r   r   r   r#   r)   r  r   r$   r"   r
  r
  N  s    HJ6r$   r
  c                   (    e Zd ZdZd Zd Zd Zd Zy)TestGenerateTaskIdCorrupteduI   generate_task_id() - 파일 손상 시 RuntimeError 발생 확인 (Fix 6)c                     t        j                         | _        t        | j                  j                        | _        | j
                  dz  j                  d       | j
                  dz  dz  | _        y r   r   r    s    r"   r#   z!TestGenerateTaskIdCorrupted.setUp  r   r$   c                 8    | j                   j                          y r&   r'   r    s    r"   r)   z$TestGenerateTaskIdCorrupted.tearDown  r*   r$   c                 Z   | j                   j                  dd       ddl}t        d| j                        5  | j                  t              5 }|j                          ddd       | j                  dt        j                               ddd       y# 1 sw Y   7xY w# 1 sw Y   yxY w)u>   파일이 존재하지만 손상된 경우 RuntimeError 발생zNOT VALID JSON {{{r   r   r   Nr:   u   손상)r   r   rp   r   r   assertRaisesRuntimeErrorgenerate_task_idr   rV   	exception)r!   rp   ctxs      r"   (test_corrupted_file_raises_runtime_errorzDTestGenerateTaskIdCorrupted.test_corrupted_file_raises_runtime_error  s    ""#7'"J'7 	8""<0 ,C))+,MM(C$67	8 	8, ,	8 	8s#   B!B-B!B	B!!B*c                    | j                   j                         r| j                   j                          ddl}t	        d| j
                        5  |j                         }ddd       | j                  d       y# 1 sw Y   xY w)u3   파일이 없으면 task-1.1 반환 (정상 동작)r   Nr:   rP   )r   existsunlinkrp   r   r   r  rq   )r!   rp   rt   s      r"   &test_nonexistent_file_returns_task_1_1zBTestGenerateTaskIdCorrupted.test_nonexistent_file_returns_task_1_1  sg    ??!!#OO""$'7 	1..0F	1,	1 	1s   A;;BN)r   r   r   r   r#   r)   r  r  r   r$   r"   r  r  }  s    SH	8	-r$   r  __main__r   )	verbosity)r   r   sysr   unittestr   pathlibr   unittest.mockr   r   r   pathinsertTestCaser	   r   r   r   r
  r  r   mainr   r$   r"   <module>r*     s     
     0 0 ( )V
H-- V
r{Lh'' {L|F[H$5$5 F[RT6!2!2 T6n,6 1 1 ,6^ -("3"3  -F zHMMA r$   