+
    $(jpw                        ^ RI t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	H
t
 ^ RIHt ^ RIHt  ! R R]P                  4      t ! R R]P                  4      tRt ! R R	]P                  4      t]R
8X  d   ]P*                  ! 4        R# R# )    N)
HTTPServerThreadingHTTPServer)patchc                      a  ] tR t^t o R tR tR tR tR tR t	R t
R tR	 tR
 tR tR tR tR tR tR tR tR tR tR tR tR tR tR tR tR tR tRtV t R# )AttentionStateTestsc                    R \         n        \         P                  ;_uu_ 4        \         P                  P	                  4        ^ \         n        RRR4       \         P                  ! 4        R#   + '       g   i     L'; i) N)server
NTFY_TOPIC_attention_lock_attention_recordsclear_attention_seq_invalidate_usage_cacheselfs   &!tests/test_companion_attention.pysetUpAttentionStateTests.setUp   sL    ###%%++-$%F! $ 	&&( $#s   *A--A=	c                d    R RRRRRRR/pVP                  V4       \        P                  ! V4      # )providerCodexeventPermissionRequest
session_idztest-sessioncwd)/Users/jameslopez/projects/CodexBar-ESP32)updater
   ingest_attention_event)r   	overridespayloads   &, r   
post_eventAttentionStateTests.post_event   s>    (.>	
 	y!,,W55    c                V    \         P                  ! 4       R ,          ^,          R,          # )	providers	attention)r
   get_status_payloadr   s   &r   codex_attention#AttentionStateTests.codex_attention    s     ((*;7:;GGr$   c                   V P                  R R7      w  rV P                  V4       V P                  VRR/4       V P                  4       pV P                  VR,          R4       V P                  VR,          ^4       V P                  VR,          R4       V P                  VR	,          R.4       V P                  VR
,          R4       R# )codexr   okTstate
needs_usercountprimary_projectCodexBar-ESP32projectsreasonpermission_requestNr"   
assertTrueassertEqualr)   )r   r.   responser'   s   &   r   9test_permission_request_sets_needs_user_with_project_nameMAttentionStateTests.test_permission_request_sets_needs_user_with_project_name#   s    8D$<0((*	7+\:7+Q/#457GH:.1A0BC8,.BCr$   c                    V P                  4        V P                  R R7      w  rV P                  V4       V P                  VRR/4       V P                  V P                  4       R,          R4       R# )
SessionEndr   r.   Tr/   idleNr7   r   r.   r:   s   &  r   (test_session_end_clears_attention_record<AttentionStateTests.test_session_end_clears_attention_record/   s\    \:D$<0--/8&Ar$   c                    V P                  R R7      w  rV P                  V4       V P                  4       pV P                  VR,          R4       V P                  VR,          R4       R# )Stopr?   r/   doner5   stopNr"   r8   r)   r9   r   r.   _r'   s   &   r   test_stop_defaults_to_done.AttentionStateTests.test_stop_defaults_to_done7   sX    f-((*	7+V48,f5r$   c                    V P                  R RR7      w  rV P                  V4       V P                  4       pV P                  VR,          R4       V P                  VR,          R4       R# )rE   z<I can implement either approach. Which option do you prefer?r   last_assistant_messager/   r0   r5   possible_questionNrH   rI   s   &   r   3test_stop_with_question_is_classified_as_needs_userGAttentionStateTests.test_stop_with_question_is_classified_as_needs_user?   sd    #a   

 	((*	7+\:8,.ABr$   c                    V P                  R RR7      w  rV P                  V4       V P                  4       pV P                  VR,          R4       V P                  VR,          R4       R# )rE   zAPossible next steps:
1. Wire hooks globally
2. Test on the devicerN   r/   r0   r5   rP   NrH   rI   s   &   r   6test_stop_with_choice_list_is_classified_as_needs_userJAttentionStateTests.test_stop_with_choice_list_is_classified_as_needs_userJ   sd    #h   

 	((*	7+\:8,.ABr$   c                4   V P                  R R7       \        P                  ;_uu_ 4        \        P                  P	                  4        F  p^ VR&   K
  	  RRR4       V P                  V P                  4       R,          R4       R#   + '       g   i     L9; i)rE   r?   
updated_atNr/   r@   )r"   r
   r   r   valuesr9   r)   r   recs   & r   &test_done_record_expires_after_timeout:AttentionStateTests.test_done_record_expires_after_timeoutU   sm    f%###00779$%L! : $ 	--/8&A	 $#s   +BB	c                   V P                  R R7       \        P                  ;_uu_ 4        \        P                  P	                  4        FG  p\        \        P                  ! 4       4      \        P                  R,          ,
          ^,
          VR&   KI  	  RRR4       V P                  V P                  4       R,          R4       R#   + '       g   i     L9; i)Notificationr?   notificationrW   Nr/   r@   
r"   r
   r   r   rX   inttimeATTENTION_REASON_TIMEOUTS_SECr9   r)   rY   s   & r   +test_notification_attention_expires_quickly?AttentionStateTests.test_notification_attention_expires_quickly^   s    n-###00779$'		$4v7[7[\j7k$kno$oL! : $ 	--/8&A	 $#   A*CC	c                    V P                  R R7       V P                  RRR7      w  rV P                  V4       V P                  V P                  4       R,          R4       R# )SessionStartr?   r^   z0Automatic approval review approved: Bash(ls -la)r   messager/   runningNr7   r   r.   rJ   s   &  r   -test_auto_approval_notification_stays_runningAAttentionStateTests.test_auto_approval_notification_stays_runningg   sW    n- F   

 	--/8)Dr$   c                ,  aa V P                  R R7       . o\        P                  oVV3R lp\        P                  ! \        RVR7      ;_uu_ 4        V P                  RRR7       RRR4       V P                  S. 4       R#   + '       g   i     L$; i)	rh   r?   c                  8   < SP                  W34       S! V / VB # Nappend)argskwargsfiredoriginals   *,r   captureWAttentionStateTests.test_auto_approval_notification_does_not_send_ntfy.<locals>.capturev   s!    LL$(T,V,,r$   _send_ntfy_asyncside_effectr^   z1Automatic approval review approved: Bash(echo hi)ri   N)r"   r
   rz   r   objectr9   )r   rx   rv   rw   s   & @@r   2test_auto_approval_notification_does_not_send_ntfyFAttentionStateTests.test_auto_approval_notification_does_not_send_ntfyq   su    n-**	- \\&"4'JJOO$K   K 	# KJs   BB	c                l  a V P                  R R7       . o\        P                  ! \        RV3R lR7      ;_uu_ 4        V P                  RR7       RRR4       V P	                  \        S4      ^4       S^ ,          w  rV P	                  VP                  R4      R4       R#   + '       g   i     LY; i)	rh   r?   rz   c                  (   < SP                  W34      # rq   rr   akwrv   s   *,r   <lambda>UAttentionStateTests.test_stop_after_running_sends_done_notification.<locals>.<lambda>   s    SXS_S_ab`gShr$   r{   rE   NkindrF   )r"   r   r}   r
   r9   lenget)r   rJ   ru   rv   s   &  @r   /test_stop_after_running_sends_done_notificationCAttentionStateTests.test_stop_after_running_sends_done_notification   s    n-\\&"4BhiiOO&O) j 	UQ'!H	F+V4 jis   B##B3	c                p  a \         P                  pR \         n         V P                  RR7       . o\        P                  ! \         RV3R lR7      ;_uu_ 4        V P                  RR7       RRR4       V P                  S. 4       V\         n        R#   + '       g   i     L/; i  T\         n        i ; i)Frh   r?   rz   c                  (   < SP                  W34      # rq   rr   r   s   *,r   r   ]AttentionStateTests.test_stop_does_not_send_done_notification_when_disabled.<locals>.<lambda>   s    W\WcWcefdkWlr$   r{   rE   N)r
   NTFY_NOTIFY_DONEr"   r   r}   r9   )r   rw   rv   s   & @r   7test_stop_does_not_send_done_notification_when_disabledKAttentionStateTests.test_stop_does_not_send_done_notification_when_disabled   s    **"'	/OO.O1Ef&8Flmmf- nUB'&.F#	 nm '/F#s#   =B( B.B( B%	 B( (B5c                  aaa / o ! R  R4      o ! R R4      oRVV3R llp\         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        P                  R	RV3R
 llR7      ;_uu_ 4        \         P                  ! \        P                  P
                  RVR7      ;_uu_ 4        \        P                  ! RRR4       RRR4       RRR4       RRR4       RRR4       V P                  SP                  R4      R4       R#   + '       g   i     LK; i  + '       g   i     LV; i  + '       g   i     La; i  + '       g   i     Ll; i)c                   ,   a  ] tR t^t o R tR tRtV tR# )TAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.FakeRespc                    V # rq    r   s   &r   	__enter__^AttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.FakeResp.__enter__       r$   c                    R # Fr   r   r   s   &*r   __exit__]AttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.FakeResp.__exit__       5r$   r   N__name__
