
    iql                        d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
Z
ddlmZ ddlmZmZmZmZ e	j"                  j%                  dd       ddlZddlmZmZmZmZmZmZ ddlmZ ddlmZ  ej>                  d	ej@                        Z!d
e"de#fdZ$ G d de      Z% G d d      Z& G d d      Z' G d d      Z( G d d      Z) G d d      Z* G d d      Z+ G d d      Z, G d d      Z- G d d       Z. G d! d"      Z/y)#u  
# VERIFICATION_STAMP
# Story: 1.07 (Track B)
# Verified By: parallel-builder
# Verified At: 2026-02-25T00:00:00Z
# Tests: 10/10
# Coverage: 100%

Module 1 White Box Integration Tests — Internal State Inspection
Story 1.07 — Track B

Tests the interceptor subsystem by inspecting internal state, execution paths,
singleton identity, and concurrency isolation that black-box tests cannot observe.

All tests use mocks — no live I/O (file writes, network calls).

Test classes:
    TestSortingAfterRegister        — WB1: _interceptors list sorted ascending by priority after register()
    TestGlobalChainSingleton        — WB2: GLOBAL_CHAIN is identical object across import paths
    TestErrorPathRouting            — WB3: error path calls on_error (not post_execute)
    TestTaskIdUUID4Format           — WB4: task_id matches UUID4 regex
    TestDispatchedAtISO8601         — WB5: dispatched_at is ISO 8601 formatted
    TestUnregisterReturnValues      — WB6: unregister returns True on success, False on unknown
    TestEmptyChainPreExecute        — WB7: empty chain pre_execute returns payload unchanged
    TestConcurrentDispatchIsolation — WB8: 10 concurrent dispatches all get unique task_ids
    TestInterceptorEnableDisable    — WB9: disabled interceptor is skipped in chain execution
    TestDuplicateNameRegistration   — WB10: registering two interceptors with same name appends both
    N)datetime)	AsyncMockpatchcall	MagicMockz/mnt/e/genesis-system)BaseInterceptorInterceptorMetadataInterceptorChainGLOBAL_CHAINdispatch_to_swarmregister_interceptor)NullInterceptor)ExecutionTelemetryInterceptorzE^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$valuereturnc                 >    t        t        j                  |             S )z8Return True if value matches the canonical UUID4 format.)bool	_UUID4_REmatch)r   s    B/mnt/e/genesis-system/tests/interceptors/test_dispatch_to_swarm.py	_is_uuid4r   =   s    	&''    c                   n    e Zd ZdZddededefdZdedefdZ	d	ededd
fdZ
dededefdZdedefdZy
)_PriorityInterceptorzIConcrete interceptor parameterised by name and priority. No-op behaviour.namepriorityenabledc                 *    t        |||      | _        y )Nr   r   r   )r	   metadata)selfr   r   r   s       r   __init__z_PriorityInterceptor.__init__I   s    +RYZr   task_payloadr   c                    K   |S wN )r!   r#   s     r   pre_executez _PriorityInterceptor.pre_executeL   s        resultNc                    K   y wr%   r&   )r!   r)   r#   s      r   post_executez!_PriorityInterceptor.post_executeO   s	     s   errorc                 $   K   dt        |      iS w)Nr,   )str)r!   r,   r#   s      r   on_errorz_PriorityInterceptor.on_errorR   s     U$$s   correction_payloadc                    K   |S wr%   r&   )r!   r0   s     r   on_correctionz"_PriorityInterceptor.on_correctionU   s     !!r(   )T)__name__
__module____qualname____doc__r.   intr   r"   dictr'   r+   	Exceptionr/   r2   r&   r   r   r   r   F   s}    S[S [C [$ [d t  T d %I %T %d %"d "t "r   r   c                   "    e Zd ZdZd Zd Zd Zy)TestSortingAfterRegisterz
    WB1: Register 3 interceptors in non-sorted priority order.
    Verify that InterceptorChain._interceptors is sorted ascending by priority
    immediately after each register() call.
    c                    t               }|j                  t        dd             |j                  t        dd             |j                  t        dd             |j                  D cg c]  }|j                  j
                   }}g d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|       dz   d|iz  }t        t        j                  |            dx}}yc c}w )zG_interceptors must be sorted ascending by priority after each register.p30   r   p10
   p20   rA   rC   r>   ==z%(py0)s == %(py3)sinternal_prioritiespy0py3zExpected [10, 20, 30] but got 
>assert %(py5)spy5Nr
   registerr   _interceptorsr    r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)r!   chainirH   @py_assert2@py_assert1@py_format4@py_format6s           r   9test_internal_list_sorted_ascending_after_three_registerszRTestSortingAfterRegister.test_internal_list_sorted_ascending_after_three_registersd   s    " 	+EB?@+EB?@+EB?@ =B<O<OPqqzz22PP&2 	
"l2 	
 	
"l 	
 	
	6	
 	
  # 	
 	
 		 # 	
 	
 		 '3 	
 	
  --@,AB	
 	
 	
 	
 	
 Q   -Ec                    t               }|j                  t        dd             |j                  D cg c]  }|j                  j
                   }}dg}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}|j                  t        d
