
     j/                       d Z ddlm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mZ ddlmZ ddlZ ee      j$                  j$                  j$                  Zedz  Z ee      ej,                  vr"ej,                  j/                  d ee             ddlmZmZmZ edz  d	z  d
z  dz  Zedz  dz  dz  Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%g dZ&ddZ'd Z(d Z)y)uf  
tests/regression/test_workflow_sha_payload.py

task-2486 회귀 테스트: CI pull_request SHA payload fallback fix
작성자: 아르고스 (dev1-team 테스터)

대상 모듈: scripts/verify_workflow_sha_payload.py
- _resolve_pr, _resolve_sha, _load_event 헬퍼 단위 테스트
- fixture 기반 dry-run 통합 테스트
- ci.yml 구조 회귀 테스트
    )annotationsN)Path)patchscripts)_load_event_resolve_pr_resolve_shatests
regressionfixturesworkflow_sha_payloadz.github	workflowszci.ymlc                 	   t         dz  } t         dz  }t        t        |             }t        |dd      5 }t	        j
                  |      }ddd       t        |ddd	      \  }}t        ||xs ddd
      \  }}}	t        |xr |      }
|
rdnd}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|       dz   d|iz  }t!        t        j"                  |            dx}}|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|      dz   d|iz  }t!        t        j"                  |            dx}}|d   }t        |      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        j                  d|d   d|      dz   d|iz  }t!        t        j"                  |            dx}x}}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z   d|iz  }t!        t        j"                  |            dx}}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z   d|iz  }t!        t        j"                  |            dx}}y# 1 sw Y   xY w)%uB   A-1: pr_event_normal.json — SHA + PR 정상 추출, exit_code 0.zpr_event_normal.jsonzpr_event_normal.expected.jsonrutf-8encodingN Tbranchrepodry_runr   r   r      	exit_code==z%(py0)s == %(py3)sgot_exitpy0py3exit_code mismatch: expected=, got=
>assert %(py5)spy5shazSHA mismatch: expected=pr)z0%(py0)s == %(py6)s
{%(py6)s = %(py2)s(%(py4)s)
}	pr_numberstr)r!   py2py4py6zPR mismatch: expected=z
>assert %(py8)spy81	sha_stagez'SHA stage should be '1' (primary), got=pr_stagez&PR stage should be '1' (primary), got=FIXTURES_DIRr   r*   openjsonloadr   r	   bool
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)
event_pathexpected_patheventfexpectedr)   r1   r'   r0   _resolved_okr   @py_assert2@py_assert1@py_format4@py_format6@py_assert3@py_assert5@py_format7@py_format9s                       A/home/jay/workspace/tests/regression/test_workflow_sha_payload.pytest_resolve_normal_eventrQ   -   s    66J #BBMJ(E	mS7	3  q99Q<  &eBRNIx$UI,=BPTUCAs(y)KqQH, 8,,  8,              -    ((='>fXJO     5/]3/!]]]3/]]]]]]3]]]3]]]/]]]%<Xe_<OvVYU\#]]]]]]]$TN N+ 9++   9+                        +    ,    !$ 2&F     T9TTT9TTTTTT9TTT9TTTTTTFymTTTTTTTQ8s?QQQ8sQQQQQQ8QQQ8QQQsQQQDXLQQQQQQQ%   s   SSc                    t         dz  } t         dz  }t        t        |             }t        |dd      5 }t	        j
                  |      }ddd       j                  di       }t        j                  t        j                  |      5  t        |ddd	
      \  }}t        ||xs ddd	      \  }}	}ddd       t        xr       }
