
    i56                         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ZddlmZ ddlZ ee      j!                         j"                  d   Zd Zd Zd Zd Zd	 Zd
 Zd Zy)u  
test_dispatch_counter_fix.py — task-counter 버그 fix (4 layer) 회귀 방지 테스트
task-2380 (dev1/아르고스)

6건 테스트:
1. test_variant_id_filtering               — 변종 ID 필터링
2. test_no_down_correction_in_source       — 다운-보정 elif 블록 제거 검증 (소스 검사)
3. test_counter_up_correction              — 카운터 위로 보정 통합 테스트
4. test_resolve_main_workspace_from_worktree — _resolve_main_workspace() 워크트리 환경
5. test_concurrent_generate_task_id        — flock 동시성 (subprocess 2개 race)
6. test_cleanup_dry_run_lists_without_deleting — cleanup 스크립트 dry-run
    N)Path   c                      dt         j                  v rYt         j                  d   } t        | d      r)| j                  rt	        t
              | j                  v r| S t         j                  d= ddl}|S )uD   항상 worktree dispatch.py를 반환 (모듈 캐시 오염 방지).dispatch__file__r   N)sysmoduleshasattrr   str_WORKTREE_ROOTr   )mds     ;/home/jay/workspace/tests/dev1/test_dispatch_counter_fix.py_get_dispatchr      sU    S[[ KK
#1j!ajjS5HAJJ5VHKK
#H    c                 2   t               }| dz  }dddiddiddiddidi}|j                  t        j                  |      d       |j	                  |      }d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d| d      dz   d|iz  }t        t        j                  |            dx}}y)u   task-9.1, task-900.1 등 변종 ID는 무시하고 4자리 정규 ID만 처리함.

    task-2376 + 1 = 2377 반환, task-2376_2.1은 phase 변형이므로 2376으로 파싱.
    task-timers.jsontasksstatusdone)ztask-9.1z
task-900.1	task-2376ztask-2376_2.1utf-8encodingiI	  ==z%(py0)s == %(py3)sresultpy0py3uK   변종 ID(task-9.1, task-900.1) 무시 후 2376+1=2377 이어야 하는데     반환
>assert %(py5)spy5N)r   
write_textjsondumps_compute_next_id_from_timers
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)	tmp_pathr   
timer_file
timer_datar   @py_assert2@py_assert1@py_format4@py_format6s	            r   test_variant_id_filteringr9   *   s   
 	A..J!6*#V,"F+&/	
J $**Z07C++J7F 6T>  6T                  VV\U]]de    r   c                     t               } t        j                  | j                        }d|v }d|v xr d|v }|s|rt	        j
                  d       | }|s{t        j                  d      dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d	}| }|s{t        j                  d
      dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d	}y	)uh  generate_task_id 소스에 다운-보정(elif next_num > timers_max) 블록이 없음을 검증.

    과거 버그: counter=5000, timers_max=2376 → 5000→2376으로 다운 보정하는
    elif 블록이 존재했음. fix 이후 해당 코드가 제거되어야 함.

    xfail: 불칸 작업 전에는 해당 코드가 여전히 존재할 수 있음.
    u.   카운터(%d)가 timers 최대(%d) 대비 1000znext_num > timers_maxznext_num - timers_maxuh   다운-보정 코드가 여전히 존재함 — 불칸 작업(elif 블록 제거) 완료 후 PASS 예상u5   다운-보정 문자열이 여전히 소스에 존재z
>assert not %(py0)sr    has_down_corr_strNu>   next_num > timers_max 하향 보정 분기가 여전히 존재has_down_corr_elif)r   inspect	getsourcegenerate_task_idpytestxfailr)   r/   r+   r,   r-   r.   r0   r1   )r   srcr;   r<   r6   @py_format2s         r   !test_no_down_correction_in_sourcerD   G   s     	A


A..
/C ICO0C7Z<SWZ<Z.v	

 ! Y YY"YYYYYYY YYY YYYYYY!!c!cc#ccccccc!ccc!ccccccr   c                     t               } dz  }|j                  d       |dz  }|j                  dd       |dz  }d	d