d             |j                  D cg c]  }|j                  j
                   }}ddg}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}|j                  t        dd             |j                  D cg c]  }|j                  j
                   }}g d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}x}}y	c c}w c c}w c c}w )z@Sort must be enforced after every register, not just at the end.r=   r>   r?   rE   z%(py1)s == %(py4)spy1py4assert %(py6)spy6Nr@   rA   rB   rC   rD   )r
   rO   r   rP   r    r   rQ   rR   rV   rX   rY   )r!   rZ   r[   @py_assert0@py_assert3r\   @py_format5@py_format7s           r   8test_internal_list_sorted_after_each_individual_registerzQTestSortingAfterRegister.test_internal_list_sorted_after_each_individual_registers   s    "+EB?@-2-@-@A

##AIAbTIATIIIIATIIIAIIITIIIIIII+EB?@-2-@-@A

##AMAb"XMAXMMMMAXMMMAMMMXMMMMMMM+EB?@-2-@-@A

##AQA\QA\QQQQA\QQQAQQQ\QQQQQQQ B B Bs   I:I" I'c                    t               }|j                  t        dd             |j                  t        dd             |j                  t        dd             |j                  D cg c]  }|j                  j
                   }}g d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|       dz   d|iz  }t        t        j                  |            dx}}yc c}w )zFInternal list order must match priority ascending (names perspective).cr>   r?   arA   brC   )rp   rq   ro   rE   rG   internal_namesrI   z!Expected ['a', 'b', 'c'] but got rL   rM   N)r
   rO   r   rP   r    r   rQ   rR   rS   rT   rU   rV   rW   rX   rY   )r!   rZ   r[   rr   r\   r]   r^   r_   s           r   *test_internal_list_names_in_priority_orderzCTestSortingAfterRegister.test_internal_list_names_in_priority_order   s    "+C"=>+C"=>+C"=>383F3FGa!**//GG!0 	
~0 	
 	