|
rdnd}|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|       dz   d|iz  }t+        t        j,                  |            dx}}|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|      dz   d|iz  }t+        t        j,                  |            dx}}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z   d|iz  }t+        t        j,                  |            dx}}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z   d|iz  }t+        t        j,                  |            dx}}y# 1 sw Y   xY w# 1 sw Y   ;xY w)z\A-2: pr_event_empty_sha.json + GITHUB_SHA env_override. fallback SHA = 'fallback_sha_value'.zpr_event_empty_sha.jsonz pr_event_empty_sha.expected.jsonr   r   r   Nenv_overridesr   Tr   r   r   r   r   r   r   r   r    r#   r$   r%   r&   r'   z fallback SHA mismatch: expected=fallback_sha_valuez&SHA must be 'fallback_sha_value', got=3r0   z)SHA fallback should reach stage '3', got=)r3   r   r*   r4   r5   r6   getr   dictosenvironr   r	   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   )rA   rB   rC   rD   rE   rS   r)   rF   r'   r0   rG   r   rH   rI   rJ   rK   s                   rP   !test_resolve_empty_sha_falls_backrZ   H   s    99J #EEMJ(E	mS7	3  q99Q<  LL"5M	BJJ	. 
"5"dK	1(9$2t
Y
 s(y)KqQH, 8,,  8,              -    ((='>fXJO     5/ 3/!  3/              "    +8E?*=VC7K     'X3&&XXX3&XXXXXX3XXX3XXX&XXX*PQTPW(XXXXXXXV9VVV9VVVVVV9VVV9VVVVVVHVVVVVVV-   

 
s   O	*O,O),O6c                    t         dz  } t         dz  }t        t        |             }t        |dd      5 }t	        j
                  |      }ddd       t        |ddd	      \  }}t        ||xs ddd
      \  }}}t        |xr |      }	|	rdnd}
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z   d|iz  }t!        t        j"                  |            dx}}d   }|
|k(  }|st        j                  d|fd|
|f      dt        j                         v st        j                  |
      rt        j                  |
      ndt        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}}| }|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}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z   d|iz  }t!        t        j"                  |            dx}}y# 1 sw Y   xY w)u>   A-3: pr_event_empty_pr.json — PR 추출 실패, exit_code 1.zpr_event_empty_pr.jsonzpr_event_empty_pr.expected.jsonr   r   r   Nr   Tr   r   r   r   r   r   r   r    z'empty PR should yield exit_code=1, got=r%   r&   r   assert %(py5)sPR should be empty, got=
>assert not %(py0)sr!   r)   noner1   zPR stage should be 'none', got=r2   )rA   rB   rC   rD   rE   r)   r1   r'   rF   rG   r   rH   rI   rJ   rK   @py_format2s                   rP   test_resolve_empty_pr_failsra   g   s    88J #DDMJ(E	mS7	3  q99Q<  &eBRNIxUI$5BMICAs(y)KqQHN8q=NNN8qNNNNNN8NNN8NNNqNNNCH:NNNNNNN,,8,,,,,8,,,,,,,8,,,8,,,,,,,,,,,=B=BB4YMBBBBBBByBBByBBBBBBM8vMMM8vMMMMMM8MMM8MMMvMMM!@MMMMMMM   s   L>>Mc                    t         dz  } t         dz  }t        t        |             }t        |dd      5 }t	        j
                  |      }ddd       t        j                  j                         D ci c]  \  }}|dk7  s|| }}}t        j                  t        j                  |d	      5  t        |d
d
d      \  }}	t        ||xs dd
d      \  }
}	}	ddd       t        
xr       }|rdnd}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z   d|iz  }t+        t        j,                  |            dx}}d   }||k(  }|st        j                  d|fd||f      dt!        j"                         v st        j$                  |      rt        j&                  |      ndt        j&                  |      dz  }dd|iz  }t+        t        j,                  |            dx}}|
 }|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# 1 sw Y   !xY wc c}}w # 1 sw Y   xY w)uM   A-4: pr_event_empty_both.json — SHA + PR 모두 추출 실패, exit_code 1.zpr_event_empty_both.jsonz!pr_event_empty_both.expected.jsonr   r   r   N
