
     jP                    J   d Z ddlm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mZ ddlZ e
e      j                         j                   d   Z ee      ej&                  vr"ej&                  j)                  d ee             ddlmZmZmZ d	Zd
ZdZdZ e
e      j:                  j:                  dz  ZddZ	 	 	 d	 	 	 	 	 	 	 ddZ dd dZ!d!dZ"d!dZ#ejH                  jK                  dg d      	 	 	 	 	 	 	 	 	 	 	 	 d"d       Z&d!dZ'd!dZ(d!dZ)d!dZ*d!dZ+d#dZ,y)$up  회귀 테스트 9건 — anu_v2.post_merge_smoke_runner (task-2539).

pytest 사용. 외부 부수효과(subprocess / file write / capabilities / clock)는
모두 fake callable로 주입.

⚠️ 테스트 코드 내 "ghp_faketoken123abc" 등 raw token placeholder는
   실제 토큰이 아닌 테스트 fake 값임 — leak detector 오탐 방지를 위해 명시.
    )annotationsN)datetimetimezone)Path)Callable   )DEFAULT_CHAT_ID"KIND_NAME_POST_MERGE_SMOKE_FAILUREPostMergeSmokeRunner(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(106e645b479b6fb1888256b0ef4a7b68ed8fad63(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbz	task-2539fixturesc            	     B    t        ddddddt        j                        S )u4   고정 시각 반환 — 테스트 결정론 보장.i     
             )tzinfo)r   r   utc     E/home/jay/workspace/anu_v2/tests/test_post_merge_smoke_runner_2539.py_fake_clockr   *   s    D!RRHLLAAr   c                4    t        j                  g | ||      S )N)args
returncodestdoutstderr)
subprocessCompletedProcess)r   r   r    s      r   _make_completed_processr#   /   s#    
 &&	 r   c                "     ddi fd}|S )uC   git rev-parse → smoke command 순서로 응답하는 fake runner.nr   c                h    dxx   dz  cc<   d| v rt        dt        dz   d      S t        d      S )Nr%      	rev-parser   
 zsmoke outputr#   FAKE_MAIN_SHA)r   _
call_countsmoke_returncodesmoke_stderrs     r   runnerz'_make_git_ok_then_smoke.<locals>.runner@   s=    31$*1md.BBGG&'7VVr   r   )r/   r0   r1   r.   s   `` @r   _make_git_ok_then_smoker2   <   s    qJW Mr   c                |   t        t        d      d t        |       }|j                  t        t
        dg      }|d   dk(  sJ |d   dk(  sJ |d	   J t        |d         }|j                         sJ d       |j                  d      j                         j                         }t        |      dk(  sJ t        j                  |d         }|d   t        k(  sJ |d   t
        k(  sJ |d   dk(  sJ d|v sJ |d   du sJ |d   du sJ d|v sJ d|v sJ d|v sJ d|v sJ d|v sJ d|v sJ |d   dk(  sJ y
)uS   smoke exit_code=0 → outcome=PASS / .smoke-evidence 파일 생성 / format 일치.r   c                     y Nr   r-   s    r   <lambda>z0test_smoke_pass_creates_marker.<locals>.<lambda>P       r   subprocess_runnercapabilities_loaderclockworkspace_root!anu_v2/post_merge_smoke_runner.pytask_idmerge_commitexpected_filesoutcomePASS	exit_codecritical_seven_classificationNsmoke_evidence_marker_pathu&   smoke-evidence marker 파일이 없음utf-8encodingr'   r@   	merge_sha
probe_passtsbuild_okTtest_okcommandduration_seconds	main_headrA   expected_files_count)r   r2   r   run_post_merge_smokeFAKE_TASK_ID
FAKE_SHA40r   exists	read_textstrip
splitlineslenjsonloads)tmp_pathr1   resultmarker_pathlinesrecords         r   test_smoke_pass_creates_markerrc   L   s   !1!4*	F ((;< ) F )&&&+!###12::: v:;<KI!II !!7!399;FFHEu:?? ZZa!F),,,+*,,,),,,6>>*%%%)$$$&   '''&   V###!V+++()Q...r   c                   t        t        dd      d t        |       }|j                  t        t
        dg      }|d   dk(  sJ |d	   d
k(  sJ |d   J dddddd}|j                  t        t
        |      }|d   d