__module____qualname____firstlineno__r   r   __static_attributes____classdictcell____classdict__s   @r   FakeRespr           ,00r$   r   c                   0   a  ] tR t^t o RR ltR tRtV tR# )[AttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.ImmediateThreadc                    Wn         R # rq   targetr   r   daemons   &&&r   __init__dAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.ImmediateThread.__init__       Fkr$   c                &    V P                  4        R # rq   r   r   s   &r   startaAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.ImmediateThread.start   
    T[[]r$   r   Nr   r   r   r   r   r   r   r   r   r   s   @r   ImmediateThreadr           J**r$   r   c                 H   < SP                  V P                  4       S! 4       # rq   r   headersreqtimeoutr   captured_headerss   &&r   rx   SAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.capture       ##CKK0:r$   r   
test-topicNTFY_SSH_HOSTr	   Threadc                    < S! V 4      # rq   r   r   r   r   s   &&r   r   TAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.<lambda>       _nou_vr$   r{   urlopenClaude	MyProjectr_   NPriorityhighr   r   	r   r}   r
   	threadingurllibrequestrz   r9   r   r   rx   r   r   r   s   & @@@r   .test_needs_user_notification_has_high_priorityBAttentionStateTests.test_needs_user_notification_has_high_priority   s    	1 	1	+ 	+	 	 \\&,==\\&/266\\&**HBvww\\&--//PP##Hk>J Q x 7 > 	)--j96B QP xw 76 >=sT   %E1,6E	":ED85E=E	E18EEEE	E.)E11F	c                  aaa / o ! R  R4      o ! R R4      oRVV3R llp\         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        P                  RRV3R llR	7      ;_uu_ 4        \         P                  ! \        P                  P
                  R
VR	7      ;_uu_ 4        \        P                  ! RRRRR7       RRR4       RRR4       RRR4       V P                  SP                  R4      R4       R#   + '       g   i     LC; i  + '       g   i     LN; i  + '       g   i     LY; i)c                   ,   a  ] tR t^t o R tR tRtV tR# )MAttentionStateTests.test_done_notification_has_low_priority.<locals>.FakeRespc                    V # rq   r   r   s   &r   r   WAttentionStateTests.test_done_notification_has_low_priority.<locals>.FakeResp.__enter__   r   r$   c                    R # r   r   r   s   &*r   r   VAttentionStateTests.test_done_notification_has_low_priority.<locals>.FakeResp.__exit__   r   r$   r   Nr   r   s   @r   r   r      r   r$   r   c                   0   a  ] tR t^t o RR ltR tRtV tR# )TAttentionStateTests.test_done_notification_has_low_priority.<locals>.ImmediateThreadc                    Wn         R # rq   r   r   s   &&&r   r   ]AttentionStateTests.test_done_notification_has_low_priority.<locals>.ImmediateThread.__init__   r   r$   c                &    V P                  4        R # rq   r   r   s   &r   r   ZAttentionStateTests.test_done_notification_has_low_priority.<locals>.ImmediateThread.start   r   r$   r   Nr   r   r   s   @r   r   r      r   r$   r   c                 H   < SP                  V P                  4       S! 4       # rq   r   r   s   &&r   rx   LAttentionStateTests.test_done_notification_has_low_priority.<locals>.capture   r   r$   r   r   r   c                    < S! V 4      # rq   r   r   s   &&r   r   MAttentionStateTests.test_done_notification_has_low_priority.<locals>.<lambda>   r   r$   r{   r   r   r   rG   rF   )r   Nr   lowr   r   r   r   s   & @@@r   'test_done_notification_has_low_priority;AttentionStateTests.test_done_notification_has_low_priority   s    	1 	1	+ 	+	 	 \\&,==\\&**HBvww\\&--//PP##Hk6O Q x >
 	)--j95A QP xw >=s<   6D3=:D 	7DD 	D3DD 	 D0+D33E	c                    V P                  R R7      w  rV P                  V4       V P                  V P                  4       R,          R4       V P                  V P                  4       R,          R4       R# )r^   r?   r/   r0   r5   r_   Nr7   rl   s   &  r   /test_genuine_notification_still_sets_needs_userCAttentionStateTests.test_genuine_notification_still_sets_needs_user   s\    n5--/8,G--/9>Jr$   c                   V P                  R R7       \        P                  ;_uu_ 4        \        P                  P	                  4        FG  p\        \        P                  ! 4       4      \        P                  R,          ,
          ^,
          VR&   KI  	  RRR4       V P                  V P                  4       R,          R4       R#   + '       g   i     L9; i)r   r?   r_   rW   Nr/   r0   r`   rY   s   & r   6test_permission_request_uses_longer_needs_user_timeoutJAttentionStateTests.test_permission_request_uses_longer_needs_user_timeout   s    12###00779$'		$4v7[7[\j7k$kno$oL! : $ 	--/8,G	 $#rf   c                   V P                  R RR7       V P                  RRR7       V P                  4       pV P                  VR,          R4       V P                  VR,          ^4       \        P                  ;_uu_ 4        V P                  \        \        P                  4      ^4       RRR4       R#   + '       g   i     R# ; i)	rE   zold-session)r   r   rh   znew-sessionr/   rk   r1   N)r"   r)   r9   r
   r   r   r   )r   r'   s   & r   7test_new_session_start_replaces_old_same_project_recordKAttentionStateTests.test_new_session_start_replaces_old_same_project_record   s    f?nG((*	7+Y77+Q/###S!:!:;Q? $###s   *B55C	c                V   \        ^4       F  pV P                  RV 2RV 2R7       K  	  V P                  4       pV P                  VR,          R4       V P                  VR,          ^4       V P                  \	        VR,          4      ^4       V P                  VR,          R	4       R
