
    Y.j:!              	          d 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mZmZmZ e	j                  j                  dej                  j!                  ej                  j#                  e      ddd             ddlmZmZmZmZ  e ed            Z ed	d
dddde      j3                         Zd Zd!dZd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+d  Z,y)"u   TASK2750 — check_cron_fire_outcome.py regression.

cron fire outcome을 executable로 판정(사람 로그해석 대체). 7 enum + tz + raw key 0.
★ r2: NOW를 explicit KST aware로 고정, KST/UTC 해석 + schedule_id exact matching 테스트 추가.
    N)datetimetimezone	timedeltaz..scripts)classifyOUTCOMES_parse_fire_at	_id_match	   )hours           7   tzinfoc                    t         j                  j                  | d      }t         j                  j                  | d      }t         j                  j                  | d      }|||fD ]  }t        j                  |d        t         j                  j                  | d      }t	        |d      j                          ||||fS )Nschedulehistory	workspaceT)exist_okzcron.logw)ospathjoinmakedirsopenclose)tmpstorehistwsdclogs         I/home/jay/workspace/tests/regression/test_check_cron_fire_outcome_2750.py_envr'      s    GGLLj)E77<<Y'D	c;	'BT2 &
A%&77<<Z(DsO$D      c           
          t        t        j                  j                  | |dz         d      j	                  t        j                  |||ddd             y )Nz.jsonr   TDEADBEEF_HASH_NOT_RAW_KEY)idchat_idr   oncebot_key_verifier)r   r   r   r   writejsondumps)r!   sidatchats       r&   _schedr5      sI    eS7]	+S177

#$B(CE 	FGr(   c                 (    t        d| dt        d|S )N   L5: )schedule_idr,   now )r   NOW)r2   kws     r&   	_classifyr=   %   s    GZSGBGGr(   c                     t        j                         5 } t        |       \  }}}}t        |dd       t	        |d      j                  d       t        d||||      }|d   }d}||k(  }|st        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }	t        j                  |      dz   d|	iz  }
t        t        j                  |
            d x}x}}d d d        y # 1 sw Y   y xY w)NT12026-06-14 23:52:32r   zp[scheduler_loop] id=T1, should execute, is_busy=true
[scheduler_loop] id=T1, chat busy, already pending -> skip
r!   history_dirworkspace_rootcron_logoutcomeBUSY_SKIP_ALREADY_AWAKE==z%(py1)s == %(py4)spy1py4
>assert %(py6)spy6tempfileTemporaryDirectoryr'   r5   r   r/   r=   
@pytest_ar_call_reprcompare	_saferepr_format_assertmsgAssertionError_format_explanationtr!   r"   r#   r%   r@py_assert0@py_assert3@py_assert2@py_format5@py_format7s              r&   /test_should_execute_plus_chat_busy_is_busy_skipr`   )   s    		$	$	& <! $QtRud12T3 ] 	^d%T"W[\|;8;|88;;;|8;;;|;;;8;;;!;;;;;;;< < <s   CC==Dc            	         t        j                         5 } t        |       \  }}}}t        |dd       t	        t
        j                  j                  |d      d      j                  t        j                  dddd      d	z          t        j                  t
        j                  j                  |d             t        d||||
      }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	t        j                   |      dz   d|	iz  }
t#        t        j$                  |
            d x}x}}d d d        y # 1 sw Y   y xY w)NT2r@   zT2.logr   2026-06-14T23:53:00+09:00okr7   tsstatusr,   
rA   rE   FIRED_AND_SPAWNEDrG   rI   rJ   rM   rN   )rP   rQ   r'   r5   r   r   r   r   r/   r0   r1   r   r=   rR   rS   rT   rU   rV   rW   rX   s              r&   0test_fire_record_plus_spawn_is_fired_and_spawnedrj   3   s   		$	$	& 6! $QtRud12RWW\\$)3/55JJ9TV`abeii	k
BGGLLT*+d%T"W[\|525|22555|2555|5552555A55555556 6 6s   E
E((E1c            	         t        j                         5 } t        |       \  }}}}t        |dd       t	        t
        j                  j                  |d      d      j                  t        j                  dddd      d	z          t        d||||
      }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	t        j                  |      dz   d|	iz  }