ddiii}|j                  t        j                  |      d       |j                  |d        |j                  |d fd       |j                         }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
t        j                  d|d      dz   d|
iz  }t        t        j                  |            dx}	}y)u   counter_file=100, timer_file에 task-2376 → generate_task_id()는 task-2377 반환.

    카운터(100) < timers 최대(2377) → 위로 보정.
    memoryTparents.task-counter100r   r   r   r   r   r   r   	WORKSPACE_resolve_main_workspacec                       S )N )r2   s   r   <lambda>z,test_counter_up_correction.<locals>.<lambda>y   s    h r   z	task-2377r   r   r   r   uU   카운터(100) < timers 최대(2377): 위로 보정 후 task-2377이어야 하는데 r"   r#   r$   N)r   mkdirr%   r&   r'   setattrr?   r)   r*   r+   r,   r-   r.   r/   r0   r1   )r2   monkeypatchr   mem_dircounter_filer3   r4   r   r5   r6   r7   r8   s   `           r   test_counter_up_correctionrU   d   s[   
 	A!GMM$M _,LEG4 --JK(F);<=J$**Z07C ;146FG!F  6[   6[              !    ``f_iipq    r   c           	      b   t               }| dz  }|j                          t        j                  ddt	        |      gdd       t        j                  g dt	        |      dd       t        j                  g dt	        |      dd       |d	z  }|j                  d       t        j                  g d
t	        |      dd       t        j                  g dt	        |      dd       | dz  }t        j                  ddddt	        |      gt	        |      dd       |j                  |d|       |j                         }|j                  } |       }|j                  }	 |	       }
||
k(  }|s6t        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      t        j                  |
      dz  }t        j                  d| d| d| d      dz   d|iz  }t!        t        j"                  |            dx}x}x}x}	}
y)uk   git worktree 환경에서 _resolve_main_workspace()가 메인 워크스페이스를 반환하는지 검증.	main_repogitinitT)checkcapture_output)rX   configz
user.emailztest@test.com)cwdrZ   r[   )rX   r\   z	user.nameTestz	README.md)rX   add.)rX   commitz-mrY   	worktree1worktreer_   z--detachrK   r   )z|%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.resolve
}()
} == %(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py6)s.resolve
}()
}r   )r    py2py4py6py8py10z	worktree(u!   )에서 호출 시 메인 리포(u   )를 반환해야 하는데 r"   z
>assert %(py12)spy12N)r   rP   
subprocessrunr   r%   rQ   rL   resolver)   r*   r+   r,   r-   r.   r/   r0   r1   )r2   rR   r   rW   dummywt_pathr   r6   @py_assert3@py_assert7@py_assert9@py_assert5@py_format11@py_format13s                 r   )test_resolve_main_workspace_from_worktreeru      sf   A ;&IOONNE63y>2$tTNN8	N$t NN.	N$t
 #E	VNN&C	N$W[\NN'	N$t $GNN	
E:s7|<	N$t ;0&&(F>> > y00 02 22   2                         )     )     1     3    G9=i[Hdekdllst     r   c                      dz  }|j                  d       |dz  j                  dd       |dz  j                  t        j                  d	i i      d        d
z  j                  dd       t	        t
              g t        j                          fd}t        d      D cg c]  }t        j                  |       }}|D ]  }|j                           |D ]  }|j                           t              }d}||k(  }|st        j                  d|fd||f      dt        j                          v st        j"                  t              rt        j$                  t              nddt        j                          v st        j"                        rt        j$                        ndt        j$                  |      t        j$                  |      dz  }	t        j&                  dt               d      dz   d|	iz  }
t)        t        j*                  |
            dx}x}}d   d   }}|j,                  }d} ||      }| }|st        j&                  d|       dz   dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |      t        j$                  |      t        j$                  |      dz  }t)        t        j*                  |            dx}x}x}}|j,                  }d} ||      }| }|st        j&                  d |       dz   d!t        j                          v st        j"                  |      rt        j$                  |      nd!t        j$                  |      t        j$                  |      t        j$                  |      dz  }t)        t        j*                  |            dx}x}x}}ddl}|j1                  d"      }|j2                  } ||      }|st        j&                  d#|      d$z   d%t        j                          v st        j"                  |      rt        j$                  |      nd%t        j$                  |      dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |      d&z  }t)        t        j*                  |            dx}}|j2                  } ||      }|st        j&                  d'|      d$z   d%t        j                          v st        j"                  |      rt        j$                  |      nd%t        j$                  |      d!t        j                          v st        j"                  |      rt        j$                  |      nd!t        j$                  |      d&z  }t)        t        j*                  |            dx}}||k7  }|st        j                  d(|fd)||f      dt        j                          v st        j"                  |      rt        j$                  |      ndd!t        j                          v st        j"                  |      rt        j$                  |      nd!d*z  }t        j&                  d+| d,| d-      d.z   d/|iz  }t)        t        j*                  |            d}yc c}w )0u   subprocess 2개를 동시에 spawn해서 generate_task_id() 호출.

    두 결과가 달라야 하며(flock 직렬화), 각각 유효한 task-NNNN 형식이어야 함.
    rF   TrG   rI   3000r   r   r   r   zconcurrent_helper.pyuK  
