
    1i&              	      4   U d Z ddlmZ ddlZddlZddl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 ddlmZ ddlZ ee      j'                         j(                  d   Z ed	       G d
 d             Z ededz  dd       ededz  dd      f ededz  dd       ededz  dd      f ededz  dd       ededz  dd      f ededz  dd      fdZd ed!<   d,d"Zd,d#Zd-d$Zd.d%Zd/d&Zd-d'Zd-d(Zd0d)Z d1d*Z!e"d+k(  r e# e!             y)2zLow-friction test ladder for Milipol demo integration.

Runs layered validation for:
- unit
- component
- integration-mock
- scenario
- full-demo
    )annotationsN)	dataclass)Path)Iterable   T)frozenc                  6    e Zd ZU ded<   ded<   ded<   ded<   y)	PytestSuitestrnamer   workdir
pythonpathztuple[str, ...]testsN)__name__
__module____qualname____annotations__     tools/demo_test_ladder.pyr
   r
      s    
IMOr   r
   zedge-proxy unitz
edge-proxy.)ztests/test_waypoints.pyztests/test_fr_loop.py)r   r   r   r   zorchestrator unitorchestratorsrc)z$src/planner/tests/test_dag_parser.pyz"src/planner/tests/test_verifier.pyzsrc/tests/test_state_machine.pyzedge-proxy component)ztests/test_server_mock.pyztests/test_rosbridge_backend.pyzorchestrator component)z1src/executor/tests/test_edge_proxy_integration.pyz4src/tests/test_state_machine_executor_integration.pyzedge-proxy integration-mock)z*tests/test_server_rosbridge_integration.pyzorchestrator integration-mock)z0src/tests/test_dynamic_replanning_integration.pyzdemo scenario (edge-proxy))z^tests/test_server_rosbridge_integration.py::test_rosbridge_demo_scenario_three_scene_waypointsunit	componentintegration-mockscenarioz"dict[str, tuple[PytestSuite, ...]]SUITES_BY_LAYERc                   	 t         j                  j                  | |      5 }d|j                  cxk  rdk  rn nd|j                   fcd d d        S dd|j                   fcd d d        S # 1 sw Y   y xY w# t         j                  j
                  $ r!}dt        |j                        fcY d }~S d }~wt        $ r}dt        |      fcY d }~S d }~ww xY w)N)timeout   i,  TFzHTTP )	urllibrequesturlopenstatuserrorURLErrorr   reason	Exception)urltimeout_secrespexcs       r   _http_okr/   f   s    ^^##C#= 	0dkk'C'}-	0 	0 E$++//	0 	0 	0 <<   &c#**o%% c#hsX   !A: 'A.
	A: A.$	A: .A73A: 7A: :CB3-C3C?CCCc                  K   	 d }| j                         j                  d      r0t        j                         }d|_        t        j
                  |_        t        j                  | ||      4 d {    	 d d d       d {    y7 7 # 1 d {  7  sw Y   y xY w# t        $ r}dt        |      fcY d }~S d }~ww xY ww)Nzwss://F)open_timeoutssl)T	connected)lower
startswithr2   create_default_contextcheck_hostname	CERT_NONEverify_mode
websocketsconnectr*   r   )r+   r,   ssl_ctxr.   s       r   _ws_okr=   r   s     	99;!!(+002G%*G""%--G%%cQ 	% 	%$	% 	% 	% 	% 	% 	% 	% c#hs   CA-B! 1B2B! 5B7B! B
B! CB! 
B! BBBB! CB! !	C*B<6C7C<CCc                V   g }t        | j                  | j                        \  }}|j                  d||f       t        | j                  | j                        \  }}|j                  d||f       t        j                  t        | j                  | j                              \  }}|j                  d||f       t        d       t        d       |D ]!  \  }}	}
|	rdnd}t        |dd	|d
d	|
        # |D cg c]
  }|d   r	| }}|rt        d       yt        d       yc c}w )Norchestrator_healthedge_proxy_healthrosbridge_wsz

PreflightzH========================================================================PASSFAIL24s 5sr   zG
Preflight failed. Fix connectivity before running full pipeline tests.z
Preflight passed.r   )
r/   r?   r,   appendedge_healthasynciorunr=   rosbridge_urlprint)argschecksorch_okorch_detailedge_okedge_detailws_ok	ws_detailr   okdetailr&   cfaileds                 r   run_preflightrY      s(   *,F#D$<$<d>N>NOG[
MM(';?@#D$4$4d6F6FGG[
MM&=>{{6$*<*<d>N>N#OPE9
MM>5)45	-	(O" 2b&6c
!F2;ax012  ,Aqta,F,XY	
  -s   ;
D&D&c                x   t         j                  j                         }| j                  |d<   ddg| j                  |}t        d| j                   d       t        d| j                          t        ddj                  |      z          t        j                  || j                  |	      }|j                  S )
N
PYTHONPATHpytestz-qz
[]workdir=cmd=rE   cwdenv)osenvironcopyr   r   rL   r   r   join
subprocessrJ   
returncode)suitepytest_argsrb   cmdprocs        r   _run_pytest_suiterm      s    
**//
C((CT
6EKK
6+
6C	C

|1
	HU]]O
$%	&388C=
 !>>#5==c:D??r   c                N    t         |    }|D ]  }t        ||      }|dk7  s|c S  y)Nr   )r   rm   )layerrj   suitesri   rcs        r   	run_layerrr      s8    U#F uk27I r   c                B   t         j                  j                         t        fddD              }|st	        d       yddd| j
                  d| j                  d	| j                  d
