+
    l1j,u  c                   6   ^ RI t^ RIHu Ht ^ 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   ]
P6                  ! 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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   &K/Users/jameslopez/projects/CodexBar-ESP32/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.   idleNr6   r   r-   r9   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.   doner4   stopNr!   r7   r(   r8   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# )rD   z<I can implement either approach. Which option do you prefer?r   last_assistant_messager.   r/   r4   possible_questionNrG   rH   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# )rD   zAPossible next steps:
1. Wire hooks globally
2. Test on the devicerM   r.   r/   r4   rO   NrG   rH   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)rD   r>   
updated_atNr.   r?   )r!   r	   r   r   valuesr8   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>   notificationrV   Nr.   r?   
r!   r	   r   r   rW   inttimeATTENTION_REASON_TIMEOUTS_SECr8   r(   rX   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.   runningNr6   r   r-   rI   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)	rg   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)rh   N)r!   r	   ry   r   objectr8   )r   rw   ru   rv   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)	rg   r>   ry   c                  (   < SP                  W34      # rp   rq   akwru   s   *,r   <lambda>UAttentionStateTests.test_stop_after_running_sends_done_notification.<locals>.<lambda>       SXS_S_ab`gShr#   rz   rD   NkindrE   )r!   r   r|   r	   r8   lenget)r   rI   rt   ru   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)Frg   r>   ry   c                  (   < SP                  W34      # rp   rq   r   s   *,r   r   ]AttentionStateTests.test_stop_does_not_send_done_notification_when_disabled.<locals>.<lambda>   s    W\WcWcefdkWlr#   rz   rD   N)r	   NTFY_NOTIFY_DONEr!   r   r|   r8   )r   rv   ru   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 # rp    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 # rp   targetr   r   daemons   &&&r   __init__dAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.ImmediateThread.__init__       Fkr#   c                &    V P                  4        R # rp   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       # rp   r   headersreqtimeoutr   captured_headerss   &&r   rw   SAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.capture       ##CKK0:r#   r
   
test-topicNTFY_SSH_HOSTr   Threadc                    < S! V 4      # rp   r   r   r   r   s   &&r   r   TAttentionStateTests.test_needs_user_notification_has_high_priority.<locals>.<lambda>       _nou_vr#   rz   urlopenClaude	MyProjectr^   NPriorityhighr   r   	r   r|   r	   	threadingurllibrequestry   r8   r   r   rw   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 # rp   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 # rp   r   r   s   &&&r   r   ]AttentionStateTests.test_done_notification_has_low_priority.<locals>.ImmediateThread.__init__   r   r#   c                &    V P                  4        R # rp   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       # rp   r   r   s   &&r   rw   LAttentionStateTests.test_done_notification_has_low_priority.<locals>.capture   r   r#   r
   r   r   c                    < S! V 4      # rp   r   r   s   &&r   r   MAttentionStateTests.test_done_notification_has_low_priority.<locals>.<lambda>   r   r#   rz   r   r   r   rF   rE   )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.   r/   r4   r^   Nr6   rk   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^   rV   Nr.   r/   r_   rX   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	 $#re   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)	rD   zold-session)r   r   rg   znew-sessionr.   rj   r0   N)r!   r(   r8   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.   r/   r0   r3   r1   z	project-3N)ranger!   r(   r8   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!   assertFalser8   assertInr@   s   &  r   !test_unknown_provider_is_rejected5AttentionStateTests.test_unknown_provider_is_rejected   sI    	:$/j(7"34r#   c                z    V P                  R RR7      w  rV P                  V4       V P                  VRR/4       R# )lmstudioTaskCompleter   r   r-   TN)r!   r7   r8   r@   s   &  r   %test_lm_studio_completion_is_accepted9AttentionStateTests.test_lm_studio_completion_is_accepted   s6    
.QD$<0r#   c                |  a . o\         P                  ! \        R V3R lR7      ;_uu_ 4        V P                  RRR7       RRR4       V P	                  \        S4      ^4       S^ ,          w  rV P	                  VR,          R
4       V P	                  VP                  R4      R	4       R#   + '       g   i     Lr; i)ry   c                  (   < SP                  W34      # rp   rq   r   s   *,r   r   kAttentionStateTests.test_lm_studio_completion_sends_done_notification_without_prior_start.<locals>.<lambda>   r   r#   rz   	LM Studior  r  N:N   Nr   rE   )r  r2   task_complete)r   r|   r	   r!   r8   r   r   )r   rs   rt   ru   s   &  @r   Etest_lm_studio_completion_sends_done_notification_without_prior_startYAttentionStateTests.test_lm_studio_completion_sends_done_notification_without_prior_start   s    \\&"4BhiiOO[OG j 	UQ'Qxb#STF+V4 jis   B++B;	c                    V P                  R RR7       \        P                  ! 4       R,           Uu. uF  qR,          NK  	  ppV P                  VRR.4       R# u upi )r  r  r  r%   namer   r   N)r!   r	   r'   r8   )r   r   namess   &  r   0test_lm_studio_is_not_returned_in_status_payloadDAttentionStateTests.test_lm_studio_is_not_returned_in_status_payload  sW    NC282K2K2Mk2Z[2Zh&!!2Z[7 34 \s   A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Rt o R tR tRtV tR# )SAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.FakeRespi  c                    V # rp   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 # rp   r   r   s   &&&r   r   cAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.ImmediateThread.__init__  r   r#   c                &    V P                  4        R # rp   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       # rp   r   r   s   &&r   rw   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      # rp   r   r   s   &&r   r   SAttentionStateTests.test_ntfy_includes_ssh_action_when_configured.<locals>.<lambda>  r   r#   rz   r   r   r   r^   NActionsz-ssh://james@jamess-mac-mini.tail02a1a0.ts.netr   r   )r   r|   r	   r   r   r   ry   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 # rp   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 # rp   r   r   s   &&&r   r   dAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.ImmediateThread.__init__*  r   r#   c                &    V P                  4        R # rp   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   r4  )  r   r#   r   c                 H   < SP                  V P                  4       S! 4       # rp   r   r   s   &&r   rw   SAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.capture-  r   r#   r
   r   r   r   r   c                    < S! V 4      # rp   r   r   s   &&r   r   TAttentionStateTests.test_ntfy_omits_ssh_action_when_not_configured.<locals>.<lambda>3  r   r#   rz   r   r   r   r^   Nr)  r   r   )r   r|   r	   r   r   r   ry   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_default9  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)rA  1rB  rC  rD  rF  rG  rH  ra   rz   N)
r   rI  rJ  rK  r|   r	   ra   r   rM  assert_called_oncerO  s   & r   8test_startup_can_replace_existing_process_when_requestedLAttentionStateTests.test_startup_can_replace_existing_process_when_requestedB  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)
rA  rT  rB  rC  rz   rF  rG  rD  rH  N)	r   rI  rJ  rK  r|   r	   r7   rM  rU  rO  s   & r   :test_startup_can_replace_existing_process_when_port_clearsNAttentionStateTests.test_startup_can_replace_existing_process_when_port_clearsK  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:   rA   rJ   rP   rS   rZ   rc   rl   r}   r   r   r   r   r   r   r   r   r  r  r  r  r*  r>  rQ  rV  rY  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155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# )AttentionHttpTestsiT  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.setUpU  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)ra  shutdownserver_closere  joinr   s   &r   tearDownAttentionHttpTests.tearDown`  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   methodri  )rc  jsondumpsencoder   r   Requestr   statusloadsread)	r   pathr    ru  urlrt  r   r   resps	   &&&&     r   request_jsonAttentionHttpTests.request_jsone  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)ru  r-   T/statusr%   r&   r.   r/   r1   r2   N)r  r8   )r   rz  bodyclaudes   &   r   #test_post_attention_then_get_status6AttentionHttpTests.test_post_attention_then_get_statusm  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)rp  r     {rq  rr  r  rs  ri  Ni  r-   zinvalid JSONr   )r   r   ry  rc  assertRaisesr   	HTTPErrorr   r8   	exceptioncoderv  r{  r|  closer   r   )r   r   ctxr  s   &   r   $test_post_attention_rejects_bad_json7AttentionHttpTests.test_post_attention_rejects_bad_json  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 usagerz   r  Nr-   r%   r&   r.   r?   )r   r|   r	   AssertionErrorr  r8   r7   )r   rz  r  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)rh  ri  Tr^  c                  D    \         P                  ! ^4       \        R4      h)   zsimulated slow wake)ra   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)r  	Exceptionrr   )excr   usage_errors    r   request_usageXAttentionHttpTests.test_health_responds_while_usage_fetch_is_slow.<locals>.request_usage  s7    (!!(+ (""3''(s    =8=r  rz   r   g?rp  z/healths   okNr_  )ra  rj  rk  re  rl  r	   r   r   r`  rb  rc  r   r   rd  r   r   r|   ra   r  r   r   r   r8   rz  r|  )r   r  r  usage_threadr  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	)ra  rc  re  )NN)r   r   r   r   r   rm  r  r  r  r  r  r   r   r   s   @r   r\  r\  T  s/     	$
8F(5 M5 5r#   r\  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%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/./.# )r  r   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      # rp   rq   )rnpnotificationss   &&&r   r   *PaceDetectionTests._fire.<locals>.<lambda>  s    ^k^r^rtusy^zr#   rz   Nr   r   )r   r|   r	   _check_underpacer  )r   rt   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  r8   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  )r8   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  r8   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)r8   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  ra   r  r8   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  ra   r  r  r8   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_payloadr7   r8   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  iQ 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_hourrD  _send_usage_reset_ntfy_asyncc                  &   < SP                  V 4      # rp   rq   rs   r  s   *r   r   ?PaceDetectionTests._reset_notifications_after.<locals>.<lambda>.      \i\p\pqu\vr#   rz   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      # rp   rq   r'  s   *r   r   ]PaceDetectionTests.test_reset_detector_does_not_notify_on_first_observation.<locals>.<lambda>5  r)  r#   rz   )r  r  r  N逗 )r   r|   r	   r*  r  r8   )r   r  s   &@r   8test_reset_detector_does_not_notify_on_first_observationKPaceDetectionTests.test_reset_detector_does_not_notify_on_first_observation3  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  r3  )r   r  r3     Tr.  r  r8   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# )r7  r  r8  Nr3  )r   r  r3  r:  Fr;  r  s   & r   9test_long_window_expected_reset_uses_quieter_notificationLPaceDetectionTests.test_long_window_expected_reset_uses_quieter_notificationB  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  r8  N:	 )r   r  rD     Fr;  r  s   & r   +test_seven_day_long_window_reset_is_covered>PaceDetectionTests.test_seven_day_long_window_reset_is_coveredJ  rA  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  NrD  r   r  r     F)r   r  rD  S   T)r.  r8   )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_earlyR  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  r8  NrD  )r   r  rD  rE  F)r.  r  r8   r  s   & r   3test_codex_reset_uses_same_provider_window_detectorFPaceDetectionTests.test_codex_reset_uses_same_provider_window_detectori  s^    ..&&wBbW`hl&m&&wAY]fnr&s

 	 EFGr#   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  r8  NrJ  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_40q  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# )rS  r  r  r8  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_hoursy  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  r8  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 # rp   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   FakeResponser_          r#   ri  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 # rp   r   r   s   &&&r   r   mPaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.ImmediateThread.__init__      $r#   c                &    V P                  4        R # rp   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   rl         % r#   r   c                 d   < SP                  V P                  P                  4       4       S! 4       # rp   )rr   rt  decode)r   r   ri  messagess   &&r   rw   \PaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.capture  s"    OOCHHOO-.>!r#   r  r   r   Fc                    < S! W4      # rp   r   r   s   &&r   r   ]PaceDetectionTests.test_reset_ntfy_message_distinguishes_early_and_expected.<locals>.<lambda>      _nou_~r#   rz   r   r   r  TNu)   Claude 5d usage reset early surprise 🎁u5   Claude 5d usage refreshed 🔄 You had 27% remaining.r   r   r3  r   r|   r	   r   r   r   r%  r8   )r   rw   ri  r   rv  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 # rp   r   r   s   &r   r   WPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.FakeResponse.__enter__  rb  r#   c                    R # r   r   rd  s   &&&&r   r   VPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.FakeResponse.__exit__  rh  r#   r   Nr   r   s   @r   ri  r    rj  r#   ri  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 # rp   r   r   s   &&&r   r   YPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.ImmediateThread.__init__  ro  r#   c                &    V P                  4        R # rp   r   r   s   &r   r   VPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.ImmediateThread.start  rr  r#   r   Nr   r   r   s   @r   r   r    rs  r#   r   c                 H   < SP                  V P                  4       S! 4       # rp   )rr   full_url)r   r   ri  urlss   &&r   rw   HPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.capture  s    KK%>!r#   r
   zattention-topicr  zreset topicr   Fc                    < S! W4      # rp   r   r   s   &&r   r   IPaceDetectionTests.test_reset_ntfy_uses_dedicated_topic.<locals>.<lambda>  rz  r#   rz   r   r   r  Nzhttps://ntfy.sh/reset%20topicr   r   rD  r{  )r   rw   ri  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  rD  rp   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.  r4  r<  r?  rF  rM  rP  rT  rW  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##_<B Br#   r  __main__r9  )builtins@py_builtins_pytest.assertion.rewrite	assertionrewrite
@pytest_arrv  rJ  r   ra   unittesturllib.errorr   urllib.requesthttp.serverr   r   unittest.mockr   companion.serverr	   TestCaser   r\  r  r  r   mainr   r#   r   <module>r     s       	      7  !C+(++ C+L
c5** c5L FB** FBR zMMO r#   