k(  sJ |d   t        k(  sJ |d   du sJ | dz  dz  }|t         dz  }|j                         rJ d       y)uX   smoke exit_code=1 → outcome=FAIL / critical_seven_classification=7 / marker 미생성.r'   zAssertionError: test failedc                     y r5   r   r6   s    r   r7   z;test_smoke_fail_classifies_critical_seven.<locals>.<lambda>   r8   r   r9   r>   r?   rC   FAILrF      rG   Npython3 -m pytest tests/smoker*   g      ?rP   rE   r   r    rQ   r@   rA   execution_resultcritical_seven_kind	kind_namereport_to_chairman_requiredTmemoryevents.smoke-evidenceu'   FAIL 시 marker가 생성되면 안 됨)	r   r2   r   rT   rU   rV   (classify_smoke_failure_as_critical_sevenr
   rW   )r^   r1   r_   exec_resultcritical
events_dirmarkers          r   )test_smoke_fail_classifies_critical_sevenrw   {   s-   !1!5RS*	F ((;< ) F )&&&12a777./777 3/K >>$ ? H
 )*a///K $FFFF12d::: H$x/J\N/::F}}I IIr   z4smoke_command, caps_command, smoke_profile, expected))explicit-cmd	from-caps
profile.pyrx   )Nry   rz   ry   )NNztests/smoke/custom.pyz'python3 -m pytest tests/smoke/custom.py)NNNz4python3 -m pytest tests/smoke/test_smoke_baseline.pyc                    |rd|indt        t        d      fdt        |       }|j                  t        ||      }||k(  sJ y)u7   _resolve_smoke_command 4 케이스 우선순위 검증.smoke_commandNr   c                    S r5   r   )r-   capss    r   r7   z/test_resolve_command_priority.<locals>.<lambda>   s    d r   r9   )r   r2   r   _resolve_smoke_commandrU   )r^   r|   caps_commandsmoke_profileexpectedr1   resolvedr~   s          @r   test_resolve_command_priorityr      sR    * /;O\*D!1!4*	F ,,\=-XHxr   c                `   t        t        d      d t        |       }|j                  t        t
        g       }|d   dk(  sJ t        t        d      d t        |       }|j                  t        t
        g       }|d   dk(  sJ t        |d         }|j                  d	
      j                         j                         }t        |      dk(  sJ dt        |       d       t        j                  |d         }t        j                  |d         }|d   |d   cxk(  r
t        k(  sJ  J y)u@   동일 task_id 2회 실행 → marker에 2 line. 덮어쓰기 X.r   c                     y r5   r   r6   s    r   r7   z/test_idempotent_marker_append.<locals>.<lambda>   r8   r   r9   r?   rC   rD   c                     y r5   r   r6   s    r   r7   z/test_idempotent_marker_append.<locals>.<lambda>   r8   r   rG   rH   rI   r   u#   marker에 2 line이어야 함 (got )r'   r@   N)r   r2   r   rT   rU   rV   r   rX   rY   rZ   r[   r\   r]   )	r^   r1   r1runner2r2r`   ra   rec1rec2s	            r   test_idempotent_marker_appendr      s?   !1!4*	F 
	$	$ 
% 
B
 i=F""" #1!4*	G 
	%	% 
& 
B
 i=F"""r678K!!7!399;FFHEu:?OA#e*QOO?::eAhD::eAhD	?d9o======r   c                    t        t        d      d t        |       }t        j                  t
        d      5  |j                  t        t        g d       ddd       y# 1 sw Y   yxY w)	uW   chat_id=999 입력 → AssertionError (chat_id != 6937032012 cross-chat 누출 차단).r   c                     y r5   r   r6   s    r   r7   z/test_chat_isolation_assertion.<locals>.<lambda>   r8   r   r9   zchat_id != 6937032012)matchi  )r@   rA   rB   chat_idN)	r   r2   r   pytestraisesAssertionErrorrT   rU   rV   )r^   r1   s     r   test_chat_isolation_assertionr      sb    !1!4*	F 
~-D	E 
## #	 	$ 	

 
 
s   A  A)c                h   dddifd}t        |d t        |       }|j                  t        t        g       }|d   d	k(  sJ d
|d   vsJ d       d|d   vsJ d       d|d   v sJ d       ddddd}|j                  t        t        |      }d
|d   vsJ d       d|d   vsJ d       y)u   fake stderr에 raw token 포함 → marker / Critical 7종 본문 모두 ***MASKED*** 처리.

    ⚠️ 아래 "ghp_faketoken123abc"는 테스트 fake 값 (실제 토큰 아님).
    z1GH_TOKEN=ghp_faketoken123abc x-api-key: secretkeyr%   r   c                h    dxx   dz  cc<   d| v rt        dt        dz   d      S t        dd      S )Nr%   r'   r(   r   r)   r*   r+   )r   r-   r.   fake_stderrs     r   runner_with_token_stderrz5test_token_raw_zero.<locals>.runner_with_token_stderr  s<    31$*1md.BBGG&q"k::r   c                     y r5   r   r6   s    r   r7   z%test_token_raw_zero.<locals>.<lambda>  r8   r   r9   r?   rC   rf   ghp_faketoken123abcstderr_summaryu"   stderr_summary에 raw token 노출	secretkeyu#   stderr_summary에 raw secret 노출z***MASKED***u   마스킹 처리되어야 함rh   r'   r*   g      ?ri   rj   u0   Critical 7종 stderr_summary에 raw token 노출u1   Critical 7종 stderr_summary에 raw secret 노출N)r   r   rT   rU   rV   rr   )r^   r   r1   r_   rs   rt   r.   r   s         @@r   test_token_raw_zeror   
  s8    FKqJ; "2*	F (( ) F )&&& /?(@@ ,@ f%566 -6 V$455V7VV5 3K >>$ ? H
 !1A(BB :B h'788 ;8r   c                h  
 t        t        d      d t        |       }t        j                  |j
                        }|j                  D cg c])  }d|j                         v sd|j                         v s(|+ }}t        |      dk(  s
J d|        t        t        d      d t        |       }|j                  t        t        g 	      }|d
   dk(  sJ d       t        
d
fd	}|j                  d|       |j                  t        t        g 	      }	|	d
   dk(  sJ |	d   J |	d   J yc c}w )uN  md/report fallback 금지 + OSError 시 EVIDENCE_INCOMPLETE 반환.

    qc-result md에 "smoke PASS" 텍스트가 있어도 run_post_merge_smoke는
    md를 참조하지 않음 — 시그니처에 md 관련 파라미터 0건 검증.
    marker dir read-only 시뮬(monkeypatch open → OSError) → outcome=EVIDENCE_INCOMPLETE.
    r   c                     y r5   r   r6   s    r   r7   z3test_md_report_fallback_forbidden.<locals>.<lambda>S  r8   r   r9   mdreportu)   md/report 관련 파라미터가 있음: r'   c                     y r5   r   r6   s    r   r7   z3test_md_report_fallback_forbidden.<locals>.<lambda>`  r8   r   r?   rC   rf   u8   exit_code=1일 때 md 텍스트 무관 FAIL이어야 함c                T    t        |       }d|v rd|v rt        d       | |fi |S )Nrq   azread-only filesystem simulation)strOSError)pathmodekwargspath_stroriginal_opens       r   mock_open_oserrorz<test_md_report_fallback_forbidden.<locals>.mock_open_oserrorp  s8    t9(SD[;<<T42622r   zbuiltins.openEVIDENCE_INCOMPLETErG   NrF   )r)r   r2   r   inspect	signaturerT   
