
    .i(                        d Z ddlZddlmc mZ ddlZej                  j                  dd       ddl
Z
ddlmZmZmZ ddlmZmZmZ d Ze
j(                  j*                  d        Ze
j(                  j*                  d        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e
j(                  j*                  d        Ze
j(                  j*                  d        Zd Z e!dk(  rddlZd Z" ejF                   e"              yy)u  
Tests for Story 4.04 (Track B): StranglerFig — Progressive Migration Wrapper

Black Box tests (BB): verify public contract from the outside
White Box tests (WB): verify internal structure and fail-safe paths

Story: 4.04
File under test: core/routing/strangler_fig.py
    Nz/mnt/e/genesis-system)	AsyncMockpatch	MagicMock)strangler_figget_migration_statusWRAPPED_FUNCTIONSc                  ,    t        j                          y)z>Clear WRAPPED_FUNCTIONS between tests that need a clean slate.N)r   clear     6/mnt/e/genesis-system/tests/track_b/test_story_4_04.py_clear_registryr      s    r   c                    K   t                dddd} t        dd      d        }t        d	t        | 
            5   |d       d{   }ddd       | 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  }t	        j                  d| d|      dz   d|iz  }t        t	        j                  |            d}y7 # 1 sw Y   xY ww)uX   BB1: @strangler_fig wraps async function → dispatch fires, dispatched result returned.	completedzabc-123intercepted)statustask_idoutput	test_typeT1tierc                    K   d| iS w)Nvaluer   )xs    r   my_funcz<test_bb1_dispatch_fires_and_result_returned.<locals>.my_func(   s     |   #core.interceptors.dispatch_to_swarm)return_valuenew*   N==)z%(py0)s == %(py2)sresultdispatch_return)py0py2zExpected dispatch result z, got z
