
    Fi7                       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Z ee      j#                         j$                  d   ZddZ edd      Z eed	       Zd
Zes.ddlZ ej4                  ej6                        Zdej:                  vZej<                  j?                  ed      Z ej<                  j?                  exs ed      Z! e"edz  dz        Z#d d!dZ$d"d!dZ%e d#d       Z&e d#d       Z'e d#d       Z(e d#d       Z)e d#d       Z*e d#d       Z+e d$d       Z,e d#d       Z-e d#d       Z.e!	 	 	 	 	 	 d%d       Z/e d#d       Z0d$dZ1y)&u  tests/regression/test_done_escalated_conflict.py — task-2471+1 F4 회귀 테스트 (Test 1).

``check_done_escalated_conflict`` 함수와 ``verify_done_preconditions`` 통합 검증.

토르(개발1팀)의 utils/silent_corruption_guard.py 수정을 영구 차단한다.
함수 시그니처:
    check_done_escalated_conflict(task_id: str, *, events_dir: Optional[str] = None) -> dict
    verify_done_preconditions(pr_number, repo, *, base_branch, gh_cmd, cwd, task_id, events_dir) -> dict

각 반환값: {"ok": bool, "reason": str, "detail": dict}
fail-closed 패턴: 파일 시스템 오류 시 ok=False.

헤임달(개발2팀 테스터) 작성 — task-2471+1 F4.
    )annotationsN)Path   c                <   t         |z  }t        j                  j                  | t	        |            }||j
                  t        d|       t        j                  j                  |      }|t        j                  | <   |j
                  j                  |       |S )u8   절대 경로로 모듈 로드 (sys.path 오염 방지).zcannot load spec for )	WORKSPACE	importlibutilspec_from_file_locationstrloaderImportErrormodule_from_specsysmodulesexec_module)mod_namefile_rel	file_pathspecmodules        D/home/jay/workspace/tests/regression/test_done_escalated_conflict.py_load_moduler      s    H$I>>11(C	NKD|t{{*1)=>>^^,,T2F"CKKKKF#M    &silent_corruption_guard_conflict_aliasz utils/silent_corruption_guard.pycheck_done_escalated_conflictFtask_iduA   check_done_escalated_conflict 미구현 (토르 작업 미완료))reasonuR   verify_done_preconditions task_id 파라미터 미구현 (토르 작업 미완료)memoryeventsc                <    | | dz  }|j                  |d       |S )u+   events_dir에 <task_id>.done 파일 생성.z.doneutf-8encoding
write_text
events_dirr   contentps       r   
_make_doner*   F   s(    y&&ALL7L+Hr   c                <    | | dz  }|j                  |d       |S )u5   events_dir에 <task_id>.done.escalated 파일 생성.z.done.escalatedr!   r"   r$   r&   s       r   _make_escalatedr,   M   s(    y00ALL7L+Hr   c                Z   t        | d       t        j                  dt        |             }t	        |t
              }|s!t        j                  d      dz   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dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      dz  }t        t        j                  |            d	}|d
   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}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  }d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  }dd|iz  }t        t        j                  |            d	x}}y	)uJ   .done 만 있고 .done.escalated 없으면 ok=True (정상 완료 상태).z	task-9001r'   u   반환값이 dict 이어야 함z7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstanceresultdictpy0py1py2py4NokTisz%(py1)s is %(py4)sr4   r6   assert %(py6)spy6r   inz%(py1)s in %(py3)sr4   py3assert %(py5)spy5detail)r*   scgr   r   r/   r1   