import sys, json
from pathlib import Path

repo_root = sys.argv[1]
workspace = Path(sys.argv[2])

# worktree dispatch.py 우선 로드
if repo_root in sys.modules.get('dispatch', type('', (), {'__file__': ''})).__file__ if 'dispatch' in sys.modules else False:
    pass
else:
    if repo_root not in sys.path:
        sys.path.insert(0, repo_root)
    if 'dispatch' in sys.modules:
        del sys.modules['dispatch']

sys.path.insert(0, repo_root)
import dispatch as d

d.WORKSPACE = workspace
d._resolve_main_workspace = lambda: workspace

result = d.generate_task_id()
print(result)
c                  `   t        j                  t        j                  t	              t	              gddd      } | j
                  j                         }|s,| j                  r d| j                  j                         d d  }5  j                  |       d d d        y # 1 sw Y   y xY w)NT   )r[   texttimeoutzERROR:    )	rj   rk   r   
executabler   stdoutstripstderrappend)routlock	repo_rootresultsscript_filer2   s     r   run_subz1test_concurrent_generate_task_id.<locals>.run_sub   s    NN^^S-y#h-HdB
 hhnnqxxAHHNN,Tc234C 	 NN3	  	  	 s   	B$$B-r   )targetr   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr   )r    py1r!   rf   u   subprocess 결과 2개 필요, u
   개 수신z
>assert %(py8)srg   Nr      zERROR:u   프로세스1 에러: zR
>assert not %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
}id1)r    rd   re   rf   u   프로세스2 에러: id2z
^task-\d+$u   결과1 형식 오류: zI
>assert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.match
}(%(py3)s)
}pat)r    rd   r!   r$   u   결과2 형식 오류: )!=)z%(py0)s != %(py2)s)r    rd   u#   동시 호출 시 ID가 중복됨: z == u#   . flock 직렬화 실패 가능성.z
>assert %(py4)sre   )rP   r%   r&   r'   r   r   	threadingLockrangeThreadstartjoinr   r)   r*   r+   r,   r-   r.   r/   r0   r1   
startswithrecompilematch)r2   rS   r   _threadstr5   rr   @py_assert4@py_format7@py_format9r   r   r6   ro   rp   @py_format8r   r   r8   @py_format3@py_format5r   r   r   r   s   `                     @@@@r    test_concurrent_generate_task_idr      s   
 !GMM$M **6G*D!!--

GR=!G .  33K2 5  : N#IG>>D	  	  :?qBAyw/BGB 		 	 w<X1X<1XXX<1XXXXXX3XXX3XXXXXXwXXXwXXX<XXX1XXX ?G~ZXXXXXXXXqz71:C ~~GhG~h'G''G'GG+A#)GGGGGGGsGGGsGGG~GGGhGGG'GGGGGG~~GhG~h'G''G'GG+A#)GGGGGGGsGGGsGGG~GGGhGGG'GGGGGG 
**]
#C99<9S><><<4SG<<<<<<<3<<<3<<<9<<<<<<S<<<S<<<><<<<<<99<9S><><<4SG<<<<<<<3<<<3<<<9<<<<<<S<<<S<<<><<<<<< #:  3#                        .cU$se;^_    + Cs   1[:c           	         ddl }ddl}ddl}ddlm} | dz  dz  dz  }| dz  dz  dz  }|j                  d	       |j                  d	       |d
z  }|d
z  }|j                  dd       |j                  dd       t        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"                  j%                  dt'        |	            }|j"                  j)                  |      }|j*                  j-                  |       |j/                  |d|        |j/                  t0        dddg       |j3                         } ||      5  |j5                         }ddd       |j7                         }d}|k(  }
|
st        j8                  d|
fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|       dz   d|iz  }t        t        j                   |            dx}
}d}||v }|st        j8                  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        j8                  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}}g }
d}||v }|}|sd&}|j:                  } |       }||v }|}|st        j8                  d |fd'||f      t        j                  |      d"t        j                         v st        j                  |      rt        j                  |      nd"d(z  }d)d*|iz  }|
j=                  |       |st        j8                  d fd+f      t        j                  |      d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                        t        j                  |      d,z  }d-d.|iz  }|
j=                  |       t        j>                  |
d/      i z  }t        j                  d0|       d1z   d2|iz  }t        t        j                   |            dx}x}
x}x}x}x}x}}|j                  }
 |
       }|st        j                  d3| d4      dz   d5t        j                         v st        j                  |      rt        j                  |      nd5t        j                  |
      t        j                  |      dz  }t        t        j                   |            dx}
}|j                  }
 |
       }|st        j                  d3| d4      dz   d6t        j                         v st        j                  |      rt        j                  |      nd6t        j                  |
      t        j                  |      dz  }t        t        j                   |            dx}
}|j@                  }
 |
       }|jB                  }  |        }!d}"|!|"k(  }|st        j8                  d|fd7|!|"f      d5t        j                         v st        j                  |      rt        j                  |      nd5t        j                  |
      t        j                  |      t        j                  |       t        j                  |!      t        j                  |"      d8z  }#d9d:|#iz  }$t        t        j                   |$            dx}