>assert %(py4)spy4)r   r   r   r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)r&   r   r%   @py_assert1@py_format3@py_format5s         r   +test_bb1_dispatch_fires_and_result_returnedr6   "   s.     !,m\O;T* + 
4)Q`:a	b #r{"# _$  6_                %    %    $O#6fVJG     ## #s/   ;EE	E
EC4EEE	Ec                  P  K   t                t        d      d        } t        dt        t	        d                  5   |         d{   }ddd       dd	i}|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7 # 1 sw Y   xY ww)uP   BB2: dispatch_to_swarm raises → original function result returned (fail-safe).r   c                     K   ddiS w)NsafeTr   r   r   r   	safe_funcz:test_bb2_failsafe_on_dispatch_exception.<locals>.safe_func9   s     ~r   r   boomside_effectr    Nr9   Tr#   z%(py0)s == %(py3)sr%   r'   py3z2Expected original result on dispatch failure, got 
>assert %(py5)spy5)r   r   r   r   RuntimeErrorr*   r+   r,   r-   r.   r/   r0   r1   r2   )r:   r%   @py_assert2r3   @py_format4@py_format6s         r   'test_bb2_failsafe_on_dispatch_exceptionrG   4   s     ;   
4)P\]cPd:e	f # {"# d^ 6^#  6^              $    =VJG     ## #s/   <D&D	D
DC
D&DD#D&c                     t                t        dd      d        } d}|t        v }|st        j                  d|fd|t        f      t        j
                  |      dt        j                         v st        j                  t              rt        j
                  t              ndd	z  }t        j                  d
      dz   d|iz  }t        t        j                  |            dx}}t        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   }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)zTBB3: WRAPPED_FUNCTIONS has an entry for the decorated function after @strangler_fig.registry_taskT0r   c                     K   y wNr   r   r   r   registered_funczCtest_bb3_registry_updated_after_decoration.<locals>.registered_funcI   	        rM   inz%(py1)s in %(py3)sr   py1r@   zCWRAPPED_FUNCTIONS should contain 'registered_func' after decorationrA   rB   N	task_typer#   z%(py1)s == %(py4)srT   r)   assert %(py6)spy6r   )r   r   r   r*   r+   r/   r,   r-   r.   r0   r1   r2   )	rM   @py_assert0rD   rE   rF   entry@py_assert3r5   @py_format7s	            r   *test_bb3_registry_updated_after_decorationr^   E   sm   ?. /   11   1          !2    !2    	N     /0E0000000000000000000= D =D    =D   =   D       r   c                     t                t        d      d        } t        dd      d        }t               }|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}}d}|d   }||v }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}d}|d   }||v }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|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}}y)zGBB4: get_migration_status() returns correct count and function details.
alpha_taskc                     K   y wrL   r   r   r   r   alphazBtest_bb4_get_migration_status_returns_correct_count.<locals>.alphaY   s	     rO   	beta_taskT2r   c                     K   y wrL   r   r   r   r   betazAtest_bb4_get_migration_status_returns_correct_count.<locals>.beta\   s	     rO   total_wrapped   r#   rV   rW   z"Expected 2 wrapped functions, got z
>assert %(py6)srY   Nrb   	functionsrP   )z%(py1)s in %(py4)srX   rf   r   )	r   r   r   r*   r+   r/   r0   r1   r2   )rb   rf   r   rZ   r\   rD   r5   r]   s           r   3test_bb4_get_migration_status_returns_correct_countrj   U   s   <  !;T* +!#F/" a "a'  "a    #    '(    -VO-D,EF     )f[))7)))))7))))7)))))))))))(VK((6(((((6((((6(((((((((((+v&v.6$6.$6666.$666.666$6666666r   c                    K   t                t        d      d        } | j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }t        j                  d| j                   d      d	z   d
|iz  }t        t        j                  |            dx}x}}| j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }t        j                  d| j                        d	z   d
|iz  }t        t        j                  |            dx}x}}yw)zCWB1: functools.wraps preserves __name__ and __doc__ on the wrapper.doc_testc                     K   i S w)This is the original docstring.r   r   r   r   well_documentedzHtest_wb1_functools_wraps_preserves_name_and_doc.<locals>.well_documentedq   s      	   ro   r#   z0%(py2)s
{%(py2)s = %(py0)s.__name__
} == %(py5)sr'   r(   rB   z+__name__ should be 'well_documented', got ''z
>assert %(py7)spy7Nrn   )z/%(py2)s
{%(py2)s = %(py0)s.__doc__
} == %(py5)sz__doc__ not preserved: )r   r   __name__r*   r+   r,   r-   r.   r/   r0   r1   r2   __doc__)ro   r3   @py_assert4r\   rF   @py_format8s         r   /test_wb1_functools_wraps_preserves_name_and_docry   l   s     :  ## '8 #'88  #'8              $    (9    6o6N6N5OqQ     "" &G "&GG  "&G              #    'H    "/"9"9!<=     s   G4G6c                  @  K   t                t        d      d        } t        j                  dddi      5   |         d{   }ddd       ddi}|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7 # 1 sw Y   xY ww)zLWB2: Fail-safe catches ImportError when dispatch_to_swarm is not importable.import_safe_taskc                     K   ddiS w)Nfragiler%   r   r   r   r   fragile_funcz<test_wb2_failsafe_catches_import_error.<locals>.fragile_func   s     8$$r   zsys.moduleszcore.interceptorsNr}   r%   r#   r>   r?   z:Fail-safe must return original result on ImportError, got rA   rB   )r   r   r   dictr*   r+   r,   r-   r.   r/   r0   r1   r2   )r~   r%   rD   r3   rE   rF   s         r   &test_wb2_failsafe_catches_import_errorr   ~   s	     %&% '% 
M$7#>	? &#~%&  * 6**  6*              +    EVJO     && &s/   4DDDDC
DDDDc                    K   t                g dfd	} t        dd      d        }t        d|       5   |        d{    ddd       t              }d	}||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                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}d   \  }}|j                  }	d}
 |	|
      }d}||k(  }|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  }t	        j                  d|      dz   d|iz  }t        t	        j                  |            dx}	x}
x}x}}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7 # 1 sw Y   xY ww) zOWB3: tier parameter is included in task_payload forwarded to dispatch_to_swarm.Nc                 :   K   j                  | |f       ddiS wNr   r   appendtask_payloadr   captured_payloadss     r   capture_dispatchzNtest_wb3_tier_included_in_task_payload_when_provided.<locals>.capture_dispatch   %       ,!56+&&   tiered_taskr   r   c                     K   i S wrL   r   r   r   r   tiered_funczItest_wb3_tier_included_in_task_payload_when_provided.<locals>.tiered_func        	rp   r   r       r#   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr   r'   rT   r@   rY   assert %(py8)spy8r   r   )zI%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get
}(%(py4)s)
} == %(py9)spayload)r'   r(   r)   rY   py9z<tier must be in task_payload when decorator tier='T1', got: z
>assert %(py11)spy11r>   kw_tierr?   z2tier kwarg to dispatch_to_swarm must be 'T1', got rA   rB   rL   )r   r   r   r   r*   r+   r,   r-   r.   r/   r1   r2   getr0   )r   r   rD   @py_assert5rw   r]   @py_format9r   r   r3   r\   @py_assert8@py_assert7@py_format10@py_format12rE   rF   r   s                    @r   4test_wb3_tier_included_in_task_payload_when_providedr      s     ' =t, - 
4:J	K m  !&Q&!Q&&&&!Q&&&&&&3&&&3&&&&&& &&& &&&!&&&Q&&&&&&&(+GW;; v ;v $ $&  $                          #'    GwkR       7d?  7d                  =WKH     	 s/   3MM L=M K7M=M  M
Mc                     K   t                g d,fd	} t        d      d,d       }t        d|       5   |dd	       d{    ddd       t              }d
}||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                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}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}}d}t        |      }||v}|st	        j
                  d|fd||f      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      dz   d|iz  }t        t	        j                  |            dx}x}}d}t        |      }||v}|st	        j
                  d|fd||f      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       dz   d|iz  }t        t	        j                  |            dx}x}}|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&   }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}}|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*   }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7 +# 1 sw Y   +xY ww)-uQ   WB4: Original function args/kwargs NOT passed to dispatch — only metadata sent.Nc                 6   K   j                  |        ddiS wr   r   r   s     r   r   zLtest_wb4_original_args_not_forwarded_only_metadata.<locals>.capture_dispatch           .+&&   metadata_taskc                    K   ddiS w)N	processedTr   )
secret_argkeywords     r   func_with_argszJtest_wb4_original_args_not_forwarded_only_metadata.<locals>.func_with_args   s     T""r   r   r    SECRET_VALUE	SENSITIVE)r   r   r#   r   r   r   r   r   r   r   r   not inz%(py1)s not in %(py3)sr   rS   z.Raw positional arg name must not be in payloadrA   rB   )z4%(py1)s not in %(py6)s
{%(py6)s = %(py3)s(%(py4)s)
}str)rT   r@   r)   rY   z/Raw positional arg value must not be in payloadz
>assert %(py8)sz&Raw kwarg value must not be in payload
args_countrV   rW   rX   rY   kwargs_keysr   sourcer   wrapped_functionr   rL   )r   r   r   r   r*   r+   r,   r-   r.   r/   r1   r2   r0   r   )r   r   rD   r   rw   r]   r   r   rZ   rE   rF   r\   r5   r   s                @r   2test_wb4_original_args_not_forwarded_only_metadatar      s     ' ?## $# 
4:J	K B^[AAAB  !&Q&!Q&&&&!Q&&&&&&3&&&3&&&&&& &&& &&&!&&&Q&&&&&&&"G X<w&XXX<wXXX<XXXXXXwXXXwXXXX(XXXXXXX`W`>-```>```>```````````````W```W``````/````````Tc'lT;l*TTT;lTTT;TTTTTTcTTTcTTTTTT'TTT'TTTlTTT,TTTTTTTT < %A% A%%%% A%%% %%%A%%%%%%%=!0i[0![0000![000!000[00000008///////////////////%&:*::&*:::::&*::::&:::*:::::::: 	BB Bs/   2Y>Y1Y.Y1X&Y>.Y11Y;6Y>c                    	K   t                g 	d	fd	} t        d      d        }t        d|       5   |        d{    ddd       	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}}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 y# 1 sw Y   yxY ww)zBWhen tier is None, the 'tier' key must NOT appear in task_payload.Nc                 :   K   j                  | |f       ddiS wr   r   r   s     r   r   z>test_no_tier_omits_tier_from_payload.<locals>.capture_dispatch   r   r   no_tier_taskc                     K   i S wrL   r   r   r   r   no_tier_funcz:test_no_tier_omits_tier_from_payload.<locals>.no_tier_func   r   rp   r   r    r   r   r   r   r   rS   z;'tier' key must be absent when decorator tier is None, got rA   rB   )is)z%(py0)s is %(py3)sr   r?   assert %(py5)srL   )r   r   r   r*   r+   r/   r,   r-   r.   r0   r1   r2   )
r   r   r   r   rZ   rD   rE   rF   r3   r   s
            @r   $test_no_tier_omits_tier_from_payloadr      sq     ' >" # 
4:J	K n )+GW 6   6          !    !    Fg[Q     7d?7d77d 	 s.   1GF;F8 F;E4G8F;;G Gc                    K   t                g dfd	} t        d      d        }t        d|       5   |        d{    dd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}}y7 # 1 sw Y   xY ww)zBoriginal_result from the wrapped function appears in task_payload.Nc                 6   K   j                  |        ddiS wr   r   r   s     r   r   z9test_original_result_in_payload.<locals>.capture_dispatch   r   r   result_pass_taskc                     K   dddS w)Nr   c   keycountr   r   r   r   func_returning_valuez=test_original_result_in_payload.<locals>.func_returning_value   s     ,,s   r   r    r   original_resultr   r   r   r#   rV   rW   rX   rY   rL   )r   r   r   r*   r+   r/   r1   r2   )	r   r   r   rZ   r\   rD   r5   r]   r   s	           @r   test_original_result_in_payloadr      s      ' %&- '- 
4:J	K %"$$$%  "G$%F2)FF%)FFFFF%)FFFF%FFF)FFFFFFFF 	%% %s.   1C#CC CBC#CC C#c                  j   t                t        d      d        } 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}}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   }|j                  }d} ||      }|stdt        j
                  |      t        j
                  |      t        j
                  |      t        j
                  |      dz  }t        t        j                  |            dx}x}x}}y)zGWRAPPED_FUNCTIONS entry includes module and qualname for introspection.introspection_taskc                     K   y wrL   r   r   r   r   introspectablezCtest_registry_entry_has_module_and_qualname.<locals>.introspectable   rN   rO   r   modulerP   rR   r[   rS   zEntry must include 'module'rA   rB   NqualnamezEntry must include 'qualname'zJassert %(py7)s
{%(py7)s = %(py3)s
{%(py3)s = %(py1)s.endswith
}(%(py5)s)
})rT   r@   rB   rt   )r   r   r   r*   r+   r/   r,   r-   r.   r0   r1   r2   endswith)	r   r[   rZ   rD   rE   rF   rw   @py_assert6rx   s	            r   +test_registry_entry_has_module_and_qualnamer      sb   '( ) ./E;8u;;;8u;;;8;;;;;;u;;;u;;;;;;;;;;;?:???:???:????????????? ???????7%%7&67%&677777777%777&67777777777r   __main__c                    K   t        d       t                t        dd      d        } d}|t        v }|st	        j
                  d|fd|t        f      t	        j                  |      d	t        j                         v st	        j                  t              rt	        j                  t              nd	d
z  }dd|iz  }t        t	        j                  |            dx}}t        d       t               }|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}}t        d       t        dt        t                    5   |         d{   }	ddd       ddi}	|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}
}t        d       | j                   }
d}|
|k(  }|st	        j
                  d|fd |
|f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |
      t	        j                  |      d!z  }d"d#|iz  }t        t	        j                  |            dx}
x}}t        d$       t        d%       y7 # 1 sw Y   xY ww)&zQuick manual smoke test.z,Running manual smoke tests for Story 4.04...
smoke_taskr   r   c                     K   ddiS w)NokTr   r   r   r   smokezrun_manual.<locals>.smoke  s     #',.r   r   rP   rR   r   rS   r   rB   Nz[PASS] BB3: registry updatedrg   r   r#   rV   rW   rX   rY   z0[PASS] BB4: get_migration_status() correct countr   r<   r    r   Tr>   r%   r?   z+[PASS] BB2: fail-safe on dispatch exceptionrq   rr   zassert %(py7)srt   z.[PASS] WB1: functools.wraps preserves __name__u7   
All manual smoke tests passed — Story 4.04 (Track B))printr   r   r   r*   r+   r/   r,   r-   r.   r1   r2   r   r   r   rC   ru   )r   rZ   rD   rE   rF   r   r\   r5   r]   r%   r3   rw   rx   s                r   
run_manualr     s    <= 		|$	/. 
0.+w+++++w++++w++++++++++++++++++,- &'o&+!+&!++++&!+++&+++!+++++++@A 8iT`>ab 	# 7]F	#%v%%%%v%%%%%%v%%%v%%%%%%%%%%;< ~~((~((((~((((((u(((u(((~((((((((((>?HI #	# 	#s1   FMM&M'M+FMMMM)$rv   builtinsr,   _pytest.assertion.rewrite	assertionrewriter*   syspathinsertpytestunittest.mockr   r   r   core.routing.strangler_figr   r   r   r   markasyncior6   rG   r^   rj   ry   r   r   r   r   r   r   ru   r   runr   r   r   <module>r      sj    
 * +  5 5 ^ ]  "   ! 7.  "  "  4 ; ;F  . G G(8 zJ< GKK
C r   