
    +j,l                       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ZddlZddlZddlmZmZ ddlmZ  ee      j+                         j,                  j,                  Z ee      ej2                  vr"ej2                  j5                  d ee             d5dZ edd        ed	d
        edd        edd        edd      Z edd        edd        edd        edd      Z edd      Zd Z G d d      Z  G d dejB                        Z" G d  d!ejB                        Z# G d" d#ejB                        Z$ G d$ d%ejB                        Z% G d& d'ejB                        Z& G d( d)ejB                        Z' G d* d+      Z( G d, d-ejB                        Z) G d. d/ejB                        Z* G d0 d1ejB                        Z+ G d2 d3ejB                        Z,e-d4k(  r ej\                          yy)6u  task-2732 — P0B_MINIMUM_PICKUP reporting path regression.

driver(scan_once) 수거 verdict → 회장 chat PASS/HOLD/CALLBACK_MISSING 자동 보고.
네트워크 0, 전부 fake sender/tmpdir(isolated). canonical events(memory/events) 0 touch.
ANU/봇 key literal 절대 노출 0 — 보고는 sendfile only(key 불요), redaction helper 검증.

커버리지(완료조건):
  ①/② verdict → PASS/HOLD/CALLBACK_MISSING 매핑(단위) + NOOP_*/매핑 밖 → 보고 안 함.
  ③ key 노출 0: 모듈 소스에 키 literal 0 · redact_argv 마스킹 · 보고 argv --cron/--key 0.
  ④ launcher_fn=None 유지(wake 0): build_launcher_fn 기본 None · main → scan_once launcher_fn None
     · reporter 가 launch_wake/cron prompt 호출 0(소스/sender argv).
  ⑤ 중복 보고 0: 동일 task_id 2회 → 전송 1회(dedupe ledger).
  ⑥ canonical write 0: 보고 경로가 memory/events 변형 0(isolated tmp root).
    )annotationsN)datetimetimezone)Pathc                r   | t         j                  v rt         j                  |    S t        j                  j	                  | t
        |z        }g }d }||u}|}|r|j                  }d }||u}	|	}|slt        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  }|j                  |       |rt        j                  d	fdf      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                   |            d x}x}x}x}x}x}	}t        j                  j#                  |      }|t         j                  | <   |j                  j%                  |       |S )N)is not)z%(py2)s is not %(py5)sspec)py2py5z%(py7)spy7)z5%(py11)s
{%(py11)s = %(py9)s.loader
} is not %(py14)s)py9py11py14z%(py16)spy16r   zassert %(py19)spy19)sysmodules	importlibutilspec_from_file_location_ROOTloader
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprappend_format_boolopAssertionError_format_explanationmodule_from_specexec_module)modnamerelpathr	   @py_assert1@py_assert4@py_assert3@py_assert0@py_assert10@py_assert13@py_assert12@py_format6@py_format8@py_format15@py_format17@py_format18@py_format20mods                    5/home/jay/workspace/tests/test_anu_pickup_reporter.py_loadr6       sI   #++{{7##>>11'57?KD7t74t77474 777774t77777747774777t77777774777777777777777477777777777777
..
)
)$
/CCKKKKC J    z dispatch.callback_owner_enforcerz#dispatch/callback_owner_enforcer.pyz(dispatch.normal_fallback_callback_helperz+dispatch/normal_fallback_callback_helper.pyz'dispatch.anu_owned_callback_enforcementz*dispatch/anu_owned_callback_enforcement.pyzdispatch.anu_collector_resultz dispatch/anu_collector_result.pyzdispatch.anu_terminal_relayzdispatch/anu_terminal_relay.pyz!dispatch.anu_result_pickup_runnerz$dispatch/anu_result_pickup_runner.pyz!dispatch.anu_pickup_wake_launcherz$dispatch/anu_pickup_wake_launcher.pyz"dispatch.anu_callback_launch_auditz%dispatch/anu_callback_launch_audit.pyzdispatch.anu_pickup_reporterzdispatch/anu_pickup_reporter.pyzdispatch.anu_pickup_driverzdispatch/anu_pickup_driver.pyc            	     B    t        ddddddt        j                        S )Ni        r   )tzinfo)r   r   utc r7   r5   <lambda>r>   :   s    $2q!Qx||D r7   c                       e Zd ZdZdddZd Zy)_FakeSenderuC   전송 호출을 기록하는 fake sender. ok 반환 제어 가능.c                     || _         g | _        y N)okcalls)selfrC   s     r5   __init__z_FakeSender.__init__@   s    
r7   c                    	 t        |dd      5 }|j                         }d d d        | j                  j	                  |f       | j
                  S # 1 sw Y   2xY w# t        $ r d}Y Bw xY w)Nrutf-8encoding )openreadOSErrorrD   r   rC   )rE   	file_pathfhcontentss       r5   __call__z_FakeSender.__call__D   sj    	iw7 %2779% 	