t!        t        j"                  |
            d x}x}}d d d        y # 1 sw Y   y xY w)NT3r@   zT3.logr   rc   rd   r7   re   rh   rA   rE   FIRED_NO_SPAWN_PROOFrG   rI   rJ   rM   rN   )rP   rQ   r'   r5   r   r   r   r   r/   r0   r1   r=   rR   rS   rT   rU   rV   rW   rX   s              r&   1test_fire_record_no_spawn_is_fired_no_spawn_proofrn   >   s    		$	$	& 9! $QtRud12RWW\\$)3/55JJ9TV`abeii	kd%T"W[\|858|55888|5888|8885888q88888889 9 9s   DD55D>c                     t        j                         5 } t        |       \  }}}}t        |dd       t	        d||||      }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	t        j                  |      d	z   d
|	iz  }
t        t        j                  |
            d x}x}}d d d        y # 1 sw Y   y xY w)NT4z2026-06-15 10:00:00rA   rE   PENDING_NOT_DUErG   rI   rJ   rM   rN   rP   rQ   r'   r5   r=   rR   rS   rT   rU   rV   rW   rX   s              r&   "test_before_due_is_pending_not_duers   H   s    		$	$	& 4! $QtRud12d%T"W[\|303|00333|0333|3330333!3333333	4 4 4   CC""C+c                     t        j                         5 } t        |       \  }}}}t        |dd       t	        d||||      }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	t        j                  |      d	z   d
|	iz  }
t        t        j                  |
            d x}x}}d d d        y # 1 sw Y   y xY w)NT5r@   rA   rE   DUE_BUT_NOT_FIREDrG   rI   rJ   rM   rN   rr   rX   s              r&   'test_due_no_record_is_due_but_not_firedrx   P   s    		$	$	& 6! $QtRud12d%T"W[\|525|22555|2555|5552555A5555555	6 6 6rt   c            	         t        j                         5 } t        |       \  }}}}t        dd||||      }|d   }d}||k(  }|st	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }	t	        j                  |      d	z   d
|	iz  }
t        t	        j                  |
            d x}x}}d d d        y # 1 sw Y   y xY w)NT6goner@   expected_fire_atr!   rB   rC   rD   rE   REMOVED_BEFORE_FIRErG   rI   rJ   rM   rN   )
rP   rQ   r'   r=   rR   rS   rT   rU   rV   rW   rX   s              r&   1test_removed_plus_no_proof_is_removed_before_firer~   X   s    		$	$	& 8! $QtRh1F!tBQUW|747|44777|4777|7774777a7777777	8 8 8s   B8CCc            	      N   t        j                         5 } t        |       \  }}}}t        |dd       t	        d||||      }t	        dd||||      }|d   }|d   }||k(  }	d}
||
k(  }|	r|st        j                  d|	|fd|||
f      t        j                  |      t        j                  |      t        j                  |
      d	z  }t        j                  ||f      d