# )   zsession-z#/Users/jameslopez/projects/project-)r   r   r/   r0   r1   r4   r2   z	project-3N)ranger"   r)   r9   r   )r   idxr'   s   &  r   Etest_multiple_waiting_projects_are_counted_and_project_list_is_cappedYAttentionStateTests.test_multiple_waiting_projects_are_counted_and_project_list_is_capped   s    8COO%cU+9#?    ((*	7+\:7+Q/Yz23Q7#45{Cr$   c                    V P                  R R7      w  rV P                  V4       V P                  VR,          R4       V P                  RVR,          4       R# )ChatGPTr-   r.   Fr   errorN)r"   assertFalser9   assertInrA   s   &  r   !test_unknown_provider_is_rejected5AttentionStateTests.test_unknown_provider_is_rejected   sI    	:$/j(7"34r$   c                0   V P                  R R7      w  rV P                  V4       V P                  VRR/4       \        P                  ! 4       R,          ^,          R,          pV P                  VR,          R4       V P                  VR,          R	4       R
# )Geminir-   r.   Tr&   r'   r/   r0   r2   r3   N)r"   r8   r9   r
   r(   )r   r.   r:   geminis   &   r    test_gemini_provider_is_accepted4AttentionStateTests.test_gemini_provider_is_accepted   s|    9D$<0**,[9!<[I,7 124DEr$   c                  aaa / o ! R  R4      o ! R R4      oRVV3R llp\         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        R	R
4      ;_uu_ 4        \         P                  ! \        P                  RRV3R llR7      ;_uu_ 4        \         P                  ! \        P                  P
                  RVR7      ;_uu_ 4        \        P                  ! RRR4       RRR4       RRR4       RRR4       RRR4       RRR4       V P                  RS4       V P                  RSR,          4       R#   + '       g   i     L]; i  + '       g   i     Lh; i  + '       g   i     Ls; i  + '       g   i     L~; i  + '       g   i     L; i)c                   ,   a  ] tR t^t o R tR tRtV tR# )SAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.FakeRespc                    V # rq   r   r   s   &r   r   ]AttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.FakeResp.__enter__   r   r$   c                    R # r   r   r   s   &*r   r   \AttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.FakeResp.__exit__  r   r$   r   Nr   r   s   @r   r   r
     r   r$   r   c                   0   a  ] tR tRt o RR ltR tRtV tR# )ZAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.ImmediateThreadi  c                    Wn         R # rq   r   r   s   &&&r   r   cAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.ImmediateThread.__init__  r   r$   c                &    V P                  4        R # rq   r   r   s   &r   r   `AttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.ImmediateThread.start  r   r$   r   Nr   r   r   s   @r   r   r    r   r$   r   c                 H   < SP                  V P                  4       S! 4       # rq   r   r   s   &&r   rx   RAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.capture  r   r$   r   r   r   z!jamess-mac-mini.tail02a1a0.ts.netNTFY_SSH_USERjamesr   c                    < S! V 4      # rq   r   r   s   &&r   r   SAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.<lambda>  r   r$   r{   r   r   r   r_   NActionsz-ssh://james@jamess-mac-mini.tail02a1a0.ts.netr   r   )r   r}   r
   r   r   r   rz   r   r   s   & @@@r   -test_ntfy_includes_ssh_action_when_configuredAAttentionStateTests.test_ntfy_includes_ssh_action_when_configured   s   	1 	1	+ 	+	 	 \\&,==\\&/3VWW\\&/7;;\\&**HBvww\\&--//PP##Hk>J Q x < X > 	i!12EGWXaGbc	 QP xw <; XW >=sl   %F;,%F(	6F:FE/F"F*F(	2F;/E?:FFFF% F(	(F83F;;G	c                  aaa / o ! R  R4      o ! R R4      oRVV3R llp\         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        P                  R	RV3R
 llR7      ;_uu_ 4        \         P                  ! \        P                  P
                  RVR7      ;_uu_ 4        \        P                  ! RRR4       RRR4       RRR4       RRR4       RRR4       V P                  RS4       R#   + '       g   i     L<; i  + '       g   i     LG; i  + '       g   i     LR; i  + '       g   i     L]; i)c                   ,   a  ] tR tRt o R tR tRtV tR# )TAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.FakeRespi  c                    V # rq   r   r   s   &r   r   ^AttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.FakeResp.__enter__  r   r$   c                    R # r   r   r   s   &*r   r   ]AttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.FakeResp.__exit__  r   r$   r   Nr   r   s   @r   r   r     r   r$   r   c                   0   a  ] tR tRt o RR ltR tRtV tR# )[AttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.ImmediateThreadi  c                    Wn         R # rq   r   r   s   &&&r   r   dAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.ImmediateThread.__init__  r   r$   c                &    V P                  4        R # rq   r   r   s   &r   r   aAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.ImmediateThread.start  r   r$   r   Nr   r   r   s   @r   r   r&    r   r$   r   c                 H   < SP                  V P                  4       S! 4       # rq   r   r   s   &&r   rx   SAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.capture   r   r$   r   r   r   r	   r   c                    < S! V 4      # rq   r   r   s   &&r   r   TAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.<lambda>&  r   r$   r{   r   r   r   r_   Nr  r   r   )r   r}   r
   r   r   r   rz   assertNotInr   s   & @@@r   .test_ntfy_omits_ssh_action_when_not_configuredBAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured  s    	1 	1	+ 	+	 	 \\&,==\\&/266\\&**HBvww\\&--//PP##Hk>J Q x 7 > 	$45 QP xw 76 >=sT   %E",6E	":D<D)5D<=E	E")D94D<<EE	EE""E2	c                   \         P                  ! \        P                  / R R7      ;_uu_ 4        \        P                  P	                  RR4       \         P
                  ! \        RR.R7      ;_uu_ 4        \         P
                  ! \        P                  RRR7      ;_uu_ 4        \         P
                  ! \        P                  R	4      ;_uu_ 4       pV P                  \        P                  ! 4       4       VP                  4        RRR4       RRR4       RRR4       RRR4       R#   + '       g   i     L*; i  + '       g   i     L5; i  + '       g   i     L@; i  + '       g   i     R# ; i)
F)r   CODEXBAR_REPLACE_EXISTINGN_pids_on_port90  return_valuegetpid韆 kill)
r   dictosenvironpopr}   r
   r   _replace_existing_if_requestedassert_not_calledr   	mock_kills   & r   6test_startup_does_not_kill_existing_process_by_defaultJAttentionStateTests.test_startup_does_not_kill_existing_process_by_default,  s    ZZ

