1111from collections .abc import AsyncIterable , Callable
1212from contextlib import asynccontextmanager
1313from datetime import datetime , timedelta
14- from typing import Final , Iterable
14+ from typing import Final , Iterable , Literal
1515from unittest .mock import AsyncMock
1616
1717import httpx
2424from models_library .projects import ProjectID
2525from models_library .projects_nodes_io import NodeID
2626from models_library .projects_state import RunningState
27- from models_library .rabbitmq_messages import LoggerRabbitMessage
27+ from models_library .rabbitmq_messages import LoggerRabbitMessage , RabbitMessageBase
2828from models_library .users import UserID
29- from pydantic import parse_obj_as
29+ from pydantic import ValidationError , parse_obj_as
3030from pytest_mock import MockerFixture , MockFixture
3131from pytest_simcore .helpers .utils_envs import (
3232 EnvVarsDict ,
@@ -170,15 +170,23 @@ def produce_logs(
170170 create_rabbitmq_client : Callable [[str ], RabbitMQClient ],
171171 user_id : UserID ,
172172):
173- async def _go (name , project_id_ = None , node_id_ = None , messages_ = None , level_ = None ):
173+ async def _go (
174+ name ,
175+ project_id_ = None ,
176+ node_id_ = None ,
177+ messages_ = None ,
178+ level_ = None ,
179+ log_message : RabbitMessageBase | None = None ,
180+ ):
174181 rabbitmq_producer = create_rabbitmq_client (f"pytest_producer_{ name } " )
175- log_message = LoggerRabbitMessage (
176- user_id = user_id ,
177- project_id = project_id_ or faker .uuid4 (),
178- node_id = node_id_ ,
179- messages = messages_ or [faker .text () for _ in range (10 )],
180- log_level = level_ or logging .INFO ,
181- )
182+ if log_message is None :
183+ log_message = LoggerRabbitMessage (
184+ user_id = user_id ,
185+ project_id = project_id_ or faker .uuid4 (),
186+ node_id = node_id_ ,
187+ messages = messages_ or [faker .text () for _ in range (10 )],
188+ log_level = level_ or logging .INFO ,
189+ )
182190 await rabbitmq_producer .publish (log_message .channel_name , log_message )
183191
184192 return _go
@@ -381,7 +389,6 @@ async def test_log_streamer_with_distributor(
381389 async def _log_publisher ():
382390 while not computation_done ():
383391 msg : str = faker .text ()
384- await asyncio .sleep (0.2 )
385392 await produce_logs ("expected" , project_id , node_id , [msg ], logging .DEBUG )
386393 published_logs .append (msg )
387394
@@ -399,6 +406,45 @@ async def _log_publisher():
399406 assert published_logs == collected_messages
400407
401408
409+ async def test_log_streamer_not_raise_with_distributor (
410+ client : httpx .AsyncClient ,
411+ app : FastAPI ,
412+ user_id ,
413+ project_id : ProjectID ,
414+ node_id : NodeID ,
415+ produce_logs : Callable ,
416+ log_streamer_with_distributor : LogStreamer ,
417+ faker : Faker ,
418+ computation_done : Callable [[], bool ],
419+ ):
420+ class InvalidLoggerRabbitMessage (LoggerRabbitMessage ):
421+ channel_name : Literal ["simcore.services.logs.v2" ] = "simcore.services.logs.v2"
422+ node_id : NodeID | None
423+ messages : int
424+ log_level : int = logging .INFO
425+
426+ def routing_key (self ) -> str :
427+ return f"{ self .project_id } .{ self .log_level } "
428+
429+ log_rabbit_message = InvalidLoggerRabbitMessage (
430+ user_id = user_id ,
431+ project_id = project_id ,
432+ node_id = node_id ,
433+ messages = 100 ,
434+ log_level = logging .INFO ,
435+ )
436+ with pytest .raises (ValidationError ):
437+ LoggerRabbitMessage .parse_obj (log_rabbit_message .dict ())
438+
439+ await produce_logs ("expected" , log_message = log_rabbit_message )
440+
441+ ii : int = 0
442+ async for log in log_streamer_with_distributor .log_generator ():
443+ _ = JobLog .parse_raw (log )
444+ ii += 1
445+ assert ii == 0
446+
447+
402448async def test_log_generator (mocker : MockFixture , faker : Faker ):
403449 mocker .patch (
404450 "simcore_service_api_server.services.log_streaming.LogStreamer._project_done" ,
0 commit comments