z   d|iz  }t        t        j                  |            d x}x}	x}x}}
d d d        y # 1 sw Y   y xY w)NT7r@   rA   r{   rE   rw   )rH   rH   )z%(py1)s == %(py5)sz%(py5)s == %(py7)s)rK   py5py7z
>assert %(py9)spy9rr   )rY   r!   r"   r#   r%   r1r2r[   @py_assert4r]   @py_assert6r\   @py_format8@py_format10s                 r&   &test_timezone_kst_naive_due_consistentr   `   s    		$	$	& O! $QtRud12t5d2X\]t.C"RRVX)}N9N}DN1DN1DDNNNN}1DNNN}NNNNNN1DNNNr2hNNNNNNNO O Os   C=DD$c                  r   t        j                         5 } t        |       \  }}}}t        |dd       t	        d||||      }t        j                  |      }g }d}||v}	|	}
|	rd}||v}|}
|
snt        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  }|j                  |       |	rt        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  }|j                  |       t        j                  |d      i z  }t        j                  d      dz   d|iz  }t!        t        j"                  |            d x}
x}x}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  }t        j                  d      dz   d|iz  }t!        t        j"                  |            d x}
}d d d        y # 1 sw Y   y xY w)NT8r@   rA   r.   DEADBEEF)not in)z%(py3)s not in %(py5)sblob)py3r   z%(py7)sr   )z%(py10)s not in %(py12)s)py10py12z%(py14)spy14r   zverifier/key leakedz
>assert %(py17)spy17c119085)z%(py1)s not in %(py3)srK   r   zraw ANU key leaked
>assert %(py5)sr   )rP   rQ   r'   r5   r=   r0   r1   rR   rS   rT   @py_builtinslocals_should_repr_global_nameappend_format_booloprU   rV   rW   )rY   r!   r"   r#   r%   rZ   r   @py_assert1r]   r   r[   @py_assert9@py_assert11@py_format6r   @py_format13@py_format15@py_format16@py_format18@py_format4s                       r&   %test_no_raw_key_or_verifier_in_outputr   j   s   		$	$	& ;! $QtRud12d%T"W[\zz!}_!_!-_*_*D2H____!___!________________*D___*______D___D__________J________:y$:::y:::y:::::::::::::&:::::::; ; ;s   JJ--J6c                  2   t        j                         5 } t        |       \  }}}}t        d||||      }|d   }|t        v }|st        j                  d|fd|t        f      t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  |      dz   d	|iz  }	t        t        j                  |	            d x}}d d d        y # 1 sw Y   y xY w)
NNONEXISTENTrA   rE   )in)z%(py1)s in %(py3)sr   r   r   r   )rP   rQ   r'   r=   r   rR   rS   rT   r   r   r   rU   rV   rW   )
rY   r!   r"   r#   r%   rZ   r[   r]   r   r   s
             r&   test_outcome_always_in_enumr   t   s    		$	$	& +! $QtRm5dSU`de|*|x'***|x***|******x***x**********+ + +s   C/DDc            	      0   t        d      } t        ddddddt              j                         }| |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                  | |f      dz   d|iz  }t        t	        j                  |            d}y)u^   naive 'YYYY-MM-DD HH:MM:SS'를 KST aware로 해석 — 서버 tz와 무관하게 고정 epoch.r@   r   r   r   r   4       r   rG   z%(py0)s == %(py2)sgotexpectpy0py2
>assert %(py4)srL   N)r	   r   KST	timestamprR   rS   r   r   r   rT   rU   rV   rW   )r   r   r   @py_format3r^   s        r&   0test_kst_naive_parse_is_aware_and_tz_independentr   }   s    
.
/CdAr2r2c:DDFF&='''3&''''''3'''3''''''&'''&''''3-''''''r(   c                     t        d      } t        d      }|| z
  }d}d}||z  }||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
                  |       rt        j                  |       ndt        j                  |      t        j                  |      d	z  }t        j                  || || z
  f      d
z   d|iz  }t        t        j                  |            dx}x}x}x}}y)uM   ISO offset 명시(+00:00)는 KST(+09:00)와 정확히 9시간(32400s) 차이.r@   2026-06-14T23:52:32+00:00r   i  rG   )z*(%(py0)s - %(py1)s) == (%(py5)s * %(py7)s)utckst)r   rK   r   r   z
>assert %(py10)sr   N
r	   rR   rS   r   r   r   rT   rU   rV   rW   )	r   r   r]   r   r   @py_assert8r\   @py_format9@py_format11s	            r&   ,test_utc_offset_parse_differs_from_kst_by_9hr      s    
.
/C
4
5C977D7D79 777977777737773777777777777777D7773S3Y"77777777r(   c                     t        d      } t        d      }| |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                  | |f      dz   d	|iz  }t        t        j                  |            d }y )
Nz2026-06-14T23:52:32Zr   rG   r   zr   r   r   rL   r   )r   r   r   r   r^   s        r&   test_z_suffix_parsed_as_utcr      s    -.A
4
5C8111aXr(   c                     d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               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
)uT   sid가 다른 토큰의 부분문자열이어도 false match 안 됨(word-boundary).z,[scheduler_loop] id=C7B5018F, should executeC7B5018FTis)z9%(py6)s
{%(py6)s = %(py0)s(%(py2)s, %(py4)s)
} is %(py9)sr
   )r   r   rL   rN   r   zassert %(py11)spy11Nz$[loop] id=XC7B5018FY, should executeFz-path=/home/x/.cokacdir/schedule/C7B5018F.jsonznothing here)	r
   rR   rS   r   r   r   rT   rV   rW   )r   r\   @py_assert5r   @py_assert7r   @py_format12s          r&   8test_schedule_id_exact_match_no_substring_false_positiver      sb    DXZX9CZPXTXXPTXXXXXPTXXXXXXX9XXX9XXXCXXXZXXXPXXXTXXXXXXXX;QZQ9;ZHQEQHEQQQQHEQQQQQQ9QQQ9QQQ;QQQZQQQHQQQEQQQQQQQDYjY9DjQYUYYQUYYYYYQUYYYYYYY9YYY9YYYDYYYjYYYQYYYUYYYYYYYY#9Z99^Z09E90E99990E99999999999999^999Z9990999E99999999r(   c                  B   t        j                         5 } t        |       \  }}}}t        |dd       t	        |d      j                  d       t        d||||      }|d   }d}||k(  }|st        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }	t        j                  |      dz   d|	iz  }
t        t        j                  |
            dx}x}}|d   d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      d
z  }	t        j                  |      dz   d|	iz  }
t        t        j                  |
            dx}x}}ddd       y# 1 sw Y   yxY w)u_   다른 id(C7B5018FEXTRA)의 should execute/chat busy 로그가 C7B5018F로 오판되지 않음.r   r@   r   z[scheduler_loop] id=C7B5018FEXTRA, should execute, is_busy=true
[scheduler_loop] id=C7B5018FEXTRA, chat busy, already pending -> skip
rA   rE   rw   rG   rI   rJ   rM   rN   Nevidencecron_log_appearsFr   )z%(py1)s is %(py4)srO   rX   s              r&   9test_substring_false_positive_does_not_classify_busy_skipr      s2   		$	$	& =! $QtRuj"78T3 h 	ij4PR]ab|525|22555|2555|5552555A5555555}/0<E<0E9<<<0E<<<0<<<E<<<1<<<<<<<= = =s   E7FFc                     t        j                         5 } t        |       \  }}}}t        |d      j	                  d       t        dddt        ||||      }|d   }d}||k(  }|st        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }	t        j                  |      dz   d|	iz  }
t        t        j                  |
            dx}x}}ddd       y# 1 sw Y   yxY w)u\   C7B5018F 실제 로그 패턴(due + busy skip + removed) → BUSY_SKIP_ALREADY_AWAKE 유지.r   z[read_schedule_entry] result: id=C7B5018F, type=absolute, schedule=2026-06-14 23:52:32, last_run=None
[scheduler_loop] id=C7B5018F, should execute, is_busy=true
[scheduler_loop] id=C7B5018F, chat busy, already pending -> skip
r   r7   r@   )r8   r,   r|   r9   r!   rB   rC   rD   rE   rF   rG   rI   rJ   rM   rN   N)rP   rQ   r'   r   r/   r   r;   rR   rS   rT   rU   rV   rW   rX   s              r&   .test_c7b5018f_realcase_fixture_still_busy_skipr      s    		$	$	& 	<! $QtRT3Q	R Z&; d2PTV |;8;|88;;;|8;;;|;;;8;;;!;;;;;;;	< 	< 	<s   CC77D )r7   )-__doc__builtinsr   _pytest.assertion.rewrite	assertionrewriterR   r0   r   sysrP   r   r   r   r   insertr   dirname__file__check_cron_fire_outcomer   r   r	   r
   r   r   r;   r'   r5   r=   r`   rj   rn   rs   rx   r~   r   r   r   r   r   r   r   r   r   r:   r(   r&   <module>r      s   
   	 
  2 2 277<< 94yQ R Q Qyq!"tQBAc2<<>!GH<69468O;+(8:
=<r(   