
    ilP                        d Z ddlZddlZddlZddlmZ ddlmZmZ ddl	Z	 ee
      j                  j                  ZddlZedz  Zej                   j#                  de      ZeJ ej                   j'                  e      Zej*                  J ej*                  j-                  e        G d d      Z G d	 d
      Z G d d      Zy)u/  
test_done_protocol.py

.done 프로토콜 수정 검증 테스트 (task-616.1 설계 반영)

테스트 항목:
- log_protocol() 단위 테스트
- 통합 테스트 시나리오 (새 설계: send_telegram_notification 기반)
- done-watcher 로직 시뮬레이션 (새 설계: escalation/acked 기반)
    N)Path)	MagicMockpatchnotify-completion.pynotify_completionc                   @    e Zd ZdZdeddfdZdeddfdZdeddfdZy)TestLogProtocolu&   log_protocol() 함수 단위 테스트tmp_pathreturnNc                     |dz  }|j                         rJ t        j                  t        dt	        |            5  t        j                  dd       ddd       |j                         sJ y# 1 sw Y   xY w)u   로그 파일 자동 생성done-protocol.logDONE_PROTOCOL_LOGz
task-010.1ztest messageN)existsr   objectr   strlog_protocol)selfr
   log_paths      Q/home/jay/workspace/.worktrees/task-2116-dev1/scripts/tests/test_done_protocol.pytest_creates_log_filez%TestLogProtocol.test_creates_log_file%   sl    11??$$$\\+-@#h-P 	I**<H	I   	I 	Is   A..A7c                 F   |dz  }t        j                  t        dt        |            5  t        j	                  dd       ddd       |j                  d      }d|v sJ d|v sJ d|v sJ |j                         }|j                  d	      sJ d
|v sJ y# 1 sw Y   WxY w)u5   [ISO8601] [notify-completion] task_id: message 포맷r   r   z
task-011.1u   상태 전이 완료Nutf-8encodingz[notify-completion][u6   ] [notify-completion] task-011.1: 상태 전이 완료)r   r   r   r   r   	read_textstrip
startswith)r   r
   r   contentlines        r   test_log_formatzTestLogProtocol.test_log_format-   s    11\\+-@#h-P 	Q**<9OP	Q$$g$6$///w&&&%000}}s###G4OOO	Q 	Qs   BB c                    |dz  }|j                  dd       t        j                  t        dt	        |            5  t        j                  dd       ddd       |j                  d      }d	|v sJ d|v sJ |j                         D cg c]  }|j                         s| }}t        |      d
k(  sJ y# 1 sw Y   fxY wc c}w )u.   기존 로그에 추가 (덮어쓰기 안 함)r   u   [기존 로그 항목]
r   r   r   z
task-012.1u
   새 항목Nu   [기존 로그 항목]   )

write_textr   r   r   r   r   r   
splitlinesr   len)r   r
   r   r   lliness         r   test_appends_to_existing_logz,TestLogProtocol.test_appends_to_existing_log<   s    116I\\+-@#h-P 	G**<F	G$$g$6'7222w&&&#..0>qAGGI>>5zQ	G 	G
 ?s   B9C"C9C)__name__
__module____qualname____doc__r   r   r!   r)        r   r	   r	   "   sA    0!d !t !P P P
T 
d 
r/   r	   c                       e Zd ZdZ ed      dededdfd       Z ed      dededdfd       Zdeddfd	Z	 ed      dededdfd
       Z
 ed      dededdfd       Z ed      dededdfd       Zy)TestDoneProtocolIntegrationuA   통합 테스트 시나리오 (새 설계: .done.notified 없음)subprocess.runmock_runr
   r   Nc           	         dt         dt         dt         dt        fd}||_        |dz  dz  j                  dd	       t	        d
ddg      5  t	        j
                  dddi      5  t	        j                   t        dt        |            5  t        j                          ddd       ddd       ddd       |j                  D cg c]*  }t        |d   d   t              s|d   d   d   dk(  s)|, }}t        |      dk\  sJ d       |d   d   d   }dj                  d |D              }d|v sJ d       d|v sJ d       d|v r|j                  d      nd}|dk\  r$|dz   t        |      k  r||dz      }	d|	vsJ d       |dz  dz  }