~ 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 "1 	
 	
  0/?@	
 	
 	
 	
 	
 Hra   N)r3   r4   r5   r6   r`   rm   rs   r&   r   r   r;   r;   ]   s    
R 

r   r;   c                       e Zd ZdZd Zd Zy)TestGlobalChainSingletonz
    WB2: GLOBAL_CHAIN must be the same Python object regardless of import path.
    Tests use id() comparison (object identity), not equality.
    c           	         ddl m} ddl m} |j                  }t        |      }t        |      }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      d	z  }t	        j                  d
t        |       dt        |             dz   d|iz  }t        t	        j                  |            dx}x}}y)zFImporting GLOBAL_CHAIN via two different paths yields the same object.r   r   NrE   )zN%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py8)s
{%(py8)s = %(py5)s(%(py6)s)
}idchain_path1chain_path2)rJ   re   rK   rM   rh   py8uG   GLOBAL_CHAIN must be the same object across import paths — id(path1)=z, id(path2)=
>assert %(py10)spy10)core.interceptorsr   interceptorsrx   rQ   rR   rS   rT   rU   rV   rW   rX   rY   )	r!   ry   interceptors_pkgrz   r\   @py_assert7@py_assert4@py_format9@py_format11s	            r   2test_global_chain_same_object_via_two_import_pathszKTestGlobalChainSingleton.test_global_chain_same_object_via_two_import_paths   s    	B 	5&33+ 	
"[/ 	
/1 	
 	
 	
/ 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	  	
 	
 
6	
 	
  #% 	
 	
 
	 #% 	
 	
 
6	
 	
  &1 	
 	
 
	 &1 	
 	
 
	 #2 	
 	
 K)bo5FH	
 	
 	
 	
 	
 	
r   c                    ddl m} ddl m} |j                  }t        |      }t	        dd      }|j                  |       t        |      }d}||z   }||k(  }	|	sMt        j                  d|	fd	||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            dx}x}	x}}|j                  d       t        |      }||k(  }	|	s#t        j                  d|	fd||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}	y)uP   Mutations via one reference are visible via the other — confirms shared state.r   rw   N__wb2_singleton_sentinel__i  r?      rE   )z<%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == (%(py5)s + %(py7)s)lenref2before)rJ   re   rK   rM   py7zALength seen through ref2 must increase after registering via ref1r|   r}   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py5)sref1)rJ   re   rK   rM   zassert %(py7)sr   )r~   r   r   r   r   rO   rQ   rR   rS   rT   rU   rV   rW   rX   rY   
unregister)r!   r   pkgr   r   sentinelr\   @py_assert6@py_assert8r   r   r   r_   @py_format8s                 r   4test_global_chain_mutation_visible_across_referenceszMTestGlobalChainSingleton.test_global_chain_mutation_visible_across_references   s   :'T'(DsSh 4y 	
Q 	
FQJ 	
yJ& 	
 	
 	
yJ 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
	6	
 	
  # 	
 	
 		 # 	
 	
 		 &' 	
 	
  P	
 	
 	
 	
 	
 	

 	454y"yF""""yF""""""s"""s""""""4"""4"""y""""""F"""F"""""""r   N)r3   r4   r5   r6   r   r   r&   r   r   ru   ru      s    

#r   ru   c                       e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	y)TestErrorPathRoutingz
    WB3: When _execute_task raises, dispatch_to_swarm must call
    GLOBAL_CHAIN.execute_error (the error handler), and must NOT call
    GLOBAL_CHAIN.execute_post.
    c                   K   t        dt        t        d            5  t        j                  t        dt        ddi      5 }t        j                  t        dt        	      5 }t        d
di       d{   }ddd       ddd       ddd       j                          j                          y7 =# 1 sw Y   <xY w# 1 sw Y   @xY w# 1 sw Y   DxY ww)z3execute_error is invoked when _execute_task raises.core.interceptors._execute_taskzforced failurenew_callableside_effectexecute_errorhandledTr   return_valueexecute_postr   promptztrigger errorN)r   r   RuntimeErrorobjectr   r   assert_awaited_onceassert_not_awaitedr!   
mock_error	mock_postr)   s       r   &test_execute_error_called_on_exceptionz;TestErrorPathRouting.test_execute_error_called_on_exception   s      3(*+;<>
	J LL&/'0$&79	
	J =GLL~&/1
	J 5>,h-HIIF
	J 
	J 
	J 	&&($$& J
	J 
	J 
	J 
	J 
	J 
	Js^   C$C!C #B44B2
5B49C C	)C2B44B=9C  C		CCCc                   K   t        dt        dddd      5  t        j                  t        dt              5 }t        j                  t        d	t              5 }t	        d
di       d{   }ddd       ddd       ddd       j                          j                          y7 =# 1 sw Y   <xY w# 1 sw Y   @xY w# 1 sw Y   DxY ww)z@execute_post is invoked on success; execute_error is NOT called.r   okdone	completed)task_idoutputstatusr   r   r   r   r   zwill succeedN)r   r   r   r   r   r   r   r   s       r   #test_execute_post_called_on_successz8TestErrorPathRouting.test_execute_post_called_on_success   s      3(+/6[Y[		I LL&/1			I
 5?LL~&/1		I 5>,h-GHHF		I 		I 		I 	%%'%%' I		I 		I 		I 		I 		I 		Is]   C!C!B8B,,B*
-B,1B89C)C*B,,B51B88C	=CC	Cc                 2  K   t        dt        t        d            5  t        ddi       d{   }ddd       d   }d}||k(  }|slt	        j
                  d	|fd
||f      t	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}d}||v }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }dd|iz  }t        t	        j                  |            dx}}d}||v }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }dd|iz  }t        t	        j                  |            dx}}y7 # 1 sw Y   xY ww)zHOn executor raise, result must have status='error' and 'correction' key.r   z	wb3 checkr   r   zerror structureNr   r,   rE   rc   rd   rg   rh   
correctioninz%(py1)s in %(py3)sr)   re   rK   assert %(py5)srM   r   )r   r   
ValueErrorr   rQ   rR   rV   rX   rY   rS   rT   rU   )	r!   r)   ri   rj   r\   rk   rl   r^   r_   s	            r   9test_error_result_carries_status_error_and_correction_keyzNTestErrorPathRouting.test_error_result_carries_status_error_and_correction_key   sX     4 ))+68 	L -h8I-JKKF	L
 h*7*7****7******7*******%|v%%%%|v%%%|%%%%%%v%%%v%%%%%%%"yF""""yF"""y""""""F"""F"""""""	 L	L 	Ls,   HH
HH
GHH

HHN)
r3   r4   r5   r6   pytestmarkasyncior   r   r   r&   r   r   r   r      sa     [[' '" [[( (  [[	# 	#r   r   c                       e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	ej
                  j                  d        Z
y)TestTaskIdUUID4Formatz
    WB4: dispatch_to_swarm must produce a task_id that matches the canonical
    UUID4 regex pattern when none is supplied by the caller.
    c                 6  K   t        ddi       d{   }|j                  dd      }t        |      }|st        j                  d|d      dz   d	t        j                         v st        j                  t              rt        j                  t              nd	dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d
z  }t        t        j                  |            d}y7 w)z=task_id from dispatch_to_swarm matches UUID4 canonical regex.r   zuuid4 format checkNr    task_id z does not match UUID4 pattern.
>assert %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}r   rJ   re   rK   )r   getr   rQ   rW   rS   rT   rU   rV   rX   rY   )r!   r)   r   r\   r^   s        r   /test_auto_generated_task_id_matches_uuid4_regexzETestTaskIdUUID4Format.test_auto_generated_task_id_matches_uuid4_regex  s      )(4H)IJJ**Y+! 	
! 	
  wk!>?	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  ! 	
 	
 		 ! 	
 	
 		 " 	
 	
 	
 	
 	
 Ks   DDDDc                   K   t        ddi       d{   }|d   }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }t        j                  d
|d   d|      dz   d|iz  }t        t        j                  |            dx}x}}y7 w)zAThe version nibble in position 14 of the UUID string must be '4'.r   zversion bitNr      4rE   rc   rd   z4UUID version nibble at position 14 must be '4', got  in 
>assert %(py6)srh   )r   rQ   rR   rV   rW   rX   rY   )r!   r)   r   ri   rj   r\   rk   rl   s           r   #test_uuid4_version_bit_is_exactly_4z9TestTaskIdUUID4Format.test_uuid4_version_bit_is_exactly_4
  s      )(M)BCC# r{ 	
c 	
{c! 	
 	
{c 	
 	
 
	  	
 	
 
	 " 	
 	
  C72;/ R	
 	
 	
 	
 	
 	
 Ds   B?B=B*B?c                   K   t        ddi       d{   }|d   }|d   j                         }d}||v }|st        j                  d|fd||f      d	t	        j
                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }t        j                  d|d|      dz   d|iz  }t        t        j                  |            dx}}y7 ޭw)zDVariant bits (position 19) must be '8', '9', 'a', or 'b' (RFC 4122).r   zvariant bitsNr      )89rp   rq   r   )z%(py0)s in %(py3)svariant_charrI   z1Variant char at position 19 must be 8/9/a/b, got r   rL   rM   )r   lowerrQ   rR   rS   rT   rU   rV   rW   rX   rY   )r!   r)   r   r   r\   r]   r^   r_   s           r   #test_uuid4_variant_bits_are_correctz9TestTaskIdUUID4Format.test_uuid4_variant_bits_are_correct  s      )(N)CDD#r{((*3 	
|33 	
 	
|3 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	  4 	
 	
  @?O P	
 	
 	
 	
 	
	 Es   C4C2CC4c                   K   d}d|d}t        |       d{   }|d   }||k(  }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndd	z  }d
d|iz  }t        t        j                  |            dx}}y7 w)z9A task_id already in the payload must not be overwritten.z$cafebabe-0000-4000-8000-000000000001z
keep my id)r   r   Nr   rE   )z%(py1)s == %(py3)smy_idr   r   rM   )	r   rQ   rR   rV   rS   rT   rU   rX   rY   )r!   r   payloadr)   ri   r\   r^   r_   s           r   0test_caller_supplied_task_id_preserved_unchangedzFTestTaskIdUUID4Format.test_caller_supplied_task_id_preserved_unchanged#  s      7)e<(11i ) E)))) E))) ))))))E)))E))))))) 2s   C	CB/C	N)r3   r4   r5   r6   r   r   r   r   r   r   r   r&   r   r   r   r      s    
 [[
 
 [[

 

 [[	
 	
 [[* *r   r   c                       e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	ej
                  j                  d        Z
y)TestDispatchedAtISO8601z
    WB5: dispatch_to_swarm must stamp 'dispatched_at' on the input payload dict
    in ISO 8601 / RFC 3339 format (parseable by datetime.fromisoformat).
    c                   K   ddi}t        |       d{    d}||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      nddz  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}}y7 w)z=dispatched_at must be written into the payload dict in-place.r   ztimestamp wb5Ndispatched_atr   r   r   r   z@dispatch_to_swarm must stamp dispatched_at onto the payload dictrL   rM   )
r   rQ   rR   rV   rS   rT   rU   rW   rX   rY   )r!   r   ri   r\   r^   r_   s         r   )test_dispatched_at_key_present_in_payloadzATestDispatchedAtISO8601.test_dispatched_at_key_present_in_payload6  s      "?3((( 	
') 	
 	
' 	
 	
 		  	
 	
	6	
 	
  #* 	
 	
 		 #* 	
 	
  O	
 	
 	
 	
 	
 	)s   CCCCc                    K   ddi}t        |       d{    |d   }	 t        j                  |      }d}|u}|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}}y7 # t        $ r%}t	        j
                  d|d|        Y d}~d}~ww xY ww)z@dispatched_at value must be parseable by datetime.fromisoformat.r   ziso8601 parseNr   dispatched_at z is not valid ISO 8601: )is not)z%(py0)s is not %(py3)sparsedrI   r   rM   )r   r   fromisoformatr   r   failrQ   rR   rS   rT   rU   rV   rX   rY   )	r!   r   tsr   excr\   r]   r^   r_   s	            r   'test_dispatched_at_parseable_as_iso8601z?TestDispatchedAtISO8601.test_dispatched_at_parseable_as_iso8601?  s      "?3(((_%	N++B/F "!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!! 	)  	NKK..FseLMM	Ns8   DC	DC B'D	D&DDDDc                   K   ddi}t        |       d{    |d   }g }d}||v }|}|s|j                  }d} ||      }	|	}|szt        j                  d|fd||f      t        j                  |      d	t        j                         v st        j                  |      rt        j                  |      nd	d
z  }
dd|
iz  }|j                  |       |sdd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                        t        j                        t        j                  	      dz  }|j                  |       t        j                  |d      i z  }t        j                  d|d      dz   d|iz  }t        t        j                  |            dx}x}x}x}x}x}}	y7 w)zFdispatched_at must include UTC timezone info ('+00:00' or 'Z' suffix).r   ztz checkNr   z+00:00Zr   )z%(py3)s in %(py5)sr   )rK   rM   z%(py7)sr   zH%(py15)s
{%(py15)s = %(py11)s
{%(py11)s = %(py9)s.endswith
}(%(py13)s)
})py9py11py13py15r   r   z$ must include UTC timezone indicatorz
>assert %(py18)spy18)r   endswithrQ   rR   rV   rS   rT   rU   append_format_booloprW   rX   rY   )r!   r   r   r]   r\   r   ri   @py_assert10@py_assert12@py_assert14r_   r   @py_format16@py_format17@py_format19s                  r   +test_dispatched_at_includes_timezone_offsetzCTestDispatchedAtISO8601.test_dispatched_at_includes_timezone_offsetK  s     ":.(((_%	
 	
B 	
"++ 	
c 	
+c"2 	
"2 	
 	
 	
B 	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 	
	6	
		
 	
	6	
 	
  #% 	
 	
 		 #% 	
 	
 		 #. 	
 	
 		 /2 	
 	
 		 #3 	
 	
	6	
		
 	
 	
  RF"FG	
 	
 	
 	
 	
 	
 	
 	)s   GGF:Gc                 z  K   ddl m} ddi}t        j                  |j                        }t	        |       d{    t        j                  |j                        }|d   }t        j
                  |      }||k  }||k  }|r|s,t        j                  d||fd|||f      d	t        j                         v st        j                  |      rt        j                  |      nd	d
t        j                         v st        j                  |      rt        j                  |      nd
dt        j                         v st        j                  |      rt        j                  |      nddz  }	t        j                  d|d| d| d| d	      dz   d|	iz  }
t        t        j                  |
            dx}}y7 ~w)zJdispatched_at must represent a time within the last 5 seconds (UTC-aware).r   )timezoner   zrecency checkNr   )<=r   )z%(py0)s <= %(py3)sz%(py3)s <= %(py4)sr   r   after)rJ   rK   rf   r   z (z!) is not within expected window [z, ]r   rh   )r   r   nowutcr   r   rQ   rR   rS   rT   rU   rV   rW   rX   rY   )r!   _tzr   r   r   r   r   r]   r\   rk   rl   s              r   test_dispatched_at_is_recentz4TestDispatchedAtISO8601.test_dispatched_at_is_recentU  s     	-!?3cgg&(((SWW%_%''+( 	
5( 	
 	
 	
v5 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
    	
 	
 
	   	
 	
 
6	
 	
  $) 	
 	
 
	 $) 	
 	
  RF"VH -xr%#	
 	
 	
 	
 	
 	)s   8F;F8E>F;N)r3   r4   r5   r6   r   r   r   r   r   r   r   r&   r   r   r   r   0  s    
 [[
 
 [[	" 	" [[
 
 [[
 
r   r   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestUnregisterReturnValuesz
    WB6: InterceptorChain.unregister() must return True when the named
    interceptor exists and was removed, False when the name is unknown.
    c                    t               }|j                  t        dd             |j                  d      }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }d	d
|iz  }t        t	        j                  |            dx}}y)z6Returns True when a registered interceptor is removed.targetrA   r?   Tisz%(py0)s is %(py3)sr)   rI   r   rM   Nr
   rO   r   r   rQ   rR   rS   rT   rU   rV   rX   rY   r!   rZ   r)   r\   r]   r^   r_   s          r   +test_unregister_returns_true_for_known_namezFTestUnregisterReturnValues.test_unregister_returns_true_for_known_namep  s     "+HrBC!!(+v~vvvr   c                    t               }|j                  d      }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d	x}}y	)
z1Returns False when the name was never registered.never_registeredFr  r  r)   rI   r   rM   N)
r
   r   rQ   rR   rS   rT   rU   rV   rX   rY   r	  s          r   .test_unregister_returns_false_for_unknown_namezITestUnregisterReturnValues.test_unregister_returns_false_for_unknown_namew  ss     "!!"45vvvvr   c                 (   t               }|j                  t        dd             |j                  t        dd             |j                  }t	        |      }d}||k(  }|s
t        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}|j                  d       |j                  }t	        |      }d}||k(  }|s
t        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}|j                  D cg c]  }|j                  j                   }	}dg}|	|k(  }
|
st        j                  d|
fd|	|f      dt        j                         v st        j                  |	      rt        j                  |	      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
}yc c}w )zIAfter a successful unregister, _interceptors list shrinks by exactly one.rp   rA   r?   rq   rC      rE   zS%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s._interceptors
})
} == %(py8)sr   rZ   rJ   re   rK   rM   r{   assert %(py10)sr}   Nr   rG   remaining_namesrI   r   rM   r
   rO   r   rP   r   rQ   rR   rS   rT   rU   rV   rX   rY   r   r    r   )r!   rZ   r\   r   r   r   r   r   r[   r  r]   r^   r_   s                r   ,test_unregister_reduces_internal_list_lengthzGTestUnregisterReturnValues.test_unregister_reduces_internal_list_length}  s    "+C"=>+C"=>&&,s&',1,'1,,,,'1,,,,,,s,,,s,,,,,,5,,,5,,,&,,,',,,1,,,,,,,&&,s&',1,'1,,,,'1,,,,,,s,,,s,,,,,,5,,,5,,,&,,,',,,1,,,,,,,494G4GHq1::??HH#&%'%''''%''''''''''''%''''''' Is   Nc                 D   t               }|j                  t        dd             |j                  }d} ||      }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      t	        j                  |      dz  }d	d
|iz  }t        t	        j                  |            dx}x}x}x}}|j                  }d} ||      }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      t	        j                  |      dz  }d	d
|iz  }t        t	        j                  |            dx}x}x}x}}y)zJUnregistering an already-removed name returns False on the second attempt.once   r?   Tr  )zP%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.unregister
}(%(py4)s)
} is %(py9)srZ   rJ   py2rf   rh   r   assert %(py11)sr   NFr  )	r!   rZ   r]   rj   @py_assert5r   r   @py_format10@py_format12s	            r   /test_unregister_twice_second_call_returns_falsezJTestUnregisterReturnValues.test_unregister_twice_second_call_returns_false  sS    "+FQ?@//'/4/'4////'4//////u///u/////////'///4///////00'050'50000'5000000u000u000000000'000500000000r   c                    t               }|j                  t        dd             |j                  D cg c]  }t	        |       }}|j                  d       |j                  D cg c]  }t	        |       }}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      ndd	z  }d
d|iz  }t        t        j                  |            d}yc c}w c c}w )z6Failing unregister must leave _interceptors unchanged.keeperrA   r?   ghostrE   z%(py0)s == %(py2)s
before_ids	after_idsrJ   r  assert %(py4)srf   N)r
   rO   r   rP   rx   r   rQ   rR   rS   rT   rU   rV   rX   rY   )r!   rZ   r[   r$  r%  r]   @py_format3rk   s           r   4test_unregister_unknown_does_not_alter_internal_listzOTestUnregisterReturnValues.test_unregister_unknown_does_not_alter_internal_list  s     "+HrBC%*%8%89be9
9!$)$7$78qRU8	8Y&&&&zY&&&&&&z&&&z&&&&&&Y&&&Y&&&&&&& :8s   E(EN)	r3   r4   r5   r6   r
  r  r  r  r)  r&   r   r   r  r  j  s     
	(1'r   r  c                   (    e Zd ZdZd Zd Zd Zd Zy)TestEmptyChainPreExecuteu   
    WB7: An InterceptorChain with no registered interceptors must return the
    exact original payload dict from execute_pre — same identity and contents.
    c                 2   t               }ddd}t        j                  |j                  |            }||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  |      rt	        j                  |      nddz  }t	        j                  d	      d
z   d|iz  }t        t	        j                  |            d}y)z;Empty chain execute_pre returns the exact same dict object.wb7zno interceptors)r   r   r  )z%(py0)s is %(py2)sr)   r   r&  zAEmpty chain must return the original dict object (identity check)z
>assert %(py4)srf   N)r
   r   runexecute_prerQ   rR   rS   rT   rU   rV   rW   rX   rY   )r!   rZ   r   r)   r]   r(  rk   s          r   .test_empty_chain_pre_execute_returns_same_dictzGTestEmptyChainPreExecute.test_empty_chain_pre_execute_returns_same_dict  s     "#/@AU..w78  	
 	
v 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  ! 	
 	
 		 ! 	
 	
  P	
 	
 	
 	
 	
r   c                    t               }dddd}t        j                  |j                  t	        |                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      ndd	z  }d
d|iz  }t        t        j                  |            d}y)z6Empty chain execute_pre does not modify dict contents.wb7b	unchanged*   )r   r   customrE   r#  r)   originalr&  r'  rf   N)r
   r   r.  r/  r8   rQ   rR   rS   rT   rU   rV   rX   rY   )r!   rZ   r6  r)   r]   r(  rk   s          r   /test_empty_chain_pre_execute_contents_unchangedzHTestEmptyChainPreExecute.test_empty_chain_pre_execute_contents_unchanged  s     "%KU..tH~>?!!!!v!!!!!!v!!!v!!!!!!!!!!!!!!!!r   c                 j    t               }t        j                  |j                  ddiddi             y)uD   Empty chain execute_post completes silently — no exception raised.r   r   r   wb7cN)r
   r   r.  r   )r!   rZ   s     r   ,test_empty_chain_execute_post_does_not_raisezETestEmptyChainPreExecute.test_empty_chain_execute_post_does_not_raise  s-     "E&&$'7)V9LMNr   c                    t               }t        j                  |j                  t	        d      ddi            }|j
                  }d} ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      d	z  }d
d|iz  }	t        t        j                  |	            dx}x}x}x}}d}
|
|v }|st        j                  d|fd|
|f      t        j                  |
      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}
}y)zDEmpty chain execute_error returns {'error': ..., 'unhandled': True}.znobody homer   wb7d	unhandledTr  )zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} is %(py9)sr)   r  r  r   Nr,   r   r   r   r   rM   )r
   r   r.  r   r   r   rQ   rR   rS   rT   rU   rV   rX   rY   )r!   rZ   r)   r]   rj   r  r   r   r  r  ri   r\   r^   r_   s                 r   9test_empty_chain_execute_error_returns_unhandled_sentinelzRTestEmptyChainPreExecute.test_empty_chain_execute_error_returns_unhandled_sentinel  s"    "] ;i=PQ
 zz.+.z+&.$.&$....&$......v...v...z...+...&...$....... w&    w&   w      &   &       r   N)r3   r4   r5   r6   r0  r7  r:  r>  r&   r   r   r+  r+    s    

"O!r   r+  c                       e Zd ZdZej
                  j                  d        Zej
                  j                  d        Zej
                  j                  d        Z	y)TestConcurrentDispatchIsolationz
    WB8: 10 concurrent dispatch_to_swarm calls must each produce a unique,
    independently-generated UUID4 task_id. No two tasks may share an ID.
    c           
        K   d}t        |      D cg c]	  }dd| i }}t        j                  |D cg c]  }t        |       c}  d{   }|D cg c]  }|d   	 }}t	        |      }t        |      }	|	|k(  }
|
st        j                  d|
fd|	|f      dt        j                         v st        j                  t
              rt        j                  t
              ndd	t        j                         v st        j                  t              rt        j                  t              nd	d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |	      dt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| dt        t	        |             d|       dz   d|iz  }t        t        j                  |            dx}x}	}
|D ]  }t        |      }|st        j                  d|d      dz   dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            d} yc c}w c c}w 7 c c}w w)z:10 concurrent dispatches produce 10 unique UUID4 task_ids.rA   r   zconcurrent-Nr   rE   zN%(py6)s
{%(py6)s = %(py0)s(%(py4)s
{%(py4)s = %(py1)s(%(py2)s)
})
} == %(py8)sr   settask_idsnrJ   re   r  rf   rh   r{   z	Expected z unique task_ids, got z: r|   r}   r   z is not a valid UUID4r   r   tidr   )ranger   gatherr   rC  r   rQ   rR   rS   rT   rU   rV   rW   rX   rY   r   )r!   rE  r[   payloadspresultsrrD  rj   r  r   r   r   rG  r\   r^   s                   r   2test_ten_concurrent_dispatches_all_unique_task_idszRTestConcurrentDispatchIsolation.test_ten_concurrent_dispatches_all_unique_task_ids  s     ;@8DaXQC01DDx(P!):1)=(PQQ*12QAiL22 x= 	
s=! 	
!Q& 	
 	
 	
!Q 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
    	
 	
 		   	
 	
 		 ! 	
 	
 		 " 	
 	
	6	
 	
  &' 	
 	
 		 &' 	
 	
  s0S]1C0DBxjQ	
 	
 	
 	
 	

  	KCS>J>JJXcW4I#JJJJJJJ9JJJ9JJJJJJSJJJSJJJ>JJJJJJ	K E(PQ2s9   L?L-L?L2L?L7L?L:#KL?:L?c           	      <  K   d}t        |      D cg c]	  }dd| i }}t        j                  |D cg c]  }t        |       c}  d{   }|D cg c]  }|d   	 }}t	        |      }t        |      }	|	|k(  }
|
st        j                  d|
fd|	|f      dt        j                         v st        j                  t
              rt        j                  t
              ndd	t        j                         v st        j                  t              rt        j                  t              nd	d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |	      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}x}	}
yc c}w c c}w 7 c c}w w)zEExtended: 20 concurrent dispatches all produce unique UUID4 task_ids.rC   r   zbig-concurrent-Nr   rE   rB  r   rC  rD  rE  rF  r  r}   )rH  r   rI  r   rC  r   rQ   rR   rS   rT   rU   rV   rX   rY   )r!   rE  r[   rJ  rK  rL  rM  rD  rj   r  r   r   r   s                r   5test_twenty_concurrent_dispatches_all_unique_task_idszUTestConcurrentDispatchIsolation.test_twenty_concurrent_dispatches_all_unique_task_ids  sJ     ?DQxH!X45HHx(P!):1)=(PQQ*12QAiL22x=&s=!&!Q&&&&!Q&&&&&&s&&&s&&&&&&3&&&3&&&&&&x&&&x&&&=&&&!&&&&&&Q&&&Q&&&&&&&	 I(PQ2s9   HH
HHHHHH#F2HHc                   K   t        d      D cg c]	  }dd| i }}t        j                  |D cg c]  }t        |       c}  d{   }|D ]  }|d   }d}||k(  }|st	        j
                  d|fd||f      t	        j                  |      t	        j                  |      d	z  }	t	        j                  d
|d         dz   d|	iz  }
t        t	        j                  |
            dx}x}} yc c}w c c}w 7 w)z@All concurrent dispatches must complete with status='completed'.rA   r   zstatus-check-Nr   r   rE   rc   rd   zExpected 'completed' but got r   rh   )
rH  r   rI  r   rQ   rR   rV   rW   rX   rY   )r!   r[   rJ  rK  rL  rM  ri   rj   r\   rk   rl   s              r   4test_concurrent_dispatch_all_return_completed_statuszTTestConcurrentDispatchIsolation.test_concurrent_dispatch_all_return_completed_status  s      >C2YGXqc23GGx(P!):1)=(PQQ 	AX; + ;+-  ;+  I   I #.    0(?     	 H(PQs'   DC5DC:DC?B3DN)
r3   r4   r5   r6   r   r   r   rN  rP  rR  r&   r   r   r@  r@    sc    
 [[K K" [[' ' [[ r   r@  c                   "    e Zd ZdZd Zd Zd Zy)TestInterceptorEnableDisablez
    WB9: Disabled interceptors (metadata.enabled=False) must be skipped
    in chain execution. The chain inspects .metadata.enabled internally.
    c                   	 g 	 G 	fddt               }t               } |ddd      } |ddd	      }|j                  |       |j                  |       t        j                  |j                  d
di             d}|	v }|st        j                  d|fd|	f      t        j                  |      dt        j                         v st        j                  	      rt        j                  	      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}d}|	v}|st        j                  d|fd|	f      t        j                  |      dt        j                         v st        j                  	      rt        j                  	      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}y)z5A disabled interceptor's pre_execute is never called.c                   "    e Zd Zdedef fdZy)jTestInterceptorEnableDisable.test_disabled_interceptor_skipped_in_execute_pre.<locals>._LoggingInterceptorr#   r   c                 Z   K   j                  | j                  j                         |S wr%   r   r    r   r!   r#   call_logs     r   r'   zvTestInterceptorEnableDisable.test_disabled_interceptor_skipped_in_execute_pre.<locals>._LoggingInterceptor.pre_execute  #      2 23##   (+Nr3   r4   r5   r8   r'   r[  s   r   _LoggingInterceptorrW        $d $t $r   r`  activerA   Tr   r   inactiverC   Fr   zenable/disable wb9r   r   r[  r   z Enabled interceptor must executerL   rM   Nnot inz%(py1)s not in %(py3)sz$Disabled interceptor must be skipped)r   r
   rO   r   r.  r/  rQ   rR   rV   rS   rT   rU   rW   rX   rY   )
