
    iF2                     N   d Z ddlZddlmc m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Z eej                  j                  dd            Z ee      e	j$                  vr"e	j$                  j'                  d ee             dede
j(                  fdZ ej,                         dede
j(                  fd	       Z ej,                         deddfd
       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 G d d      Z G d d      Z y)uz  
test_dispatch_resume_retry.py

dispatch.py --resume 옵션 (재시도 채번) 단위 테스트 (벨레스 작성)

테스트 항목:
- _resolve_resume(): 미완료 task → +1 채번
- _resolve_resume(): 2회 재시도 → +2 채번
- _resolve_resume(): 완료된 task (.done 존재) → 에러
- _resolve_resume(): base task 파일 없음 → 에러
- _resolve_resume(): 3회 이상 재시도 → 에러 (--force 없이)
- _resolve_resume(): 3회 이상 + --force → 성공
- _resolve_resume(): --resume과 --task-id 동시 → argparse 에러 (main 레벨)
- _resolve_resume(): task 파일 복사 + 재시도 메타 추가 확인
    N)PathWORKSPACE_ROOTz/home/jay/workspacetmp_pathreturnc                 >   t         }t        |      t        j                  vr)t        j                  j	                  dt        |             ddl}t        t        j                  j                               D ]  }|dk(  s	t        j                  |=  ddl	}| |_
        |S )uF   dispatch 모듈을 tmp_path를 WORKSPACE로 설정하여 로드한다.r   Ndispatch)
_WORKSPACEstrsyspathinsertprompts.team_promptslistmoduleskeysr   	WORKSPACE)r   	workspacepromptsmod_name	_dispatchs        7/home/jay/workspace/tests/test_dispatch_resume_retry.py_load_dispatch_with_workspacer      sx    I
9~SXX%3y>*))+, &z!H%& !"I    c                 |    | dz  dz  j                  dd       | dz  dz  j                  dd       t        |       S )u:   격리된 WORKSPACE를 사용하는 dispatch 모듈 반환memorytasksTparentsexist_okevents)mkdirr   )r   s    r   dispatch_modr"   .   sI     7"))$)F8#**4$*G(22r   c           
          | dz  dz  dz  }|j                  dd       | dz  dz  }|j                  t        j                  ddd	d
ddii      d       y)u,   base task 파일 + timers.json 기본 설정r   r   task-9999.mdu6   # task-9999: 테스트 작업

작업 내용입니다.utf-8encodingztask-timers.json	task-9999running	dev4-team   테스트 작업)statusteam_iddescriptionN)
write_textjsondumps)r   	task_filetimers_files      r   setup_base_taskr4   6   s~     8#g->IS^efX%(::K4::#&1
'    r   c                       e Zd ZdZdej
                  deddddfdZdej
                  deddddfdZdej
                  deddddfd	Z	y)
