
    Rj:                    P   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mZ ddlmZ ddlZej(                  j+                  dd      Z ee      dz  d	z  d
z  Ze
j0                  j3                  de      Ze
j0                  j7                  e      Zej:                  j=                  e       ej>                  Zej@                  Z ejB                  Z!d+dZ"d+dZ#d+dZ$d+dZ%d+dZ&d+dZ'd+dZ(dZ)dZ*dZ+d,dZ,d-dZ- e-       Z.ej^                  ja                  e. d      d+d       Z1 ee      dz  dz  Z2 ee      dz  dz  Z3 ee      dz  dz  dz  Z4 ee      dz  dz  d z  Z5 ejl                  d!      Z7d.d"Z8d.d#Z9d.d$Z:d/d%Z;d.d&Z<d.d'Z=d0d(Z>d.d)Z?d.d*Z@y)1u\   task-2962: 성공 알림 단일 소유자 + O_EXCL 원자적 선점 규약 회귀 테스트.    )annotationsN)ThreadPoolExecutor)PathWORKSPACE_ROOTz/home/jay/workspacescriptslibznotify_claim.pynotify_claimc           	        | dz  }t        |      }t        |      }d}||u }|sSt        j                  d|fd||f      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dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}t        |      }t        |      }d}||u }|sSt        j                  d|fd||f      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dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}y)uE   동일 마커에 대해 첫 claim은 True, 두 번째 claim은 False.notify.markerTiszN%(py6)s
{%(py6)s = %(py0)s(%(py4)s
{%(py4)s = %(py1)s(%(py2)s)
})
} is %(py9)sclaim_notificationstrmarkerpy0py1py2py4py6py9assert %(py11)spy11NF)
r   r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationtmp_pathr   @py_assert3@py_assert5@py_assert8@py_assert7@py_format10@py_format12s           ;/home/jay/workspace/tests/test_notify_single_owner_claim.py/test_claim_notification_first_true_second_falser,   "   s   'F!&k2k*2d2*d2222*d222222222222222c222c222222&222&222k222*222d2222222!&k3k*3e3*e3333*e333333333333333c333c333333&333&333k333*333e3333333    c           	        | dz  dz  dz  }|j                   }|j                  } |       }| }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}x}x}}t        |      }t        |      }d}||u }|sSt	        j                  d	|fd
||f      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dt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            dx}x}x}}|j                   }|j                  } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }
t        t	        j                  |
            dx}x}}|j                  } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}y)uK   부모 디렉토리가 없어도 claim_notification이 자동 생성한다.nesteddeepr   zaassert not %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.parent
}.exists
}()
}r   )r   r   r   r   NTr   r   r   r   r   r   r   z]assert %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.parent
}.is_dir
}()
}zAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r   r   r   )parentexistsr   r   r   r   r    r!   r"   r   r   r   is_dir)r$   r   @py_assert1r%   r&   r(   @py_format8r'   r)   r*   @py_format7@py_format5s               r+   *test_claim_notification_creates_parent_dirr9   )   s     6)O;F}}%}##%#%%%%%%%%%%%v%%%v%%%}%%%#%%%%%%%%%%!&k2k*2d2*d2222*d222222222222222c222c222222&222&222k222*222d2222222==!=!!!!!!!!!6!!!6!!!=!!!!!!!!!!!!!===??66=?r-   c           	     t   | dz  }t        |      }t        |      }d}||u }|sSt        j                  d|fd||f      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dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}t        t        |             |j                  } |       }| }|sddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}x}}t        |      }t        |      }d}||u }|sSt        j                  d|fd||f      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dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}y)uU   claim -> release -> 재claim 이 True (전송 실패 시 재시도 가능해야 함).r   Tr   r   r   r   r   r   r   r   NEassert not %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r1   )r   r   r   r   r   r   r   r    r!   r"   release_notificationr3   )
r$   r   r%   r&   r'   r(   r)   r*   r5   @py_format6s
             r+   "test_release_then_reclaim_succeedsr>   5   s   'F!&k2k*2d2*d2222*d222222222222222c222c222222&222&222k222*222d2222222V%}}}vv}!&k2k*2d2*d2222*d222222222222222c222c222222&222&222k222*222d2222222r-   c                   | dz  }|j                   } |       }| }|sddt        j                         v st        j                  |      rt        j
                  |      ndt        j
                  |      t        j
                  |      dz  }t        t        j                  |            dx}x}}t        t        |             y)uW   존재하지 않는 마커에 release를 호출해도 예외가 발생하지 않는다.znever-claimed.markerr;   r   r1   N)