|
dz  j                         rJ d        y# 1 sw Y   
xY w# 1 sw Y   xY w# 1 sw Y   xY wc c}w )!uO   정상 플로우: send_telegram_notification 호출, wake_anu_session 미호출cmdargskwargsr   c                 L   t               }d|_        d|_        t        | t              r_dj                  d | D              }d|v r%d|v r!t        j                  ddd d d      |_        |S t        j                  d	d
i      |_        |S t        j                  d	d
i      |_        |S )Nr     c              3   2   K   | ]  }t        |        y wNr   .0cs     r   	<genexpr>zhTestDoneProtocolIntegration.test_normal_flow_sends_telegram_only.<locals>.side_effect.<locals>.<genexpr>U        "7a3q6"7   chain_manager.pycheckFin_chainis_lastchain_idnext_task_idstatusok	r   
returncodestderr
isinstancelistjoinjsondumpsstdoutr5   r6   r7   resultcmd_strs        r   side_effectzUTestDoneProtocolIntegration.test_normal_flow_sends_telegram_only.<locals>.side_effectP       [F !FFM#t$(("73"77%0W5G$(JJ%*u$`de%FM M %)JJ$/?$@FM M !%

Hd+; <Mr/   memoryeventsTparentsexist_oksys.argvr   z
task-030.1
os.environCOKACDIR_KEY_ANUtest-keyWORKSPACE_ROOTNr   cokacdir   u;   send_telegram_notification(cokacdir)가 호출되어야 함r:   c              3   2   K   | ]  }t        |        y wr<   r=   )r?   xs     r   rA   zSTestDoneProtocolIntegration.test_normal_flow_sends_telegram_only.<locals>.<genexpr>p   s     #AqCF#ArC   u+   메시지에 task_id가 포함되어야 함   완료u,   메시지에 '완료'가 포함되어야 함--cron
done.clearu?   wake_anu_session의 구형 프롬프트가 전송되면 안 됨ztask-030.1.done.notified-   .done.notified 파일이 생성되면 안 됨)r   r   rY   mkdirr   dictr   r   maincall_args_listrP   rQ   r&   rR   indexr   )r   r3   r
   rY   r@   cokacdir_callscokacdir_cmdcokacdir_cmd_strcron_idxmsg
events_dirs              r   $test_normal_flow_sends_telegram_onlyz@TestDoneProtocolIntegration.test_normal_flow_sends_telegram_onlyL   s   	V 	F 	f 	 	   +	H	x	'..td.K *5|DE	%JJ|&8*%EF	% LL*,<c(mL	%
 ""$	% 	% 	% &.%<%<w
1Q4PQ7TX@Y^_`a^bcd^efg^hlv^v!ww>"a'f)ff' &a(+A.88#AL#AA//^1^^/++[-[[+ 4<|3K<%%h/QSq=X\C,==x!|,Cs*m,mm* (83
!;;CCEvGvvEE5	% 	% 	% 	% 	% 	% xsN   G $%F3	F&F3&G G G/G&F0+F33F=	8G  G
c           	         dt         dt         dt         dt        fd}||_        |dz  dz  j                  dd	       t	        d
ddg      5  t	        j
                  dddi      5  t	        j                   t        dt        |            5  t        j                          ddd       ddd       ddd       |dz  dz  }|dz  j                         rJ d       |j                  D cg c]D  }t        |d   d   t              r,t        |d   d         dk\  rdt        |d   d   d         v r|F }}t        |      dk\  sJ d       |j                  D cg c]*  }t        |d   d   t              s|d   d   d   dk(  s)|, }}t        |      dk\  sJ d       y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY wc c}w c c}w )uZ   체인 중간: dispatch(bash) 호출, 텔레그램 알림 전송, .done.notified 미생성r5   r6   r7   r   c                 &   t               }d|_        d|_        t        | t              rdj                  d | D              }d|v r%d|v r!t        j                  ddd	d
d      |_        |S d|v r%d|v r!t        j                  dddd
d      |_        |S d|v rt        j                  ddi      |_        |S d|v rt        j                  ddi      |_        |S t        j                  ddi      |_        |S t        j                  ddi      |_        |S )Nr   r9   r:   c              3   2   K   | ]  }t        |        y wr<   r=   r>   s     r   rA   zsTestDoneProtocolIntegration.test_chain_middle_dispatches_and_sends_telegram.<locals>.side_effect.<locals>.<genexpr>   rB   rC   rD   rE   TFz	chain-031z
task-031.2rF   nextdispatchzmemory/tasks/task-031.2.mdz	dev1-team)action	task_fileteamtask_idbashrK   
dispatchedre   rL   rM   rV   s        r   rY   z`TestDoneProtocolIntegration.test_chain_middle_dispatches_and_sends_telegram.<locals>.side_effect   s,   [F !FFM#t$(("73"77%0W5G$(JJ(,',(3,8	%FM2 M# (72v7H$(JJ&0)E$/'3	%FM  M w&$(JJ,/G$HFM M  7*$(JJ$/?$@FM
 M %)JJ$/?$@FM M !%