TestResolveResumeFirstRetryu8   base task가 미완료 상태일 때 +1로 채번된다.r"   r   r4   Nr   c                 ,   |j                  ddd      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }	t	        t        j
                  |	            dx}x}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }	t	        t        j
                  |	            dx}x}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }	t	        t        j
                  |	            dx}x}}y)u9   task-9999 미완료 → task-9999+1 채번, 결과 검증r(   r*   r+   base_task_idr-   	task_descr,   ok==z%(py1)s == %(py4)spy1py4assert %(py6)spy6Nnew_task_idtask-9999+1retry_count   _resolve_resume
@pytest_ar_call_reprcompare	_safereprAssertionError_format_explanation)
selfr"   r   r4   result@py_assert0@py_assert3@py_assert2@py_format5@py_format7s
             r   test_resolve_resume_first_retryz;TestResolveResumeFirstRetry.test_resolve_resume_first_retryP   s    --$( . 
 h'4'4''''4''''''4'''''''m$55$5555$555$5555555555m$))$))))$)))$))))))))))r   c                    |j                  ddd       |dz  dz  dz  }|j                  } |       }|st        j                  d      d	z   d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}y)u0   task-9999+1.md 파일이 생성되어야 한다.r(   r*   r+   r8   r   r   task-9999+1.mdu5   task-9999+1.md 파일이 생성되지 않았습니다C
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}new_filepy0py2rA   N)
rI   existsrJ   _format_assertmsg@py_builtinslocals_should_repr_global_namerL   rM   rN   )rO   r"   r   r4   rZ   @py_assert1rR   rT   s           r   ,test_resolve_resume_first_retry_creates_filezHTestResolveResumeFirstRetry.test_resolve_resume_first_retry_creates_file^   s     	$$$( 	% 	
 h&03CCY Y YY"YYYYYYYxYYYxYYYYYY YYYYYYr   c                    |j                  ddd       |dz  dz  dz  }|j                  d	      }d
}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d|iz  }	t        t        j                  |	            dx}}y)uD   생성된 파일에 '재시도' 텍스트가 포함되어야 한다.r(   r*   r+   r8   r   r   rX   r%   r&   	   재시도inz%(py1)s in %(py3)scontentr@   py3u9   생성된 파일에 '재시도' 텍스트가 없습니다
>assert %(py5)spy5N)rI   	read_textrJ   rK   rL   r`   ra   rb   r_   rM   rN   )
rO   r"   r   r4   rZ   rj   rQ   rS   @py_format4@py_format6s
             r   8test_resolve_resume_first_retry_file_contains_retry_textzTTestResolveResumeFirstRetry.test_resolve_resume_first_retry_file_contains_retry_textk   s     	$$$( 	% 	
 h&03CC$$g$6b{g%bbb{gbbb{bbbbbbgbbbgbbbb'bbbbbbbr   )
__name__
__module____qualname____doc__types
ModuleTyper   rV   rd   rr    r   r   r6   r6   M   s    B*!,,*8<*OS*	*Z!,,Z8<ZOSZ	Zc!,,c8<cOSc	cr   r6   c                   <    e Zd ZdZdej
                  deddddfdZy)TestResolveResumeSecondRetryu<   이미 +1 형제 파일이 존재할 때 +2로 채번된다.r"   r   r4   Nr   c                    |dz  dz  dz  }|j                  dd       |dz  dz  dz  }|j                  d	d       |j                  d
dd      }|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}	}y)u9   task-9999+1 존재 + retry_count=1 → task-9999+2 채번r   r   rX   #   # task-9999+1

첫 번째 재시도r%   r&   r    ztask-9999+1.retry_count1rE   r*   r+   r8   r,   r;   r<   r>   r?   rB   rC   NrD   task-9999+2rF      r/   rI   rJ   rK   rL   rM   rN   )rO   r"   r   r4   
plus1_fileretry_count_filerP   rQ   rR   rS   rT   rU   s               r    test_resolve_resume_second_retryz=TestResolveResumeSecondRetry.test_resolve_resume_second_retry   so   
 (725EE
EPWX $h.9<UU##C'#:--&( . 
 h'4'4''''4''''''4'''''''m$55$5555$555$5555555555m$))$))))$)))$))))))))))r   )rs   rt   ru   rv   rw   rx   r   r   ry   r   r   r{   r{      s0    F*!,,*8<*OS*	*r   r{   c                   <    e Zd ZdZdej
                  deddddfdZy)TestResolveResumeDoneTaskErroruJ   완료된 task (.done 파일 존재) 재시도 시 에러를 반환한다.r"   r   r4   Nr   c                 f   |dz  dz  dz  }|j                  dd       |j                  ddd	
      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}y)u5   memory/events/task-9999.done 존재 → 에러 반환r   r    ztask-9999.doneu   완료r%   r&   r(   r*   r+   r8   r,   errorr<   r>   r?   rB   rC   Nu   이미 완료된 작업messagerg   z%(py1)s in %(py4)sr   )rO   r"   r   r4   	done_filerP   rQ   rR   rS   rT   rU   s              r   #test_resolve_resume_done_task_errorzBTestResolveResumeDoneTaskError.test_resolve_resume_done_task_error   s     x'(25EE	X8--$( . 
 h*7*7****7******7*******(=F9,==(,=====(,====(===,========r   )rs   rt   ru   rv   rw   rx   r   r   ry   r   r   r   r      s0    T>!,,>8<>OS>	>r   r   c                   8    e Zd ZdZdej
                  deddfdZy) TestResolveResumeNoTaskFileErroru>   task 파일이 존재하지 않을 때 에러를 반환한다.r"   r   r   Nc                 *   |j                  ddd      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t	        t        j
                  |            dx}x}}d}|d   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t	        t        j
                  |            dx}x}}y)u%   task-9999.md 없음 → 에러 반환r(   r*   r+   r8   r,   r   r<   r>   r?   rB   rC   Nu   존재하지 않습니다r   rg   r   rH   )	rO   r"   r   rP   rQ   rR   rS   rT   rU   s	            r   &test_resolve_resume_no_task_file_errorzGTestResolveResumeNoTaskFileError.test_resolve_resume_no_task_file_error   s     --$( . 
 h*7*7****7******7********?fY.??*.?????*.????*???.????????r   )rs   rt   ru   rv   rw   rx   r   r   ry   r   r   r   r      s,    H@!,,@8<@	@r   r   c                   <    e Zd ZdZdej
                  deddddfdZy)%TestResolveResumeMaxRetryWithoutForceuA   3회 이상 재시도 시 force 없으면 에러를 반환한다.r"   r   r4   Nr   c                    dD ]+  }|dz  dz  d| dz  }|j                  d| d| dd	
       - |dz  dz  dz  }|j                  dd	
       |j                  dddd      }|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}
}	d}|d   }	||	v }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}
}	y)u?   retry_count=3, force=False → 에러 + '3회 이상' 메시지)rG   r   r   r   
task-9999+.md# task-9999+

   번째 재시도r%   r&   r    ztask-9999+2.retry_count2r   r*   r+   Fr9   r-   r:   forcer,   r   r<   r>   r?   rB   rC   Nu   3회 이상r   rg   r   r   rO   r"   r   r4   n	plus_filer   rP   rQ   rR   rS   rT   rU   s                r   +test_resolve_resume_max_retry_without_forcezQTestResolveResumeMaxRetryWithoutForce.test_resolve_resume_max_retry_without_force   sH   
  	^A 8+g5*QCs8KKI  <s$qc9I!JU\ ]	^
 $h.9<UU##C'#:--&(	 . 
 h*7*7****7******7*******1y 11} 11111} 1111}111 11111111r   )rs   rt   ru   rv   rw   rx   r   r   ry   r   r   r   r      s0    K2!,,28<2OS2	2r   r   c                   <    e Zd ZdZdej
                  deddddfdZy)"TestResolveResumeMaxRetryWithForceu=   3회 이상 재시도이지만 force=True이면 성공한다.r"   r   r4   Nr   c                    dD ]+  }|dz  dz  d| dz  }|j                  d| d| dd	
       - |dz  dz  dz  }|j                  dd	
       |j                  dddd      }|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}
}	|d   }d}	||	k(  }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}
}	y)u=   retry_count=3, force=True → 성공, new_task_id=task-9999+4)rG   r      r   r   r   r   r   r   r   r%   r&   r    ztask-9999+3.retry_count3ztask-9999+3r*   r+   Tr   r,   r;   r<   r>   r?   rB   rC   NrD   ztask-9999+4r   r   s                r   (test_resolve_resume_max_retry_with_forcezKTestResolveResumeMaxRetryWithForce.test_resolve_resume_max_retry_with_force   sH   
  	^A 8+g5*QCs8KKI  <s$qc9I!JU\ ]	^
 $h.9<UU##C'#:--&(	 . 
 h'4'4''''4''''''4'''''''m$55$5555$555$5555555555r   )rs   rt   ru   rv   rw   rx   r   r   ry   r   r   r   r      s0    G6!,,68<6OS6	6r   r   c                   <    e Zd ZdZdej
                  deddddfdZy)'TestResolveResumeWithExistingPlusSuffixu\   base_task_id가 task-9999+1로 들어올 때 +N 제거 후 원본 기준으로 채번한다.r"   r   r4   Nr   c                 h   |dz  dz  dz  }|j                  dd       |j                  ddd	
      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}y)u<   task-9999+1 입력 → base task-9999 기준으로 +2 채번r   r   rX   r}   r%   r&   rE   r*   r+   r8   r,   r;   r<   r>   r?   rB   rC   NrD   r   r   )rO   r"   r   r4   r   rP   rQ   rR   rS   rT   rU   s              r   -test_resolve_resume_with_existing_plus_suffixzUTestResolveResumeWithExistingPlusSuffix.test_resolve_resume_with_existing_plus_suffix  s    
 (725EE
EPWX--&( . 
 h'4'4''''4''''''4'''''''m$55$5555$555$5555555555r   )rs   rt   ru   rv   rw   rx   r   r   ry   r   r   r   r     s0    f6!,,68<6OS6	6r   r   c                   8    e Zd ZdZdej
                  deddfdZy)$TestResolveResumeTaskFileCopyContentua   task 파일 복사 시 원본 내용과 재시도 메타가 새 파일에 포함되어야 한다.r"   r   r   Nc                 n   d}|dz  dz  dz  }|dz  dz  j                  dd       |dz  dz  j                  dd       |j                  |d	       |j                  d
dd      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}|dz  dz  dz  }|j                  } |       }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j
                  |      ndt        j
                  |      t        j
                  |      dz  }	t        t        j                  |	            dx}}|j                  d	      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d       d!z   d"|iz  }t        t        j                  |            dx}}d#}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d$      d!z   d"|iz  }t        t        j                  |            dx}}y)%uR   새 파일에 원본 내용 + '재시도' 헤더가 모두 포함되어야 한다.uX   # task-9999: 오리지널 작업

이 내용이 새 파일에 복사되어야 합니다.r   r   r$   Tr   r    r%   r&   r(   r*   r+   r8   r,   r;   r<   r>   r?   rB   rC   NrX   u/   새 task 파일이 생성되지 않았습니다rY   rZ   r[   rf   rg   ri   new_contentrk   u'   재시도 메타 헤더가 없습니다rm   rn   u6   이 내용이 새 파일에 복사되어야 합니다.u-   원본 내용이 복사되지 않았습니다)r!   r/   rI   rJ   rK   rL   rM   rN   r^   r_   r`   ra   rb   ro   )rO   r"   r   original_contentr2   rP   rQ   rR   rS   rT   rU   rZ   rc   r   rp   rq   s                   r   *test_resolve_resume_task_file_copy_contentzOTestResolveResumeTaskFileCopyContent.test_resolve_resume_task_file_copy_content+  s   
 xx''1NB		H	w	&--dT-J	H	x	'..td.K-@--$( . 
 h'4'4''''4''''''4'''''''h&03CCS S SS"SSSSSSSxSSSxSSSSSS SSSSSS(('(: T{k)TTT{kTTT{TTTTTTkTTTkTTTT+TTTTTTT H  	HG;V  	H  	H  	HG;  	H  	H  	HG  	H  	H  	H  	H  	H  	H;  	H  	H  	H;  	H  	H  	H  	H  YH  	H  	H  	H  	H  	H  	Hr   )rs   rt   ru   rv   rw   rx   r   r   ry   r   r   r   r   (  s,    kH!,,H8<H	Hr   r   )!rv   builtinsr`   _pytest.assertion.rewrite	assertionrewriterJ   r0   osr   rw   pathlibr   pytestenvirongetr	   r
   r   r   rx   r   fixturer"   r4   r6   r{   r   r   r   r   r   r   ry   r   r   <module>r      s1      	 
   "**..!13HIJ
z?#(("HHOOAs:'D U5E5E " 34 3E$4$4 3 3 d t  ,*c *cd* *>> >2@ @,2 2@6 6@6 66H Hr   