
    YiXb                        d dl Z d dlZd dlmZmZ d dlZd dlZd dlZd dlmZ	 d dlm
Z
mZmZmZmZmZmZmZmZmZmZmZmZmZ d dlmZ ej4                  j7                  dg d      d        Z G d d	ej:                        Z G d
 dej:                        Zej4                  j7                  dg d      d        Z d Z!d Z"d Z#d Z$ G d dej:                        Z% G d dej:                        Z& G d dej:                        Z'y)    N)datedatetime)APIErrorDatetimeSerializerGetResponseKEEP_ALIVE_SOCKET_OPTIONSQuotaLimitError_mask_tokens_in_url
batch_postdecidedetermine_server_hostdisable_connection_reuseenable_keep_aliveflagsgetset_socket_options)TEST_API_KEYzurl, expected))zAhttps://example.com/api/flags?token=phc_abc123xyz789&send_cohortsz>https://example.com/api/flags?token=phc_abc123...&send_cohorts)z4https://example.com/api/flags?token=phc_abc123xyz789z1https://example.com/api/flags?token=phc_abc123...))https://example.com/api/flags?other=valuer   ))https://example.com/api/flags?token=shortr   )z.https://example.com/api/flags?token=1234567890z1https://example.com/api/flags?token=1234567890...c                 $    t        |       |k(  sJ y N)r
   )urlexpecteds     c/mnt/e/genesis-system/.venvs/browser-army/lib/python3.12/site-packages/posthog/test/test_request.pytest_mask_tokens_in_urlr      s    > s#x///    c                   B    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestRequestsc                 h    t        t        ddddg      }| j                  |j                  d       y )Ndistinct_idpython eventtrackr    eventtypebatch   r   r   assertEqualstatus_codeselfress     r   test_valid_requestzTestRequests.test_valid_request@   s5     -PWX
 	#.r   c                 @    | j                  t        t        dddd       y )N
testsecrethttps://t.posthog.comFz[{]assertRaises	Exceptionr   r-   s    r   test_invalid_request_errorz'TestRequests.test_invalid_request_errorI   s    z<1H%QV	
r   c                 @    | j                  t        t        ddg        y )Nr1   t.posthog.com/r&   r3   r6   s    r   test_invalid_hostzTestRequests.test_invalid_hostN   s!    z<1A 	 	
r   c           
          dt        ddddddd      i}t        j                  |t        	      }| j	                  |d
       y )Ncreatedi                 i clsz){"created": "2012-03-04T05:06:07.891011"})r   jsondumpsr   r*   )r-   dataresults      r   test_datetime_serializationz(TestRequests.test_datetime_serializationS   s?    8D!Q1a@AD&89!LMr   c                     t        j                         }d|i}t        j                  |t              }d|j                         z  }| j                  ||       y )Nr<   rB   z{"created": "%s"})r   todayrD   rE   r   	isoformatr*   )r-   rJ   rF   rG   r   s        r   test_date_serializationz$TestRequests.test_date_serializationX   sI    

5!D&89&)::*r   c                 j    t        t        ddddgd      }| j                  |j                  d       y )Nr    r!   r"   r#      r'   timeoutr(   r)   r,   s     r   test_should_not_timeoutz$TestRequests.test_should_not_timeout_   s:     -PWX 
 	#.r   c                     | j                  t        j                        5  t        dddddgd       d d d        y # 1 sw Y   y xY w)Nkeyr    r!   r"   r#   g-C6?rO   )r4   requestsReadTimeoutr   r6   s    r   test_should_timeoutz TestRequests.test_should_timeouti   sP    x334 	 (5!/ ' 
	 	 	s	   =Ac                    t        j                         }d|_        t        j                  dgi i dd      j                  d      |_        t        j                  d|      5  | j                  t              5 }t        dd	       d d d        | j                  j                  j                  d       | j                  |j                  j                  d
       d d d        y # 1 sw Y   ^xY w# 1 sw Y   y xY w)Nr(   feature_flagsFquotaLimitedfeatureFlagsfeatureFlagPayloadserrorsWhileComputingFlagsutf-8posthog.request._session.postreturn_valuefake_key	fake_hostzFeature flags quota limited)rT   Responser+   rD   rE   encode_contentmockpatchr4   r	   r   r*   	exceptionstatusmessage)r-   mock_responsecms      r   test_quota_limited_responsez(TestRequests.test_quota_limited_responsew   s     ))+$'!!%!0 1 "')-2	"
 &/ 	 ZZ7mT 	R""?3 0rz;/0 R\\00#6R\\113PQ	R 	R0 0	R 	Rs%   "C.8C"AC."C+	'C..C7c                 6   t        j                         }d|_        t        j                  ddii dd      j                  d      |_        t        j                  d|      5  t        d	d
      }| j                  |d   ddi       d d d        y # 1 sw Y   y xY w)Nr(   flag1TFr[   r\   r]   r^   r_   r`   rb   rc   r[   )rT   rd   r+   rD   rE   re   rf   rg   rh   r   r*   )r-   rl   responses      r   test_normal_decide_responsez(TestRequests.test_normal_decide_response   s     ))+$'!!%!($')-2"
 &/ 	 ZZ7mT 	Hj+6HXn5G	H 	H 	Hs   "$BBN)__name__