parameterslowerr[   rU   rV   opensetattr)r^   monkeypatchr1   sigp	md_paramsfail_runnerresult_failr   result_incompleter   s             @r   !test_md_report_fallback_forbiddenr   J  sc    "1!4*	F 

F77
8CNNYqdaggi.?8qwwyCXYIYy>QW"KI; WW '1!4*	K 22 3 K
 y!V+ B+
 M3 ):;33 4 
 Y'+@@@@9:BBB<=EEEK Zs   )D/6D/c                
   d }t        |d t        |       }|j                  t        t        g       }|d   dk(  sJ |d   dk(  sJ |d	   d
k(  sJ |d   J | dz  dz  }|t         dz  }|j                         rJ d       y)uV   TimeoutExpired raise → outcome=FAIL / exit_code=124 / critical=7 / marker 미생성.c                `    d| v rt        dt        dz   d      S t        j                  | d      )Nr(   r   r)   r*   i,  )cmdtimeout)r#   r,   r!   TimeoutExpired)r   r-   s     r   timeout_runnerz>test_timeout_classifies_critical_seven.<locals>.timeout_runner  s1    $*1md.BBGG''D#>>r   c                     y r5   r   r6   s    r   r7   z8test_timeout_classifies_critical_seven.<locals>.<lambda>  r8   r   r9   r?   rC   rf   rE   |   rF   rg   rG   Nro   rp   rq   u*   timeout 시 marker가 생성되면 안 됨)r   r   rT   rU   rV   rW   )r^   r   r1   r_   ru   rv   s         r   &test_timeout_classifies_critical_sevenr     s    ?
 "(*	F (( ) F )&&&+#%%%12a777./777 H$x/J\N/::F}}L LLr   c                    t        j                  t        j                        } t	        | j
                  j                               }d|v sJ d       d|v sJ d       d|v sJ d       d|v sJ d|v sJ d	|v sJ t        j                  t        j                        }t	        |j
                  j                               }d|v sJ d       d|v sJ d       d
|v sJ d       t        j                  t        j                        }t	        |j
                  j                               }d|v sJ d|v sJ d|v sJ d|v sJ t        dk(  sJ t        dk(  sJ y)u   run_post_merge_smoke / classify_smoke_failure_as_critical_seven 시그니처 보존.

    task-2540 critical_escalation_reporter / task-2541 self-resume이 import 가능 형태.
    r@   u   task_id 파라미터 없음rA   u    merge_commit 파라미터 없음rB   u"   expected_files 파라미터 없음r|   r   r   rk   u$   execution_result 파라미터 없음r:   r;   r<   r=   l   L5: POST_MERGE_SMOKE_FAILUREN)r   r   r   rT   setr   keysrr   __init__r	   r
   )sig_run
params_runsig_classifyparams_classifysig_initparams_inits         r   test_interface_contractr     s     4 I IJGW'',,./J
"A$AA"Z'K)KK'z)O+OO) j(((j(((
""" $$%9%b%bcL,116689O'F)FF'_,P.PP,0X2XX0   !5!>!>?Hh))..01K+--- K///k!!!{*** j((( .1KKKKr   )returnr   )r   okr*   )r   intr   r   r    r   r   zsubprocess.CompletedProcess)r   r*   )r/   r   r0   r   r   z*Callable[..., subprocess.CompletedProcess])r^   r   r   None)r^   r   r|   
str | Noner   r   r   r   r   r   r   r   )r   r   )-__doc__
__future__r   r   r\   r!   sysr   r   pathlibr   typingr   r   __file__resolveparentsWORKSPACE_ROOTr   r   insertanu_v2.post_merge_smoke_runnerr	   r
   r   rV   FAKE_MERGE_SHAr,   rU   parentFIXTURE_DIRr   r#   r2   rc   rw   markparametrizer   r   r   r   r   r   r   r   r   r   <module>r      s|   #    
 '    h'')11!4~chh&HHOOAs>*+  
;8n##**Z7B 


 
 !	

 )/^&JX :	      	 
   
  .%>V
(:@5FvMD&Lr   