Be44JJNN6=foUGLLfiiFFfii00I  !F!F!HI++- 1 G M 54 10 GF ML 544sT   AE%70E	'.D?5D,
D?E	E%,D<7D??E
E	E"E%%E6	c                L   \         P                  ! \        P                  R R/4      ;_uu_ 4        \         P                  ! \
        RR.R7      ;_uu_ 4        \         P                  ! \
        P                  RRR7      ;_uu_ 4        \         P                  ! \
        P                  R4      ;_uu_ 4       p\         P                  ! \
        P                  R^ ^.R	7      ;_uu_ 4        V P                  \
        P                  ! 4       4       VP                  4        R
R
R
4       R
R
R
4       R
R
R
4       R
R
R
4       R
R
R
4       R
#   + '       g   i     L2; i  + '       g   i     L=; i  + '       g   i     LH; i  + '       g   i     LS; i  + '       g   i     R
# ; i)r3  1r4  r5  r6  r8  r9  r:  rb   r{   N)
r   r;  r<  r=  r}   r
   rb   r   r?  assert_called_oncerA  s   & r   8test_startup_can_replace_existing_process_when_requestedLAttentionStateTests.test_startup_can_replace_existing_process_when_requested5  s    ZZ

%@#$FGG\\&/HH\\&))XEBB\\&))V,,	\\&++vAq6BBVBBDE((* C - C I HG CB -, CB IH HGGsk   'F0E?	.E,52E'5EE$E,,E?	4FEEE)$E,,E<7E?	?F
FF#	c                   \         P                  ! \        P                  R R/4      ;_uu_ 4        \         P                  ! \
        RR.. .R7      ;_uu_ 4        \         P                  ! \
        P                  RRR7      ;_uu_ 4        \         P                  ! \
        P                  R4      ;_uu_ 4       pV P                  \
        P                  ! 4       4       VP                  4        R	R	R	4       R	R	R	4       R	R	R	4       R	R	R	4       R	#   + '       g   i     L*; i  + '       g   i     L5; i  + '       g   i     L@; i  + '       g   i     R	# ; i)
r3  rF  r4  r5  r{   r8  r9  r6  r:  N)	r   r;  r<  r=  r}   r
   r8   r?  rG  rA  s   & r   :test_startup_can_replace_existing_process_when_port_clearsNAttentionStateTests.test_startup_can_replace_existing_process_when_port_clears>  s    ZZ

%@#$FGG\\&/}MM\\&))XEBB\\&))V,,	OOFAACD((* - C N HG -, CB NM HGGsS   )E0D4		.D!75D,D!4D4	<EDD!!D1,D4	4E?EE	r   N)!r   r   r   r   r   r"   r)   r;   rB   rK   rQ   rT   r[   rd   rm   r~   r   r   r   r   r   r   r   r   r  r  r  r0  rC  rH  rK  r   r   r   s   @r   r   r      s     )6H
DB6	C	CBBE$"5
/C.B,KH@D5Fd26..++ +r$   r   c                   N   a  ] tR tRt o R tR tRR ltR tR tR t	R	 t
R
tV tR# )AttentionHttpTestsiG  c                   R \         n        \         P                  ;_uu_ 4        \         P                  P	                  4        ^ \         n        RRR4       \         P                  ! 4        \        R\         P                  4      V n	        V P                  P                  ^,          V n        \        P                  ! V P                  P                  RR7      V n        V P                  P!                  4        R#   + '       g   i     L; i)r	   NTr   r   z	127.0.0.1r   )r
   r   r   r   r   r   r   r   Handlerhttpdserver_addressportr   r   serve_foreverthreadr   r   s   &r   r   AttentionHttpTests.setUpH  s    ###%%++-$%F! $ 	&&( 0&..A
JJ--a0	&&djj.F.FtT $#s   *C99D		c                    V P                   P                  4        V P                   P                  4        V P                  P	                  ^R7       R# )   r   N)rS  shutdownserver_closerW  joinr   s   &r   tearDownAttentionHttpTests.tearDownS  s7    