r3   r   r   r   r   r    r!   r"   r<   r   )r$   r   r5   r%   r&   r=   s         r+   (test_release_nonexistent_marker_no_raiser@   >   sy    ..F}}}vv}V%r-   c           	     $   | dz  }t        |      }t        |      }d}||u }|sSt        j                  d|fd||f      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dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}dddd}t        t        |      |       |j                  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  }dd|iz  }t        t        j                  |            d}y)uW   claim -> finalize(payload) 후 마커 파일에 JSON이 기록되고 json.loads 가능.r   Tr   r   r   r   r   r   r   r   Nz	task-2962success   )task_idstatusnutf-8encoding==z%(py0)s == %(py2)sloadedpayloadr   r   zassert %(py4)sr   )r   r   r   r   r   r   r   r    r!   r"   finalize_notification	read_textjsonloads)r$   r   r%   r&   r'   r(   r)   r*   rN   rawrM   r5   @py_format3r8   s                 r+   !test_finalize_writes_json_payloadrV   H   st   'F!&k2k*2d2*d2222*d222222222222222c222c222222&222&222k222*222d2222222%CG#f+w/


G

,CZZ_FW6W66WWr-   c           	     ,   | dz  }t        |      }t        |      }d}||u }|sSt        j                  d|fd||f      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dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}t        t        |      d       y)uM   finalize를 payload=None으로 호출해도 예외가 발생하지 않는다.r   Tr   r   r   r   r   r   r   r   N)r   r   r   r   r   r   r   r    r!   r"   rP   r#   s           r+   (test_finalize_with_none_payload_no_raiserX   S   s    'F!&k2k*2d2*d2222*d222222222222222c222c222222&222&222k222*222d2222222#f+t,r-   c           
     >   | dz  }d}t        |      5 }t        |      D cg c]!  }|j                  t        t	        |            # }}|D cg c]  }|j                          }}ddd       t              }||k(  }	|	s#t        j                  d|	fd||f      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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}}	|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  }t        j                   d|       dz   d|iz  }t        t        j                  |            dx}x}x}x}}|j                  }d} ||      }d}||z
  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}}yc c}w c c}w # 1 sw Y   xY w)uM   N=20 스레드가 동일 마커를 동시에 claim -> True는 정확히 1개.zconcurrent-thread.marker   )max_workersNrJ   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py5)slenresults	n_workersr   r   py3py5assert %(py7)spy7TrC   zK%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.count
}(%(py4)s)
} == %(py9)sr   r   r   r   r      True 개수가 1이 아님: 
>assert %(py11)sr   FzX%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.count
}(%(py4)s)
} == (%(py8)s - %(py10)s)r   r   r   r   py8py10assert %(py13)spy13)r   rangesubmitr   r   resultr]   r   r   r   r   r   r    r!   r"   count_format_assertmsg)r$   r   r_   executor_futuresfr^   @py_assert2@py_assert4r=   r6   r5   r%   r&   r'   r(   r)   r*   @py_assert9@py_assert11@py_format14s                         r+   /test_concurrent_claim_thread_pool_single_winnerr}   ]   s   22FI			2 0hFKIFV
ABHOO.F<
 
 (//!188://	0 w<$<9$$$$<9$$$$$$3$$$3$$$$$$w$$$w$$$<$$$$$$9$$$9$$$$$$$==MM=M!M!#MMM!MMMMMM7MMM7MMM=MMMMMMMMM!MMM'CG9%MMMMMMMM==00=0q09q=0=0000=00000070007000=00000000000090009000q00000000
 0	0 0s(   P&PPP%P
PPg      4@g      >@zimport multiprocessing
def _f(x):
    return x
if __name__ == '__main__':
    ctx = multiprocessing.get_context('fork')
    with ctx.Pool(processes=2) as pool:
        r = pool.map(_f, [1, 2])
    assert r == [1, 2]
    print('MP_PROBE_OK')
c           	          d| d|d| d| d	S )Nav  import multiprocessing, importlib.util
def _claim(args):
    mpath, mkpath = args
    spec = importlib.util.spec_from_file_location('notify_claim_mp_worker', mpath)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod.claim_notification(mkpath)
if __name__ == '__main__':
    ctx = multiprocessing.get_context('fork')
    args = [(z, z)] * z
    with ctx.Pool(processes=za) as pool:
        results = pool.map(_claim, args)
    print(','.join(str(r) for r in results))
 )module_pathmarker_pathr_   s      r+   _mp_claim_scriptr      s4    		 $buYK H''0k 29	9r-   c                     	 t        j                  ddt        gddt              } | j                  dk(  xr d| j
                  v S # t        $ r Y yw xY w)u  이 실행 환경이 multiprocessing(fork)을 실제로 지원하는지 격리된 서브프로세스로 확인.

    hang 하더라도 subprocess.run의 timeout이 강제로 끊어주므로 이 함수는
    collection을 절대 블로킹하지 않는다.
    python3-cTcapture_outputtexttimeoutr   MP_PROBE_OKF)