Hd+; <Mr/   r[   r\   Tr]   r`   r   z
task-031.1ra   rb   rc   rd   Nztask-031.1.done.notifiedu0   체인 중간에서 .done.notified 생성 금지r   r#   r   rf   u-   dispatch(bash -c ...) 호출이 있어야 함re   uA   체인 중간에서도 텔레그램 알림이 전송되어야 함)r   r   rY   rn   r   ro   r   r   rp   r   rq   rP   rQ   r&   )r   r3   r
   rY   rx   r@   
bash_callsrs   s           r   /test_chain_middle_dispatches_and_sends_telegramzKTestDoneProtocolIntegration.test_chain_middle_dispatches_and_sends_telegram   s    	V  	F  	f  	  	D  +	H	x	'..td.K *5|DE	%JJ|&8*%EF	% LL*,<c(mL	%
 ""$	% 	% 	% (83
 !;;CCEyGyyE
 ,,
!A$q'4(S1a\Q->6SQRSTQUVWQXYZQ[_C\ 

 

 :!#T%TT# &.%<%<w
1Q4PQ7TX@Y^_`a^bcd^efg^hlv^v!ww>"a'l)ll'-	% 	% 	% 	% 	% 	%
 xsU   F4$%F'	FF'&F4&A	GG0G?GF$ F''F1	,F44F>c           
      z   dt         dt         dt         dt        fd}|dz  dz  }|j                  dd	       |d
z  }|j                  t	        j
                  ddd      d       t        d|      5  t        dddg      5  t        j                  dddi      5  t        j                   t        dt        |            5  t        j                          ddd       ddd       ddd       ddd       |j                         sJ d       y# 1 sw Y   9xY w# 1 sw Y   =xY w# 1 sw Y   AxY w# 1 sw Y   ExY w)u8   .done 파일은 notification 후에도 events/에 유지r5   r6   r7   r   c                 L   t               }d|_        d|_        t        | t              r_dj                  d | D              }d|v r%d|v r!t        j                  ddd d d      |_        |S t        j                  d	d
