1212from unittest .mock import patch , MagicMock , AsyncMock
1313
1414from pytrickle .server import StreamServer
15- from pytrickle .state import PipelineState
1615from pytrickle .test_utils import MockFrameProcessor , create_mock_client
1716
17+ def get_stream_route (server , endpoint ):
18+ """Get the full route path for a streaming endpoint."""
19+ prefix = server .route_prefix .rstrip ('/' )
20+ return f"{ prefix } /stream/{ endpoint } "
21+
1822
1923@pytest_asyncio .fixture
2024async def test_server ():
@@ -71,7 +75,7 @@ async def test_start_stream_success_with_validation(self, test_server):
7175 }
7276 }
7377
74- resp = await client .post ("/api/stream/ start" , json = payload )
78+ resp = await client .post (get_stream_route ( server , " start") , json = payload )
7579 assert resp .status == 200
7680
7781 data = await resp .json ()
@@ -109,7 +113,7 @@ async def test_stream_state_updates_during_lifecycle(self, test_server):
109113 assert server .state .active_client is True
110114
111115 # Verify this reflects in status endpoint
112- resp = await client .get ("/api/stream/ status" )
116+ resp = await client .get (get_stream_route ( server , " status") )
113117 assert resp .status == 200
114118 data = await resp .json ()
115119 assert data ["active_streams" ] == 1
@@ -138,7 +142,7 @@ async def test_start_stream_validation_error(self, test_server):
138142 # Missing publish_url and gateway_request_id
139143 }
140144
141- resp = await client .post ("/api/stream/ start" , json = payload )
145+ resp = await client .post (get_stream_route ( server , " start") , json = payload )
142146 assert resp .status == 400
143147
144148 # Verify state wasn't changed
@@ -160,7 +164,7 @@ async def test_update_params_success_with_monitoring(self, test_server):
160164
161165 payload = {"intensity" : 0.9 }
162166
163- resp = await client .post ("/api/stream/ params" , json = payload )
167+ resp = await client .post (get_stream_route ( server , " params") , json = payload )
164168 assert resp .status == 200
165169
166170 data = await resp .json ()
@@ -182,7 +186,7 @@ async def test_update_params_no_active_stream(self, test_server):
182186
183187 payload = {"intensity" : 0.9 }
184188
185- resp = await client .post ("/api/stream/ params" , json = payload )
189+ resp = await client .post (get_stream_route ( server , " params") , json = payload )
186190 assert resp .status == 400
187191
188192 data = await resp .json ()
@@ -194,7 +198,7 @@ async def test_get_status_no_client(self, test_server):
194198 """Test status endpoint when no client is active."""
195199 client , server = test_server
196200
197- resp = await client .get ("/api/stream/ status" )
201+ resp = await client .get (get_stream_route ( server , " status") )
198202 assert resp .status == 200
199203
200204 data = await resp .json ()
@@ -218,7 +222,7 @@ async def test_get_status_with_active_client(self, test_server):
218222 gateway_request_id = "status-test"
219223 )
220224
221- resp = await client .get ("/api/stream/ status" )
225+ resp = await client .get (get_stream_route ( server , " status") )
222226 assert resp .status == 200
223227
224228 data = await resp .json ()
@@ -243,7 +247,7 @@ async def test_stop_stream_success_with_monitoring(self, test_server):
243247 server .state .set_active_client (True )
244248 server .state .update_active_streams (1 )
245249
246- resp = await client .post ("/api/stream/ stop" , json = {})
250+ resp = await client .post (get_stream_route ( server , " stop") , json = {})
247251 assert resp .status == 200
248252
249253 data = await resp .json ()
@@ -267,7 +271,7 @@ async def test_stop_stream_no_active_stream(self, test_server):
267271 """Test stop stream when no stream is active."""
268272 client , server = test_server
269273
270- resp = await client .post ("/api/stream/ stop" , json = {})
274+ resp = await client .post (get_stream_route ( server , " stop") , json = {})
271275 assert resp .status == 400
272276
273277 data = await resp .json ()
@@ -287,7 +291,7 @@ async def test_direct_state_manipulation(self, test_server):
287291 server .state .update_active_streams (1 )
288292 server .state .set_active_client (True )
289293
290- resp = await client .get ("/api/stream/ status" )
294+ resp = await client .get (get_stream_route ( server , " status") )
291295 assert resp .status == 200
292296 data = await resp .json ()
293297 assert data ["active_streams" ] == 1
@@ -296,7 +300,7 @@ async def test_direct_state_manipulation(self, test_server):
296300 server .state .update_active_streams (0 )
297301 server .state .set_active_client (False )
298302
299- resp = await client .get ("/api/stream/ status" )
303+ resp = await client .get (get_stream_route ( server , " status") )
300304 assert resp .status == 200
301305 data = await resp .json ()
302306 assert data ["active_streams" ] == 0
@@ -316,7 +320,7 @@ async def test_error_state_handling_with_validation(self, test_server):
316320 assert data == {"status" : "ERROR" }
317321
318322 # Verify status endpoint reflects error
319- resp = await client .get ("/api/stream/ status" )
323+ resp = await client .get (get_stream_route ( server , " status") )
320324 assert resp .status == 200
321325 data = await resp .json ()
322326 assert server .state .is_error ()
@@ -331,6 +335,78 @@ async def test_error_state_handling_with_validation(self, test_server):
331335 assert data ["status" ] in ["IDLE" , "LOADING" ] # Should be back to normal
332336
333337
338+ class TestDynamicRoutes :
339+ """Test dynamic route functionality with different prefixes."""
340+
341+ @pytest .mark .parametrize ("route_prefix" , ["/" , "/api" , "/v1" , "/custom" ])
342+ @pytest .mark .asyncio
343+ async def test_routes_with_different_prefixes (self , route_prefix ):
344+ """Test that routes work with different prefixes."""
345+ processor = MockFrameProcessor ()
346+
347+ server = StreamServer (
348+ frame_processor = processor ,
349+ port = 0 ,
350+ route_prefix = route_prefix ,
351+ capability_name = "test-model" ,
352+ pipeline = "test-pipeline" ,
353+ version = "1.0.0" ,
354+ )
355+
356+ # Attach state and mark ready
357+ processor .attach_state (server .state )
358+ server .state .set_startup_complete ()
359+
360+ # Test that routes are constructed correctly
361+ expected_start_route = f"{ route_prefix .rstrip ('/' )} /stream/start"
362+ actual_start_route = get_stream_route (server , "start" )
363+ assert actual_start_route == expected_start_route
364+
365+ expected_status_route = f"{ route_prefix .rstrip ('/' )} /stream/status"
366+ actual_status_route = get_stream_route (server , "status" )
367+ assert actual_status_route == expected_status_route
368+
369+ expected_params_route = f"{ route_prefix .rstrip ('/' )} /stream/params"
370+ actual_params_route = get_stream_route (server , "params" )
371+ assert actual_params_route == expected_params_route
372+
373+ expected_stop_route = f"{ route_prefix .rstrip ('/' )} /stream/stop"
374+ actual_stop_route = get_stream_route (server , "stop" )
375+ assert actual_stop_route == expected_stop_route
376+
377+ @pytest .mark .asyncio
378+ async def test_functional_test_with_custom_prefix (self ):
379+ """Test that endpoints actually work with a custom prefix."""
380+ processor = MockFrameProcessor ()
381+
382+ server = StreamServer (
383+ frame_processor = processor ,
384+ port = 0 ,
385+ route_prefix = "/api/v2" ,
386+ capability_name = "test-model" ,
387+ pipeline = "test-pipeline" ,
388+ version = "1.0.0" ,
389+ )
390+
391+ # Attach state and mark ready
392+ processor .attach_state (server .state )
393+ server .state .set_startup_complete ()
394+
395+ app = server .get_app ()
396+ test_server_instance = TestServer (app )
397+
398+ async with test_server_instance :
399+ client = TestClient (test_server_instance )
400+ async with client :
401+ # Test status endpoint with custom prefix
402+ resp = await client .get (get_stream_route (server , "status" ))
403+ assert resp .status == 200
404+
405+ data = await resp .json ()
406+ assert data ["client_active" ] is False
407+ assert data ["active_streams" ] == 0
408+
409+
334410class TestErrorHandling :
335411 """Test error handling scenarios with state validation."""
336412
@@ -351,7 +427,7 @@ async def test_client_error_state_propagation(self, test_server):
351427 "gateway_request_id" : "error-test"
352428 }
353429
354- resp = await client .post ("/api/stream/ start" , json = payload )
430+ resp = await client .post (get_stream_route ( server , " start") , json = payload )
355431 # API call succeeds, but client will fail in background
356432 assert resp .status == 200
357433
@@ -385,7 +461,7 @@ async def test_concurrent_stream_operations(self, test_server):
385461
386462 # Send multiple concurrent requests
387463 tasks = [
388- client .post ("/api/stream/ start" , json = payload )
464+ client .post (get_stream_route ( server , " start") , json = payload )
389465 for _ in range (3 )
390466 ]
391467
0 commit comments