9h/0ww% % 	H	s'   A AA AA A,+A,N)T)rC   bool)__name__
__module____qualname____doc__rF   rS   r=   r7   r5   r@   r@   =   s    Mr7   r@   c                  B    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestMapReportc                j    | j                  t        j                  d      t        j                         y )NCLOSEOUT_DONEassertEqualR
map_reportREPORT_PASSrE   s    r5   test_closeout_done_passz%TestMapReport.test_closeout_done_passP   s    o6Fr7   c                    | j                  t        j                  d      t        j                         | j                  t        j                  t        j                        t        j                         y )NAUTHORITATIVE)r^   r_   r`   ra   VERDICT_AUTHORITATIVErb   s    r5   test_authoritative_passz%TestMapReport.test_authoritative_passS   sB    o6Fa&=&=>Nr7   c                j    | j                  t        j                  d      t        j                         y )N
QUARANTINE)r^   r_   r`   REPORT_HOLDrb   s    r5   test_quarantine_holdz"TestMapReport.test_quarantine_holdW   s    l3Q]]Cr7   c                p    | j                  t        j                  dddi      t        j                         y )Nr\   callback_schedule_createdTr^   r_   r`   REPORT_CALLBACK_MISSINGrb   s    r5   (test_callback_schedule_created_violationz6TestMapReport.test_callback_schedule_created_violationZ   s-    LL+F*MN%%	
r7   c                p    | j                  t        j                  dddi      t        j                         y )Nr\   callback_presentFrn   rb   s    r5   test_callback_absent_signalz)TestMapReport.test_callback_absent_signala   s-    LL+=u*EF%%	
r7   c                    | j                  t        j                  dddi      t        j                         | j                  t        j                  dddi      t        j                         y )Nr\   rm   Fre   rr   Tr]   rb   s    r5   test_callback_ok_stays_passz)TestMapReport.test_callback_ok_stays_passg   sV    LL+F*NOMM	
 	LL+=t*DEMM	
