
    j'                        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ZddlmZmZ ddlmZ ddlZ ee      j'                         j(                  d   Zedz  dz  Zdefd	Zdefd
ZdedededdfdZdedefdZdedee   fdZdedededededz  dedz  defdZ dee   dededefdZ! ejD                         d        Z#d Z$d Z%d Z&d Z'd Z(d  Z)y)!u  
test_stash_lifecycle_dryrun.py
task: task-2571 TODO-7 T-2

검증 목표:
- spec §3 dry-run 기본값 검증
- FINISH_TASK_STASH_APPROVE 미설정 시 stash 변경 없음
- spec §2 결정 흐름 참조구현(reference implementation)으로 dry-run 결정 검증
- audit log 포맷 검증 (approval_mode == "dry-run", action == "dry-run-pop")

작성자: 하누만 (개발4팀 QA)
    N)datetimetimezone)Path   scriptszstash_audit.pyreturnc                     t        j                  d      } t               }t        j                  g d| d|       t        j                  g d| d|       t        j                  g d| d|       t        |       dz  j                  d	       t        j                  g d
| d|       t        j                  g d| d|       | S )u$   격리된 임시 git repo 초기화.zstash-lifecycle-test-)prefix)gitinit-qz-bmainTcwdcheckenv)r   configz
user.emailtest@example.com)r   r   z	user.nametesta.txthello)r   addr   )r   commitr   -mr   )tempfilemkdtemp_git_env
subprocessrunr   
write_text)dr   s     C/home/jay/workspace/tests/regression/test_stash_lifecycle_dryrun.py_init_temp_repor#   "   s     78A
*CNN6ATsSNNFAUY_bcNN9qRUV	!Ww""7+NN*3GNN8atQTUH    c                  j    t         j                  j                         } d| d<   d| d<   d| d<   d| d<   | S )u"   git 명령 실행용 환경변수.r   GIT_AUTHOR_NAMEr   GIT_AUTHOR_EMAILGIT_COMMITTER_NAMEGIT_COMMITTER_EMAIL)osenvironcopy)r   s    r"   r   r   /   sC    
**//
C#C0C &C!3CJr$   repo_dirmessagefilenamec                     t               }t        |       |z  }|j                  d| d       t        j                  dd|g| d|       t        j                  dddd	|g| d|       y
)u3   파일 하나 dirty 상태로 만들고 stash push.zdirty: 
r   r   Tr   stashpushr   N)r   r   r    r   r   )r-   r.   r/   r   fpaths        r"   _stash_pushr5   9   sf    
*CNX%E	wwir*+NNE5(+3ONNE7FD':PTZ]^r$   c                    t        j                  t        j                  t	        t
              dd| gdd      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d	z  }t        j                  d
|j                   d|j                         dz   d|iz  }t        t        j                   |            dx}x}}t#        j$                  |j&                        S )u7   stash_audit.py --json 실행 후 파싱된 dict 반환.z--jsonz--workspaceT)capture_outputtextr   ==)z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sresult)py0py2py5u#   stash_audit.py 실행 실패 (exit=z
)
stderr: z
>assert %(py7)spy7N)r   r   sys
executablestrSTASH_AUDIT_PY
returncode
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgstderrAssertionError_format_explanationjsonloadsstdout)r-   r;   @py_assert1@py_assert4@py_assert3@py_format6@py_format8s          r"   _run_audit_jsonrW   B   s   ^^	^,hxPF
   !                    !"    .f.?.?-@ A==/	#     ::fmm$$r$   c                     t        j                  g d| ddt                     }|j                  dk7  s|j                  j                         sg S |j                  j                         j                         S )u   git stash list 반환.)r   r2   listT)r   r7   r8   r   r   )r   r   r   rD   rQ   strip
splitlines)r-   r;   s     r"   _stash_listr\   P   sa    ^^ JF AV]]%8%8%:	== ++--r$   sourceapprovepr_verifiedidx_in_drop_listetidtask_idc                 b    | dk(  r|ryy| dk(  r|r|r||k(  ry|syy| dk(  r	|r|ry|syy| d	v ryy
)u  
    spec §2 결정 흐름 reference implementation.

    Returns:
        action 문자열:
            "dry-run-pop"   — APPROVE 미설정, pre-task
            "dry-run-drop"  — APPROVE 미설정, other-files
            "popped"        — APPROVE=1, pre-task
            "dropped"       — APPROVE=1, other-files + idx_in_drop_list
            "preserved"     — wip / quarantine / unknown, 또는 조건 미충족 finish-task
            "skipped"       — 알 수 없는 source
    zpre-taskpoppeddry-run-popzfinish-task	preservedzother-filesdroppedzdry-run-drop)wip