GITHUB_SHAT)clearr   r   r   r   r   r   r   r   r    z)empty both should yield exit_code=1, got=r%   r&   r   r\   zSHA should be empty, got=r^   r!   r'   r]   r)   )r3   r   r*   r4   r5   r6   rX   rY   itemsr   rW   r   r	   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   )rA   rB   rC   rD   rE   kvenv_without_shar)   rF   r'   rG   r   rH   rI   rJ   rK   r`   s                     rP   test_resolve_empty_both_failsri   |   sa    ::J #FFMJ(E	mS7	3  q99Q<  )+

(8(8(:P1a<>Oq!tPOP	BJJt	< R"5"dK	1 	(9TDQ	QR s(y)KqQHP8q=PPP8qPPPPPP8PPP8PPPqPPPEhZPPPPPPP,,8,,,,,8,,,,,,,8,,,8,,,,,,,,,,,77777/w7777777s777s777777=B=BB4YMBBBBBBByBBByBBBBBB    QR Rs#   M*4M7M70*M=*M4=Nc                    ddddddi} t        d      5 }t        | dd	d
      \  }}}ddd       d}|k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}d}|k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}d
}|u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}j                          y# 1 sw Y   xY w)uC   B-5: SHA 1단계(primary) 채택 시 gh pr view 호출 0건 확인.pull_request/   (deadbeef1234567890abcdef1234567890abcdefztask-2486-dev1r'   refnumberhead+scripts.verify_workflow_sha_payload._run_gh47
owner/repoT)r)   r   r   Nr   r   r'   r    r\   r&   r/   r0   isz%(py0)s is %(py3)ssha_is_canonical)r   r	   r8   r9   r:   r;   r<   r=   r?   r@   assert_not_called)	rC   mock_ghr'   r0   ry   rH   rI   rJ   rK   s	            rP   %test_canonical_skip_when_primary_usedr|      s~    	A'
E 
<	= 
+7Td,
(Y(
 =<3<<<<<3<<<<<<<3<<<3<<<<<<<<<<<9999##t####t############t#######
 
s   H44H>c                    ddl m}  d}d}d}d}t        j                  d|i      }t	        d|	      5   | |||      \  }}d
d
d
       d}|u }	|	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z   d|
iz  }t        t        j                  |            d
x}	}|k(  }	|	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z   d|iz  }t        t        j                  |            d
}	||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z   d|iz  }t        t        j                  |            d
}	y
# 1 sw Y   xY w) u]   B-6: fallback SHA(3단계) 사용 시 canonical 비교 강제. mismatch → canonical 교체.r   )_verify_canonicalrT   $canonical_sha_value_abcdef1234567890rt   ru   
headRefOidrs   return_valueNTrv   rx   was_mismatchr    z%canonical mismatch should be detectedr%   r&   r   )z%(py0)s == %(py2)s	final_shacanonical_shar!   r+   zfinal SHA should be canonical=r$   
>assert %(py4)sr,   )!=)z%(py0)s != %(py2)sfallback_shaz3fallback SHA should have been replaced by canonical)#scripts.verify_workflow_sha_payloadr~   r5   dumpsr   r8   r9   r:   r;   r<   r=   r>   r?   r@   )r~   r   r   r)   r   mock_outputr   r   rH   rI   rJ   rK   @py_format3@py_format5s                 rP   !test_canonical_used_when_fallbackr      s   E'L:MID **lM:;K	<;	W S"3L)T"R	<S  H<4HHH<4HHHHHH<HHH<HHH4HHH!HHHHHHH%  9                &    &    )(9	}M     $[[[9[[[[[[9[[[9[[[[[[[[[[[[[&[[[[[[[S Ss   KKc                    ddddddd} t        j                  dddd	id
dddd	id
g      }t        d|      5  t        | ddd      \  }}ddd       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z   d|iz  }t        t	        j                  |            dx}}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z   d|iz  }t        t	        j                  |            dx}}y# 1 sw Y   xY w)uO   C-7: gh pr list 결과 2건 이상이면 PR fallback 실패 (모호함 방지).Nsome_shafeature-branchrn   rp   )rk   rq   
   loginowner)rq   headRefNameheadRepositoryOwner   rs   r   ru   Fr   r   r   r   r)   r    zAPR should be empty when gh pr list returns multiple results, got=r%   r&   r_   r1   z3PR stage should be 'none' on ambiguous result, got=)r5   r   r   r   r8   r9   r:   r;   r<   r=   r>   r?   r@   )rC   multi_resultr)   r1   rH   rI   rJ   rK   s           rP   test_pr_list_multiple_abortsr      s   
 &/?@
 E ::&6PWY`Oab&6PWY`Oab L
 
<<	X 
)*u
	8
  9?  9                  LI=Y      8v  8v                  >h\J    
 
s   GG c                 :   ddddddd} t        | ddd	
      \  }}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z   d|iz  }t        t        j                  |            dx}}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z   d|iz  }t        t        j                  |            dx}}y)uY   C-8: event.pull_request.number 없고 event.number 만 있는 경우 event.number 사용.c   Nsome_sha_value_herer   rn   rp   )rq   rk   r   Tr   99r   r   r)   r    z)should fall back to event.number=99, got=r%   r&   2r1   z2should use stage '2' (event.number fallback), got=)
r   r8   r9   r:   r;   r<   r=   r>   r?   r@   )rC   r)   r1   rH   rI   rJ   rK   s          rP   test_pr_event_number_fallbackr      sw    ,'
	E &eBRNIx 9  9                  4I=A      8s?  8s                  =XLI        )	zcancel-kill-switchzqc-checkzhidden-path-auditzlock-in-checkzmerge-safety-checkgemini-review-gatephase3-merge-gatezci-guardguardc                 |    t        t        dd      5 } t        j                  |       cd d d        S # 1 sw Y   y xY w)Nr   r   r   )r4   CI_YMLyaml	safe_load)rD   s    rP   _load_ci_ymlr     s1    	fcG	, !~~a ! ! !s   2;c            	        t               } | j                  di       }t        D cg c]	  }||vs| }}| }|st        j                  d| dt        |j                                      dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d}yc c}w )u>   D-9: ci.yml 에 필수 job 9개 모두 존재하는지 확인.jobsu(   ci.yml 에서 다음 job 이 누락됨: u   
존재하는 job: r^   r!   missingN)r   rV   REQUIRED_JOBSr8   r>   listkeysr:   r;   r<   r=   r?   r@   )cir   jobr   rI   r`   s         rP    test_ci_yml_required_jobs_intactr     s    	B#D+?ss$s?G?; ;   37) <!$))+./	1               @s
   	CCc                 |   t               } | j                  di       }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
      dz   d|iz  }t        t        j                  |            d}||   j                  dg       }d}	|D ]d  }