r7   c                \    dD ]'  }| j                  t        j                  |      |       ) y )N)NOOP_DISABLEDNOOP_NOT_TARGETNOOP_NOT_READYNOOP_LEGACY_SKIPNOOP_MAX_FILES_DEFER)assertIsNoner_   r`   rE   vs     r5   test_noop_not_reportedz$TestMapReport.test_noop_not_reportedr   s+    > 	2Aall1oq1	2r7   c                n    dD ]0  }| j                  t        j                  |      t        |             2 y )N)
WAKE_BUILTPICKUP_SKIPFIRE_FAILEDrL   N)r|   r_   r`   reprr}   s     r5   &test_out_of_spec_verdicts_not_reportedz4TestMapReport.test_out_of_spec_verdicts_not_reportedw   s-    G 	8Aall1otAw7	8r7   c                l   | j                  t        j                  t        j                        t        j
                         | j                  t        j                  t        j                        t        j                         | j                  t        j                  t        j                               y rB   )
r^   r_   r`   DRVVERDICT_CLOSEOUT_DONEra   VERDICT_QUARANTINErj   r|   VERDICT_NOOP_DISABLEDrb   s    r5   #test_driver_verdict_constants_alignz1TestMapReport.test_driver_verdict_constants_align|   se    c&?&?@!--Pc&<&<=q}}M!,,s'@'@ABr7   N)rU   rV   rW   rc   rg   rk   rp   rs   ru   r   r   r   r=   r7   r5   rZ   rZ   O   s3    GOD

	
2
8
Cr7   rZ   c                      e Zd Zd Zd Zy)TestReportLinec                t    t         j                  dt         j                  dd      }| j                  |d       y )N	task-2732r\   abcdef0123456789u0   task-2732: PASS · CLOSEOUT_DONE · abcdef012345)r_   build_report_linera   r^   )rE   lines     r5   test_line_formatzTestReportLine.test_line_format   s0    "";#57QRr7   c                    | j                  t        j                  d      d       | j                  t        j                  d      d       y )Nz&/x/memory/events/task-2732.result.jsonr   z
/x/foo.txtrL   )r^   r_   task_id_from_pathrb   s    r5   test_task_id_from_pathz%TestReportLine.test_task_id_from_path   s=     HI;	X,,\:B?r7   N)rU   rV   rW   r   r   r=   r7   r5   r   r      s    S
@r7   r   c                  $    e Zd Zd Zd Zd Zd Zy)TestKeyExposureZeroc                    g d}t         j                  |      }| j                  d|       | j                  t         j                  |       y )N)z/usr/local/bin/cokacdir--cronmsg--key	SECRET123r   )r_   redact_argvassertNotInassertInREDACTED)rE   argvreds      r5   test_redact_argv_masks_keyz.TestKeyExposureZero.test_redact_argv_masks_key   s7    QmmD!c*ajj#&r7   c                r    t         j                  dg      }| j                  ddj                  |             y )Nz--key=SECRET123r   rL   )r_   r   r   join)rE   r   s     r5   test_redact_argv_eq_formz,TestKeyExposureZero.test_redact_argv_eq_form   s,    mm./0bggcl3r7   c                    t         dz  dz  j                  d      }dd l}|j                  d|      }| j	                  |g d|        y )Ndispatchanu_pickup_reporter.pyrI   rJ   r   z\b[0-9a-f]{16}\bu   key-like literal 발견: )r   	read_textrefindallr^   )rE   srcr   hitss       r5   !test_module_source_no_key_literalz5TestKeyExposureZero.test_module_source_no_key_literal   sO    z!$<<GGQXGYzz-s3r%>tf#EFr7   c                    t         j                  dt        j                        }| j	                  |d   d       | j                  d|       | j                  d|       y )N/tmp/x.report.txt   z
--sendfiler   r   )TRbuild_send_report_argvr_   ANU_CHAT_IDr^   r   )rE   r   s     r5   #test_report_argv_is_sendfile_no_keyz7TestKeyExposureZero.test_report_argv_is_sendfile_no_key   sM    (()<ammLa,/$'4(r7   N)rU   rV   rW   r   r   r   r   r=   r7   r5   r   r      s    '4G)r7   r   c                      e Zd Zd Zd Zd Zy)TestWakeZeroc                    | j                  t        j                  dd              | j                  t        j                  dd              y )Nz/nonexistent-rootc                      y rB   r=   r=   r7   r5   r>   zBTestWakeZero.test_build_launcher_fn_default_none.<locals>.<lambda>       r7   )real_wake_readerc                      y)Ndisabledr=   r=   r7   r5   r>   zBTestWakeZero.test_build_launcher_fn_default_none.<locals>.<lambda>   r   r7   )r|   r   build_launcher_fnrb   s    r5   #test_build_launcher_fn_default_nonez0TestWakeZero.test_build_launcher_fn_default_none   sQ    #//, 0 @ 	A#//2D 0 F 	Gr7   c                   t        j                         5 i ddddfd
}fd}t        t        d      }t        t        d      }t        t        d      }	 t	        t        d       t	        t        d|       t	        t        d|       t        j                         }t	        t        d|       t	        t        d|       t	        t        d|       | j                  |d	       | j                  d
   d       | j                  t        d         d       d d d        y # t	        t        d|       t	        t        d|       t	        t        d|       w xY w# 1 sw Y   y xY w)NFUNSETlegacy_cutofflauncher_fncallback_launch_fnc               j    | d<   |d<   |d<   dt         j                  j                  d      dgS )Nrootr   r   r\   task-1.result.jsonverdictresult_pathospathr   )r   r   r   r   kwcapturedtds        r5   fake_scan_oncezFTestWakeZero.test_main_launch_zero_and_reports.<locals>.fake_scan_once   sJ    #' *5'1C-.$3(*R9M(NP Q Qr7   c                    | d<   g S )Nrecordsr=   )r   r   r   s     r5   fake_report_recordszKTestWakeZero.test_main_launch_zero_and_reports.<locals>.fake_report_records   s    &-#	r7   CANONICAL_ROOT	scan_oncereport_recordsr   r   z!launcher_fn must be None (wake 0)r   r   )	tempfileTemporaryDirectorygetattrr   setattrmainr^   r|   len)	rE   r   r   	orig_root	orig_scanorig_reportrcr   r   s	          @@r5   !test_main_launch_zero_and_reportsz.TestWakeZero.test_main_launch_zero_and_reports   s4    ((* 	:bH6;29Q  %56I[1I!#'78K<-r2[.9-/BCXXZ-y9[)4-{;R#h}57Z[S)!45q9?	: 	:0 -y9[)4-{;5	: 	:s&   AEAD#"A8E#5EEE$c                    t         dz  dz  j                  d      }| j                  d|       | j                  d|       | j                  d|       y )Nr   r   rI   rJ   launch_wakerelay_to_anur   )r   r   r   rE   r   s     r5   test_reporter_source_no_wakez)TestWakeZero.test_reporter_source_no_wake   sQ    z!$<<GGQXGY,-3'r7   N)rU   rV   rW   r   r   r   r=   r7   r5   r   r      s    G#:J(r7   r   c                  6    e Zd Zd Zd Zd Zd Zd Zd Zd Z	y)	TestReportOnec                0   t         j                  j                  |dd      }t        j                  |d       t         j                  j                  || d      }t	        |dd      5 }t        j                  ||       d d d        |S # 1 sw Y   |S xY w)	NmemoryeventsTexist_ok.result.jsonwrI   rJ   r   r   r   makedirsrM   jsondump)rE   r   task_iddatar   prQ   s          r5   _result_filezTestReportOne._result_file   sw    b(H5