@pytest_ar_format_assertmsg@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation_call_reprcompare)	tmp_pathr0   @py_assert3@py_format5@py_assert0@py_assert2@py_format7@py_format4@py_format6s	            r   test_done_only_okrX   W   s    x%..{s8}.UFfd#F#FF%FFFFFFF:FFF:FFFFFFfFFFfFFFFFFdFFFdFFF#FFFFFF$<4<4<4<48v8v8vv8v8v8vvr   c           	        t        | dt        j                  ddd             t        j	                  dt        |             }|d   }d}||u }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)uV   .done.escalated 만 있고 .done 없으면 ok=True (에스컬레이션 완료 상태).z	task-9002tr)triggerr   r(   r.   r7   Tr8   r:   r;   r<   r=   N)r,   jsondumpsrF   r   r   rG   rO   rL   rM   rN   rP   r0   rS   rQ   rT   rR   rU   s          r   test_escalated_only_okra   e   s     Hk4::#Y\>]3^_..{s8}.UF$<4<4<4<4r   c                B   t         j                  dt        |             }|d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}y
)uS   .done / .done.escalated 모두 없으면 ok=True (미완료 상태, 충돌 없음).z	task-9003r.   r7   Tr8   r:   r;   r<   r=   N)rF   r   r   rG   rO   rL   rM   rN   r`   s          r   test_both_absent_okrc   p   sk     ..{s8}.UF$<4<4<4<4r   c                .   t        | dd       t        | dd       t        j                  dt	        |             }|d   }d}||u }|slt        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}d}|d   }|j                  } |       }||v }|st        j                  d|fd||f      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }	t        j                  d|d         dz   d|	iz  }
t        t        j                  |
            dx}x}x}x}}y)ud   정상 .done + 빈 .done.escalated 동시 존재 → conflict → ok=False, reason='coexist' 포함.z	task-9004doner]    r.   r7   Fr8   r:   r;   r<   r=   Ncoexistr   r>   zD%(py1)s in %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s.lower
}()
}r4   r6   r=   py8   reason에 'coexist' 없음: 
>assert %(py10)spy10)r*   r,   rF   r   r   rG   rO   rL   rM   rN   lowerrH   )rP   r0   rS   rQ   rT   rR   rU   @py_assert5@py_assert7@py_format9@py_format11s              r   &test_done_and_empty_escalated_conflictrs   z   sY    xf5Hk26..{s8}.UF$< 5 <5    <5   <   5        x( (.. .0 900  90        )    /    1    'vh'7&:;     r   c           
        t        | dd       t        j                  ddddt        | dz        d	d
d      }t	        | d|       t
        j                  dt        |             }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}x}}y)uV   정상 .done + 정상 payload .done.escalated 동시 존재 → conflict → ok=False.z	task-9005re   r]   z done-watcher.sh:stale_done_30minz2026-05-07T00:00:00Zzscripts/done-watcher.shtesthostztask-9005.doneil  zstale .done >= 1800s)r\   tssourcehost	done_pathage_secondsr   r.   r7   Fr8   r:   r;   uM   정상 .done + 정상 .done.escalated 동시 존재는 conflict 이어야 함
>assert %(py6)sr=   N)r*   r^   r_   r   r,   rF   r   rG   rO   rL   rH   rM   rN   )rP   valid_payloadr0   rS   rQ   rT   rR   rU   s           r   &test_done_and_valid_escalated_conflictr}      s     xf5JJ5$+$445(  M Hk=A..{s8}.UF$<q5q<5 qqq<5qqq<qqq5qqq"qqqqqqqqr   c                   t        | d       | dz  }|j                          t        j                  dt	        |            }|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}t        j                  dt	        |             }|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y)uF   events_dir=str(tmp_path) 명시 시 해당 경로에서 파일 탐색.z	task-9006otherr.   r7   Tr8   r:   r;   r<   r=   N)
r*   mkdirrF   r   r   rG   rO   rL   rM   rN   )	rP   	other_dirresult_otherrS   rQ   rT   rR   rU   	result_oks	            r   !test_events_dir_explicit_tmp_pathr      s    x%7"IOO44I 5 L %%%%%%%%%%%%%%%%%%% 11H 2 I T?"d"?d""""?d"""?"""d"""""""r   c                 ,   t         j                  d      } | d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	)
u  events_dir 미지정 시 /home/jay/workspace/memory/events 기본값 사용 확인.

    기본 이벤트 디렉토리가 실제로 존재하지 않아도 ok=True (파일 없음 = 충돌 없음).
    task_id가 실제 .done을 생성하지 않으면 ok=True를 반환해야 한다.
    z#task-nonexistent-heimdall-test-9007r7   Tr8   r:   r;   r<   r=   N)rF   r   rG   rO   rL   rM   rN   )r0   rS   rQ   rT   rR   rU   s         r   test_events_dir_default_pathr      sc     ../TUF$<4<4<4<4r   c                   t        | d       t        j                  dt        |             }|j	                  di       }h d}|t        |j                               z
  }| }|st        j                  d|d|      dz   dd	t        j                         v st        j                  |      rt        j                  |      nd	iz  }t        t        j                  |            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}||u }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            d
x}x}	}|d   }d}||u }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            d
x}x}	}y
)u_   detail dict에 task_id, done_path, escalated_path, done_exists, escalated_exists 포함 검증.z	task-9008r.   rE   >   r   ry   done_existsescalated_pathescalated_existsu   detail에 누락된 키: u   
실제 detail: z
>assert not %(py0)sr3   missingNr   ==)z%(py1)s == %(py4)sr;   r<   r=   r   Tr8   r:   r   F)r*   rF   r   r   getsetkeysrG   rH   rI   rJ   rK   rL   rM   rN   rO   )rP   r0   rE   required_keysr   @py_assert1@py_format2rS   rQ   rT   rR   rU   s               r   'test_detail_dict_contains_required_keysr      s    x%..{s8}.UFZZ"%FaMc&++-00G;Z;ZZ3G;>OPVzZZZZZZZwZZZwZZZZZZ)+++++++++++++++++++- (D( D(((( D((( (((D((((((($%..%....%...%..........r   c                   t        | d       t        | dd       t        j                  dt	        |             }|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                  di       }|j                  }d} ||      }	d}
|	|
u }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}x}	x}}
|j                  }d} ||      }	d}
|	|
u }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}x}	x}}
|j                  }d} ||      }	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}x}	x}}
y)uP   충돌 케이스에서 detail에 done_exists=True, escalated_exists=True 검증.z
task-9008brf   r]   r.   r7   Fr8   r:   r;   r<   r=   NrE   r   T)zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} is %(py9)s)r3   r5   r6   r=   py9zassert %(py11)spy11r   r   r   )zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)s)r*   r,   rF   r   r   rG   rO   rL   rM   rN   r   rI   rJ   rK   )rP   r0   rS   rQ   rT   rR   rU   rE   r   ro   @py_assert8rp   @py_format10@py_format12s                 r   test_detail_dict_conflict_caser      sV    x&HlB7..|H.VF$< 5 <5    <5   <   5       ZZ"%F::,m,:m$,,$,,,,$,,,,,,6,,,6,,,:,,,m,,,$,,,,,,,,,,::1(1:()1T1)T1111)T11111161116111:111(111)111T1111111::0i0:i 0L0 L0000 L00000060006000:000i000 000L00000000r   c           	     d   t        | d       t        | dd       t        j                  dt	        |             }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }t        j                  d
      dz   d|iz  }t        t        j                  |            dx}x}}d}|d   }|j                  } |       }	||	v }|st        j                  d|fd||	f      t        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }
t        j                  d|d         dz   d|
iz  }t        t        j                  |            dx}x}x}x}}	d }|j                  t        d|       t        t        d      r"|j                  t        j                  dd        t        j                  ddddt	        |             }|d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }t        j                  d|      dz   d|iz  }t        t        j                  |            dx}x}}y) uU  verify_done_preconditions(task_id=...) 호출 시 conflict 검사 통합 검증.

    .done + .done.escalated 충돌 상황에서 verify_done_preconditions가
    check_done_escalated_conflict를 내부적으로 호출하여 ok=False를 반환해야 한다.
    PR 검사는 monkeypatch로 우회하지 않고, 대신 conflict가 먼저 감지되어
    PR 검사 전에 실패하는 경우를 검증한다.

    Note: conflict 검사가 PR 검사보다 먼저 실행되는 구현을 가정.
          만약 PR 검사가 먼저라면 PR 검사 실패 후 conflict도 포함된 detail 검증.
    z	task-9009rf   r]   r.   r7   Fr8   r:   r;   u=   check_done_escalated_conflict가 conflict를 감지해야 함r{   r=   Nrg   r   r>   rh   ri   rk   rl   rm   c                      ~ ~y)N)rf   zgh: not available in test )_args_kwargss     r   	_fake_runzKtest_verify_done_preconditions_task_id_conflict_detected.<locals>._fake_run  s
    74r   _runtimesleepc                     y )Nr   )_s    r   <lambda>zJtest_verify_done_preconditions_task_id_conflict_detected.<locals>.<lambda>  s    r   i  z
owner/repomain)	pr_numberrepobase_branchr   r'   uI   conflict 상황에서 verify_done_preconditions가 ok=True를 반환함: )r*   r,   rF   r   r   rG   rO   rL   rH   rM   rN   rn   setattrhasattrr   verify_done_preconditions)rP   monkeypatchconflict_resultrS   rQ   rT   rR   rU   ro   rp   rq   rr   r   r0   s                 r   8test_verify_done_preconditions_task_id_conflict_detectedr      s    x%Hk26 77H 8 O 4  E  E)   E    !    %*    	H      1 177 79 999  99        2    8    :    'x'@&CD     5 VY/sFCHHg~>**x= + F $< 5 <5   <5        !    TTZS]^     r   c                   d}t        | |       t        j                  |t        |             }t	        |t
              }|sd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dt        j                         v st        j                  t
              rt        j                  t
              ndt        j                  |      dz  }t        t        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  }dd|iz  }t        t        j                  |            dx}}|d	   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}y)uR   task_id에 '+' 등 특수문자 포함 시 정상 처리 (파일시스템 안전).ztask-2471+1r.   z5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r/   r0   r1   r2   Nr7   r>   r@   rA   rC   rD   Tr8   r:   r;   r<   r=   )r*   rF   r   r   r/   r1   rI   rJ   rG   rK   rL   rM   rN   rO   )
rP   r   r0   rQ   rR   rS   rT   rV   rW   rU   s
             r   'test_task_id_with_special_chars_handledr   %  sZ    Gx!..w3x=.QFfd########:###:######f###f######d###d##########46>46466$<4<4<4<4r   c                    d} t        t        |       }|st        j                  d      dz   dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      dz  }t        t        j                  |            dx} }y)u   check_done_escalated_conflict 함수가 silent_corruption_guard에 존재해야 함.

    토르 작업 미완료 시 이 테스트가 FAIL하여 CI에서 즉시 감지 가능.
    r   uk   check_done_escalated_conflict 함수 미존재 — 토르의 utils/silent_corruption_guard.py 수정 필요z7
>assert %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
}r   rF   )r3   r4   rB   rD   N)
r   rF   rG   rH   rI   rJ   rK   rL   rM   rN   )rT   @py_assert4rW   s      r   /test_smoke_check_done_escalated_conflict_existsr   3  s    
 8 7378 8   	v                       8    9     r   )r   r   r   r   )re   )r'   r   r   r   r(   r   returnr   )rf   )rP   r   r   None)r   r   )rP   r   r   zpytest.MonkeyPatchr   r   )2__doc__
__future__r   builtinsrI   _pytest.assertion.rewrite	assertionrewriterG   importlib.utilr   r^   r   pathlibr   pytest__file__resolveparentsr   r   rF   r   CONFLICT_FN_MISSINGVERIFY_EXTENDED_MISSINGinspect	signaturer   _verify_sig
parametersmarkskipifSKIP_CONFLICTSKIP_VERIFY_EXTENDEDr   DEFAULT_EVENTS_DIRr*   r,   rX   ra   rc   rs   r}   r   r   r   r   r   r   r   r   r   r   <module>r      s   #      
  
 N""$,,Q/		 ,& "#'FGG  #'##C$A$ABK'{/E/EE""N #  {{))22_ *  
 X-89            	 	 r r* # #. 	  	  / /& 1 1" 00!30	0 0l    r   