@@ -279,23 +279,23 @@ void testListenerForwardingEmitsJobTaskAndErrorEvents() throws Exception {
279279 Thread .sleep (50 );
280280 }
281281
282- Consumer <JobStatusEventDTO > jobStatusEventDTOConsumer = jobListener .get ();
283- Consumer <TaskStatusEventDTO > taskStatusEventDTOConsumerStarted = taskStartedListener .get ();
284- Consumer <TaskStatusEventDTO > taskStatusEventDTOConsumerCompleted = taskCompletedListener .get ();
285- Consumer <ExecutionErrorEventDTO > executionErrorEventDTOConsumer = errorListener .get ();
282+ Consumer <JobStatusEventDTO > jobStatusEventConsumer = jobListener .get ();
283+ Consumer <TaskStatusEventDTO > taskStatusEventStartedConsumer = taskStartedListener .get ();
284+ Consumer <TaskStatusEventDTO > taskStatusEventCompletedConsumer = taskCompletedListener .get ();
285+ Consumer <ExecutionErrorEventDTO > executionErrorEventConsumer = errorListener .get ();
286286
287- assertThat (jobStatusEventDTOConsumer ).isNotNull ();
288- assertThat (taskStatusEventDTOConsumerStarted ).isNotNull ();
289- assertThat (taskStatusEventDTOConsumerCompleted ).isNotNull ();
290- assertThat (executionErrorEventDTOConsumer ).isNotNull ();
287+ assertThat (jobStatusEventConsumer ).isNotNull ();
288+ assertThat (taskStatusEventStartedConsumer ).isNotNull ();
289+ assertThat (taskStatusEventCompletedConsumer ).isNotNull ();
290+ assertThat (executionErrorEventConsumer ).isNotNull ();
291291
292292 // Fire synthetic events
293- jobStatusEventDTOConsumer .accept (new JobStatusEventDTO (jobId , "STARTED" , Instant .now ()));
294- taskStatusEventDTOConsumerStarted .accept (
293+ jobStatusEventConsumer .accept (new JobStatusEventDTO (jobId , "STARTED" , Instant .now ()));
294+ taskStatusEventStartedConsumer .accept (
295295 new TaskStatusEventDTO (jobId , 1L , STARTED , null , null , Instant .now (), null ));
296- taskStatusEventDTOConsumerCompleted .accept (
296+ taskStatusEventCompletedConsumer .accept (
297297 new TaskStatusEventDTO (jobId , 1L , COMPLETED , "t" , "type" , null , Instant .now ()));
298- executionErrorEventDTOConsumer .accept (new ExecutionErrorEventDTO (jobId , "Oops" ));
298+ executionErrorEventConsumer .accept (new ExecutionErrorEventDTO (jobId , "Oops" ));
299299
300300 // Allow a brief moment for SSE forwarding to flush before finishing
301301 Duration duration = Duration .ofMillis (50 );
@@ -363,21 +363,19 @@ void testPendingEventsBoundedAndFlushedOnAttach() throws Exception {
363363 // Obtain the key from the controller's 'runs' map (wait briefly if needed)
364364 String key = waitForRunKey ();
365365
366- // Remove emitters to force buffering
367- Object emitters = ReflectionTestUtils .getField (controller , "emitter" );
366+ // Remove emitter to force buffering
367+ Object emitter = ReflectionTestUtils .getField (controller , "emitter" );
368368
369- assert emitters != null ;
369+ assert emitter != null ;
370370
371- if (emitters instanceof Cache <?, ?> cache ) {
371+ if (emitter instanceof Cache <?, ?> cache ) {
372372 @ SuppressWarnings ("unchecked" )
373- Cache <String , CopyOnWriteArrayList <SseEmitter >> emitterCache =
374- (Cache <String , CopyOnWriteArrayList <SseEmitter >>) cache ;
373+ Cache <String , SseEmitter > emitterCache = (Cache <String , SseEmitter >) cache ;
375374
376375 emitterCache .invalidate (key );
377- } else if (emitters instanceof ConcurrentMap <?, ?>) {
376+ } else if (emitter instanceof ConcurrentMap <?, ?>) {
378377 @ SuppressWarnings ("unchecked" )
379- ConcurrentMap <String , CopyOnWriteArrayList <SseEmitter >> emitterMap =
380- (ConcurrentMap <String , CopyOnWriteArrayList <SseEmitter >>) emitters ;
378+ ConcurrentMap <String , SseEmitter > emitterMap = (ConcurrentMap <String , SseEmitter >) emitter ;
381379
382380 emitterMap .remove (key );
383381 }
@@ -476,14 +474,12 @@ void testPendingEventsClearedOnStop() throws Exception {
476474
477475 if (emitter instanceof Cache <?, ?> cache ) {
478476 @ SuppressWarnings ("unchecked" )
479- Cache <String , CopyOnWriteArrayList <SseEmitter >> emitterCache =
480- (Cache <String , CopyOnWriteArrayList <SseEmitter >>) cache ;
477+ Cache <String , SseEmitter > emitterCache = (Cache <String , SseEmitter >) cache ;
481478
482479 emitterCache .invalidate (key );
483480 } else if (emitter instanceof ConcurrentMap <?, ?>) {
484481 @ SuppressWarnings ("unchecked" )
485- ConcurrentMap <String , CopyOnWriteArrayList <SseEmitter >> emitterMap =
486- (ConcurrentMap <String , CopyOnWriteArrayList <SseEmitter >>) emitter ;
482+ ConcurrentMap <String , SseEmitter > emitterMap = (ConcurrentMap <String , SseEmitter >) emitter ;
487483
488484 emitterMap .remove (key );
489485 }
@@ -546,11 +542,18 @@ void testPendingEventsClearedOnStop() throws Exception {
546542 }
547543
548544 private static String normalizeSse (String body ) {
549- // Normalize potential double-space after 'event:' introduced by different SSE encoders
550- String normalized = body .replace ("event: " , "event: " );
545+ if (body == null || body .isEmpty ()) {
546+ return body ;
547+ }
551548
552- // Also collapse any accidental triple spaces just in case
553- return normalized .replace ("event: " , "event: " );
549+ // Normalize whitespace after 'event:' at the beginning of SSE lines, regardless of encoder quirks.
550+ // This collapses any sequence of whitespace after 'event:' to a single space.
551+ // Example:
552+ // event: started
553+ // event:\tcompleted
554+ // becomes:
555+ // event: started
556+ return body .replaceAll ("(?m)^(event:)(\\ s*)" , "$1 " );
554557 }
555558
556559 @ Configuration
0 commit comments