t        | j                        g
}| j                  r|j                  d       | j                  r|j                  d       t	        d       t	        dt        dz          t	        ddj                  |      z          t        j                   |t        dz        }|j"                  S )Nc              3  R   K   | ]  }t        j                  |               y w)N)boolget).0r   rb   s     r   	<genexpr>z%run_live_llm_smoke.<locals>.<genexpr>   s&       	SWWT]s   $')Z_AI_API_KEYMODELAPI_KEYMODEL_API_KEYOPENAI_API_KEYz^Missing API key env var. Set one of: Z_AI_API_KEY, MODELAPI_KEY, MODEL_API_KEY, OPENAI_API_KEY   python3zscripts/live_plan_demo.pyz
--endpointz--modelz--intentz--timeout-sz--use-openai-sdkz--no-response-formatz
[live-llm orchestrator smoke]r^   r   r_   rE   r`   )rc   rd   re   anyrL   live_llm_endpointlive_llm_modellive_llm_intentr   live_llm_timeout_seclive_llm_use_openai_sdkrG   live_llm_no_response_formatROOTrf   rg   rJ   rh   )rM   api_key_presentrk   rl   rb   s       @r   run_live_llm_smoker      s   
**//
C W O H	
  	#D%%&C ##

%&''

)*	
+,	HTN*+
,-	&388C=
 !>>#4.#8cBD??r   c                   | j                   st        |       }|dk7  r|S dD ]T  }|dk(  r | j                  rt        |       }|dk7  r|c S t	        d|        t        || j                        }|dk7  sR|c S  t	        d       t	        d       y)Nr   r   r   z
Running layer: z
Full-demo test ladder passed.z^Next manual step: run live robot dry-run (dashboard + orchestrator + edge-proxy + ros2 stack).)skip_preflightrY   with_live_llmr   rL   rr   rj   )rM   rq   ro   s      r   run_full_demor      s    4 7IF J4#5#5#D)BQw	!%)*ud../7I 

+,	
jkr   c            
        t        j                  d      } | j                  dddd       | j                  dt        j                  d	d
             | j                  dt        j                  dd             | j                  dt        j                  dd             | j                  dt
        dd       | j                  ddd       | j                  ddd       | j                  dt        j                  dt        j                  dd                   | j                  d t        j                  d!t        j                  d"d#                   | j                  d$d%       | j                  d&t        d'(       | j                  d)dd*       | j                  d+dd,       | j                  d-t         j                  d./       | j                         S )0NzMilipol demo test ladder runner)descriptionz--mode)	preflightr   r   r   live-llmr   	full-demor   zTest ladder mode to run)choicesdefaulthelpz--orchestrator-healthORCHESTRATOR_HEALTH_URLzhttp://127.0.0.1:8000/health)r   z--edge-healthEDGE_PROXY_HEALTH_URLzhttp://127.0.0.1:8080/healthz--rosbridge-urlROSBRIDGE_URLzwss://127.0.0.1:9090z--timeout-secg       @zTimeout for preflight checks)typer   r   z--skip-preflight
store_truez5Skip connectivity checks (only for offline/unit work))actionr   z--with-live-llmzVRun a real orchestrator planner call against configured LLM endpoint in full-demo modez--live-llm-endpointLIVE_LLM_ENDPOINTORCHESTRATOR_LLM_ENDPOINTz.https://modelapi.klass.dev/v1/chat/completionsz--live-llm-modelLIVE_LLM_MODELORCHESTRATOR_LLM_MODELzQwen3-Next-80B-A3B-FP8z--live-llm-intentz?Navigate to office_scene, scan area, verify chemical container.z--live-llm-timeout-sec-   )r   r   z--live-llm-use-openai-sdkz'Use openai-python SDK for live-llm modez--live-llm-no-response-formatz5Disable response_format=json_object for live-llm moderj   z/Extra args forwarded to pytest (prefix with --))nargsr   )	argparseArgumentParseradd_argumentrc   getenvfloatint	REMAINDER
parse_args)parsers    r   r   r      s   $$1RSF
k&	   		35ST   		13QR   		/+AB   +	   D  
 e  
 		II13cd
   		*BII6NPh,ij   Q      
 #6  
 'D  
   >  
 r   c                 J   t               } | j                  dk(  rt        |       S | j                  dk(  rt        |       S | j                  dk(  rt	        |       S | j
                  s | j                  dv rt        |       }|dk7  r|S t        | j                  | j                        S )Nr   r   r   >   r   r   )r   moderY   r   r   r   rr   rj   )rM   rq   s     r   mainr   3  s    <DyyKT""yyJ!$''yyKT""499#<4 7ITYY 0 011r   __main__)r+   r   r,   r   returnztuple[bool, str])rM   argparse.Namespacer   r   )ri   r
   rj   Iterable[str]r   r   )ro   r   rj   r   r   r   )r   r   )r   r   )$__doc__
__future__r   r   rI   rc   r2   rg   urllib.errorr#   urllib.requestdataclassesr   pathlibr   typingr   r:   __file__resolveparentsr   r
   r   r   r/   r=   rY   rm   rr   r   r   r   r   r   
SystemExitr   r   r   <module>r      s   #   	 
    !    H~''* $   	"<'F		
 	$>)			
& 	'<'R		
 	)>)		
$ 	.<'A		
 	0>)G		
 	-<'		
	e<73 <~	
6	"J*GT2$ z
TV
 r   