i      |_        |S t        j                  d	d
i      |_        |S )Nr   r9   r:   c              3   2   K   | ]  }t        |        y wr<   r=   r>   s     r   rA   zhTestDoneProtocolIntegration.test_done_file_survives_notification.<locals>.side_effect.<locals>.<genexpr>   rB   rC   rD   rE   FrF   rK   rL   rM   rV   s        r   rY   zUTestDoneProtocolIntegration.test_done_file_survives_notification.<locals>.side_effect   rZ   r/   r[   r\   Tr]   ztask-033.1.donez
task-033.1	completedr   rK   r   r   r2   )rY   r`   r   ra   rb   rc   rd   NuE   .done 파일이 notification 후에도 events/에 유지되어야 함)r   r   rn   r$   rS   rT   r   ro   r   r   rp   r   )r   r
   rY   rx   	done_paths        r   $test_done_file_survives_notificationz@TestDoneProtocolIntegration.test_done_file_survives_notification   s@   	V 	F 	f 	 	  (83
5!22	JJ<;GH 	 	
 "<	%*5|DE	% JJ|&8*%EF	% LL*,<c(mL		% ""$	% 	% 	% 	% !j#jj!	% 	% 	% 	% 	% 	% 	% 	%sT   3D1D%%D D	DD%%D1DDD"D%%D.	*D11D:c           	         dt         dt         dt         dt        fd}||_        |dz  dz  }|j                  dd	       |d
z  }t	        j
                  ddd      }|j                  |d       t        dddg      5  t        j                  dddi      5  t        j                   t        dt        |            5  t        j                          ddd       ddd       ddd       |j                         sJ d       |j                  d      |k(  sJ d       |dz  j                         rJ d       y# 1 sw Y   gxY w# 1 sw Y   kxY w# 1 sw Y   oxY w)u4   .done 파일이 rename/삭제되지 않는지 확인r5   r6   r7   r   c                 L   t               }d|_        d|_        t        | t              r_dj                  d | D              }d|v r%d|v r!t        j                  ddd d d      |_        |S t        j                  d	d
i      |_        |S t        j                  d	d
i      |_        |S )Nr   r9   r:   c              3   2   K   | ]  }t        |        y wr<   r=   r>   s     r   rA   zrTestDoneProtocolIntegration.test_done_file_not_modified_after_notification.<locals>.side_effect.<locals>.<genexpr>   rB   rC   rD   rE   FrF   rK   rL   rM   rV   s        r   rY   z_TestDoneProtocolIntegration.test_done_file_not_modified_after_notification.<locals>.side_effect   rZ   r/   r[   r\   Tr]   ztask-034.1.donez
task-034.1r   r   r   r   r`   r   ra   rb   rc   rd   Nu$   .done 파일이 삭제되면 안 됨u+   .done 파일 내용이 변경되면 안 됨ztask-034.1.done.clearu*   .done.clear 파일이 생성되면 안 됨)r   r   rY   rn   rS   rT   r$   r   ro   r   r   rp   r   r   )r   r3   r
   rY   rx   r   original_contents          r   .test_done_file_not_modified_after_notificationzJTestDoneProtocolIntegration.test_done_file_not_modified_after_notification   sk   	V 	F 	f 	 	   +(83
5!22	::,+&VW-@ *5|DE	%JJ|&8*%EF	% LL*,<c(mL	%
 ""$	% 	% 	% !I#II!""G"48HHwJwwH!88@@BpDppBB	% 	% 	% 	% 	% 	%s<   =E%E;D6EE6D?;EE	EEc           	         dt         dt         dt         dt        fd}||_        |dz  dz  }|j                  dd	       t	        d
ddg      5  t	        j
                  dddi      5  t	        j                   t        dt        |            5  t        j                          ddd       ddd       ddd       |dz  j                         rJ d       y# 1 sw Y   4xY w# 1 sw Y   8xY w# 1 sw Y   <xY w)u=   .done.notified 파일이 절대 생성되지 않는지 확인r5   r6   r7   r   c                 L   t               }d|_        d|_        t        | t              r_dj                  d | D              }d|v r%d|v r!t        j                  ddd d d      |_        |S t        j                  d	d
i      |_        |S t        j                  d	d
i      |_        |S )Nr   r9   r:   c              3   2   K   | ]  }t        |        y wr<   r=   r>   s     r   rA   zaTestDoneProtocolIntegration.test_no_done_notified_created.<locals>.side_effect.<locals>.<genexpr>  rB   rC   rD   rE   FrF   rK   rL   rM   rV   s        r   rY   zNTestDoneProtocolIntegration.test_no_done_notified_created.<locals>.side_effect  rZ   r/   r[   r\   Tr]   r`   r   z
task-035.1ra   rb   rc   rd   Nztask-035.1.done.notifiedrm   )
r   r   rY   rn   r   ro   r   r   rp   r   )r   r3   r
   rY   rx   s        r   test_no_done_notified_createdz9TestDoneProtocolIntegration.test_no_done_notified_created  s    	V 	F 	f 	 	   +(83
5 *5|DE	%JJ|&8*%EF	% LL*,<c(mL	%
 ""$	% 	% 	% !;;CCEvGvvEE	% 	% 	% 	% 	% 	%s<   C+&%CC C(C+CCC(	$C++C4c           	      H   dt         dt         dt         dt        fd}||_        |dz  dz  }|j                  dd	       t	        d
ddg      5  t	        j
                  dddi      5  t	        j                   t        dt        |            5  t        j                          ddd       ddd       ddd       |j                  D cg c]*  }t        |d   d   t              s|d   d   d   dk(  s)|, }}t        |      dk\  sJ d       |d   d   d   }d|v r|j                  d      nd}|dk\  sJ d       ||dz      }	d|	v s
J d|	        d|	v s
J d|	        d|	vs
J d|	        d|	vs
J d|	        y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   xY wc c}w ) uT   독립 작업에서 send_telegram이 호출되고 wake_anu가 호출되지 않는지r5   r6   r7   r   c                 L   t               }d|_        d|_        t        | t              r_dj                  d | D              }d|v r%d|v r!t        j                  ddd d d      |_        |S t        j                  d	d
i      |_        |S t        j                  d	d
i      |_        |S )Nr   r9   r:   c              3   2   K   | ]  }t        |        y wr<   r=   r>   s     r   rA   zqTestDoneProtocolIntegration.test_independent_task_sends_telegram_not_wake.<locals>.side_effect.<locals>.<genexpr><  rB   rC   rD   rE   FrF   rK   rL   rM   rV   s        r   rY   z^TestDoneProtocolIntegration.test_independent_task_sends_telegram_not_wake.<locals>.side_effect7  rZ   r/   r[   r\   Tr]   r`   r   z
task-036.1ra   rb   rc   rd   Nr   re   rf   uE   독립 작업에서 send_telegram_notification이 호출되어야 함rj   rk   u#   cokacdir 명령에 --cron이 없음u    메시지에 task_id가 없음: ri   u!   메시지에 '완료'가 없음: rl   u3   wake_anu_session 구형 프롬프트가 전송됨: zdone.notifiedu-   done.notified 참조 메시지가 전송됨: )r   r   rY   rn   r   ro   r   r   rp   rq   rP   rQ   r&   rr   )
r   r3   r
   rY   rx   r@   rs   rt   rv   rw   s
             r   -test_independent_task_sends_telegram_not_wakezITestDoneProtocolIntegration.test_independent_task_sends_telegram_not_wake3  s   	V 	F 	f 	 	   +(83
5 *5|DE	%JJ|&8*%EF	% LL*,<c(mL	%
 ""$	% 	% 	% &.%<%<w
1Q4PQ7TX@Y^_`a^bcd^efg^hlv^v!ww>"a'p)pp' &a(+A.3;|3K<%%h/QS1}CCC}8a<(s"L&Fse$LL"3I"CC5 II 3&c*]^a]b(cc&c)`-Z[^Z_+``)+	% 	% 	% 	% 	% 	% xsN   F&%FE; F(FF"F1F;F FF	FF)r*   r+   r,   r-   r   r   r   ry   r   r   r   r   r   r.   r/   r   r1   r1   I   s+   K
0wY 0wRV 0w[_ 0w 0wd >m	 >m]a >mfj >m >m@$kT $kd $kL 'qy 'q\` 'qei 'q 'qR  wi  w4  wTX  w  wD -ai -a[_ -adh -a -ar/   r1   c                       e Zd ZdZ	 ddededededef
dZdededed	edef
d
Z	deddfdZ
deddfdZdeddfdZdeddfdZy)TestDoneWatcherLogicuR   done-watcher 새 설계 로직 시뮬레이션 테스트 (escalation/acked 기반)rx   r   age_minutesescalation_thresholdr   c                 p    || dz  }|| dz  }|j                         sy|j                         ry||k\  S )u   
        .done 파일이 age_minutes 경과했을 때 에스컬레이션 여부 반환.
        threshold(기본 30분) 이상이면 True, 미만이면 False.
        .done.escalated가 이미 존재하면 중복 방지 → False.
        .done.done.escalatedF)r   )r   rx   r   r   r   r   escalated_paths          r   _simulate_stale_done_escalationz4TestDoneWatcherLogic._simulate_stale_done_escalationg  sP     G9E!22	#	&AA!  "222r/   archive_diracked_age_hoursc                     || dz  }|j                         sy|dk\  r+|j                  dd       |j                  || dz         yy)uf   
        .done.acked가 acked_age_hours 이상이면 archive로 이동. 이동 여부 반환.
        .done.ackedF   Tr]   )r   rn   rename)r   rx   r   r   r   
acked_paths         r   _simulate_acked_cleanupz,TestDoneWatcherLogic._simulate_acked_cleanupx  s_      WI["99
  "b dT:kwi{,CCDr/   r
   Nc                     |dz  dz  }|j                  dd       d}|| dz  j                  dd	       | j                  ||d
      du sJ | j                  ||d      du sJ y)u0   .done 파일 30분 이상 → 에스컬레이션r[   r\   Tr]   z
task-050.1r   {}r   r      r   <   Nrn   r$   r   r   r
   rx   r   s       r   test_stale_done_escalationz/TestDoneWatcherLogic.test_stale_done_escalation  s    (83
5		'	'33D73K 33JUW3X\````33JUW3X\````r/   c                     |dz  dz  }|j                  dd       d}|| dz  j                  dd	       | j                  ||d
      du sJ | j                  ||d      du sJ y)u2   .done 파일 30분 미만 → 아무 동작 없음r[   r\   Tr]   z