__module____qualname__r/   r7   r:   rH   rL   rQ   rV   rn   rs    r   r   r   r   ?   s2    /



N
+/R&Hr   r   c                   P   e Zd ZdZ ej
                  d      d        Z ej
                  d      d        Z ej
                  d      d        Z ej
                  d      d        Z	 ej
                  d      d        Z
 ej
                  d      d        Z ej
                  d      d	        Z ej
                  d      d
        Z ej
                  d      d        Z ej
                  d      d        Z ej
                  d      d        Z ej
                  d      d        Zy)TestGetz6Unit tests for the get() function HTTP-level behavior.zposthog.request._session.getc                    t        j                         }d|_        d|j                  d<   t	        j
                  dddigi      j                  d      |_        ||_        t        dd	d
      }| j                  |t               | j                  |j                  dddigi       | j                  |j                  d       | j                  |j                          y)zDTest that get() returns GetResponse with data and etag from headers.r(   z"abc123"ETagr   rS   	test-flagr^   api_key	/test-urlhttps://example.comhostN)rT   rd   r+   headersrD   rE   re   rf   ra   r   assertIsInstancer   r*   rF   etagassertFalsenot_modifiedr-   mock_getrl   rr   s       r   test_get_returns_data_and_etagz&TestGet.test_get_returns_data_and_etag   s     !))+$'!(2f%!%W{7K6L,M!N!U!U"
 !.y+4IJh4E;3G2H(IJ
3../r   c                 (   t        j                         }d|_        d|j                  d<   t	        j
                  dg i      j                  d      |_        ||_        t        dddd	
       |j                  d   }| j                  |d   d   d	       y)zGTest that If-None-Match header is sent when etag parameter is provided.r(   z
"new-etag"r{   r   r^   r}   r~   r   z"previous-etag"r   r      r   If-None-MatchN)rT   rd   r+   r   rD   rE   re   rf   ra   r   	call_argsr*   r-   r   rl   call_kwargss       r   6test_get_sends_if_none_match_header_when_etag_providedz>TestGet.test_get_sends_if_none_match_header_when_etag_provided   s     !))+$'!(4f%!%WbM!:!A!A'!J -I{)>EVW((+Y/@BSTr   c                    t        j                         }d|_        t        j                  dg i      j                  d      |_        ||_        t        ddd       |j                  d   }| j                  d	|d
          y)zATest that If-None-Match header is not sent when no etag provided.r(   r   r^   r}   r~   r   r   r   r   r   N)rT   rd   r+   rD   rE   re   rf   ra   r   r   assertNotInr   s       r   1test_get_does_not_send_if_none_match_when_no_etagz9TestGet.test_get_does_not_send_if_none_match_when_no_etag   st     !))+$'!!%WbM!:!A!A'!J -I{)>?((++i*@Ar   c                 T   t        j                         }d|_        d|j                  d<   ||_        t        dddd      }| j                  |t               | j                  |j                         | j                  |j                  d       | j                  |j                         y)	zKTest that 304 Not Modified response returns not_modified=True with no data.0  z"unchanged-etag"r{   r}   r~   r   r   N)rT   rd   r+   r   ra   r   r   r   assertIsNonerF   r*   r   