quarantineunknownskipped r]   r^   r_   r`   ra   rb   s         r"   decide_actionrn   b   s]    ( { '!11r$   entriesc           
      \   g }d}| D ]_  }|d   }|j                  d      }|d   }t        ||dd||      }	|dk(  r|dz  }|j                  ||||j                  d	d
      |	d       a t        j                  t
        j                        j                         ||rdndt        |       ||dS )uj   
    spec §2/§3 기반 dispatch 시뮬레이션.
    audit log 포맷(§4.2)에 맞는 dict 반환.
    r   r]   rb   indexFrm   rj      reason )rq   r]   rb   rs   actionapproveddry-runtimestamp_utcrb   approval_modestash_count_before	decisionsskipped_unknown_count)	getrn   appendr   nowr   utc	isoformatlen)
ro   r^   rb   r|   r}   er]   ra   idxru   s
             r"   simulate_dispatchr      s    
 I 8uuYj"
 Y!Q&!eeHb)
 	#4 "hll3==?'.I!'l!6 r$   c               #   p   K   t               } t        | dd       |  t        j                  | d       yw)u-   pre-task stash 1건만 시드된 임시 repo.zWIP: pre-task-2571 stash samplezb.txtT)ignore_errorsN)r#   r5   shutilrmtree)r-   s    r"   pretask_repor      s0       H;WE
N
MM($/s   46c                 \   t        |       }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|       dz   d	|iz  }t        t        j                  |            d
x}x}}t        |       }|j                  dg       }t        |      }d}||k(  }|st        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  }dd	|iz  }t        t        j                  |            d
x}x}}t        |       }	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t        |	             dz   d	|iz  }t        t        j                  |            d
x}x}}y
)ur   
    dry-run 시뮬레이션 후 stash 수가 변하지 않아야 한다.
    (실제 pop/drop 없음 검증)
    rr   r9   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   beforer<   py1py3py6u%   시드 후 stash 수가 1이 아님: z
>assert %(py8)spy8Nro   assert %(py8)safteru;   dry-run 시뮬레이션 후 stash 수가 변경됨: before=z, after=)r\   r   rE   rF   rG   rH   rI   rJ   rK   rM   rN   rW   r~   )
r   r   @py_assert2@py_assert5rS   @py_format7@py_format9dataro   r   s
             r"   test_dryrun_stash_not_modifiedr      sm   
 &Fv;M!M;!MMM;!MMMMMM3MMM3MMMMMMvMMMvMMM;MMM!MMMDVHMMMMMMMM <(Dhhy"%Gw<1<1<133ww<1%Eu:  :?   :                                Fc&k]RZ[^_d[eZfg     r$   c                    t        |       }|j                  dg       }t        |      }d}||k(  }|st        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  }dd|iz  }t        t        j                  |            d	x}x}}t        |d
d      }|d   }	d}
|	|
k(  }|st        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }t        j                  d|d          dz   d|iz  }t        t        j                  |            d	x}	x}}
|d   }t        |      }
d}|
|k(  }|st        j                  d|fd|
|f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}
x}}|d   d   }|d   }	d}
|	|
k(  }|st        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }t        j                  d|d          dz   d|iz  }t        t        j                  |            d	x}	x}}
y	)ud   
    APPROVE 미설정 상태에서 pre-task stash 의 action 은 dry-run-pop 이어야 한다.
    ro   rr   r9   r   r   r   r   r   NF	task-2571r^   rb   rz   rw   z%(py1)s == %(py4)sr   py4u'   approval_mode 기대: dry-run, 실제: 
>assert %(py6)sr   r|   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)s)r<   r=   r   r?   zassert %(py9)spy9r   ru   re   u$   action 기대: dry-run-pop, 실제: )rW   r~   r   rE   rF   rG   rH   rI   rJ   rM   rN   r   rK   )r   r   ro   r   r   rS   r   r   log@py_assert0rT   @py_format5rR   @py_assert6rV   @py_format10decisions                    r"   +test_dryrun_decision_pretask_is_dry_run_popr      sz    <(Dhhy"%Gw<1<1<133ww<1
GUK
HC 9 9,  9         $-    2#o2F1GH     ;%3 %A% A%%%% A%%%%%%3%%%3%%%%%% %%%A%%%%%%%;"HH  .          "/    /x/A.BC     r$   c           
      v   t        |       }|j                  dg       }t        |dd      }g d}|D ]  }||v }|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t        |j                                      dz   d|iz  }t        t        j                  |            d} y)uX   
    시뮬레이션 audit log 가 spec §4.2 필수 필드를 포함해야 한다.
    ro   Fr   r   rx   in)z%(py0)s in %(py2)sfieldr   )r<   r=   u   audit log 에 'u   ' 필드 없음
log keys: z
>assert %(py4)sr   N)rW   r~   r   rE   rF   rG   rH   rI   rJ   rK   rY   keysrM   rN   )	r   r   ro   r   required_fieldsr   rR   @py_format3r   s	            r"   )test_dryrun_audit_log_has_required_fieldsr      s    <(Dhhy"%G
GUK
HCSO  
| 	
 	
u 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
  eW$?SXXZ@P?QR	
 	
 	
 	
 	

r$   c                    t        |       }|j                  dg       }t        |dd      }|d   }g }d}||v }|}|sd}	|	|v }
|
}|
sd}||v }|}|s t        j                  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                  |       |st        j                  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        j                  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                  |       t        j                  |d      i z  }t        j                  d|       dz   d|iz  }t        t        j                  |            dx}x}x}x}x}	x}
x}}y)uW   
    timestamp_utc 가 UTC timezone-aware ISO 형식이어야 한다 (spec §4.3).
    ro   Fr   r   ry   z+00:00ZUTCr   )z%(py3)s in %(py5)sts_str)r   r>   z%(py7)sr?   )z%(py10)s in %(py12)s)py10py12z%(py14)spy14)z%(py17)s in %(py19)s)py17py19z%(py21)spy21rr   u>   timestamp_utc 가 timezone-aware 가 아닌 것으로 보임: z
>assert %(py24)spy24N)rW   r~   r   rE   rF   rJ   rG   rH   rI   r   _format_booloprK   rM   rN   )r   r   ro   r   r   rR   r   rS   r   @py_assert9@py_assert11@py_assert16@py_assert18rU   rV   @py_format13@py_format15@py_format20@py_format22@py_format23@py_format25s                        r"   ,test_dryrun_audit_log_timestamp_is_utc_awarer     s    <(Dhhy"%G
GUK
HC!FH H # #- 5 5F?   H                   #    #&      *0    *0     5F    49      =C    =C        IQ      r$   c                    t        |       }|j                  dg       }t        |dd      }|d   d   d   }|d   d   }||k(  }|st        j                  d|fd	||f      t        j
                  |      t        j
                  |      d
z  }t        j                  d|d   d   d    d|d   d    d      dz   d|iz  }t        t        j                  |            dx}x}}y)uB   decisions[0].source 가 entries[0].source 와 일치해야 한다.ro   Fr   r   r|   r   r]   r9   r   r   zdecision source (z) != entry source ()r   r   N)	rW   r~   r   rE   rF   rJ   rK   rM   rN   	r   r   ro   r   r   rT   r   r   r   s	            r"   )test_dryrun_decision_source_matches_entryr     s    <(Dhhy"%G
GUK
HC{Ax( GAJx,@ (,@@  (,@    )    -A    C,Q/9: ; H-.a	1     r$   c                    t        |       }|j                  dg       }t        |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   d   }d}||k(  }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      d	z  }t        j                  d|d   d   d          dz   d|iz  }t        t        j                  |            dx}x}}y)u   
    APPROVE=1 로 설정 시 pre-task action 이 'popped' 으로 변경되어야 한다
    (reference implementation 검증).
    ro   Tr   r   rz   rv   r9   r   r   zassert %(py6)sr   Nr|   r   ru   rd   u-   APPROVE=1 시 action 기대: popped, 실제: r   )	rW   r~   r   rE   rF   rJ   rM   rN   rK   r   s	            r"   1test_dryrun_approve_flag_changes_action_to_poppedr     s)   
 <(Dhhy"%G
GT;
GC-:-:----:------:-------{Ax( H (H4  (H    )    -5    8K8H8KH8U7VW     r$   )*__doc__builtinsrG   _pytest.assertion.rewrite	assertionrewriterE   rO   r*   r   r   r@   r   r   r   pathlibr   pytest__file__resolveparentsWORKTREE_ROOTrC   rB   r#   dictr   r5   rW   rY   r\   boolrn   r   fixturer   r   r   r   r   r   r   rl   r$   r"   <module>r      sq     	   
  '  X&&(003*-==
 
$ _# _ _s _t _%c %d %.# .$s) .$,,, , 	,
 *, 4Z, 	,^(tDz (D (3 (4 (^ 0 0&(
 	r$   