subprocessrun_MP_PROBE_SCRIPT_MP_PROBE_TIMEOUT_S
returncodestdout	Exception)rq   s    r+   _detect_mp_availabler      s\    	./'	
   A%H-6==*HH s   AA 	AAu)  이 환경에서 multiprocessing(fork)이 동작하지 않음 (세마포어/샌드박스 clone 제약으로 추정 — 격리된 서브프로세스 프로브가 hang/실패함). 프로세스 간 O_EXCL 보장은 스레드 테스트(test_concurrent_claim_thread_pool_single_winner)로 대체 커버)reasonc           	     T   | dz  }d}t        t        t              t        |      |      }	 t        j                  dd|gddt
              }j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      t        j"                  |      dz  }	t        j$                  d|j                   d|j                  d	|j                        dz   d|	iz  }
t'        t        j(                  |
            d
x}x}}|j                  j+                         j-                  d      }|D cg c]  }|dk(  	 }}t/        |      }||k(  }|sLt        j                  d|fd||f      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t        j"                  |      dt        j                         v st        j                   |      rt        j"                  |      nddz  }	t        j$                  dt/        |       d| d|d      dz   d|	iz  }
t'        t        j(                  |
            d
x}}|j0                  }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  }t        j$                  d"|       d#z   d$|iz  }t'        t        j(                  |            d
x}x}x}x}}|j0                  }d%} ||      }d}||z
  }||k(  }|st        j                  d|fd&||f      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      t        j"                  |      t        j"                  |      dt        j                         v st        j                   |      rt        j"                  |      ndt        j"                  |      d'z  }d(d)|iz  }t'        t        j(                  |            d
x}x}x}x}x}}y
# t        j                  $ rA}t        j                  dt
         d|j                  d	|j                         Y d
}~Qd
}~ww xY wc c}w )*u  N=20 프로세스가 동일 마커를 동시에 claim -> True는 정확히 1개 (프로세스 간 O_EXCL 보장).

    실제 claim 호출도 격리된 서브프로세스에서 수행하고 hard timeout을 건다.
    (mp 자체는 가용하다고 프로브에서 확인했으므로, 여기서 timeout이 발생하면
    claim_notification 구현의 fork 안전성 문제로 간주해 실패 처리한다.)
    zconcurrent-mp.markerrZ   r   r   Tr   u/   멀티프로세스 claim 서브프로세스가 uD   s 내에 끝나지 않음 (fork 안전성 문제 가능성): stdout= stderr=Nr   rJ   z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)srq   r   r   rb   u9   멀티프로세스 claim 서브프로세스 실패 (exit=
): stdout=
>assert %(py7)srd   ,Truer\   r]   r^   r_   r`   u   결과 개수 불일치: z != z (raw=)rC   re   rf   rg   rh   r   Fri   rj   rm   rn   )r   r   _NOTIFY_CLAIM_PATHr   r   _MP_CLAIM_TIMEOUT_STimeoutExpiredpytestfailr   stderrr   r   r   r   r   r   r    rs   r!   r"   stripsplitr]   rr   )r$   r   r_   scriptrq   excr5   ry   r%   r=   r6   raw_resultsrr^   rx   r&   r'   r(   r)   r*   rz   r{   r|   s                          r+   3test_concurrent_claim_multiprocessing_single_winnerr      sW     ..FIc"45s6{INF
f%'	
   !                    !"    DFDUDUCV W--"(6==*;	=     --%%'--c2K$/0qqF{0G0w< <9$   <9                              %    %    $CL>i[{oUVW     ==QQ=Q!Q!#QQQ!QQQQQQ7QQQ7QQQ=QQQQQQQQQ!QQQ'CK=%QQQQQQQQ==00=0q09q=0=0000=00000070007000=00000000000090009000q00000000% $$ 
=>Q=R SJJM** Xjj^%	
 	

 1s    U >V%V"!6VV"zdone-watcher.shzactivity-watcher.pydeploysystemdzactivity-watcher.servicezdone-watcher.servicez"\$\{?COKACDIR_CHAT_ID(:-[^}]*)?\}?c                 z   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}}y
)uZ   done-watcher.sh 텍스트에 DONE_WATCHER_SH_SUCCESS_NOTIFY 가드가 존재해야 한다.rG   rH   DONE_WATCHER_SH_SUCCESS_NOTIFYinz%(py1)s in %(py3)scontentr   ra   assert %(py5)srb   N)
_DONE_WATCHER_SHrQ   r   r   r    r   r   r   r!   r"   r   @py_assert0rx   @py_format4r=   s        r+   -test_done_watcher_sh_has_success_notify_guardr      sq    (('(:G+6+w6666+w666+666666w666w6666666r-   c                 z   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}}y
)u_   activity-watcher.py 텍스트에 ACTIVITY_WATCHER_SUCCESS_NOTIFY 가드가 존재해야 한다.rG   rH   ACTIVITY_WATCHER_SUCCESS_NOTIFYr   r   r   r   r   rb   N)
_ACTIVITY_WATCHER_PYrQ   r   r   r    r   r   r   r!   r"   r   s        r+   1test_activity_watcher_py_has_success_notify_guardr      sq    ",,g,>G,7,7777,777,7777777777777777r-   c                    t         j                  d      } g }t        j                  |       D ]:  }|j	                  d      }|j                  d      rd|v r*|j                  |       < | }|s~t        j                  d|       dz   dd	t        j                         v st        j                  |      rt        j                  |      nd	iz  }t        t        j                  |            d
}y
)u   done-watcher.sh 에 COKACDIR_CHAT_ID 가 가드 없는 bare 참조로 남아있지 않아야 한다.

    ${COKACDIR_CHAT_ID:-...} 형태(디폴트 값 가드)만 허용한다.
    rG   rH   r   z${z:-u3   가드 없는 bare COKACDIR_CHAT_ID 참조 발견: z
>assert not %(py0)sr   bare_matchesN)r   rQ   _CHAT_ID_REF_REfinditergroup
startswithappendr   rs   r   r   r   r    r!   r"   )r   r   mfullr5   @py_format2s         r+   .test_done_watcher_sh_no_bare_chat_id_referencer      s    
 (('(:GL%%g. "wwqz??4 TT\D!	"
 aaaRS_R`aaaaaaa|aaa|aaaaaar-   c                    | j                         D ]<  }|j                         }|j                  d      r%t        j                  d|      s< y y)u	  실제 systemd `EnvironmentFile=` 지시자 라인이 있는지 검사한다.

    주석(`#...`)에 설명 목적으로 "EnvironmentFile=" 문자열이 등장하는 것은
    허용한다 — 실제 지시자로 파싱될 라인만 위반으로 간주한다.
    #z^EnvironmentFile\s*=TF)