!#r$   Nc                   R V P                    V 2pVf   RM#\        P                  ! V4      P                  4       pVe   RR/M/ p\        P
                  P                  WEWcR7      p\        P
                  P                  V^R7      ;_uu_ 4       pVP                  \        P                  ! VP                  4       4      3uuRRR4       #   + '       g   i     R# ; i)http://127.0.0.1:NContent-Typeapplication/jsondatar   methodr[  )rU  jsondumpsencoder   r   Requestr   statusloadsread)	r   pathr!   rg  urlrf  r   r   resps	   &&&&     r   request_jsonAttentionHttpTests.request_jsonX  s    !$))TF3tDJJw,?,F,F,H:A:M>#56SUnn$$SW$T^^##C#33t;;

499; 77 4333s   0CC	c                j   V P                  R RRRRRRRR/R	R
7      w  rV P                  V^4       V P                  VRR/4       V P                  R4      w  rV P                  V^4       VR,          ^ ,          R,          pV P                  VR,          R4       V P                  VR,          R4       R# )
/attentionr   r   r   r   r   zhttp-sessionr   r   POST)rg  r.   T/statusr&   r'   r/   r0   r2   r3   N)rr  r9   )r   rl  bodyclaudes   &   r   #test_post_attention_then_get_status6AttentionHttpTests.test_post_attention_then_get_status`  s    ((H,nB	  ) 	
 	%d|,((3%k"1%k2,7 124DEr$   c                   \         P                  P                  R V P                   R2RRR/RR7      pV P	                  \         P
                  P                  4      ;_uu_ 4       p\         P                  P                  V^R7       RRR4       V P                  XP                  P                  R	4       \        P                  ! VP                  P                  4       4      pVP                  P                  4        V P                  VR
,          4       V P!                  RVR,          4       R#   + '       g   i     L; i)rb  ru     {rc  rd  rv  re  r[  Ni  r.   zinvalid JSONr   )r   r   rk  rU  assertRaisesr   	HTTPErrorr   r9   	exceptioncoderh  rm  rn  closer   r   )r   r   ctxrx  s   &   r   $test_post_attention_rejects_bad_json7AttentionHttpTests.test_post_attention_rejects_bad_jsont  s    nn$$		{*5#%78	 % 
 v||5566#NN""3"2 7 	++S1zz#--,,./d$nd7m4 76s   %"D00E 	c                p   \         P                  ! \        R \        R4      R7      ;_uu_ 4        V P	                  R4      w  rRRR4       V P                  X^4       V P                  XR,          4       V P                  VR,          ^ ,          R,          R,          R	4       R#   + '       g   i     Lj; i)
get_access_tokenzshould not fetch usager{   rw  Nr.   r&   r'   r/   r@   )r   r}   r
   AssertionErrorrr  r9   r8   )r   rl  rx  s   &  r   =test_status_does_not_fetch_usage_credentials_or_provider_apisPAttentionHttpTests.test_status_does_not_fetch_usage_credentials_or_provider_apis  s    \\&"4.QiBjkk,,Y7LF l 	%T
#k*1-k:7CVL lks   B%%B5	c           	        a a S P                   P                  4        S P                   P                  4        S P                  P	                  ^R7       \
        P                  ! 4        \        R\
        P                  4      S n         S P                   P                  ^,          S n
        \        P                  ! S P                   P                  RR7      S n        S P                  P                  4        R p. oV V3R lp\        P                   ! \
        RVR7      ;_uu_ 4        \        P                  ! VR7      pVP                  4        \"        P$                  ! R	4       \&        P(                  P+                  R
S P                   R2^R7      ;_uu_ 4       pS P-                  VP.                  ^4       S P-                  VP1                  4       R4       RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i)rZ  r[  TrP  c                  D    \         P                  ! ^4       \        R4      h)   zsimulated slow wake)rb   sleepRuntimeErrorr   r$   r   slow_keychainXAttentionHttpTests.test_health_responds_while_usage_fetch_is_slow.<locals>.slow_keychain  s    JJqM455r$   c                     <  SP                  R 4       R#   \         d   p SP                  T 4        Rp ? R# Rp ? ii ; i)z/usageN)rr  	Exceptionrs   )excr   usage_errors    r   request_usageXAttentionHttpTests.test_health_responds_while_usage_fetch_is_slow.<locals>.request_usage  s7    (!!(+ (""3''(s    =8=r  r{   r   g?rb  z/healths   okNrQ  )rS  r\  r]  rW  r^  r
   r   r   rR  rT  rU  r   r   rV  r   r   r}   rb   r  r   r   r   r9   rl  rn  )r   r  r  usage_threadrq  r  s   f    @r   .test_health_responds_while_usage_fetch_is_slowAAttentionHttpTests.test_health_responds_while_usage_fetch_is_slow  se   



!#&&(()96>>J
JJ--a0	&&djj.F.FtT	6 	( \\&"4-PP$++=AL JJsO''*;DII;g(NXY'ZZ^b  c2  e4 [ QP
 [Z QPPs%   %A5G<=G)	G<)G94G<<H	)rS  rU  rW  )NN)r   r   r   r   r   r_  rr  rz  r  r  r  r   r   r   s   @r   rN  rN  G  s/     	$
