
    =XjH                    R   d Z ddl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mZ dZeej                  vrej                  j                  de       ddlmZ ddlZ ee      Zedz  Zd	 Z G d
 d      ZddZddZddZdd	 	 	 	 	 	 	 	 	 ddZdZdZdZd Zd Z d Z!d Z"d Z#y)u  task-2708 P2-A 회귀 테스트 RS-1~5.

아르고스 (dev1 QA/테스터) — CHAIR-AUTH-TASK-2708-P2A-CALLBACK-BEFORE-FAILFAST-PREREGISTRATION-260529

대상: scripts/harness/v36/callback_preregistration.py (헬퍼 코드 수정 0)
전략:
  - importlib.util.spec_from_file_location 으로 헬퍼 직접 로드 (패키지 경로 의존 최소화)
  - dispatch.normal_fallback_callback_helper 를 모듈 레벨에서 미리 import 하여
    _load_prereg() 내 exec_module 시 sys.modules 캐시 히트로 ModuleNotFoundError 방지
  - monkeypatch 로 prereg._cb_helper.launch_callback 을 mock (실제 cron 등록 회피)
  - tmp_path 로 events_dir / envelope 완전 격리
    )annotationsN)Path)List)	MagicMockz/home/jay/workspacez/scripts/harness/v36/callback_preregistration.pyc                     t         j                  j                  dt              } t         j                  j	                  |       }| j
                  j                  |       |S )u   callback_preregistration 모듈을 매 테스트 함수마다 깨끗하게 로드.

    dispatch.normal_fallback_callback_helper 는 모듈 레벨에서 이미
    sys.modules 에 등록되어 있으므로 exec_module 내 import 가 성공한다.
    #callback_preregistration_under_test)	importlibutilspec_from_file_location_HELPER_PATHmodule_from_specloaderexec_module)specmods     F/home/jay/workspace/tests/harness/test_p2a_callback_preregistration.py_load_preregr   (   sJ     >>11-|D ..
)
)$
/CKKC J    c                  4    e Zd ZdZdddZedd       Zd	dZy)
_FakeDecisionu?   LaunchDecision 의 가벼운 mock (ok/verdict/reasons/to_json).Nc                6    || _         || _        |xs g | _        y N)_okverdictreasons)selfokr   r   s       r   __init__z_FakeDecision.__init__;   s    }"r   c                    | j                   S r   )r   r   s    r   r   z_FakeDecision.ok@   s    xxr   c                4    | j                   | j                  dS )N)r   r   )r   r   r    s    r   to_jsonz_FakeDecision.to_jsonD   s    <<txx88r   r   )r   boolr   strr   zList[str] | None)returnr#   )r%   dict)__name__
__module____qualname____doc__r   propertyr   r"    r   r   r   r   8   s#    I%
  9r   r   c                     t        dd      S )NTPASS)r   r   r   r,   r   r   _pass_decisionr0   H   s    D&11r   c                      t        dddg      S )NFFAIL_CLOSEDzself-key detected)r   r   r   r/   r,   r   r   _fail_closed_decisionr3   L   s    E=CVBWXXr   c                h    | | dz  }|j                  t        j                  |dd      d       |S )u/   dummy envelope 파일 생성 후 경로 반환.z.envelope.jsonnormal)task_idkindzutf-8)encoding)
write_textjsondumps)tmp_pathr6   ps      r   _make_enveloper>   R   s6    gYn--ALLBCgLVHr   )	workspacec               J    dd|d|d|d|d|d|d|d	|g}	| j                  |	      S )
u+   prereg.main() 을 argv 리스트로 호출.launchz	--task-idz--kindz--owner-keyz	--chat-idz--executor-keyz--envelope-pathz--events-dirz--workspace)main)
preregr6   r7   	owner_keyexecutor_keychat_idenvelope_path
events_dirr?   argvs
             r   _invokerJ   Y   sG    
 	W$yW,=