FT*GGLLG9L!9:!S7+ 	 rIIdB	 	 s   *BBc           	        t        j                         5 }| j                  |ddddd      }t        d      }t        j                  d|||t              }| j                  |j                  t        j                         | j                  |j                         | j                  t        |j                        d	       | j                  d
|j                  d   d	          | j                  d|j                  d   d	          | j                  t        j                  d|             d d d        y # 1 sw Y   y xY w)Nr   deadbeefcafe0000F)r   sha256rm   TrC   r\   r   senderclockr   ztask-2732: PASSr   deadbeefcafer   )r   r   r   r@   r_   
report_one_CLOCKr^   decisionra   
assertTruesentr   rD   r   already_reportedrE   r   r   r  decs        r5   test_pass_sends_and_marksz'TestReportOne.test_pass_sends_and_marks   s   ((* 	Fb!!"k.9EW@E#GHA !D)F,,6QW,XCS\\1==9OOCHH%S.2MM+V\\!_Q-?@MM.&,,q/!*<=OOA..{.DE	F 	F 	Fs   DD44D=c                   t        j                         5 }| j                  |dddi      }t        d      }t        j                  d|||t              }t        j                  d|||t              }| j                  |j                         | j                  |j                         | j                  |j                         | j                  t        |j                        dd       d d d        y # 1 sw Y   y xY w)	Nr   r   Tr   r\   r   r   u   중복 보고 0 — 전송 1회)r   r   r   r@   r_   r  r  r  r	  assertFalsededupedr^   r   rD   )rE   r   r   r  d1d2s         r5   test_dedupe_no_double_reportz*TestReportOne.test_dedupe_no_double_report   s    ((* 		Vb!!"k#,k":<A D)Foqr&PVWBoqr&PVWBOOBGG$RWW%OOBJJ'S.3TU		V 		V 		Vs   CC33C<c                    t        j                         5 }t        d      }t        j	                  dd||      }| j                  |j                         | j                  t        |j                        d       d d d        y # 1 sw Y   y xY w)NTr   rw   rL   )r   r  r   )
r   r   r@   r_   r  r|   r  r^   r   rD   )rE   r   r  r  s       r5   test_noop_not_sentz TestReportOne.test_noop_not_sent  sp    ((* 	3b D)F,,F,KCcll+S.2		3 	3 	3s   A&BBc                V   t        j                         5 }| j                  |dddi      }t        d      }t        j                  d|||t              }| j                  |j                         | j                  t        j                  d|             d d d        y # 1 sw Y   y xY w)Nr   r   Fr   r\   r   r  )
r   r   r   r@   r_   r  r  r  r	  r
  r  s        r5   test_sender_failure_not_markedz,TestReportOne.test_sender_failure_not_marked  s    ((* 	Gb!!"kI{3KLA E*F,,6QW,XCSXX&Q//"/EF	G 	G 	Gs   BBB(c                   t        j                         5 }| j                  |dddd      }t        d      }t        j                  d|||t              }| j                  |j                  t        j                         | j                  |j                         | j                  d|j                  d   d	          d d d        y # 1 sw Y   y xY w)
Nztask-99T)r   rm   r   r\   r   CALLBACK_MISSINGr   r   )r   r   r   r@   r_   r  r  r^   r  ro   r  r	  r   rD   r  s        r5   test_callback_missing_reportedz,TestReportOne.test_callback_missing_reported  s    ((* 	Bb!!"i.7VZ"[]A D)F,,6QW,XCS\\1+D+DEOOCHH%MM,fll1oa.@A	B 	B 	Bs   B(CCc           	        t        j                         5 }t        j                  j	                  |dd      }t        j
                  |d       t        t        j                  |            }dt        j                  j	                  |d      ddd	t        j                  j	                  |d
      ddddg}t        d      }t        j                  |||t              }t        t        j                  |            }| j                  ||d       | j                  t        j                  j                  t        j                  j	                  |t        j                                     |D cg c]  }|j                   s| }	}| j                  |	D ch c]  }|j"                   c}t        j$                  t        j&                  h       d d d        y c c}w c c}w # 1 sw Y   y xY w)Nr   r   Tr   r\   r   aa11bb22cc33dd44)r   r   r   ri   ztask-2.result.jsonr   rw   rL   r   r   u   canonical events 변형 0)r   r   r   r   r   r   setlistdirr@   r_   r   r  r^   r  isfileREPORTER_LEDGER_RELr	  r  ra   rj   )