8F(5 M5 5r$   rN  c                     a  ] tR tRt o R tR'R ltR(R ltR(R ltR tR t	R	 t
R
 tR tR tR tR tR tR tR tR tR tR tR tR tR tR)R ltR tR tR tR tR tR tR t R  t!R! t"R" t#R# t$R$ t%R% t&R&t'V t(R# )*PaceDetectionTestsi  c                p   R \         n        R \         n        ^\         n        \        \         n        R\         n        R\         n        \         P                  ;_uu_ 4        ^ \         n	        RRR4       \         P                  ;_uu_ 4        \         P                  P                  4        RRR4       \         P                  ;_uu_ 4        \         P                  P                  4        ^ \         n        RRR4       R#   + '       g   i     L; i  + '       g   i     Lo; i  + '       g   i     R# ; i)r	   i  7dN)r
   r   NTFY_USAGE_RESET_TOPICUNDERPACE_PCT_THRESHOLDTWO_DAYSUNDERPACE_MIN_REMAINING_SECUNDERPACE_COOLDOWN_SECUNDERPACE_WINDOW_underpace_lock_underpace_last_fired_usage_reset_lock_usage_reset_windowsr   r   r   r   r   s   &r   r   PaceDetectionTests.setUp  s    (*%)+&-5*(,%"&###+,F( $%%%''--/ &###%%++-$%F! $#	 $#%%###s$   C>D
*D$>D	D!	$D5	c                "    R RRRRRVRVRV/./.# )namer   windowslabelr  pctresets_in_secduration_secr   )r   r  r  r  s   &&&&r   
_providersPaceDetectionTests._providers  s>    9uc?\iky  |H  0I  /J  K  L  	Lr$   Nc                L    T;'       g    VR 8X  d   RMRpRRRRVRVRVR	V/./.# )
PF  5h5dr  r   r  r  r  r  r  r   )r   r  r  r  r  s   &&&&&r   _reset_provider"PaceDetectionTests._reset_provider  T    BB,%"7$T9sO]jlz  }I  0J  /K  L  M  	Mr$   c                L    T;'       g    VR 8X  d   RMRpRVRRVRVRVRV/./.# )	r  r  r  r  r  r  r  r  r  r   )r   r   r  r  r  r  s   &&&&&&r   _reset_provider_named(PaceDetectionTests._reset_provider_named  r  r$   c                ^    \         P                  ! ^(RR4      pV P                  VR^R7       R# )(   0*  r  g      ?placesNr
   _compute_paceassertAlmostEqualr   paces   & r   test_compute_pace_on_pace,PaceDetectionTests.test_compute_pace_on_pace  +    ##Bu5tS3r$   c                ^    \         P                  ! ^RR4      pV P                  VR^R7       R# )   r  r  g      ?r  Nr  r  s   & r   test_compute_pace_underpace.PaceDetectionTests.test_compute_pace_underpace  s+    ##Aue4tU15r$   c                ^    \         P                  ! ^PRR4      pV P                  VR^R7       R# )P   i@8  r  g      @r  Nr  r  s   & r   test_compute_pace_overpace-PaceDetectionTests.test_compute_pace_overpace  r  r$   c                T    V P                  \        P                  ! ^ RR4      4       R# )r   r  NassertIsNoner
   r  r   s   &r   1test_compute_pace_returns_none_at_start_of_windowDPaceDetectionTests.test_compute_pace_returns_none_at_start_of_window  s    &..q%?@r$   c                T    V P                  \        P                  ! ^2R^ 4      4       R# )2   i  Nr  r   s   &r   +test_compute_pace_returns_none_bad_duration>PaceDetectionTests.test_compute_pace_returns_none_bad_duration  s    &..r4;<r$   c           	        a . o\         P                  ! \        R RV3R llR7      ;_uu_ 4        \        P                  ! V P                  ! R/ VB 4       RRR4       S#   + '       g   i     S# ; i)_send_underpace_ntfy_asyncc                 (   < SP                  W34      # rq   rr   )rnpnotificationss   &&&r   r   *PaceDetectionTests._fire.<locals>.<lambda>  s    ^k^r^rtusy^zr$   r{   Nr   r   )r   r}   r
   _check_underpacer  )r   ru   r  s   &,@r   _firePaceDetectionTests._fire  sS    \\&">Lz{{##DOO$=f$=> | |{s   'A  A1	c                    V P                  ^RR7      pV P                  \        V4      ^4       V P                  V^ ,          R4       R# )   r  r  N )r  r  )r  r9   r   r   hitss   & r   ,test_fires_when_under_25pct_and_2d_remaining?PaceDetectionTests.test_fires_when_under_25pct_and_2d_remaining  s<    zzb	z:TA&a/2r$   c           	     ^    V P                  \        V P                  ^ RR7      4      ^4       R# )r   r  Nr  )r9   r   r  r   s   &r   test_fires_at_zero_pct)PaceDetectionTests.test_fires_at_zero_pct  s$    TZZAYZGH!Lr$   c                L    V P                  V P                  ^RR7      . 4       R# )   r  Nr  r9   r  r   s   &r   test_does_not_fire_at_25pct.PaceDetectionTests.test_does_not_fire_at_25pct      )DbIr$   c                L    V P                  V P                  ^2RR7      . 4       R# )r  r  Nr  r  r   s   &r   "test_does_not_fire_above_threshold5PaceDetectionTests.test_does_not_fire_above_threshold  r  r$   c                L    V P                  V P                  ^
RR7      . 4       R# )
   r  NiQ r  r   s   &r   .test_does_not_fire_when_less_than_2d_remainingAPaceDetectionTests.test_does_not_fire_when_less_than_2d_remaining  r  r$   c           	     f    V P                  \        V P                  ^
\        R7      4      ^4       R# )r  r  N)r9   r   r  r  r   s   &r   "test_fires_at_exactly_2d_remaining5PaceDetectionTests.test_fires_at_exactly_2d_remaining  s$    TZZBhZGH!Lr$   c                    \         P                  ;_uu_ 4        \        P                  ! 4       ^
,
          \         n        RRR4       V P	                  V P                  ^
RR7      . 4       R#   + '       g   i     L5; i)r  Nr  r  )r
   r  rb   r  r9   r  r   s   &r   test_respects_cooldown)PaceDetectionTests.test_respects_cooldown  sL    ###+/99;+;F( $)DbI $#s   &A,,A<	c           	     :   \         P                  ;_uu_ 4        \        P                  ! 4       \         P                  ,
          ^,
          \         n        RRR4       V P                  \        V P                  ^
RR7      4      ^4       R#   + '       g   i     L>; i)r  Nr  r  )r
   r  rb   r  r  r9   r   r  r   s   &r   'test_fires_again_after_cooldown_expires:PaceDetectionTests.test_fires_again_after_cooldown_expires  s]    ###+/99;9V9V+VYZ+ZF( $TZZBiZHI1M $#s   ;B