y
D ;;tr   c119085addb0f8b7zexecutor-self-key-other
6937032012c                   t        d      }t        j                  |j                               }|d   }t	               }g fd}|j                  |j                  d|       | dz  }|j                          t        | |      }t        |||d   |d   |d   |d	   t        |      t        |      
      }	|	dk(  s
J d|	        || dz  }
|
j                         s
J d|
        t        j                  |
j                               }|d   dk(  sJ d|d           |d   du sJ d       || dz  }|j                         s
J d|        t              dk(  sJ dt                      y)u.  RS-1: envelope 존재 + ANU owner → pre-registration PASS.

    검증:
      - exit 0
      - {task_id}.callback-prereg-launch.json 존재
      - 마커 status == "ANU_OWNED_READY"
      - lock 파일 존재 ({task_id}.callback-prereg-lock)
      - launch_callback 이 정확히 1회 호출됨
    zH/home/jay/workspace/tests/fixtures/p2a/task-2707-tdd-check-failfast.jsonr6   c                 :    j                  d       t               S Ncalledappendr0   kwargscall_logs    r   fake_launch_callbackzGtest_rs1_failfast_path_registers_callback.<locals>.fake_launch_callback       !r   launch_callbackeventsr7   rD   rE   rF   r6   r7   rD   rE   rF   rG   rH   r   z!RS-1: exit code should be 0, got .callback-prereg-launch.jsonzRS-1: launch marker not found: statusANU_OWNED_READYz+RS-1: expected status ANU_OWNED_READY, got rC   Tz RS-1: prereg flag should be True.callback-prereg-lockzRS-1: lock file not found:    z9RS-1: launch_callback should be called exactly once, got Nr   r:   loads	read_textr   setattr
_cb_helpermkdirr>   rJ   r$   existslen)r<   monkeypatchfixture_pathfixturer6   rC   rV   rH   enveloperclaunch_markermarker_datalockrU   s                @r   )test_rs1_failfast_path_registers_callbackrp   u   s    bcLjj//12Gi G^FH  ))+<>RSH$Jh0H	V_+&^,	"(mz?	
B 7<7t<<7G9,H!IIM!T%D]O#TT!**]4467Kx $55 
5k(6K5LM5 x D(L*LL(7)#899D;;=>7v>>=x=Aj!Z[^_g[hZijjr   c                   t        d      }t        j                  |j                               }|d   }t	               }g fd}|j                  |j                  d|       | dz  }|j                          t        | |      }t        |||d   |d   |d   |d	   t        |      t        |      
      }	|	dk(  s
J d|	        || dz  }
|
j                         s
J d|
        t        j                  |
j                               }|d   dk(  sJ d|d           |d   dk(  sJ d       || dz  }|j                         s
J d|        t              dk(  sJ dt                      y)uH  RS-2: fallback kind, envelope 존재 + ANU owner → PASS.

    scope_guard fail 이 발생해도 fail-fast 이전 fallback pre-reg 가 동작함을 검증.
    검증:
      - {task_id}.callback-fallback-launch.json 존재
      - status == "ANU_OWNED_READY"
      - fallback lock ({task_id}.callback-fallback-lock) 존재
    zD/home/jay/workspace/tests/fixtures/p2a/scope-guard-violation-35.jsonr6   c                 :    j                  d       t               S rO   rQ   rS   s    r   rV   zEtest_rs2_scope_guard_failfast_registers.<locals>.fake_launch_callback   rW   r   rX   rY   r7   rD   rE   rF   rZ   r   z!RS-2: exit code should be 0, got .callback-fallback-launch.jsonz(RS-2: fallback launch marker not found: r\   r]   z+RS-2: expected status ANU_OWNED_READY, got fallbackzRS-2: kind should be fallback.callback-fallback-lockzRS-2: fallback lock not found: r_   z1RS-2: launch_callback should be called once, got Nr`   )r<   rh   ri   rj   r6   rC   rV   rH   rk   rl   fallback_markerrn   fallback_lockrU   s                @r   'test_rs2_scope_guard_failfast_registersrx      s    ^_Ljj//12Gi G^FH  ))+<>RSH$Jh0H	V_+&^,	"(mz?	
B 7<7t<<7 gY.L#MMO!!#a'OP_O`%aa#**_6689Kx $55 
5k(6K5LM5 v*,N0MN,G9,C!DDM!T%D]O#TT!x=Ab!RSVW_S`Rabbr   c                   t        d      }t        j                  |j                               }|d   }t	               }g fd}|j                  |j                  d|       | dz  }|j                          t        | dz        }t        ||dt        t        t        |t        |            }	|	d	k(  s
J d
|	        || dz  }
|
j                         rJ d       t              d	k(  sJ d       | dz  }|j                          t        | |      }t        ||dt        t        t        t        |      t        |            }|d	k(  s
J d|        || dz  }|j                         s
J d|        t        j                  |j                               }|d   dk(  sJ d|d           t              dk(  sJ dt                      y)u   RS-3: 두 케이스 모두 검증.

    Case A: envelope 부재 → skip, exit 0, launch 마커 없음 (success path 깨지지 않음)
    Case B: envelope 존재 + ANU → 정상 prereg-launch 마커 생성
    z>/home/jay/workspace/tests/fixtures/p2a/success-baseline-5.jsonr6   c                 :    j                  d       t               S rO   rQ   rS   s    r   rV   zGtest_rs3_success_baseline_normal_callback.<locals>.fake_launch_callback   rW   r   rX   events_azdoes_not_exist.envelope.jsonr5   rZ   r   z(RS-3 Case A: exit code should be 0, got r[   z>RS-3 Case A: launch marker must NOT exist when envelope absentzDRS-3 Case A: launch_callback must not be called when envelope absentevents_bz(RS-3 Case B: exit code should be 0, got z)RS-3 Case B: launch marker should exist: r\   r]   z+RS-3 Case B: expected ANU_OWNED_READY, got r_   zBRS-3 Case B: launch_callback should be called once in Case B, got N)r   r:   ra   rb   r   rc   rd   re   r$   rJ   ANU_OWNER_KEYEXECUTOR_OTHER_KEYCHAT_IDrf   rg   r>   )r<   rh   ri   rj   r6   rC   rV   events_dir_amissing_enveloperc_alaunch_marker_aevents_dir_b