rE   r   r   beforer   r  decsafterdr	  s
             r5   "test_canonical_events_not_modifiedz0TestReportOne.test_canonical_events_not_modified   su   ((* 	YbWW\\"h9FKK.F+,F+f&:;GY[(f&:;=+B?G !D)F##G"V6#RD

6*+EVU,GHOOBGGNN277<<A<Q<Q+RST#.!qvvA.D.$7Qajj7!--9WX%	Y 	Y" /7%	Y 	Ys0   EG"/GGG"G
)&G"
G""G+N)
rU   rV   rW   r   r  r  r  r  r  r%  r=   r7   r5   r   r      s*    F
V3GBYr7   r   c                      e Zd Zd Zy)TestReportRecordsDataclassc                   t        j                         5 }t        j                  dt        j
                  j                  |d      t        j                        }t        d      }t        j                  |g||t              }| j                  |d   j                  t        j                         | j                  |d   j                          d d d        y # 1 sw Y   y xY w)Nttask-7.result.json)tsr   r   Tr   r   r   )r   r   r   DriverRecordr   r   r   r   r@   r_   r   r  r^   r  ra   r  r	  )rE   r   recr  r"  s        r5   test_driverrecord_objectsz4TestReportRecordsDataclass.test_driverrecord_objects9  s    ((* 	*b""BGGLL5I$J11 # 3C !D)F##SE6#PDT!W--q}}=OODGLL)	* 	* 	*s   B:CC!N)rU   rV   rW   r.  r=   r7   r5   r'  r'  8  s    *r7   r'  c                      e Zd ZdZd Zy)	_FakeProcu4   returncode 속성만 갖는 CompletedProcess 모사.c                    || _         y rB   )
returncode)rE   r2  s     r5   rF   z_FakeProc.__init__H  s	    $r7   N)rU   rV   rW   rX   rF   r=   r7   r5   r0  r0  E  s
    >%r7   r0  c                  @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)!TestDefaultSenderSuccessSemanticsu2  ★ (a) HIGH: send 성공은 **실제 전송 성공(returncode==0 확인)** 인 경우에만 True.
    이전 ``getattr(res, "returncode", 0)`` 는 None/속성부재를 0 으로 오인 → 미전송을
    성공으로 기록하는 HIGH 결함이었다. send_report 를 monkeypatch 하여 의미론 고정.c                .    t         j                  | _        y rB   r_   send_report_origrb   s    r5   setUpz'TestDefaultSenderSuccessSemantics.setUpQ      ]]
r7   c                :    t        t        d| j                         y Nr7  r   r_   r8  rb   s    r5   tearDownz*TestDefaultSenderSuccessSemantics.tearDownT      =$**-r7   c                t    t        t        dd        | j                  t        j                  dd             y )Nr7  c                   t        d      S Nr   r0  fpchat_ids     r5   r>   zSTestDefaultSenderSuccessSemantics.test_returncode_zero_is_success.<locals>.<lambda>X  
    1 r7   r   crF  )r   r_   r  _default_senderrb   s    r5   test_returncode_zero_is_successzATestDefaultSenderSuccessSemantics.test_returncode_zero_is_successW  s,    ="EF))*=s)KLr7   c                t    t        t        dd        | j                  t        j                  dd             y )Nr7  c                   t        d      S )N   rC  rD  s     r5   r>   zVTestDefaultSenderSuccessSemantics.test_returncode_nonzero_is_failure.<locals>.<lambda>\  rG  r7   r   rH  rI  r   r_   r  rJ  rb   s    r5   "test_returncode_nonzero_is_failurezDTestDefaultSenderSuccessSemantics.test_returncode_nonzero_is_failure[  s.    ="EF**+>*LMr7   c                t    t        t        dd        | j                  t        j                  dd             y )Nr7  c                    y rB   r=   rD  s     r5   r>   zPTestDefaultSenderSuccessSemantics.test_none_result_not_success.<locals>.<lambda>a  r   r7   r   rH  rI  rO  rb   s    r5   test_none_result_not_successz>TestDefaultSenderSuccessSemantics.test_none_result_not_success_  s.    ="=>**+>*LMr7   c                     G d d      t        t        dfd       | j                  t        j                  dd             y )Nc                      e Zd Zy)YTestDefaultSenderSuccessSemantics.test_missing_returncode_attr_not_success.<locals>._NoRCN)rU   rV   rW   r=   r7   r5   _NoRCrV  e  s    r7   rW  r7  c                           S rB   r=   )rE  rF  rW  s     r5   r>   z\TestDefaultSenderSuccessSemantics.test_missing_returncode_attr_not_success.<locals>.<lambda>h  s	     r7   r   rH  rI  rO  )rE   rW  s    @r5   (test_missing_returncode_attr_not_successzJTestDefaultSenderSuccessSemantics.test_missing_returncode_attr_not_successd  s;    	 	 	="@A**+>*LMr7   c                t    t        t        dd        | j                  t        j                  dd             y )Nr7  c                   t        d       S rB   rC  rD  s     r5   r>   zWTestDefaultSenderSuccessSemantics.test_non_int_returncode_not_success.<locals>.<lambda>m  s
    4 r7   r   rH  rI  rO  rb   s    r5   #test_non_int_returncode_not_successzETestDefaultSenderSuccessSemantics.test_non_int_returncode_not_successk  s.    ="HI**+>*LMr7   c                x    d }t        t        d|       | j                  t        j                  dd             y )Nc                   t        d      )Nzsend blew upRuntimeErrorrD  s     r5   _boomzKTestDefaultSenderSuccessSemantics.test_exception_not_success.<locals>._boomq      ~..r7   r7  r   rH  rI  rO  )rE   ra  s     r5   test_exception_not_successz<TestDefaultSenderSuccessSemantics.test_exception_not_successp  s4    	/ 	=%(**+>*LMr7   N)rU   rV   rW   rX   r9  r>  rK  rP  rS  rY  r\  rc  r=   r7   r5   r4  r4  L  s6    l#.MNN
NN
Nr7   r4  c                  @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestLedgerOnlyOnRealSendSuccessu
  ★ 검증 #8 / ANCHOR-3: dedupe ledger 성공 기록이 **실제 send 성공(returncode==0)**
    후에만 발생함을 default sender(주입 없이) 경로로 증명. None/예외/nonzero 반환 시
    ledger 미기록 → 다음 cycle 재시도 가능(중복 0).c                .    t         j                  | _        y rB   r6  rb   s    r5   r9  z%TestLedgerOnlyOnRealSendSuccess.setUp~  r:  r7   c                :    t        t        d| j                         y r<  r=  rb   s    r5   r>  z(TestLedgerOnlyOnRealSendSuccess.tearDown  r?  r7   c                4   t         j                  j                  |dd      }t        j                  |d       t         j                  j                  || d      }t	        |dd      5 }t        j                  d	|i|       d d d        |S # 1 sw Y   |S xY w)