splitlinesr   r   rematch)r   linestrippeds      r+   _has_environmentfile_directiver   	  sO     ""$ ::<s#88+X6 r-   c                    t         j                  d      } 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                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            dx}}y)	u  activity-watcher.service 에 EnvironmentFile= 지시자가 없어야 한다.

    (.env.keys 의 `export` 접두 때문에 systemd EnvironmentFile= 파싱이 실패하는
    함정을 해소 — load-env-keys.sh 를 통한 source 방식으로 대체되어야 함)
    rG   rH   uK   activity-watcher.service 에 실제 EnvironmentFile= 지시자가 존재함2
>assert not %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}r   r   r   r   ra   N)_ACTIVITY_WATCHER_SERVICErQ   r   r   rs   r   r   r   r    r!   r"   r   rx   ry   r8   s       r+   4test_activity_watcher_service_has_no_environmentfiler     s     (1171CG-g6 66 6   	V     .    .      /6    /6    7     r-   c                    t         j                  d      } 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                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            dx}}y)	uH   done-watcher.service 에 EnvironmentFile= 지시자가 없어야 한다.rG   rH   uG   done-watcher.service 에 실제 EnvironmentFile= 지시자가 존재함r   r   r   r   N)_DONE_WATCHER_SERVICErQ   r   r   rs   r   r   r   r    r!   r"   r   s       r+   0test_done_watcher_service_has_no_environmentfiler   $  s    #--w-?G-g6 66 6   	R     .    .      /6    /6    7     r-   c                     t        t              dz  dz  } t        j                  | j	                  d            }t        |d         S )Nconfigzconstants.jsonrG   rH   chat_id)r   r   rR   rS   rQ   r   )constants_pathdatas     r+   _expected_chat_idr   /  sB    .)H47GGN::n...@ADtIr-   c            	        t               } d}t        j                  dd|gt        i t        j
                  dt        iddd      }|j                  }d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                   d|j                  d|j                        dz   d|iz  }t!        t        j"                  |            dx}x}}|j                  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                  d|d| d|j                  d      dz   d|	iz  }