x}x} x}!x}}"|j@                  }
 |
       }|jB                  }  |        }!d}"|!|"k(  }|st        j8                  d|fd7|!|"f      d6t        j                         v st        j                  |      rt        j                  |      nd6t        j                  |
      t        j                  |      t        j                  |       t        j                  |!      t        j                  |"      d8z  }#d9d:|#iz  }$t        t        j                   |$            dx}
x}x} x}!x}}"y# 1 sw Y   xY w);u   cleanup_stale_task_counter.py --dry-run 실행.

    - 가짜 worktree 구조(.worktrees/fake1, fake2) 생성
    - WORKSPACE를 임시 경로로 패치 후 main() 직접 호출
    - dry-run: 파일 경로 출력, 파일 삭제 안 함
    r   N)redirect_stdoutz
.worktreesfake1rF   fake2TrG   rI   1234r   r   5678scriptszcleanup_stale_task_counter.pyu   cleanup 스크립트 없음: zC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}script_path)r    rd   re   _cleanup_stale_tcrK   argvz	--dry-runr   r   retr   u   main() 반환 코드: r#   r$   )in)z%(py1)s in %(py3)soutput)r   r!   u    dry-run 출력에 fake1 없음:
u    dry-run 출력에 fake2 없음:
zdry-run)z%(py3)s in %(py5)s)r!   r$   z%(py7)spy7)zJ%(py10)s in %(py16)s
{%(py16)s = %(py14)s
{%(py14)s = %(py12)s.lower
}()
})rh   ri   py14py16z%(py18)spy18r   u   dry-run 메시지 없음:
z
>assert %(py21)spy21u   dry-run임에도 u
    삭제됨counter1counter2)z{%(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.read_text
}()
}.strip
}()
} == %(py11)s)r    rd   re   rf   rg   py11zassert %(py13)spy13)"	importlibimportlib.utilio
contextlibr   rP   r%   r   existsr)   r/   r+   r,   r-   r.   r0   r1   utilspec_from_file_locationr   module_from_specloaderexec_modulerQ   r   StringIOmaingetvaluer*   lowerr   _format_boolop	read_textr   )%r2   rR   r   r   r   wt1wt2r   r   r   r6   ro   r   specmodbufr   r   r5   r7   r8   @py_assert0r   rq   @py_assert13@py_assert15@py_assert11r   @py_format17@py_format19@py_format20@py_format22rr   rp   @py_assert10@py_format12@py_format14s%                                        r   +test_cleanup_dry_run_lists_without_deletingr     s    * \
!G
+h
6C
\
!G
+h
6CIIdIIIdI_$H_$H11 !9,/NNKNNNN#@!NNNNNNN;NNN;NNNNNNNNNNNN >>112Es;GWXD
..
)
)$
/CKKC  [(3 V&E{%ST ++-C		 hhj\\^F 33!83333!33333333333333!333-cU3333333 J7fJJJ7fJJJ7JJJJJJfJJJfJJJJ A&JJJJJJJJ7fJJJ7fJJJ7JJJJJJfJJJfJJJJ A&JJJJJJJ; ;&  I   I$?   ;&          !    !     I    %.      28    28    2>    2@        &fX.      
 ??F?FFF 1(:FFFFFFF8FFF8FFF?FFFFFFFFF??F?FFF 1(:FFFFFFF8FFF8FFF?FFFFFFFFF11%%1%'161'61111'611111181118111111111%111'11161111111111%%1%'161'61111'611111181118111111111%111'111611111111% s   'g''g1)__doc__builtinsr+   _pytest.assertion.rewrite	assertionrewriter)   r=   r&   rj   r   r   pathlibr   r@   r   rl   rH   r   r   r9   rD   rU   ru   r   r   rN   r   r   <module>r      sl        
    h'')11!4:d:D'\St:2r   