r!   r`  rZ   rb  rd  ri   r\   r^   r_   r[  s
            @r   0test_disabled_interceptor_skipped_in_execute_prezMTestInterceptorEnableDisable.test_disabled_interceptor_skipped_in_execute_pre  s:   	$"6 	$
 !"$XDI&zBNvx E%%x1E&FGHGx8#GGGx8GGGxGGGGGG8GGG8GGGG%GGGGGGGQz)QQQzQQQzQQQQQQQQQQQQQ+QQQQQQQr   c                   	 g 	 G 	fddt               }t               } |ddd      } |ddd	      }|j                  |       |j                  |       t        j                  |j                  d
diddi             d}|	v }|st        j                  d|fd|	f      t        j                  |      dt        j                         v st        j                  	      rt        j                  	      nddz  }dd|iz  }t        t        j                  |            dx}}d}|	v}|st        j                  d|fd|	f      t        j                  |      dt        j                         v st        j                  	      rt        j                  	      nddz  }dd|iz  }t        t        j                  |            dx}}y)z6A disabled interceptor's post_execute is never called.c                   &    e Zd Zdededdf fdZy)oTestInterceptorEnableDisable.test_disabled_interceptor_skipped_in_execute_post.<locals>._PostLoggingInterceptorr)   r#   r   Nc                 X   K   j                  | j                  j                         y wr%   rY  )r!   r)   r#   post_logs      r   r+   z|TestInterceptorEnableDisable.test_disabled_interceptor_skipped_in_execute_post.<locals>._PostLoggingInterceptor.post_execute  s      2 23s   '*)r3   r4   r5   r8   r+   )rm  s   r   _PostLoggingInterceptorrk    s    4 4T 4d 4r   rn  enabled_postrA   Trc  disabled_postrC   Fr   r   r   wb9br   r   rm  r   r   rM   Nre  rg  )r   r
   rO   r   r.  r   rQ   rR   rV   rS   rT   rU   rX   rY   )
r!   rn  rZ   enabled_onedisabled_oneri   r\   r^   r_   rm  s
            @r   1test_disabled_interceptor_skipped_in_execute_postzNTestInterceptorEnableDisable.test_disabled_interceptor_skipped_in_execute_post  s*   	4&: 	4 !"-nrSWX.UZ[{#|$E&&$'7)V9LMN)~))))~)))~)))))))))))))))).h....h.........h...h.......r   c                    g  G fddt               }t               } |ddd      }|j                  |       t        j                  |j                  ddi             d}|v}|st        j                  d	|fd
|f      t        j                  |      dt        j                         v st        j                        rt        j                        nddz  }dd|iz  }t        t        j                  |            dx}}t        ddd      |_        t        j                  |j                  ddi             d}|v }|st        j                  d|fd|f      t        j                  |      dt        j                         v st        j                        rt        j                        nddz  }dd|iz  }t        t        j                  |            dx}}y)zGAfter enabling a disabled interceptor, it re-enters the execution path.c                   "    e Zd Zdedef fdZy)lTestInterceptorEnableDisable.test_re_enabling_interceptor_makes_it_execute_again.<locals>._ToggleInterceptorr#   r   c                 Z   K   j                  | j                  j                         |S wr%   rY  rZ  s     r   r'   zxTestInterceptorEnableDisable.test_re_enabling_interceptor_makes_it_execute_again.<locals>._ToggleInterceptor.pre_execute,  r\  r]  Nr^  r_  s   r   _ToggleInterceptorrw  +  ra  r   ry  togglerA   Frc  r   z	first runre  rg  r[  r   r   rM   NTr   z
second runr   r   )r   r
   rO   r   r.  r/  rQ   rR   rV   rS   rT   rU   rX   rY   r	   r    )	r!   ry  rZ   rz  ri   r\   r^   r_   r[  s	           @r   3test_re_enabling_interceptor_makes_it_execute_againzPTestInterceptorEnableDisable.test_re_enabling_interceptor_makes_it_execute_again'  s8   	$!5 	$
 !"#Hr5Iv 	E%%x&=>?'xx''''xx'''x''''''x'''x''''''' .8bRVWE%%x&>?@#x8####x8###x######8###8#######r   N)r3   r4   r5   r6   rh  rt  r{  r&   r   r   rT  rT    s    
R*/($r   rT  c                   (    e Zd ZdZd Zd Zd Zd Zy)TestDuplicateNameRegistrationub  
    WB10: InterceptorChain.register() does NOT deduplicate by name.
    Registering two interceptors with the same name appends both — the internal
    list grows by 2, and both execute during chain traversal.

    (This is the actual implementation behaviour: unregister() removes ALL
    interceptors matching the name in a list comprehension.)
    c                    t               }|j                  t        dd             |j                  t        dd             |j                  }t	        |      }d}||k(  }|s t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      t        j                  |      d
z  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}x}x}}y)zGRegistering two same-named interceptors results in length=2 internally.duprA   r?   rC   r  rE   r  r   rZ   r  uO   Both same-named interceptors must be stored — register() does not deduplicater|   r}   N)r
   rO   r   rP   r   rQ   rR   rS   rT   rU   rV   rW   rX   rY   )r!   rZ   r\   r   r   r   r   r   s           r   2test_duplicate_name_both_appended_to_internal_listzPTestDuplicateNameRegistration.test_duplicate_name_both_appended_to_internal_listL  sR    "+EB?@+EB?@&& 	
s&' 	
1 	
'1, 	
 	
 	
'1 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		 ' 	
 	
 		 ( 	
 	
 		 ,- 	
 	
  ^	
 	
 	
 	
 	
 	
r   c                 V   g  G fddt               }t               }|j                   |dd             |j                   |dd             t        j                  |j                  ddi             t              }d	}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                        rt        j                        ndt        j                  |      t        j                  |      dz  }t        j                  dt                     dz   d|iz  }t        t        j                  |            dx}x}}y)z9Both same-named interceptors execute when the chain runs.c                   "    e Zd Zdedef fdZy)eTestDuplicateNameRegistration.test_duplicate_name_both_execute_in_chain.<locals>._CountingInterceptorr#   r   c                 2   K   j                  d       |S w)Nr   )r   )r!   r#   execution_counts     r   r'   zqTestDuplicateNameRegistration.test_duplicate_name_both_execute_in_chain.<locals>._CountingInterceptor.pre_executeZ  s     &&q)##s   Nr^  )r  s   r   _CountingInterceptorr  Y  ra  r   r  r  rA   r?   rC   r   zdup testr  rE   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)ssumr  )rJ   re   rK   rh   z3Expected both duplicates to execute (count=2), got z
>assert %(py8)sr{   N)r   r
   rO   r   r.  r/  r  rQ   rR   rS   rT   rU   rV   rW   rX   rY   )	r!   r  rZ   r\   r  r   rl   r   r  s	           @r   )test_duplicate_name_both_execute_in_chainzGTestDuplicateNameRegistration.test_duplicate_name_both_execute_in_chainU  sn   	$#7 	$
 !"+EB?@+EB?@E%%x&<=>?# 	
q 	
#q( 	
 	
 	
#q 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  # 	
 	
 		 # 	
 	
 		 $ 	
 	
 		 () 	
 	
  B#oBVAWX	
 	
 	
 	
 	
 	
r   c                 J   t               }|j                  t        dd             |j                  t        dd             |j                  t        dd             |j                  }t	        |      }d}||k(  }|s
t        j                  d|fd	||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}|j                  d       |j                  }t	        |      }d}||k(  }|s
t        j                  d|fd	||f      d
t        j                         v st        j                  t              rt        j                  t              nd
dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}|j                  d   }|j                  }|j                  }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}}y)zOunregister('dup') removes ALL interceptors with that name (list comprehension).r  rA   r?   rC   r!  r>      rE   r  r   rZ   r  r  r}   Nr   r   )zJ%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.metadata
}.name
} == %(py8)s)re   rK   rM   r{   r  )	r!   rZ   r\   r   r   r   r   r   ri   s	            r   3test_unregister_removes_all_same_named_interceptorszQTestDuplicateNameRegistration.test_unregister_removes_all_same_named_interceptorsh  s/    "+EB?@+EB?@+HrBC&&,s&',1,'1,,,,'1,,,,,,s,,,s,,,,,,5,,,5,,,&,,,',,,1,,,,,,,&&,s&',1,'1,,,,'1,,,,,,s,,,s,,,,,,5,,,5,,,&,,,',,,1,,,,,,,""1%?%..?.33?x?3x????3x???%???.???3???x????????r   c                 n   t               }|j                  t        dd             |j                  t        dd             |j                  D cg c]  }|j                  j
                   }}ddg}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d	|       d
z   d|iz  }t        t        j                  |            dx}}yc c}w )zFTwo same-named interceptors are sorted by their respective priorities.r  2   r?   r  rE   rG   
prioritiesrI   z3Duplicate-named interceptors must still be sorted: rL   rM   NrN   )r!   rZ   r[   r  r\   r]   r^   r_   s           r   6test_register_same_name_different_priority_both_sortedzTTestDuplicateNameRegistration.test_register_same_name_different_priority_both_sortedu  s    "+EB?@+EA>?383F3FGaajj))G
GW 	
zW$ 	
 	
zW 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 % 	
 	
  B*N	
 	
 	
 	
 	
 Hs   D2N)r3   r4   r5   r6   r  r  r  r  r&   r   r   r}  r}  B  s    

&@	
r   r}  )0r6   builtinsrS   _pytest.assertion.rewrite	assertionrewriterQ   r   resysuuidr   unittest.mockr   r   r   r   pathinsertr   r~   r   r	   r
   r   r   r   'core.interceptors.integration_contractsr   %core.interceptors.execution_telemetryr   compile
IGNORECASEr   r.   r   r   r   r;   ru   r   r   r   r  r+  r@  rT  r}  r&   r   r   <module>r     s   :   	 
   ; ; * +   D O
 BJJLMM	(S (T ("? ".0
 0
n%# %#X4# 4#v.* .*j3
 3
t,' ,'f#! #!T* *bC$ C$T<
 <
r   