Nr   r   Tr   r   r   rI   rJ   r   r   )rE   r   r   r   r   rQ   s         r5   r   z,TestLedgerOnlyOnRealSendSuccess._result_file  s|    b(H5
FT*GGLLG9L!9:!S7+ 	0rIIy'*B/	0	0s   *BBc                   g fd}t        j                         5 }| j                  |d      }t        t        d|       t        j                  d||t              }| j                  |j                         | j                  t              dd       | j                  t        j                  d|      d	       d d d        y # 1 sw Y   y xY w)
Nc               <    j                  |        t        d      S rB  r   r0  )rE  rF  
sent_filess     r5   _ok_sendzUTestLedgerOnlyOnRealSendSuccess.test_real_send_success_marks_ledger.<locals>._ok_send  s    b!Q<r7   r   r7  r\   r   r  r   u!   실제 send 1회 발생 후에만r  u9   실제 send 성공(returncode==0) 후에만 ledger 기록)r   r   r   r   r_   r  r  r  r	  r^   r   r
  )rE   rm  r   r   r  rl  s        @r5   #test_real_send_success_marks_ledgerzCTestLedgerOnlyOnRealSendSuccess.test_real_send_success_marks_ledger  s    
	  ((* 	Yb!!"k2AA}h/,,&,ICOOCHH%S_a1TUOOA..{.DWY	Y 	Y 	Ys   BCCc                ^   t        j                         5 }| j                  |d      }t        t        dd        t        j                  d||t              }| j                  |j                  d       | j                  t        j                  d|      d       d d d        y # 1 sw Y   y xY w)	Nr   r7  c                    y rB   r=   rD  s     r5   r>   zVTestLedgerOnlyOnRealSendSuccess.test_none_result_no_ledger_retriable.<locals>.<lambda>  r   r7   r\   rn  u   None 반환은 성공 간주 0r  u2   ledger 미기록 — 다음 cycle 재시도 가능
r   r   r   r   r_   r  r  r  r	  r
  rE   r   r   r  s       r5   $test_none_result_no_ledger_retriablezDTestLedgerOnlyOnRealSendSuccess.test_none_result_no_ledger_retriable  s    ((* 	Sb!!"k2AA}&AB,,&,ICSXX'GHQ//"/EQS	S 	S 	Ss   BB##B,c                Z   t        j                         5 }| j                  |d      }t        t        dd        t        j                  d||t              }| j                  |j                         | j                  t        j                  d|             d d d        y # 1 sw Y   y xY w)Nr   r7  c                   t        d      S )Nr   rC  rD  s     r5   r>   zSTestLedgerOnlyOnRealSendSuccess.test_nonzero_returncode_no_ledger.<locals>.<lambda>  s
    Yq\ r7   r\   rn  r  rr  rs  s       r5   !test_nonzero_returncode_no_ledgerzATestLedgerOnlyOnRealSendSuccess.test_nonzero_returncode_no_ledger  s    ((* 	Gb!!"k2AA}&IJ,,&,ICSXX&Q//"/EF	G 	G 	Gs   BB!!B*c                ^   d }t        j                         5 }| j                  |d      }t        t        d|       t        j                  d||t              }| j                  |j                         | j                  t        j                  d|             d d d        y # 1 sw Y   y xY w)Nc                   t        d      )Nznetwork downr_  rD  s     r5   ra  zLTestLedgerOnlyOnRealSendSuccess.test_send_exception_no_ledger.<locals>._boom  rb  r7   r   r7  r\   rn  r  rr  )rE   ra  r   r   r  s        r5   test_send_exception_no_ledgerz=TestLedgerOnlyOnRealSendSuccess.test_send_exception_no_ledger  s    	/ ((* 	Gb!!"k2AA}e,,,&,ICSXX&Q//"/EF	G 	G 	Gs   BB##B,c                4   g t        j                         5 }| j                  |d      }t        t        dd        t        j                  d||t              }| j                  |j                         fd}t        t        d|       t        j                  d||t              }| j                  |j                         | j                  t              dd       | j                  t        j                  d|	             d d d        y # 1 sw Y   y xY w)
Nr   r7  c                    y rB   r=   rD  s     r5   r>   z\TestLedgerOnlyOnRealSendSuccess.test_no_send_no_dedupe_then_retry_succeeds.<locals>.<lambda>  r   r7   r\   rn  c               <    j                  |        t        d      S rB  rk  )rE  rF  r	  s     r5   _okzWTestLedgerOnlyOnRealSendSuccess.test_no_send_no_dedupe_then_retry_succeeds.<locals>._ok  s    B |#r7   r   u#   재시도 시 정확히 1회 전송r  )r   r   r   r   r_   r  r  r  r	  r  r^   r   r
  )rE   r   r   r  r~  r  r	  s         @r5   *test_no_send_no_dedupe_then_retry_succeedszJTestLedgerOnlyOnRealSendSuccess.test_no_send_no_dedupe_then_retry_succeeds  s    ((* 	Fb!!"k2AA}&ABoqrHBRWW%$ A}c*oqrHBOOBGG$SY+PQOOA..{.DE	F 	F 	Fs   C-DDN)rU   rV   rW   rX   r9  r>  r   ro  rt  rw  rz  r  r=   r7   r5   re  re  y  s5    E#.Y"SG	GFr7   re  c                  0    e Zd Zd Zd Zd Zd Zd Zd Zy)TestResultLoaderBoundedScanc                   t        j                         5 }t        j                  j	                  |dd      }t        j
                  |d       t        j                  j	                  |d      }t        |dd      5 }t        j                  d	d
