
    #iB                        S r SSKrSSKJs  Jr  SSKrSSKrSSK	r	SSK
J
r
Jr  SSKJrJrJr  SSKrSSKJr  \R&                  R)                  \R&                  R+                  \5      SS5      r\\	R&                  ;  a  \	R&                  R1                  S\5        S\R2                  S	'   S
\R2                  S'   SSKrS r\R8                  S 5       r " S S5      r " S S5      r " S S5      r  " S S5      r! " S S5      r" " S S5      r#g)z7Tests for notification service endpoints and providers.    N)datetime	timedelta)	AsyncMock	MagicMockpatch)
TestClientz..backendzmongodb://localhost:27017	MONGO_URLtest_tipsharksDB_NAMEc                     [        5       n [        5       U l        [        5       U l        [        5       U R                  R                  l        [        / S9U R                  R                  R
                  R                  l        [        / S9U R                  R                  l        [        5       U l        [        5       U l        [        5       U l	        U $ )zAReturn a MagicMock that behaves like an async MongoDB collection.return_value)
r   r   
insert_onefindr   sortto_list
update_one
delete_onedelete_many)ms    </root/tipsharks/tipsharks-client/tests/test_notifications.py_make_mock_collectionr      s    A;AL[AF({AFF4=24NAFF))1"+"<AFF;AL;ALKAMH    c               #     #    [         R                  " [        S5      n [         R                  " [        S5      n[         R                  " [        S5      n[         R                  " [        S[        S9n[         R                  " [        S[        S9nU R	                  5       nUR	                  5       nUR	                  5       nUR	                  5       nUR	                  5       n	[        5       Ul        [        5       Ul        [        5       Ul        [        SS9UR                  l	        S	Ul
        SU	l
        [        5       n
[        S
S9U
l        Xl
        [        5       n[        S
S9Ul        Xl
        [        [        R                  5       nUv   SSS5        U R!                  5         UR!                  5         UR!                  5         UR!                  5         UR!                  5         g! , (       d  f       N_= f7f)zFastAPI TestClient with all external dependencies mocked.

This fixture patches MongoDB, provider classes, and rate-limit
helpers so that TestClient-based tests never hit real services.
dbTwilioClientEmailClientcheck_rate_limit)new_callableincrement_rate_limitNr   )T
   T)r   objectserverr   startr   notificationsscheduled_notificationsrate_limitsfind_oner   r   send_sms
send_emailr   appstop)
patcher_dbpatcher_twiliopatcher_emailpatcher_rate_checkpatcher_rate_incrmock_dbmock_twilio_clsmock_email_clsmock_rate_checkmock_rate_incrmock_twilio
mock_emailcs                r   clientr;   /   s     fd+J\\&.9NLL7M" &Y  G$**,O"((*N(..0O&,,.N 23G&;&=G#/1G#,$#?G  $.O "&N +K$$7K#. J%48J",	FJJ	1 
  OO 
 	s   FG7G&AG7&
G40G7c                   6    \ rS rSrSrS rS rS rS rS r	Sr
g	)
TestTwilioClienth   u>   TwilioClient – direct unit tests (no fixture-based mocking).c                 :   [         R                  " [        R                  S5       n[	        5       nSS0UR
                  l        [        US9UR                  R                  R                  l	        [        R                  " 5       nSUl        SUl        SUl        [        R                  " 5       nUR!                  UR#                  SS5      5      nS	oeUL ow(       d  [$        R&                  " S
U4SXV45      S[(        R*                  " 5       ;   d  [$        R,                  " U5      (       a  [$        R.                  " U5      OS[$        R.                  " U5      S.-  nSSU0-  n	[1        [$        R2                  " U	5      5      eS =pvS S S 5        g ! , (       d  f       g = f)NAsyncClientsidSM123r   token+15551234567+15559876543Hello!Tisz%(py0)s is %(py3)ssuccesspy0py3assert %(py5)spy5)r   r#   r$   httpxr   jsonr   r   
__aenter__postr   account_sid
auth_tokenphone_numberasyncioget_event_looprun_until_completer*   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)
selfmock_ac	mock_resptclooprJ   @py_assert2@py_assert1@py_format4@py_format6s
             r   test_send_sms_configured)TestTwilioClient.test_send_sms_configuredk   s   \\&,,6'!I+0'*:INN'@I&AG  ++88= $$&B"BN#BM,BO))+D--bkk.(.STG""d?""""7""""""7""""7"""d""""""" 766s   EF
Fc                     [         R                  " 5       n[        R                  " 5       nUR	                  UR                  SS5      5      nSoCUL oU(       d  [        R                  " SU4SX445      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  nSS	U0-  n[        [        R                  " U5      5      eS =pTg )
NrE   rF   TrG   rI   rJ   rK   rN   rO   )r$   r   rW   rX   rY   r*   rZ   r[   r\   r]   r^   r_   r`   ra   )rb   re   rf   rJ   rg   rh   ri   rj   s           r   test_send_sms_fallback'TestTwilioClient.test_send_sms_fallback|   s      "%%'))"++nh*OP$www$r   c                    [         R                  " [        R                  S5       n[	        [        S5      S9UR                  R                  R                  l        [        R                  " 5       nSUl
        SUl        SUl        [        R                  " 5       nUR                  UR!                  SS5      5      nS	oTUL of(       d  ["        R$                  " S
U4SXE45      S[&        R(                  " 5       ;   d  ["        R*                  " U5      (       a  ["        R,                  " U5      OS["        R,                  " U5      S.-  nSSU0-  n[/        ["        R0                  " U5      5      eS =peS S S 5        g ! , (       d  f       g = f)Nr@   zTwilio downside_effectrA   rC   rD   rE   OopsFrG   rI   rJ   rK   rN   rO   )r   r#   r$   rP   r   	Exceptionr   rR   rS   r   rT   rU   rV   rW   rX   rY   r*   rZ   r[   r\   r]   r^   r_   r`   ra   )	rb   rc   re   rf   rJ   rg   rh   ri   rj   s	            r   test_send_sms_failure&TestTwilioClient.test_send_sms_failure   s    \\&,,6'@I%m4AG  ++88= $$&B"BN#BM,BO))+D--bkk.&.QRG##e#####7######7####7###e####### 766s   E	E88
Fc                    [         R                  " 5       nS Ul        S Ul        S Ul        UR
                  nSo2UL oD(       d  [        R                  " SU4SX#45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=pCg )NFrG   z/%(py2)s
{%(py2)s = %(py0)s.enabled
} is %(py5)sre   rL   py2rO   assert %(py7)spy7r$   r   rT   rU   rV   enabledrZ   r[   r\   r]   r^   r_   r`   ra   rb   re   rh   @py_assert4@py_assert3rj   @py_format8s          r   'test_send_sms_not_enabled_without_creds8TestTwilioClient.test_send_sms_not_enabled_without_creds   s      "zz"U"U"""""z""""""r""""r"""z"""U"""""""r   c                    [         R                  " 5       nSUl        SUl        SUl        UR
                  nSo2UL oD(       d  [        R                  " SU4SX#45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  nS	S
U0-  n[        [        R                  " U5      5      eS =n=pCg )NrA   rC   rD   TrG   rx   re   ry   r{   r|   r}   r   s          r    test_send_sms_enabled_with_creds1TestTwilioClient.test_send_sms_enabled_with_creds   s      "(zz!T!T!!!!!z!!!!!!r!!!!r!!!z!!!T!!!!!!!r    N)__name__
__module____qualname____firstlineno____doc__rk   rn   ru   r   r   __static_attributes__r   r   r   r=   r=   h   s    H#"$#"r   r=   c                   6    \ rS rSrSrS rS rS rS rS r	Sr
g	)
TestEmailClient   u=   EmailClient – direct unit tests (no fixture-based mocking).c                    [         R                  " [        R                  S5       n[	        5       UR
                  R                  R
                  l        [        R                  " 5       nSUl	        S Ul
        [        R                  " 5       nUR                  UR                  SSS5      5      nSoTUL of(       d  [        R                   " SU4SXE45      S	["        R$                  " 5       ;   d  [        R&                  " U5      (       a  [        R(                  " U5      OS	[        R(                  " U5      S
.-  nSSU0-  n[+        [        R,                  " U5      5      eS =peS S S 5        g ! , (       d  f       g = f)Nr@   sg_keya@b.comSubBodyTrG   rI   resultrK   rN   rO   r   r#   r$   rP   r   r   rR   rS   r   sendgrid_key
resend_keyrW   rX   rY   r+   rZ   r[   r\   r]   r^   r_   r`   ra   	rb   rc   ecrf   r   rg   rh   ri   rj   s	            r   test_sendgrid_configured(TestEmailClient.test_sendgrid_configured   s    \\&,,6'@IG  ++88=##%B&BO BM))+D,,R]]9eV-TUF!!T>!!!!6!!!!!!6!!!!6!!!T!!!!!!! 766   D;E**
E8c                    [         R                  " [        R                  S5       n[	        5       UR
                  R                  R
                  l        [        R                  " 5       nS Ul	        SUl
        [        R                  " 5       nUR                  UR                  SSS5      5      nSoTUL of(       d  [        R                   " SU4SXE45      S	["        R$                  " 5       ;   d  [        R&                  " U5      (       a  [        R(                  " U5      OS	[        R(                  " U5      S
.-  nSSU0-  n[+        [        R,                  " U5      5      eS =peS S S 5        g ! , (       d  f       g = f)Nr@   re_keyr   r   r   TrG   rI   r   rK   rN   rO   r   r   s	            r   test_resend_fallback$TestEmailClient.test_resend_fallback   s    \\&,,6'@IG  ++88=##%B"BO$BM))+D,,R]]9eV-TUF!!T>!!!!6!!!!!!6!!!!6!!!T!!!!!!! 766r   c                    [         R                  " 5       nS Ul        S Ul        [        R
                  " 5       nUR                  UR                  SSS5      5      nSoCUL oU(       d  [        R                  " SU4SX445      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  nS	S
U0-  n[        [        R                  " U5      5      eS =pTg )Nr   r   r   TrG   rI   r   rK   rN   rO   )r$   r   r   r   rW   rX   rY   r+   rZ   r[   r\   r]   r^   r_   r`   ra   )rb   r   rf   r   rg   rh   ri   rj   s           r   test_email_fallback_logging+TestEmailClient.test_email_fallback_logging   s    !%%'((y%)PQ~vvvr   c                    [         R                  " [        R                  S5       n[	        [        S5      S9UR                  R                  R                  l        [        R                  " 5       nSUl
        S Ul        [        R                  " 5       nUR                  UR                  SSS5      5      nSoTUL of(       d  [         R"                  " S	U4S
XE45      S[$        R&                  " 5       ;   d  [         R(                  " U5      (       a  [         R*                  " U5      OS[         R*                  " U5      S.-  nSSU0-  n[-        [         R.                  " U5      5      eS =peS S S 5        g ! , (       d  f       g = f)Nr@   zSendGrid downrq   r   r   r   r   FrG   rI   r   rK   rN   rO   )r   r#   r$   rP   r   rt   r   rR   rS   r   r   r   rW   rX   rY   r+   rZ   r[   r\   r]   r^   r_   r`   ra   r   s	            r   test_email_failure"TestEmailClient.test_email_failure   s    \\&,,6'@I%o6AG  ++88= ##%B&BO BM))+D,,R]]9eV-TUF""U?""""6""""""6""""6"""U""""""" 766s   EE22
F c           
         [         R                  " [        R                  S5       n[	        5       nX!R
                  R                  R
                  l        [        R                  " 5       nSUl	        [        R                  " 5       nUR                  UR                  SSSSS95      nSoeUL ow(       d  [        R                  " S	U4S
XV45      S[         R"                  " 5       ;   d  [        R$                  " U5      (       a  [        R&                  " U5      OS[        R&                  " U5      S.-  nSSU0-  n	[)        [        R*                  " U	5      5      eS =pvUR,                  S   n
U
S   nUS    Vs1 s H  oS   iM	     nnSoU;   of(       d  [        R                  " SU4SX45      [        R&                  " U5      S[         R"                  " 5       ;   d  [        R$                  " U5      (       a  [        R&                  " U5      OSS.-  nSSU0-  n	[)        [        R*                  " U	5      5      eS =pSoU;   of(       d  [        R                  " SU4SX45      [        R&                  " U5      S[         R"                  " 5       ;   d  [        R$                  " U5      (       a  [        R&                  " U5      OSS.-  nSSU0-  n	[)        [        R*                  " U	5      5      eS =pS S S 5        g s  snf ! , (       d  f       g = f)Nr@   r   r   r   r   z<p>Body</p>)htmlTrG   rI   r   rK   rN   rO      rQ   contenttypez
text/plaininz%(py1)s in %(py3)scontent_typespy1rM   z	text/html)r   r#   r$   rP   r   r   rR   rS   r   r   rW   rX   rY   r+   rZ   r[   r\   r]   r^   r_   r`   ra   	call_args)rb   rc   	mock_postr   rf   r   rg   rh   ri   rj   call_kwargspayloadr:   r   @py_assert0s                  r   test_send_email_with_html)TestEmailClient.test_send_email_with_html   s   \\&,,6'!I@I  ++88=##%B&BO))+D,,i]KF "!T>!!!!6!!!!!!6!!!!6!!!T!!!!!!! $--a0K!&)G07	0BC0B1vY0BMC0=00000<000<000000=0000=0000000/-/////;///;//////-////-///////% 76  D! 76s   EK;5K6E*K;6K;;
L	r   N)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r      s    G
"
"#0r   r   c                   b    \ rS rSrSr\R                  " SS9S 5       rS rS r	S r
S	 rS
 rSrg)TestRateLimiting   z<Rate-limit helper tests using real functions with mocked db.T)autousec              #      #    [         R                  " [        S5       n[        5       Ul        Uv   SSS5        g! , (       d  f       g= f7f)z;Mock server.db only (don't patch the functions themselves).r   N)r   r#   r$   r   r(   )rb   r3   s     r   _mock_dbTestRateLimiting._mock_db   s2      \\&$'7"7"9GM (''s   A;	A
A	Ac                 |   [        S S9UR                  l        [        R                  " 5       nUR                  [        R                  " SS5      5      u  p4SoSUL of(       d  [        R                  " SU4SX545      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  nS	S
U0-  n[        [        R                  " U5      5      eS =peSoTU:H  of(       d  [        R                  " SU4SXE45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  nS	S
U0-  n[        [        R                  " U5      5      eS =peg )Nr   user-1smsTrG   rI   allowedrK   rN   rO   r"   ==z%(py0)s == %(py3)s	remainingr   r(   r)   rW   rX   rY   r$   r   rZ   r[   r\   r]   r^   r_   r`   ra   	rb   r   rf   r   r   rg   rh   ri   rj   s	            r   test_check_rate_limit_allows-TestRateLimiting.test_check_rate_limit_allows   s    (1t(D%%%'!44##He4
 $www$ByyyBr   c                    [        SS0S9UR                  l        [        R                  " 5       nUR                  [        R                  " SS5      5      u  p4SoSUL of(       d  [        R                  " SU4SX545      S	[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS	[        R                  " U5      S
.-  nSSU0-  n[        [        R                  " U5      5      eS =peSoTU:H  of(       d  [        R                  " SU4SXE45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S
.-  nSSU0-  n[        [        R                  " U5      5      eS =peg )Ncountr"   r   r   r   FrG   rI   r   rK   rN   rO   r   r   r   r   r   r   s	            r   test_check_rate_limit_blocks-TestRateLimiting.test_check_rate_limit_blocks  s   (1}(M%%%'!44##He4
  %www%A~yyyAr   c                    [        SS0S9UR                  l        [        R                  " 5       nUR                  [        R                  " SS5      5      u  p4SoSUL of(       d  [        R                  " SU4SX545      S	[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS	[        R                  " U5      S
.-  nSSU0-  n[        [        R                  " U5      5      eS =peSoTU:H  of(       d  [        R                  " SU4SXE45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S
.-  nSSU0-  n[        [        R                  " U5      5      eS =peg )Nr      r   r   r   TrG   rI   r   rK   rN   rO      r   r   r   r   r   s	            r   test_check_rate_limit_partial.TestRateLimiting.test_check_rate_limit_partial  s    (1|(L%%%'!44##He4
 $www$A~yyyAr   c                     [         R                  " 5       nUR                  [        R                  " SS5      5        UR
                  R                  R                  5         g )Nr   email)rW   rX   rY   r$   r!   r(   r   assert_called_once)rb   r   rf   s      r   test_increment_rate_limit*TestRateLimiting.test_increment_rate_limit  sC    %%' ; ;Hg NO''::<r   c                 v   [         R                  S   nSo!U:H  o3(       do  [        R                  " SU4SX45      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=p2[         R                  S   nS	o!U:H  o3(       do  [        R                  " SU4SX45      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=p2[         R                  S
   nSo!U:H  o3(       do  [        R                  " SU4SX45      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=p2g )Nr   r"   r   z%(py1)s == %(py4)sr   py4assert %(py6)spy6r   2   pushd   )r$   RATE_LIMITSrZ   r[   r_   r`   ra   )rb   r   r   rg   @py_format5@py_format7s         r   test_rate_limits_constants+TestRateLimiting.test_rate_limits_constants  s   !!%(.B.B.....(...(...B.......!!'*0b0b00000*000*000b0000000!!&)0S0S00000)000)000S0000000r   r   N)r   r   r   r   r   pytestfixturer   r   r   r   r   r   r   r   r   r   r   r      s9    F^^D! "=
1r   r   c                   B    \ rS rSrSrS rS rS rS rS r	S r
S	 rS
rg)TestSendNotificationi&  zPOST /api/notifications/sendc                    SSSSS.nUR                  SUS9nUR                  nSoTU:H  of(       d  [        R                  " S	U4S
XE45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n[        [        R                  " U5      5      eS =n=peUR                  5       n	U	S   n
SojU:H  o(       do  [        R                  " S	U4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n
=pU	S   n
SojU:H  o(       do  [        R                  " S	U4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n
=pSoU	;   o(       d  [        R                  " SU4SX45      [        R                  " U
5      S[        R
                  " 5       ;   d  [        R                  " U	5      (       a  [        R                  " U	5      OSS.-  nSSU0-  n[        [        R                  " U5      5      eS =p[        R                  R                  5         g )NrD   zTest SMSHello from testr   tosubjectbodychannel/api/notifications/sendrQ      r   z3%(py2)s
{%(py2)s = %(py0)s.status_code
} == %(py5)srespry   
>assert %(py7)sr|   statussentr   r   r   r   r   idr   r   datar   rN   rO   )rS   status_coderZ   r[   r\   r]   r^   r_   _format_assertmsgtextr`   ra   rQ   r$   r!   r   )rb   r;   r   r   rh   r   r   rj   r   r   r   rg   r   r   ri   s                  r   test_send_sms"TestSendNotification.test_send_sms)  s    !%	
 {{47{C1313&1111111111t1111t11111131111		1111111yy{H~'''''''~'''~''''''''''I'%'%'''''''''''%'''''''t|tttt 	##668r   c                 V   SSSSS.nUR                  SUS9nUR                  nSoTU:H  of(       d  [        R                  " S	U4S
XE45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n[        [        R                  " U5      5      eS =n=peUR                  5       n	U	S   n
SojU:H  o(       do  [        R                  " S	U4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n
=pU	S   n
SojU:H  o(       do  [        R                  " S	U4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n
=pg )Nuser@example.comz
Test Emailr   r   r   r   r   r   r   r   r   ry   r   r|   r   r   r   r   r   r   r   rS   r   rZ   r[   r\   r]   r^   r_   r  r  r`   ra   rQ   rb   r;   r   r   rh   r   r   rj   r   r   r   rg   r   r   s                 r   test_send_email$TestSendNotification.test_send_email:  sT   $#%	
 {{47{C1313&1111111111t1111t11111131111		1111111yy{H~'''''''~'''~''''''''''I)')')))))))))))')))))))r   c                 V   SSSSS.nUR                  SUS9nUR                  nSoTU:H  of(       d  [        R                  " S	U4S
XE45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n[        [        R                  " U5      5      eS =n=peUR                  5       n	U	S   n
SojU:H  o(       do  [        R                  " S	U4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n
=pU	S   n
SojU:H  o(       do  [        R                  " S	U4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n
=pg )Nzdevice-tokenz	Test Pushr   r   r   r   r   r   r   r   r   ry   r   r|   r   r   r   r   r   r   r   r  r  s                 r   test_send_push#TestSendNotification.test_send_pushG  sT    "%	
 {{47{C1313&1111111111t1111t11111131111		1111111yy{H~'''''''~'''~''''''''''I(&(&(((((((((((&(((((((r   c                    SSSSS.nUR                  SUS9nUR                  nSoTU:H  of(       d  [        R                  " S	U4S
XE45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n[        [        R                  " U5      5      eS =n=pe/ nSoR                  oU
;   oUo(       d  SoR                  oU;   onU(       Gd  [        R                  " SU4SX45      [        R                  " U	5      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U
5      S.-  nSSU0-  oR                  U5        U(       d  [        R                  " SW4SWW45      [        R                  " U5      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  nSSU0-  nUR                  U5        [        R                  " US5      0 -  nSSU0-  n[        [        R                  " U5      5      eS =n=n=n	=n=n
=n=pg )NsomeoneBadzBad channelfaxr   r   r     r   r   r   ry   r   r|   zUnsupported channelr   )z,%(py3)s in %(py7)s
{%(py7)s = %(py5)s.text
})rM   rO   r|   z%(py9)spy9)z0%(py12)s in %(py16)s
{%(py16)s = %(py14)s.text
})py12py14py16z%(py18)spy18r   zassert %(py21)spy21)rS   r   rZ   r[   r\   r]   r^   r_   r  r  r`   ra   append_format_boolop)rb   r;   r   r   rh   r   r   rj   r   rg   @py_assert6r   @py_assert11@py_assert15@py_assert13@py_format10@py_format17@py_format19@py_format20@py_format22s                       r   test_invalid_channel)TestSendNotification.test_invalid_channelT  s   !	
 {{47{C1313&1111111111t1111t11111131111		1111111GuG		G	!G%:GiiGi%GGGGGuGGGuGGGGGGGGGGGGG	GGGGGGGG%:iGGG%:GGGGGGdGGGGdGGGiGGGGGGGGGGGGGGGr   c                    S[         R                  l        SSSSS.nUR                  SUS9nUR                  nS	oTU:H  of(       d  [
        R                  " S
U4SXE45      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS[
        R                  " U5      [
        R                  " U5      S.-  n[
        R                  " UR                  5      S-   SU0-  n[        [
        R                  " U5      5      eS=n=peSoR                  oYU;   o(       d  [
        R                  " SU
4SX45      [
        R                  " U	5      S[        R                  " 5       ;   d  [
        R                  " U5      (       a  [
        R                  " U5      OS[
        R                  " U5      S.-  nSSU0-  n[        [
        R                  " U5      5      eS=n	=pg)zAWhen check_rate_limit returns (False, 0) the endpoint should 429.)Fr   rD   zRate limitedzShould failr   r   r   r   i  r   r   r   ry   r   r|   Nz
Rate limitr   z,%(py1)s in %(py5)s
{%(py5)s = %(py3)s.text
}r   rM   rO   r{   )r$   r   r   rS   r   rZ   r[   r\   r]   r^   r_   r  r  r`   ra   )rb   r;   r   r   rh   r   r   rj   r   r   rg   s              r   test_rate_limit_exceeded-TestSendNotification.test_rate_limit_exceeded_  s,   /9, !%!	
 {{47{C1313&1111111111t1111t11111131111		1111111(yy(y(((((|(((|((((((t((((t(((y(((((((r   c                    [         R                  R                  n[        SS9Ul        SSSSS.nUR                  SUS	9nUR                  nS
oeU:H  ow(       d  [        R                  " SU4SXV45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n	[        [        R                   " U	5      5      eS=n=pvUR#                  5       n
U
S   nSo{U:H  o(       do  [        R                  " SU4SX45      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                   " U5      5      eS=n=pU
S   nSo{ULo(       do  [        R                  " SU4SX45      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                   " U5      5      eS=n=pg)z7When Twilio returns failure, status should be 'failed'.Fr   rD   zFailing SMSz	Will failr   r   r   r   r   r   r   r   ry   r   r|   Nr   failedr   r   r   r   error)is not)z%(py1)s is not %(py4)s)r$   r   r   r   r*   rS   r   rZ   r[   r\   r]   r^   r_   r  r  r`   ra   rQ   )rb   r;   twilio_instancer   r   rh   r   r   rj   r   r   r   rg   r   r   s                  r   test_sms_provider_failure.TestSendNotification.test_sms_provider_failurem  st    --::#,%#@  !$	
 {{47{C1313&1111111111t1111t11111131111		1111111yy{H~)))))))~)))~))))))))))G}(D(D(((((}(((}(((D(((((((r   c                 N   SSSSSS.nUR                  SUS9nUR                  nS	oTU:H  of(       d  [        R                  " S
U4SXE45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n[        [        R                  " U5      5      eS=n=peUR                  5       n	U	S   n
SojU:H  o(       do  [        R                  " S
U4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS=n
=pg)z9user_id in request body overrides the authenticated user.rD   zCustom userTestr   zcustom-user-123)r   r   r   r   user_idr   r   r   r   r   r   ry   r   r|   Nr   r   r   r   r   r   r  r  s                 r   test_custom_user_id(TestSendNotification.test_custom_user_id~  s    !$(
 {{47{C1313&1111111111t1111t11111131111		1111111yy{H~'''''''~'''~''''''''''r   r   N)r   r   r   r   r   r  r	  r  r$  r)  r0  r5  r   r   r   r   r   r   &  s)    &9"*)	H))"(r   r   c                   *    \ rS rSrSrS rS rS rSrg)TestScheduleNotificationi  z POST /api/notifications/schedulec                    [         R                  " 5       [        SS9-   R                  5       nSSSSUS.nUR	                  SUS	9nUR
                  nS
oeU:H  ow(       d  [        R                  " SU4SXV45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n	[        [        R                  " U	5      5      eS =n=pvUR!                  5       n
U
S   nSo{U:H  o(       do  [        R                  " SU4SX45      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=pU
S   nSo{U:H  o(       do  [        R                  " SU4SX45      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=pSoU
;   o(       d  [        R                  " SU4SX45      [        R                  " U5      S[        R                  " 5       ;   d  [        R                  " U
5      (       a  [        R                  " U
5      OSS.-  nSSU0-  n[        [        R                  " U5      5      eS =pg )N   hoursr  	ScheduledLaterr   r   r   r   r   scheduled_time/api/notifications/scheduler   r   r   r   r   ry   r   r|   r   	scheduledr   r   r   r   r   r   r   r   r   r   rN   rO   )r   utcnowr   	isoformatrS   r   rZ   r[   r\   r]   r^   r_   r  r  r`   ra   rQ   )rb   r;   futurer   r   rh   r   r   rj   r   r   r   rg   r   r   ri   s                   r   test_schedule_future-TestScheduleNotification.test_schedule_future  s   //#ia&88CCE$"$
 {{8w{G1313&1111111111t1111t11111131111		1111111yy{H~,,,,,,,~,,,~,,,,,,,,,,I)')')))))))))))')))))))t|ttttr   c                 *   [         R                  " 5       [        SS9-
  R                  5       nSSSSUS.nUR	                  SUS	9nUR
                  nS
oeU:H  ow(       d  [        R                  " SU4SXV45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n	[        [        R                  " U	5      5      eS =n=pvSoR                  ojU;   o(       d  [        R                  " SU4SX45      [        R                  " U
5      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  nSSU0-  n	[        [        R                  " U	5      5      eS =n
=pg )Nr   r;  r  PastzToo later   r?  rA  r   r  r   r   r   ry   r   r|   rE  r   r'  r(  r{   r   rC  r   rD  rS   r   rZ   r[   r\   r]   r^   r_   r  r  r`   ra   )rb   r;   pastr   r   rh   r   r   rj   r   r   rg   s               r   test_schedule_past_rejected4TestScheduleNotification.test_schedule_past_rejected  s>   !IA$66AAC$"
 {{8w{G1313&1111111111t1111t11111131111		1111111$99$9$$$$$x$$$x$$$$$$4$$$$4$$$9$$$$$$$r   c                    [         R                  " 5       [        SS9-   R                  5       nSSSSUSS.nUR	                  S	US
9nUR
                  nSoeU:H  ow(       d  [        R                  " SU4SXV45      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " UR                  5      S-   SU0-  n	[        [        R                  " U	5      5      eS =n=pvg )Nr:  r;  r  z
Race alertzRace starts soonr   zrace-123)r   r   r   r   r@  race_idrA  r   r   r   r   r   ry   r   r|   rJ  )
rb   r;   rE  r   r   rh   r   r   rj   r   s
             r   test_schedule_with_race_id3TestScheduleNotification.test_schedule_with_race_id  s    //#ia&88CCE$#&$!
 {{8w{G1313&1111111111t1111t11111131111		1111111r   r   N)	r   r   r   r   r   rF  rL  rP  r   r   r   r   r8  r8    s    * %2r   r8  c                   *    \ rS rSrSrS rS rS rSrg)TestProvidersEndpointi  z GET /api/notifications/providersc                 (   UR                  S5      nUR                  nSoCU:H  oU(       d  [        R                  " SU4SX445      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS	=n=pTUR                  5       nUS
   n	U	S   S   n
SoZUL o(       do  [        R                  " SU4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS	=n
=pU	S   S   n
SoZUL o(       do  [        R                  " SU4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS	=n
=pU	S   S   n
SoZUL o(       do  [        R                  " SU4SX45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS	=n
=pg	)zCWithout env vars for Twilio/SendGrid/Resend, only push should show./api/notifications/providersr   r   r   r   ry   r{   r|   N	providersr   	availableTrG   z%(py1)s is %(py4)sr   r   r   r   Fr   )getr   rZ   r[   r\   r]   r^   r_   r`   ra   rQ   )rb   r;   r   rh   r   r   rj   r   r   provr   rg   r   r   s                 r   test_providers_default,TestProvidersEndpoint.test_providers_default  s   zz89&3&3&&&&&&&&&&&t&&&&t&&&&&&3&&&&&&&yy{K F|K(0D0D00000(000(000D0000000E{;'050500000'000'00050000000G}[)2U2U22222)222)222U2222222r   c                    [         R                  " [        R                  SSSS.5         UR	                  S5      nUR
                  nSoCU:H  oU(       d  [        R                  " SU4SX445      S	[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS	[        R                  " U5      [        R                  " U5      S
.-  nSSU0-  n[        [        R                  " U5      5      eS =n=pTUR                  5       nUS   S   S   n	SoYUL o(       do  [        R                  " SU
4SX45      [        R                  " U	5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n	=pUS   S   S   n	SoYU:H  o(       do  [        R                  " SU
4SX45      [        R                  " U	5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n	=pS S S 5        g ! , (       d  f       g = f)NrA   rC   rD   )TWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKENTWILIO_PHONE_NUMBERrU  r   r   r   r   ry   r{   r|   rV  r   rW  TrG   rX  r   r   r   providertwilior   r   dictosenvironrY  r   rZ   r[   r\   r]   r^   r_   r`   ra   rQ   rb   r;   r   rh   r   r   rj   r   r   r   rg   r   r   s                r    test_providers_twilio_configured6TestProvidersEndpoint.test_providers_twilio_configured  sv   ZZJJ&+%,'5
 ::<=D##*s*s*****#******4****4***#***s*******99;D$U+K8@D@D@@@@@8@@@8@@@D@@@@@@@$U+J7C8C8CCCCC7CCC7CCC8CCCCCCC
 
 
s   HI
Ic                    [         R                  " [        R                  SS05         UR	                  S5      nUR
                  nSoCU:H  oU(       d  [        R                  " SU4SX445      S[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  nS	S
U0-  n[        [        R                  " U5      5      eS =n=pTUR                  5       nUS   S   S   n	SoYUL o(       do  [        R                  " SU
4SX45      [        R                  " U	5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n	=pUS   S   S   S   n	SoYUL o(       do  [        R                  " SU
4SX45      [        R                  " U	5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n	=pS S S 5        g ! , (       d  f       g = f)NSENDGRID_API_KEYr   rU  r   r   r   r   ry   r{   r|   rV  r   rW  TrG   rX  r   r   r   sendgridrc  rg  s                r   test_providers_email_configured5TestProvidersEndpoint.test_providers_email_configured  sm   ZZ

%7$BC::<=D##*s*s*****#******4****4***#***s*******99;D$W-k:BdBdBBBBB:BBB:BBBdBBBBBBB$W-k::FN$N$NNNNNFNNNFNNN$NNNNNNN DCCs   HI
Ir   N)	r   r   r   r   r   r[  rh  rm  r   r   r   r   rS  rS    s    *3DOr   rS  )$r   builtinsr\   _pytest.assertion.rewrite	assertionrewriterZ   rW   re  sysr   r   unittest.mockr   r   r   r   fastapi.testclientr   pathjoindirname__file__BACKEND_DIRinsertrf  r$   r   r   r;   r=   r   r   r   r8  rS  r   r   r   <module>r|     s    =    	 
 ( 5 5  ) ggll277??84dIFchhHHOOA{# 6

; (

9  & 0 0p6" 6"rE0 E0Z01 01pd( d(N+2 +2\"O "Or   