t!        t        j"                  |
            d}y)uW   load-env-keys.sh source 후 COKACDIR_CHAT_ID 가 constants.json 의 chat_id 와 일치.zWset -u; source "$WORKSPACE_ROOT/scripts/lib/load-env-keys.sh"; echo "$COKACDIR_CHAT_ID"bashr   r   T   cwdenvr   r   r   r   rJ   r   rq   r   u%   load-env-keys.sh source 실패 (exit=r   r   r   rd   NrL   actualexpectedrO   u    COKACDIR_CHAT_ID 불일치: got=z
 expected=z	 (stderr=r   z
>assert %(py4)sr   )r   r   r   r   osenvironr   r   r   r   r   r   r    rs   r   r   r!   r"   r   )r   r   rq   r5   ry   r%   r=   r6   r   rU   r8   s              r+   .test_load_env_keys_sets_chat_id_from_constantsr   5  s    "H	#  ^^	v<rzz<+^<F   !                    !"    00A0A/B C--"(6==*;	=     ]]  "FX  6X                        +6*Jxl K==#1	&    r-   c                    d} t        j                  dd| gt        i t        j                  dt        iddd      }|j
                  }d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                  d|j                        dz   d|iz  }t        t        j                   |            dx}x}}d}|j                  }||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}y)uX   set -u 상태에서 load-env-keys.sh 를 source 해도 exit code 0 (unbound var 없음).zKset -u; source "$WORKSPACE_ROOT/scripts/lib/load-env-keys.sh"; echo LOAD_OKr   r   r   Tr   r   r   rJ   r   rq   r   u8   set -u 하에서 load-env-keys.sh source 실패: stdout=r   r   rd   NLOAD_OKr   )z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stdout
})r   ra   rb   rc   )r   r   r   r   r   r   r   r   r   r   r   r    rs   r   r   r!   r"   )	r   rq   r5   ry   r%   r=   r6   r   rx   s	            r+   (test_load_env_keys_safe_under_set_dash_ur   O  s   ZF^^	v<rzz<+^<F   !                    !"   --"(6==*;	=     %%9%%%%9%%%9%%%%%%%%%%%%%%%%%%%r-   )r$   r   returnNone)r   r   r   r   r_   intr   r   )r   bool)r   r   )r   r   r   r   )r   r   )A__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   importlib.util	importlibrR   r   r   r   concurrent.futuresr   pathlibr   r   r   getr   r   utilspec_from_file_location_specmodule_from_spec_notify_claimloaderexec_moduler   r<   rP   r,   r9   r>   r@   rV   rX   r}   r   r   r   r   r   _MP_AVAILABLEmarkskipifr   r   r   r   r   compiler   r   r   r   r   r   r   r   r   r   r   r-   r+   <module>r     s   b "      	 	  1   02GH .)I5=@QQ ..~?QR//6    '"55 $99 %;; 43&-1,   ! $$ %& 	  $1$1Z ')36GG N+i7:OO 8#i/2LL  	8#i/2HH  "**BC78b	 4&r-   