|
j                  dd      xs d}||v rd}	 nF|
j                  di       xs i }|j                         D ]  }t        |t              s||v sd}	 d f |	rpt        j                  d	| d| d|D cg c]  }|j                  dd       c}       dz   ddt	        j
                         v st        j                  |	      rt        j                  |	      ndiz  }t        t        j                  |             yc c}w )uy   D-10: gemini-review-gate 와 phase3-merge-gate 의 steps 에 verify_workflow_sha_payload.py --mode resolve 포함 확인.r   r   r   z-verify_workflow_sha_payload.py --mode resolve)in)z%(py0)s in %(py2)sjob_namer   zjob 'z' not found in ci.ymlr   r,   NstepsFrunr   Twithu   ' steps 에서 'u   ' 를 찾지 못함.
steps: namez	(no name)z
>assert %(py0)sr!   found)r   rV   r8   r9   r:   r;   r<   r=   r>   r?   r@   values
isinstancer*   )r   r   target_jobsEXPECTED_FRAGMENTr   rI   r   r   r   r   steprun_cmdwith_valrg   s@py_format1s                   rP   test_ci_yml_uses_resolve_stepr   &  s   	B#D')<=KG 
4HHHx4HHHHHHxHHHxHHHHHH4HHH4HHHH5
2G!HHHHHHHX""7B/ 	Dhhub)/RG G+xx+1rH__& a%*;q*@ E	  	
  H:-.?-@ A;@AaquuV[1ABD	
 	
 
6	
 	
   	
 	
 
	  	
 	
 	
 	
 	
%
( Bs   /H9)returnrW   )*__doc__
__future__r   builtinsr:   _pytest.assertion.rewrite	assertionrewriter8   r5   rX   syspathlibr   unittest.mockr   r   __file__parentWORKTREE_ROOTSCRIPTS_DIRr*   pathinsertr   r   r   r	   r3   r   rQ   rZ   ra   ri   r|   r   r   r   r   r   r   r    r   rP   <module>r      s   
 #    	 
   
 X%%,,33i'{388#HHOOAs=)*  w&5
BE[[		"[	08	;R6W>N*C: 2\6>8
!
	
r   