B	c                `   V P                  ^
R
R7      p\        P                  ! V4      pV P                  VR,          4       V P	                  VR,          ^4       VR,          ^ ,          pV P	                  VR,          R4       V P                  VR,          4       V P                  RV4       R	# )r  r  r.   pct_thresholdr  r  r  idle_triggerr  Nr  )r  r
   get_pace_payloadr8   r9   r   )r   r&   r!   ws   &   r   'test_get_pace_payload_idle_trigger_true:PaceDetectionTests.test_get_pace_payload_idle_trigger_true
  s    OO)OD	)))4&126Iq!7T*.)*fa r$   c                    V P                  ^RR7      pV P                  \        P                  ! V4      R,          ^ ,          R,          4       R# )r  r  r  r	  Nr  r  r   r
   r
  r   r&   s   & r   5test_get_pace_payload_idle_trigger_false_at_thresholdHPaceDetectionTests.test_get_pace_payload_idle_trigger_false_at_threshold  s<    OO)OD	00;IFqI.YZr$   c                    V P                  ^
RR7      pV P                  \        P                  ! V4      R,          ^ ,          R,          4       R# )r  Q r  r  r	  Nr  r  s   & r   6test_get_pace_payload_idle_trigger_false_low_remainingIPaceDetectionTests.test_get_pace_payload_idle_trigger_false_low_remaining  s<    OO%O@	00;IFqI.YZr$   c           	     r  a . o\         P                  ! \        R VR7      ;_uu_ 4        \         P                  ! \        RV3R lR7      ;_uu_ 4        \        P                  ! V4       \        P                  ! V4       RRR4       RRR4       S#   + '       g   i     L; i  + '       g   i     S# ; i)_is_sleeping_hourr6  _send_usage_reset_ntfy_asyncc                  &   < SP                  V 4      # rq   rr   rt   r  s   *r   r   ?PaceDetectionTests._reset_notifications_after.<locals>.<lambda>!      \i\p\pqu\vr$   r{   N)r   r}   r
   _check_usage_resets)r   beforeaftersleepingr  s   &&&&@r   _reset_notifications_after-PaceDetectionTests._reset_notifications_after  s}    \\&"5HMM\\&"@Nvww&&v.&&u- x N  xw NM s#   *B%-B	 B%B"B%%B6	c           
     
  a . o\         P                  ! \        R V3R lR7      ;_uu_ 4        \        P                  ! V P	                  ^ RRR7      4       RRR4       V P                  S. 4       R#   + '       g   i     L$; i)r  c                  &   < SP                  V 4      # rq   rr   r  s   *r   r   ]PaceDetectionTests.test_reset_detector_does_not_notify_on_first_observation.<locals>.<lambda>(  r  r$   r{   )r  r  r  N逗 )r   r}   r
   r  r  r9   )r   r  s   &@r   8test_reset_detector_does_not_notify_on_first_observationKPaceDetectionTests.test_reset_detector_does_not_notify_on_first_observation&  sa    \\&"@Nvww&&t';';QZir';'st x 	+ xws   )A22B	c           
         V P                  V P                  ^IRRRR7      V P                  ^ RRRR7      4      pV P                  VR.4       R# )I   r  r  r  r  r  N  r'  )r   r  r'     Tr"  r  r9   r  s   & r   7test_long_window_reset_notifies_on_provider_early_resetJPaceDetectionTests.test_long_window_reset_notifies_on_provider_early_reset-  sX    ..  Ryy`d e  Qii_c d

 	 EFGr$   c           
         V P                  V P                  ^I^<RRR7      V P                  ^ RRRR7      4      pV P                  VR.4       R# )r+  r  r,  Nr'  )r   r  r'  r.  Fr/  r  s   & r   9test_long_window_expected_reset_uses_quieter_notificationLPaceDetectionTests.test_long_window_expected_reset_uses_quieter_notification5  X    ..  Rr	Y] ^  Qii_c d

 	 FGHr$   c           
         V P                  V P                  ^U^<RRR7      V P                  ^ RRRR7      4      pV P                  VR.4       R# )U   r  r,  N:	 )r   r  r8     Fr/  r  s   & r   +test_seven_day_long_window_reset_is_covered>PaceDetectionTests.test_seven_day_long_window_reset_is_covered=  r5  r$   c                    R RRRRR^FR^<RR/RR	R^RRRR/./.pR RRRRR^ RRRR/RR	R^ RRRR/./.pV P                  W4      pV P                  VRR.4       R
# )r  r   r  r  r  r  r  r  r  r  Nr8  r   r  r     F)r   r  r8  S   T)r"  r9   )r   r  r   r  s   &   r   ?test_simultaneous_five_hour_and_weekly_reset_marks_weekly_earlyRPaceDetectionTests.test_simultaneous_five_hour_and_weekly_reset_marks_weekly_earlyE  s    H$r?BPUV$r?BPYZ
  H$q/5.RWX$q/9nV_`
  ..v=.1 
 	r$   c                    V P                  V P                  R ^U^<RRR7      V P                  R ^ RRRR7      4      pV P                  VR.4       R# )r   r  r,  Nr8  )r   r  r8  r9  Fr"  r  r9   r  s   & r   3test_codex_reset_uses_same_provider_window_detectorFPaceDetectionTests.test_codex_reset_uses_same_provider_window_detector\  s^    ..&&wBbW`hl&m&&wAY]fnr&s

 	 EFGr$   c                    V P                  V P                  R ^dRRRR7      V P                  R ^ RRRR7      4      pV P                  VR.4       R# )r  r  Pror,  Nr=  )r  rH  r  r   FrD  r  s   & r   9test_gemini_reset_can_notify_after_unknown_previous_timerLPaceDetectionTests.test_gemini_reset_can_notify_after_unknown_previous_timerd  s^    ..&&xSY^fk&l&&xQeZ_gl&m

 	 BCDr$   c                   \         P                  ! R RRR^RR/RRRRRR/RRRR	RR