d|       d d d        t        j                  ||      }| j                  |j                  d      d
       d d d        y # 1 sw Y   JxY w# 1 sw Y   y xY w)Nr   r   Tr   ztask-5.result.jsonr   rI   rJ   ztask-5r   )r   xr  r  )r   r   r   r   r   r   rM   r   r   r_   _default_result_loaderr^   get)rE   r   r   r   rQ   r   s         r5   test_direct_candidate_no_scanz9TestResultLoaderBoundedScan.test_direct_candidate_no_scan  s    ((* 	/bWW\\"h9FKK.V%9:Aaw/ =2		hQ7<=++AB+7DTXXc]A.	/ 	/= =		/ 	/s%   A'C+<CA C+C(	$C++C4c                2   t        j                         5 }t        j                  j	                  |ddd      }t        j
                  |d       d}t        t        j                  j	                  ||      dd	      5 }t        j                  d
dd|       d d d        t        j                  j	                  |dd|      }t        j                  ||      }| j                  |j                  d             d d d        y # 1 sw Y   kxY w# 1 sw Y   y xY w)Nr   	p0b_state	processedTr   ztask-6.result.jsonr   rI   rJ   ztask-6)r   movedr   r  r  )r   r   r   r   r   r   rM   r   r   r_   r  r  r  )rE   r   pdirbaserQ   rpr   s          r5   $test_processed_basename_direct_matchz@TestResultLoaderBoundedScan.test_processed_basename_direct_match  s    ((* 	/b77<<Hk;GDKKt,'Dbggll4.gF D"		h>CDb(Hd;B++BR+8DOODHHW-.	/ 	/D D		/ 	/s%   A(D=DA!DD
	DDc           
        t        j                         5 }t        j                  j	                  |ddd      }t        j
                  |d       d}t        d      D ]J  }t        t        j                  j	                  |d| d	      d
      5 }|j                  d       d d d        L t        t        j                  j	                  ||dz         d
