@@ -13,23 +13,26 @@ public async Task MapGenAIEventStream_ShouldEmitCorrectEventType(string status,
1313
1414 var readTask = Task . Run ( async ( ) =>
1515 {
16- var response = await client . GetAsync ( "/api/v1/events/genai" , HttpCompletionOption . ResponseHeadersRead ) ;
16+ using var response = await client . GetAsync ( "/api/v1/events/genai" , HttpCompletionOption . ResponseHeadersRead ) ;
1717 await using var stream = await response . Content . ReadAsStreamAsync ( ) ;
1818 using var reader = new StreamReader ( stream ) ;
1919
20- var line = await reader . ReadLineAsync ( ) ;
21- response . Dispose ( ) ;
22- return line ;
20+ while ( true )
21+ {
22+ var line = await reader . ReadLineAsync ( ) ;
23+ if ( line == null ) return null ;
24+ if ( line . StartsWith ( "event:" ) ) return line ;
25+ }
2326 } ) ;
2427
25- await Task . Delay ( 100 , TestContext . Current . CancellationToken ) ;
28+ while ( sseStream . ClientCount == 0 ) await Task . Delay ( 50 , TestContext . Current . CancellationToken ) ;
2629
2730 var genAiEvent = status == "Completed"
2831 ? new GenAIEvent ( Guid . NewGuid ( ) , "Test summary" , DateTimeOffset . UtcNow )
2932 : new GenAIEvent ( Guid . NewGuid ( ) , string . Empty , DateTimeOffset . UtcNow , "Service error" ) ;
3033 sseStream . Publish ( genAiEvent ) ;
3134
32- using var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 2 ) ) ;
35+ using var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 15 ) ) ;
3336 var eventLine = await readTask . WaitAsync ( cts . Token ) ;
3437
3538 eventLine . Should ( ) . Be ( $ "event: { expectedEventType } ") ;
@@ -42,16 +45,31 @@ public async Task MapGenAIEventStream_WithMultipleEvents_ShouldStreamInOrder()
4245 using var server = SseTestHelpers . CreateSseTestServer ( sseStream , endpoints => endpoints . MapGenAIEventStream ( ) ) ;
4346
4447 var client = server . CreateClient ( ) ;
45- using var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 5 ) ) ;
48+ using var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 30 ) ) ;
4649 var token = cts . Token ;
4750 var readTask = Task . Run ( ( ) => ReadEventsAsync ( client , 3 , token ) , token ) ;
4851
49- await Task . Delay ( 300 , TestContext . Current . CancellationToken ) ;
52+ // Wait for client to connect with timeout
53+ var waitStart = DateTime . UtcNow ;
54+ while ( sseStream . ClientCount == 0 )
55+ {
56+ if ( DateTime . UtcNow - waitStart > TimeSpan . FromSeconds ( 10 ) )
57+ throw new TimeoutException ( "Client did not connect within timeout" ) ;
58+ await Task . Delay ( 50 , TestContext . Current . CancellationToken ) ;
59+ }
60+
61+ // Give the HTTP connection a moment to stabilize
62+ await Task . Delay ( 100 , TestContext . Current . CancellationToken ) ;
63+
5064 sseStream . Publish ( new GenAIEvent ( Guid . NewGuid ( ) , "Summary 1" , DateTimeOffset . UtcNow ) ) ;
65+ await Task . Delay ( 50 , TestContext . Current . CancellationToken ) ;
66+
5167 sseStream . Publish ( new GenAIEvent ( Guid . NewGuid ( ) , "Summary 2" , DateTimeOffset . UtcNow ) ) ;
68+ await Task . Delay ( 50 , TestContext . Current . CancellationToken ) ;
69+
5270 sseStream . Publish ( new GenAIEvent ( Guid . NewGuid ( ) , string . Empty , DateTimeOffset . UtcNow , "Error occurred" ) ) ;
5371
54- var events = await readTask . WaitAsync ( TimeSpan . FromSeconds ( 2 ) , TestContext . Current . CancellationToken ) ;
72+ var events = await readTask . WaitAsync ( TimeSpan . FromSeconds ( 30 ) , TestContext . Current . CancellationToken ) ;
5573
5674 events [ 0 ] . Event . Should ( ) . Be ( "event: genai-completed" ) ;
5775 events [ 0 ] . Data . Should ( ) . Contain ( "Summary 1" ) ;
@@ -73,16 +91,29 @@ public async Task MapGenAIEventStream_WithMultipleEvents_ShouldStreamInOrder()
7391 using var reader = new StreamReader ( stream ) ;
7492
7593 var events = new List < ( string Event , string Data ) > ( ) ;
76- for ( var i = 0 ; i < count ; i ++ )
77- {
78- var eventLine = await reader . ReadLineAsync ( cancellationToken ) ;
79- var dataLine = await reader . ReadLineAsync ( cancellationToken ) ;
80-
81- if ( eventLine == null || dataLine == null )
82- throw new InvalidOperationException ( $ "Unexpected end of stream while reading event { i + 1 } of { count } ") ;
94+ string ? currentEvent = null ;
95+ string ? currentData = null ;
8396
84- events . Add ( ( eventLine , dataLine ) ) ;
85- await reader . ReadLineAsync ( cancellationToken ) ;
97+ while ( events . Count < count )
98+ {
99+ var line = await reader . ReadLineAsync ( cancellationToken ) ;
100+ if ( line == null ) break ;
101+
102+ if ( string . IsNullOrWhiteSpace ( line ) )
103+ {
104+ if ( currentEvent != null && currentData != null )
105+ {
106+ events . Add ( ( currentEvent , currentData ) ) ;
107+ currentEvent = null ;
108+ currentData = null ;
109+ }
110+ continue ;
111+ }
112+
113+ if ( line . StartsWith ( "event:" ) )
114+ currentEvent = line ;
115+ else if ( line . StartsWith ( "data:" ) )
116+ currentData = line ;
86117 }
87118
88119 return events ;
0 commit comments