/./4      pV P                  V^ ,          R,          R4       V P                  V^ ,          R,          ^d4       V P                  V^ ,          R,          R4       V P                  V^,          R,          R4       V P                  V^,          R,          ^ 4       R# )bucketsmodelIdzgemini-2.5-flashremainingFraction	resetTimez2026-06-09T14:44:34Zzgemini-2.5-prog?zgemini-3-pro-previewg        z1970-01-01T00:00:00Zr  rH  r  r  FlashNr=  )r
   build_gemini_windowsr9   )r   r  s   & r   .test_build_gemini_windows_groups_model_bucketsAPaceDetectionTests.test_build_gemini_windows_groups_model_bucketsl  s    --.0CQUkl,.A3Ukl24Gk[qr/
  	G,e4E*C0O4b9G,g6E*A.r$   c           
         V P                  V P                  ^F^<RRR7      V P                  ^ RRRR7      4      pV P                  VR.4       R# )F   r  r  r,  Nr>  r/  r  s   & r   Htest_five_hour_reset_notifies_when_awake_and_previous_remaining_under_40[PaceDetectionTests.test_five_hour_reset_notifies_when_awake_and_previous_remaining_under_40{  sX    ..  RrUY Z  Qe%W[ \

 	 BCDr$   c           
         V P                  V P                  ^F^<RRR7      V P                  ^ RRRR7      RR7      pV P                  V. 4       R# )rU  r  r  r,  T)r!  Nr/  r  s   & r   :test_five_hour_reset_does_not_notify_during_sleeping_hoursMPaceDetectionTests.test_five_hour_reset_does_not_notify_during_sleeping_hours  s\    ..  RrUY Z  Qe%W[ \ / 
 	r"r$   c           
         V P                  V P                  ^<^<RRR7      V P                  ^ RRRR7      4      pV P                  V. 4       R# )<   r  r  r,  Nr/  r  s   & r   9test_five_hour_reset_requires_previous_remaining_under_40LPaceDetectionTests.test_five_hour_reset_requires_previous_remaining_under_40  sT    ..  RrUY Z  Qe%W[ \

 	r"r$   c                  aaa . o ! R  R4      o ! R R4      oRVV3R llp\         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        P                  RRV3R	 llR
7      ;_uu_ 4        \         P                  ! \        P                  P
                  RVR
7      ;_uu_ 4        \        P                  ! RRR^R4       \        P                  ! RRR^R4       RRR4       RRR4       RRR4       V P                  S^ ,          R4       V P                  S^,          R4       R#   + '       g   i     LT; i  + '       g   i     L_; i  + '       g   i     Lj; i)c                   ,   a  ] tR tRt o R tR tRtV tR# )aPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.FakeResponsei  c                    V # rq   r   r   s   &r   r   kPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.FakeResponse.__enter__      r$   c                    R # r   r   r   exc_typer  tbs   &&&&r   r   jPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.FakeResponse.__exit__      r$   r   Nr   r   s   @r   FakeResponsera          r$   rk  c                   0   a  ] tR tRt o RR ltR tRtV tR# )dPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.ImmediateThreadi  c                    Wn         R # rq   r   r   s   &&&r   r   mPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.ImmediateThread.__init__      $r$   c                &    V P                  4        R # rq   r   r   s   &r   r   jPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.ImmediateThread.start      r$   r   Nr   r   r   s   @r   r   rn         % r$   r   c                 d   < SP                  V P                  P                  4       4       S! 4       # rq   )rs   rf  decode)r   r   rk  messagess   &&r   rx   \PaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.capture  s"    OOCHHOO-.>!r$   r  r   r   Fc                    < S! W4      # rq   r   r   s   &&r   r   ]PaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.<lambda>      _nou_~r$   r{   r   r   r  TNu)   Claude 5d usage reset early surprise 🎁u5   Claude 5d usage refreshed 🔄 You had 27% remaining.r   r   r'  r   r}   r
   r   r   r   r  r9   )r   rx   rk  r   rx  s   & @@@r   8test_reset_ntfy_message_distinguishes_early_and_expectedKPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected  s    	 		 		" 	" \\&":LII\\&**HB~\\&--//PP//$	2tT//$	2uU Q @ J 	!&QR!&]^ QP @ JIs<   6E=:E	75D8,E	4E8EE	EEE.	c                  aaa . o ! R  R4      o ! R R4      oRVV3R llp\         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        RR4      ;_uu_ 4        \         P                  ! \        P                  R	RV3R llR7      ;_uu_ 4        \         P                  ! \        P                  P
                  RVR7      ;_uu_ 4        \        P                  ! RRR^R
4       RRR4       RRR4       RRR4       RRR4       V P                  SR.4       R#   + '       g   i     L=; i  + '       g   i     LH; i  + '       g   i     LS; i  + '       g   i     L^; i)c                   ,   a  ] tR tRt o R tR tRtV tR# )MPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.FakeResponsei  c                    V # rq   r   r   s   &r   r   WPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.FakeResponse.__enter__  rd  r$   c                    R # r   r   rf  s   &&&&r   r   VPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.FakeResponse.__exit__  rj  r$   r   Nr   r   s   @r   rk  r    rl  r$   rk  c                   0   a  ] tR tRt o RR ltR tRtV tR# )PPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.ImmediateThreadi  c                    Wn         R # rq   r   r   s   &&&r   r   YPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.ImmediateThread.__init__  rq  r$   c                &    V P                  4        R # rq   r   r   s   &r   r   VPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.ImmediateThread.start  rt  r$   r   Nr   r   r   s   @r   r   r    ru  r$   r   c                 H   < SP                  V P                  4       S! 4       # rq   )rs   full_url)r   r   rk  urlss   &&r   rx   HPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.capture  s    KK%>!r$   r   zattention-topicr  zreset topicr   Fc                    < S! W4      # rq   r   r   s   &&r   r   IPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.<lambda>  r|  r$   r{   r   r   r  Nzhttps://ntfy.sh/reset%20topicr   r   r8  r}  )r   rx   rk  r   r  s   & @@@r   $test_reset_ntfy_uses_dedicated_topic7PaceDetectionTests.test_reset_ntfy_uses_dedicated_topic  s    	 		 		" 	" \\&,0ABB\\&":MJJ\\&**HB~\\&--//PP//y"eT Q @ K C 	 ?@A QP @ KJ CBsT   %E%,6E	":D?D,7D??E	E%,D<7D??E
E	E"E%%E5	r   )r  r8  rq   r   ))r   r   r   r   r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r"  r(  r0  r3  r:  rA  rE  rI  rR  rV  rY  r]  r~  r  r   r   r   s   @r   r  r    s     &LMM4
6
4
A=
3
MJJJMJ
N![[,HII.HE/E##_<B Br$   r  __main__r-  )rh  r<  r   rb   unittesturllib.errorr   urllib.requesthttp.serverr   r   unittest.mockr   companion.serverr
   TestCaser   rN  r  r  r   mainr   r$   r   <module>r     s     	      7  !v+(++ v+r	c5** c5L ]B** ]B@	 zMMO r$   