task-051.1r   r   r   r      r   Fr   Nr   r   s       r   %test_stale_done_under_30min_no_actionz:TestDoneWatcherLogic.test_stale_done_under_30min_no_action  s    (83
5		'	'33D73K 33JUW3X\aaaa33JUV3W[````r/   c                     |dz  dz  }|j                  dd       d}|| dz  j                  dd	       || d
z  j                  dd	       | j                  ||d      du sJ y)u/   .done.escalated 존재 시 중복 알림 없음r[   r\   Tr]   z
task-052.1r   r   r   r   r   r   r   FNr   r   s       r   (test_escalated_marker_prevents_duplicatez=TestDoneWatcherLogic.test_escalated_marker_prevents_duplicate  s    (83
5		'	'33D73K		1	1==dW=U 33JUW3X\aaaar/   c                    |dz  dz  }|j                  dd       |dz  dz  }d}|| dz  j                  dd	
       | j                  |||d      }|du sJ || dz  j                         sJ d       | j                  |||d      }|du sJ || dz  j                         rJ d       || dz  j                         sJ d       y)u.   .done.acked 24시간 이상 → archive 이동r[   r\   Tr]   archivez
task-053.1r   r   r   r      )r   Fu2   24시간 미만에는 archive 이동 없어야 함r   u7   24시간 이상이면 events/에서 제거되어야 함u   archive/로 이동되어야 함N)rn   r$   r   r   )r   r
   rx   r   r   moveds         r   test_acked_cleanup_after_24hz1TestDoneWatcherLogic.test_acked_cleanup_after_24h  s   (83
5)I5		-	-99$9Q ,,Zg_a,b~~y44<<>t@tt> ,,Zg_a,b}}G9K!88@@B}D}}B	55==?bAbb?r/   )r   )r*   r+   r,   r-   r   r   intboolr   r   r   r   r   r   r.   r/   r   r   r   d  s    \ ]_33),3;>3VY3	3"$ T TW jm rv 
a4 
aD 
a
ad 
at 
a
b 
b$ 
bcT cd cr/   r   )r-   rS   ossyspathlibr   unittest.mockr   r   pytest__file__parent_SCRIPTS_DIRimportlib.util	importlib_MODULE_PATHutilspec_from_file_locationspecmodule_from_specr   loaderexec_moduler	   r1   r   r.   r/   r   <module>r      s   	  	 
  *  H~$$++ 44~~--.A<P NN33D9 {{    ) *$ $NXa XavWc Wcr/   