envelope_brc_blaunch_marker_brn   rU   s                   @r   )test_rs3_success_baseline_normal_callbackr      s    XYLjj//12Gi G^FH  ))+<>RS j(L8&DDE'&|$	D 19G@GG9"y0L%MMO%%'i)ii'x=Aeee j(L'2J'*o|$	D 19G@GG9"y0L%MMO!!#b'PQ`Pa%bb#**_6689Kx $55 
5k(6K5LM5 x=As!cdghpdqcrssr   c                V   t        d      }t        j                  |j                               }|d   }t	               }g fd}|j                  |j                  d|       | dz  }|j                          t        | |      }t        |dt        t        t        t        |      t        |            }	t        |fi |	}
|
dk(  s
J d	|
        || d
z  }|j                         sJ d       |j!                         j"                  }t%              dk(  sJ dt%                      || dz  }|j                         sJ d       t        |fi |	}|dk(  s
J d|        t%              dk(  sJ dt%                      |j!                         j"                  }||k(  sJ d       y)u  RS-4: 1차 호출(ANU PASS) → lock+marker 생성. 2차 호출 → silent skip.

    검증:
      - launch_callback call count == 1 (2차 호출에서 호출 안 됨)
      - 마커 재생성 안 됨 (mtime 변화 없음)
      - lock 존재
      - 두 번 모두 exit 0
    z?/home/jay/workspace/tests/fixtures/p2a/duplicate-call-mock.jsonr6   c                 :    j                  d       t               S rO   rQ   rS   s    r   rV   z@test_rs4_duplicate_idempotent_skip.<locals>.fake_launch_callbackC  rW   r   rX   rY   r5   rZ   r   z*RS-4: 1st call exit code should be 0, got r[   z/RS-4: launch marker should exist after 1st callr_   z=RS-4: after 1st call, launch_callback count should be 1, got r^   z&RS-4: lock should exist after 1st callz*RS-4: 2nd call exit code should be 0, got zJRS-4: after 2nd call, launch_callback should still be 1 (idempotent), got uN   RS-4: launch marker must NOT be recreated on 2nd call (idempotent §5.3/§9.2)N)r   r:   ra   rb   r   rc   rd   re   r>   r&   r}   r~   r   r$   rJ   rf   statst_mtimerg   )r<   rh   ri   rj   r6   rC   rV   rH   rk   common_argsrc1rm   mtime_after_firstro   rc2mtime_after_secondrU   s                   @r   "test_rs4_duplicate_idempotent_skipr   3  s    YZLjj//12Gi G^FH  ))+<>RSH$Jh0H'(mz?K &