assertTruer   r   s       r   !test_get_handles_304_not_modifiedz)TestGet.test_get_handles_304_not_modified   s     !))+$'!(:f% -{)>EW
 	h4(--((:;--.r   c                     t        j                         }d|_        ||_        t	        dddd      }| j                  |j                         | j                  |j                  d       y)zFTest that 304 response without ETag header falls back to request etag.r   r}   r~   r   z"original-etag"r   N)	rT   rd   r+   ra   r   r   r   r*   r   r   s       r   2test_get_304_without_etag_header_uses_request_etagz:TestGet.test_get_304_without_etag_header_uses_request_etag   s`     !))+$'! -{)>EV
 	--.(9:r   c                 b   t        j                         }d|_        t        j                  dg i      j                  d      |_        ||_        t        ddd      }| j                  |j                         | j                  |j                         | j                  |j                  dg i       y)	zATest that 200 response without ETag header returns None for etag.r(   r   r^   r}   r~   r   r   N)rT   rd   r+   rD   rE   re   rf   ra   r   r   r   r   r   r*   rF   r   s       r    test_get_200_without_etag_headerz(TestGet.test_get_200_without_etag_header   s     !))+$'!!%WbM!:!A!A'!J -y+4IJ../(--("6r   c                    t        j                         }d|_        t        j                  ddi      j                  d      |_        ||_        | j                  t              5 }t        ddd       d	d	d	       | j                  j                  j                  d       | j                  |j                  j                  d       y	# 1 sw Y   VxY w)
z)Test that error responses raise APIError.i  detailUnauthorizedr^   bad_keyr~   r   r   N)rT   rd   r+   rD   rE   re   rf   ra   r4   r   r   r*   ri   rj   rk   )r-   r   rl   ctxs       r   (test_get_error_response_raises_api_errorz0TestGet.test_get_error_response_raises_api_error   s     !))+$'!!%X~,F!G!N!Nw!W -x( 	DC	;-BC	D 	--s3..?		D 	Ds   #CCc                    t        j                         }d|_        t        j                  i       j                  d      |_        ||_        t        ddd       |j                  d   }| j                  |d   d	   d
       y)z9Test that Authorization header is sent with Bearer token.r(   r^   z
my-api-keyr~   r   r   r   r   AuthorizationzBearer my-api-keyNrT   rd   r+   rD   rE   re   rf   ra   r   r   r*   r   s       r   #test_get_sends_authorization_headerz+TestGet.test_get_sends_authorization_header  su     !))+$'!!%B!6!6w!? -L+,AB((+Y/@BUVr   c                 J   t        j                         }d|_        t        j                  i       j                  d      |_        ||_        t        ddd       |j                  d   }| j                  d|d	          | j                  |d	   d   j                  d
             y)z$Test that User-Agent header is sent.r(   r^   r}   r~   r   r   r   z
User-Agentr   zposthog-python/N)rT   rd   r+   rD   rE   re   rf   ra   r   r   assertInr   
startswithr   s       r    test_get_sends_user_agent_headerz(TestGet.test_get_sends_user_agent_header  s     !))+$'!!%B!6!6w!? -I{)>?((+lK	$:;	"<0;;<MN	
r   c                     t        j                         }d|_        t        j                  i       j                  d      |_        ||_        t        dddd       |j                  d   }| j                  |d	   d       y
)z5Test that timeout parameter is passed to the request.r(   r^   r}   r~   r      )r   rP   r   rP   Nr   r   s       r   test_get_passes_timeoutzTestGet.test_get_passes_timeout$  sq     !))+$'!!%B!6!6w!? -I{)>K((+Y/4r   c                     t        j                         }d|_        t        j                  i       j                  d      |_        ||_        t        ddd       |j                  d   }| j                  |d   d       y	)
z.Test that host and url are combined correctly.r(   r^   r}   
/api/flagsr   r   r   https://example.com/api/flagsNr   r-   r   rl   r   s       r   test_get_constructs_full_urlz$TestGet.test_get_constructs_full_url1  so     !))+$'!!%B!6!6w!? -I|*?@&&q)	1'FGr   c                     t        j                         }d|_        t        j                  i       j                  d      |_        ||_        t        ddd       |j                  d   }| j                  |d   d       y	)
z.Test that trailing slash is removed from host.r(   r^   r}   r   zhttps://example.com/r   r   r   Nr   r   s       r   )test_get_removes_trailing_slash_from_hostz1TestGet.test_get_removes_trailing_slash_from_host>  so     !))+$'!!%B!6!6w!? -I|*@A&&q)	1'FGr   N)rt   ru   rv   __doc__rg   rh   r   r   r   r   r   r   r   r   r   r   r   r   rw   r   r   ry   ry      s   @TZZ./0 00" TZZ./U 0U TZZ./
B 0
B TZZ.// 0/  TZZ./; 0; TZZ./7 07 TZZ./@ 0@ TZZ./
W 0
W TZZ./
 0
 TZZ./
5 0
5 TZZ./
H 0
H TZZ./
H 0
Hr   ry   zhost, expected))r2   r2   )https://t.posthog.com/r   )t.posthog.comr   )r9   r9   )#https://us.posthog.com.rg.proxy.comr   )app.posthog.comr   )eu.posthog.comr   )zhttps://app.posthog.comhttps://us.i.posthog.com)zhttps://eu.posthog.comhttps://eu.i.posthog.com)zhttps://us.posthog.comr   )zhttps://app.posthog.com/r   )zhttps://eu.posthog.com/r   )zhttps://us.posthog.com/r   )Nr   c                 $    t        |       |k(  sJ y r   )r   )r   r   s     r   test_routing_to_custom_hostr   L  s    ( !&(222r   c                      	 t                ddlm}  | j                  d      }|j                  t
        k(  sJ 	 t        d        y # t        d        w xY wNr   )_sessionr   )r   posthog.requestr   get_adaptersocket_optionsr   r   r   adapters     r   *test_enable_keep_alive_sets_socket_optionsr   c  sH    !,&&'<=%%)BBBB4 4 s   6A Ac                      	 t                t        d        ddlm}  | j	                  d      }|j
                  J 	 t        d        y # t        d        w xY wr   )r   r   r   r   r   r   r   s     r   (test_set_socket_options_clears_with_noner   n  sM    !4 ,&&'<=%%---4 4    :A	 	Ac                      	 t                t        j                         } t        j                         }| |usJ 	 dt        _        y # dt        _        w xY w)NT)r   request_module_get_session_pooling_enabledsession1session2s     r   4test_disable_connection_reuse_creates_fresh_sessionsr   z  sH    / "!..0!..0x'''*.'$'s   8A Ac                      	 t                t        j                  } t                t        j                  }| |u sJ 	 t        d        y # t        d        w xY wr   )r   r   r   r   r   s     r   %test_set_socket_options_is_idempotentr     sI    !!**!**8###4 4 r   c                   |    e Zd ZdZd Zd Z ej                  d      d        Z ej                  d      d        Z	y)TestFlagsSessionz&Tests for flags session configuration.c                 4    ddl m} | j                  d|       y)zBVerify 429 (rate limit) is NOT retried - need to wait, not hammer.r   RETRY_STATUS_FORCELIST  Nr   r   r   r-   r   s     r   0test_retry_status_forcelist_excludes_rate_limitszATestFlagsSession.test_retry_status_forcelist_excludes_rate_limits      :45r   c                 4    ddl m} | j                  d|       y)zCVerify 402 (payment required/quota) is NOT retried - won't resolve.r   r     Nr   r   s     r   1test_retry_status_forcelist_excludes_quota_errorszBTestFlagsSession.test_retry_status_forcelist_excludes_quota_errors  r   r   z"posthog.request._get_flags_sessionc                    t        j                         }d|_        t        j                  ddii dd      j                  d      |_        t        j                         }||j                  _
        ||_
        t        ddd	
      }| j                  |d   d   d       |j                          |j                  j                          y)zBflags() uses the dedicated flags session, not the general session.r(   r|   TFrq   r^   test-keyhttps://test.posthog.comuser123r    r[   N)rT   rd   r+   rD   rE   re   rf   rg   	MagicMockpostra   r   r*   assert_called_once)r-   mock_get_flags_sessionrl   mock_sessionrG   s        r   test_flags_uses_flags_sessionz.TestFlagsSession.test_flags_uses_flags_session  s     !))+$'!!%!,d 3')-2"
 &/ 	 ~~')6&.:+z#=9U/<dC113,,.r   c                    t        j                         }d|_        t        j                  dgi i dd      j                  d      |_        t        j                         }||j                  _
        ||_
        | j                  t              5  t        ddd	       d
d
d
       | j                  |j                  j                  d       y
# 1 sw Y   0xY w)zGflags() raises QuotaLimitError without retrying (at application level).r(   rX   FrY   r^   r   r   r   r   Nr   )rT   rd   r+   rD   rE   re   rf   rg   r   r   ra   r4   r	   r   r*   
call_count)r-   r   rl   r   s       r   "test_flags_no_retry_on_quota_limitz3TestFlagsSession.test_flags_no_retry_on_quota_limit  s     !))+$'!!%!0 1 "')-2	"
 &/ 	 ~~')6&.:+/ 	Q*8iP	Q 	**55q9		Q 	Qs   C

CN)
rt   ru   rv   r   r   r   rg   rh   r   r   rw   r   r   r   r     sO    066 TZZ45/ 6/, TZZ45: 6:r   r   c                   "    e Zd ZdZd Zd Zd Zy)TestFlagsSessionNetworkRetriesz7Tests for network failure retries in the flags session.c                 @   ddl m}  |       }|j                  d      }|j                  }| j	                  |j
                  dd       | j	                  |j                  dd       | j	                  |j                  dd       | j                  d|j                  d	       y
)a(  
        Verify that the flags session is configured to retry on connection errors.

        The urllib3 Retry adapter with connect=2 and read=2 automatically
        retries on network-level failures (DNS failures, connection refused,
        connection reset, etc.) up to 2 times each.
        r   _build_flags_sessionr      zShould have 2 total retriesz$Should retry connection errors twicezShould retry read errors twicePOSTzShould allow POST retriesN)
r   r   r   max_retriesr*   totalconnectreadr   allowed_methodsr-   r   sessionr   retrys        r   :test_flags_session_retry_config_includes_connection_errorszYTestFlagsSessionNetworkRetries.test_flags_session_retry_config_includes_connection_errors  s     	9&( %%&@A ##a)FG+QRQ(HIfe335PQr   c                 
   ddl m}m}  |       }|j                  d      }|j                  }| j                  t        |j                        t        |      d       | j                  d|j                         | j                  d|j                         | j                  d|j                         | j                  d|j                         | j                  d	|j                         | j                  d
|j                         y)z
        Verify that transient server errors (5xx) trigger retries.

        This tests the status_forcelist configuration which specifies
        which HTTP status codes should trigger a retry.
        r   )r   r   r   z'Should retry on transient server errorsi  i    i  r   r   N)
r   r   r   r   r   r*   setstatus_forcelistr   r   )r-   r   r   r   r   r   s         r   +test_flags_session_retries_on_server_errorszJTestFlagsSessionNetworkRetries.test_flags_session_retries_on_server_errors  s     	Q&(%%&@A## 	&&'&'5	
 	c5112c5112c5112c5112 	e445e445r   c                     ddl m}  |       }|j                  d      }|j                  }| j	                  |j
                  dd       y)zW
        Verify that retries use exponential backoff to avoid thundering herd.
        r   r   r   g      ?z0Should use 0.5s backoff factor (0.5s, 1s delays)N)r   r   r   r   r*   backoff_factorr   s        r   test_flags_session_has_backoffz=TestFlagsSessionNetworkRetries.test_flags_session_has_backoff  sH     	9&(%%&@A##  >	
r   N)rt   ru   rv   r   r   r  r  rw   r   r   r   r     s    AR,6<
r   r   c                       e Zd ZdZd Zd Zy) TestFlagsSessionRetryIntegrationzHIntegration tests that verify actual retry behavior with a local server.c           
         ddl }ddlm}m} ddlm} ddlm} ddlm	}m
} d G fdd|      } G d	 d
||      }	 |	d|      }
|
j                  d   }|j                  |
j                        }d|_        |j                          	  | |dddd|dg            }t!        j"                         }|j%                  d|       |j'                  d| dddid      }| j)                  |j*                  d       | j)                  d       |
j-                          |
j/                          y# |
j-                          |
j/                          w xY w)z
        Verify that 503 errors trigger retries and eventually succeed.

        Uses a local HTTP server that fails twice with 503, then succeeds.
        This tests the full retry flow including backoff timing.
        r   N)
HTTPServerBaseHTTPRequestHandler)ThreadingMixInRetryHTTPAdapterWithSocketOptionsr   c                   "    e Zd ZdZ fdZd Zy)\TestFlagsSessionRetryIntegration.test_retries_on_503_then_succeeds.<locals>.RetryTestHandlerzHTTP/1.1c                 v   dz  t        | j                  j                  dd            }|dkD  r| j                  j	                  |       dk  ru| j                  d       | j                  dd       d}| j                  dt        t        |                   | j                          | j                  j                  |       y | j                  d	       | j                  dd       d
}| j                  dt        t        |                   | j                          | j                  j                  |       y )Nr   zContent-Lengthr   r   r  zContent-Typezapplication/jsons    {"error": "Service unavailable"}r(   s;   {"featureFlags": {"test": true}, "featureFlagPayloads": {}})intr   r   rfiler   send_responsesend_headerstrlenend_headerswfilewrite)r-   content_lengthbodyrequest_counts      r   do_POSTzdTestFlagsSessionRetryIntegration.test_retries_on_503_then_succeeds.<locals>.RetryTestHandler.do_POST+  s   " "%T\\%5%56F%J!K!A%JJOON3 A%&&s+$$^5GH>D$$%5s3t9~F$$&JJ$$T*&&s+$$^5GHV  $$%5s3t9~F$$&JJ$$T*r   c                      y r   rw   )r-   formatargss      r   log_messagezhTestFlagsSessionRetryIntegration.test_retries_on_503_then_succeeds.<locals>.RetryTestHandler.log_messageE  s    r   N)rt   ru   rv   protocol_versionr"  r&  )r!  s   r   RetryTestHandlerr  (  s    )+4r   r(  c                       e Zd ZdZy)^TestFlagsSessionRetryIntegration.test_retries_on_503_then_succeeds.<locals>.ThreadedHTTPServerTN)rt   ru   rv   daemon_threadsrw   r   r   ThreadedHTTPServerr*  I  s    !Nr   r,  z	127.0.0.1r   r   )targetTr   g{Gz?r   r   r   r   r  r  r   r   http://http://127.0.0.1:/flags/?v=2r    r   r?   rD   rP   r(   r=   )	threadinghttp.serverr  r  socketserverr  urllib3.util.retryr  r   r  r   server_addressThreadserve_foreverdaemonstartrT   Sessionmountr   r*   r+   shutdownserver_close)r-   r5  r  r  r  r  r  r   r(  r,  serverportserver_threadr   r   rr   r!  s                   @r   !test_retries_on_503_then_succeedszBTestFlagsSessionRetryIntegration.test_retries_on_503_then_succeeds  sO    	B/,X	5 	B	" 	" $$46FG$$Q'!((0D0D(E#	" 3!#'%;%+H	G &&(GMM)W-||#D65#Y/ $ H X1137]A.OO! OO!s   	BD. ."Ec           
      x   ddl }ddl}ddlm} ddlm}m} |j                  |j                  |j                        }|j                  d       |j                         d   }|j                           | |dddd|d	g
            }t        j                         }	|	j                  d|       |j                         }
| j                  t        j                   j"                        5  |	j%                  d| dddid       ddd       |j                         |
z
  }| j'                  |dd       y# 1 sw Y   0xY w)z
        Verify that connection errors (no server) trigger retries.

        Binds a socket to get a guaranteed available port, then closes it
        so connection attempts fail with ConnectionError.
        r   Nr  r  r-  r   r   g?r   r/  r0  r1  r2  r3  r    r   r4  z#Should have some delay from retries)sockettimer8  r  r   r  r   AF_INETSOCK_STREAMbindgetsocknamecloserT   r>  r?  r4   
exceptionsConnectionErrorr   assertGreater)r-   rG  rH  r  r  r   sockrC  r   r   r=  elapseds               r   "test_connection_errors_are_retriedzCTestFlagsSessionRetryIntegration.test_connection_errors_are_retriedp  s"    	,X }}V^^V-?-?@		"#!!$

.#!7!'	
 ""$i)		x22BBC 	LL#D65#Y/  	 ))+% 	7D*OP	 	s   &D00D9N)rt   ru   rv   r   rE  rS  rw   r   r   r
  r
    s    RU"n*Qr   r
  )(rD   unittestr   r   rg   pytestrT   r   requestr   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   posthog.test.test_utilsr   markparametrizer   TestCaser   ry   r   r   r   r   r   r   r   r
  rw   r   r   <module>r[     s	     #    (     1 <0=<0XH8$$ XHvoHh oHd &3'&3!	!/!<:x(( <:~E
X%6%6 E
PDQx'8'8 DQr   