d      5 }t        j                  ddd|       d d d        t        j                  j	                  |dd|      }t        j                  ||      }| j                  |j                  d             d d d        y # 1 sw Y   
xY w# 1 sw Y   xxY w# 1 sw Y   y xY w)Nr   r  r  Tr   r*  <   ztask-other-r   r   z{}z.1700000000000rI   rJ   ztask-7)r   variantr   r  r  )r   r   r   r   r   r   rangerM   writer   r   r_   r  r  r  )rE   r   r  r  irQ   r  r   s           r5   %test_processed_suffix_variant_boundedzATestResultLoaderBoundedScan.test_processed_suffix_variant_bounded  sK   ((* 	1b77<<Hk;GDKKt,'D2Y #"'',,t{1#\-JKSQ #UWHHTN# ## bggll40@)@A3&( F+-		h4@"EF b(Hd;B++BR+8DOODHHY/0	1 	1
# #F F	1 	1s=   A8E5E9E5E)2A!E5E&!E5)E2	.E55E>c                6   t        j                         5 }t        j                  j	                  |ddd      }| j                  t        j                  ||      i        | j                  t        j                  d|      i        d d d        y # 1 sw Y   y xY w)Nr   r   ztask-404.result.jsonr  rL   )r   r   r   r   r   r^   r_   r  )rE   r   r  s      r5   test_missing_returns_empty_dictz;TestResultLoaderBoundedScan.test_missing_returns_empty_dict  s    ((* 	Hbb(H6LMBQ55br5BBGQ55br5BBG	H 	H 	Hs   A1BBc                    | j                  t        j                  t               | j	                  t        j                  d       y rB  )assertIsInstancer_   PROCESSED_SCAN_LIMITintassertGreaterrb   s    r5   test_scan_limit_is_positive_intz;TestResultLoaderBoundedScan.test_scan_limit_is_positive_int  s.    a44c:11115r7   c                    t         dz  dz  j                  d      }| j                  d|d       | j                  d|d       y )	Nr   r   rI   rJ   zos.listdir(uK   reporter 는 무조건 listdir() 대신 직접후보+bounded scandir 사용zos.scandir(u   bounded scandir 사용 확인)r   r   r   r   r   s     r5   'test_no_unconditional_listdir_in_loaderzCTestResultLoaderBoundedScan.test_no_unconditional_listdir_in_loader  sJ     z!$<<GGQXGYf	hmS*IJr7   N)	rU   rV   rW   r  r  r  r  r  r  r=   r7   r5   r  r    s"    	/
/1 H6Kr7   r  c                      e Zd Zd Zd Zy)$TestDriverReportingFailureObservablec                D   dd l }dd l}t        j                         5 ddddfd
}d }t	        t
        d      }t	        t
        d      }t	        t
        d	      }|j                         }	 t        t
        d       t        t
        d|       t        t
        d	|       |j                  |      5  t
        j                         }	d d d        t        t
        d|       t        t
        d|       t        t
        d	|       | j                  	dd
       |j                         }
| j                  d|
d       | j                  d|
       d d d        y # 1 sw Y   xY w# t        t
        d|       t        t
        d|       t        t
        d	|       w xY w# 1 sw Y   y xY w)Nr   Fr   r   c               L    dt         j                  j                  d      dgS )Nr\   r   r   r   )r   r   r   r   r   r   s        r5   r   zoTestDriverReportingFailureObservable.test_driver_main_no_silent_pass_on_reporting_error.<locals>.fake_scan_once  s+    $3(*R9M(NP Q Qr7   c                    t        d      )Nreporter explodedr_  )r   r   s     r5   boom_reportzlTestDriverReportingFailureObservable.test_driver_main_no_silent_pass_on_reporting_error.<locals>.boom_report  s    "#677r7   r   r   r   u-   보고 예외는 비치명 — driver crash 0reporting failureu6   silent pass 금지 — reporting failure 관찰 가능r  )io
contextlibr   r   r   r   StringIOr   redirect_stderrr   r^   getvaluer   )rE   r  r  r   r  r   r   r   bufr   errr   s              @r5   2test_driver_main_no_silent_pass_on_reporting_errorzWTestDriverReportingFailureObservable.test_driver_main_no_silent_pass_on_reporting_error  se    	((* 	4b6;29Q
8  %56I[1I!#'78K++-C	<-r2[.9-{;//4 $B$ -y9[)4-{;R$ST,,.CMM-sRTMM-s37	4 	4"$ $ -y9[)4-{;-	4 	4s>   AF-AE1EEA;FE	E5FFFc                    t         dz  dz  j                  d      }| j                  d|       | j                  d|j	                  d      d          y )	Nr   zanu_pickup_driver.pyrI   rJ   r  zlaunch_wake(z	def main()r   r   r   r   splitr   s     r5   !test_driver_source_no_silent_passzFTestDriverReportingFailureObservable.test_driver_source_no_silent_pass0  sM    z!$::EEwEW)3/;)?)CDr7   N)rU   rV   rW   r  r  r=   r7   r5   r  r    s    !4FEr7   r  __main__)r%   strr&   r  )/rX   
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   importlib.utilr   r   r   r   r   unittestr   r   pathlibr   __file__resolveparentr   r  r   insertr6   r   r_   r   r  r@   TestCaserZ   r   r   r   r   r'  r0  r4  re  r  r  rU   r   r=   r7   r5   <module>r     s   #      	 
   ' X ''..u:SXXHHOOAs5z" (*O P 035 /24 %'I J
(*JK )+Q R )+Q R *,S T	
(*KL(*IJ	D $1CH%% 1Cj	@X&& 	@)(++ )62(8$$ 2(lRYH%% RYl	*!2!2 	*% %)N(9(9 )NZRFh&7&7 RFl9K("3"3 9Kz)E8+<+< )EX zHMMO r7   