(K
(C!8GA#GG8G9,H!IIM!T#TT!%**,55x=An!^_bck_l^mnn7)#899D;;=BBB= &
(K
(C!8GA#GG8x=A 
TUXYaUbTcd
 '++-66 22 X2r   c                p   t        d      }t        j                  |j                               }|d   }t	               }g fd}|j                  |j                  d|       | dz  }|j                          t        | |      }t        |dt        t        t        t        |      t        |            }	t        |fi |	}
|
dk(  s
J d	|
        || d
z  }|j                         s
J d|        t        j                  |j                               }|d   dk(  sJ d|d           |d   dk(  sJ d       || dz  }|j                         s
J d|        t!              dk(  sJ dt!                      t        |fi |	}|dk(  s
J d|        t!              dk(  sJ dt!                      y)ul  RS-5: fallback kind 1차 호출 → fallback-launch.json 생성 + fallback-lock.

    fallback lock 존재 → 재호출 시 silent skip (무한 재귀 방지).
    검증:
      - {task_id}.callback-fallback-launch.json 존재, status ANU_OWNED_READY
      - fallback lock 존재
      - 2차 호출 시 launch_callback 호출 안 됨 (total call count == 1)
    zA/home/jay/workspace/tests/fixtures/p2a/layer1-self-fail-mock.jsonr6   c                 :    j                  d       t               S rO   rQ   rS   s    r   rV   zDtest_rs5_layer1_self_fail_no_recursion.<locals>.fake_launch_callback  rW   r   rX   rY   rt   rZ   r   z*RS-5: 1st call exit code should be 0, got rs   z(RS-5: fallback launch marker not found: r\   r]   z$RS-5: expected ANU_OWNED_READY, got r7   zRS-5: kind should be fallbackru   zRS-5: fallback lock not found: r_   z-RS-5: after 1st call, count should be 1, got z*RS-5: 2nd call exit code should be 0, got zaRS-5: 2nd call must NOT invoke launch_callback again (no recursion). Expected total count=1, got N)r   r:   ra   rb   r   rc   rd   re   r>   r&   r}   r~   r   r$   rJ   rf   rg   )r<   rh   ri   rj   r6   rC   rV   rH   rk   r   r   rv   rn   rw   r   rU   s                  @r   &test_rs5_layer1_self_fail_no_recursionr   w  s    [\Ljj//12Gi G^FH  ))+<>RSH$Jh0H'(mz?K &
(K
(C!8GA#GG8 gY.L#MMO!!#a'OP_O`%aa#**_6689Kx $55 
.{8/D.EF5 v*,M.MM,G9,C!DDM!T%D]O#TT!x=A^!NsS[}o^^ &
(K
(C!8GA#GG8x=A ''*8}o	7r   )r%   r   )r<   r   r6   r$   r%   r   )r6   r$   r7   r$   rD   r$   rE   r$   rF   r$   rG   r$   rH   r$   r?   r$   r%   int)$r*   
__future__r   importlib.utilr	   r:   syspathlibr   typingr   unittest.mockr   _WORKSPACE_STRpathinsert(dispatch.normal_fallback_callback_helpernormal_fallback_callback_helper_cb_helper_preloadpytest
_WORKSPACEr   r   r   r0   r3   r>   rJ   r}   r~   r   rp   rx   r   r   r   r,   r   r   <module>r      s    #   
   # '!HHOOA~& F  .!
MM 9 9 2Y 3),:=7:& #. 
5kx4cv@tN=H=r   