@@ -392,7 +392,7 @@ func TestHTTPGatewayGetOperationsErrors(t *testing.T) {
392392 assert .Contains (t , w .Body .String (), assert .AnError .Error ())
393393}
394394
395- // TestHTTPGatewayStreamingResponse verifies that chunked encoding is used for streaming responses
395+ // TestHTTPGatewayStreamingResponse verifies that streaming produces valid JSON array
396396func TestHTTPGatewayStreamingResponse (t * testing.T ) {
397397 gw := setupHTTPGatewayNoServer (t , "" )
398398
@@ -424,12 +424,17 @@ func TestHTTPGatewayStreamingResponse(t *testing.T) {
424424 gw .router .ServeHTTP (w , r )
425425
426426 assert .Equal (t , http .StatusOK , w .Code )
427-
428427 assert .Equal (t , "application/json" , w .Header ().Get ("Content-Type" ))
429428
430- assert .Equal (t , "identity" , w .Header ().Get ("Content-Encoding" ))
431-
432429 body := w .Body .String ()
430+
431+ // Verify response is valid JSON array
432+ var jsonArray []map [string ]any
433+ err = json .Unmarshal ([]byte (body ), & jsonArray )
434+ require .NoError (t , err , "Response should be valid JSON array" )
435+
436+ // We should have individual trace objects in the array
437+ assert .GreaterOrEqual (t , len (jsonArray ), 1 , "Should have at least 1 trace" )
433438 assert .Contains (t , body , "foobar" ) // First trace span name
434439 assert .Contains (t , body , "second-span" ) // Second trace span name
435440}
@@ -467,6 +472,12 @@ func TestHTTPGatewayStreamingMultipleBatches(t *testing.T) {
467472 assert .Equal (t , http .StatusOK , w .Code )
468473
469474 body := w .Body .String ()
475+
476+ // Verify response is valid JSON
477+ var jsonArray []map [string ]any
478+ err = json .Unmarshal ([]byte (body ), & jsonArray )
479+ require .NoError (t , err , "Response should be valid JSON array" )
480+
470481 assert .Contains (t , body , "foobar" )
471482 assert .Contains (t , body , "batch2-span" )
472483}
@@ -574,7 +585,14 @@ func TestHTTPGatewayStreamingWithEmptyBatches(t *testing.T) {
574585 gw .router .ServeHTTP (w , r )
575586
576587 assert .Equal (t , http .StatusOK , w .Code )
577- assert .Contains (t , w .Body .String (), "foobar" )
588+
589+ body := w .Body .String ()
590+ // Verify response is valid JSON
591+ var jsonArray []map [string ]any
592+ err = json .Unmarshal ([]byte (body ), & jsonArray )
593+ require .NoError (t , err , "Response should be valid JSON array" )
594+
595+ assert .Contains (t , body , "foobar" )
578596}
579597
580598// TestHTTPGatewayStreamingNoTracesFound tests 404 when no traces exist
@@ -615,10 +633,17 @@ func TestHTTPGatewayFindTracesStreaming(t *testing.T) {
615633 gw .router .ServeHTTP (w , r )
616634
617635 assert .Equal (t , http .StatusOK , w .Code )
618- assert .Contains (t , w .Body .String (), "foobar" )
636+
637+ body := w .Body .String ()
638+ // Verify response is valid JSON
639+ var jsonArray []map [string ]any
640+ err = json .Unmarshal ([]byte (body ), & jsonArray )
641+ require .NoError (t , err , "Response should be valid JSON array" )
642+
643+ assert .Contains (t , body , "foobar" )
619644}
620645
621- // TestHTTPGatewayStreamingMarshalError tests handling of marshal errors during streaming
646+ // TestHTTPGatewayStreamingMarshalError tests handling of write errors during streaming
622647func TestHTTPGatewayStreamingMarshalError (t * testing.T ) {
623648 gw := setupHTTPGatewayNoServer (t , "" )
624649
@@ -647,15 +672,15 @@ func TestHTTPGatewayStreamingMarshalError(t *testing.T) {
647672 gw .router = & mux.Router {}
648673 hgw .RegisterRoutes (gw .router )
649674
650- // Use a ResponseWriter that fails immediately
675+ // Use a ResponseWriter that fails immediately on first write
651676 w := & failingWriter {
652677 ResponseRecorder : httptest .NewRecorder (),
653678 failImmediately : true ,
654679 }
655680 gw .router .ServeHTTP (w , r )
656681
657- // Should log the marshal error
658- assert .Contains (t , log .String (), "Failed to marshal trace chunk " )
682+ // Should log error for failing to write opening bracket (first write operation)
683+ assert .Contains (t , log .String (), "Failed to write opening bracket " )
659684}
660685
661686// failingWriter is a ResponseWriter that simulates write failures
@@ -709,8 +734,15 @@ func TestHTTPGatewayStreamingFirstChunkWrite(t *testing.T) {
709734 gw .router .ServeHTTP (w , r )
710735
711736 assert .Equal (t , http .StatusOK , w .Code )
712- assert .Contains (t , w .Body .String (), "foobar" )
713- assert .Contains (t , w .Body .String (), "span2" )
737+
738+ body := w .Body .String ()
739+ // Verify response is valid JSON
740+ var jsonArray []map [string ]any
741+ err = json .Unmarshal ([]byte (body ), & jsonArray )
742+ require .NoError (t , err , "Response should be valid JSON array" )
743+
744+ assert .Contains (t , body , "foobar" )
745+ assert .Contains (t , body , "span2" )
714746}
715747
716748// TestHTTPGatewayStreamingErrorBeforeFirstChunk tests error handling before streaming starts
@@ -784,8 +816,8 @@ func TestHTTPGatewayStreamingFallbackNoTraces(t *testing.T) {
784816 assert .Contains (t , w .ResponseRecorder .Body .String (), "No traces found" )
785817}
786818
787- // TestHTTPGatewayStreamingClientSideParsing demonstrates how clients should parse
788- // NDJSON (newline-delimited JSON) responses from the streaming API
819+ // TestHTTPGatewayStreamingClientSideParsing verifies that the streaming response
820+ // is valid JSON that clients can parse normally
789821func TestHTTPGatewayStreamingClientSideParsing (t * testing.T ) {
790822 gw := setupHTTPGateway (t , "" )
791823
@@ -826,8 +858,6 @@ func TestHTTPGatewayStreamingClientSideParsing(t *testing.T) {
826858 assert .Equal (t , http .StatusOK , resp .StatusCode )
827859 assert .Equal (t , "application/json" , resp .Header .Get ("Content-Type" ))
828860
829- assert .Equal (t , "identity" , resp .Header .Get ("Content-Encoding" ), "Should use streaming path" )
830-
831861 body := make ([]byte , 0 )
832862 buf := make ([]byte , 1024 )
833863 for {
@@ -842,47 +872,22 @@ func TestHTTPGatewayStreamingClientSideParsing(t *testing.T) {
842872
843873 bodyStr := string (body )
844874
845- newlineCount := 0
846- for _ , b := range body {
847- if b == '\n' {
848- newlineCount ++
849- }
850- }
875+ // The response MUST be valid JSON that can be parsed as a whole
876+ var jsonArray []map [string ]any
877+ err = json .Unmarshal (body , & jsonArray )
878+ require .NoError (t , err , "Response should be valid JSON array that can be parsed" )
851879
852- if newlineCount > 1 {
853- var combinedObj map [string ]any
854- err = json .Unmarshal (body , & combinedObj )
855- require .Error (t , err , "Combined response with multiple chunks should NOT be valid JSON - it's NDJSON format" )
856- }
880+ // Verify we got multiple trace results
881+ assert .GreaterOrEqual (t , len (jsonArray ), 3 , "Should have at least 3 trace objects in array" )
857882
858- lines := 0
859- currentPos := 0
860- validChunks := []map [string ]any {}
861-
862- for i := 0 ; i < len (body ); i ++ {
863- if body [i ] == '\n' {
864- line := body [currentPos :i ]
865- if len (line ) > 0 {
866- // Each individual line MUST be valid JSON
867- var jsonObj map [string ]any
868- err := json .Unmarshal (line , & jsonObj )
869- require .NoError (t , err , "Each line should be valid JSON independently" )
870-
871- // Verify it has the expected structure with a "result" field
872- result , hasResult := jsonObj ["result" ]
873- assert .True (t , hasResult , "Each chunk should have a 'result' field" )
874- assert .NotNil (t , result , "Result should not be nil" )
875-
876- validChunks = append (validChunks , jsonObj )
877- lines ++
878- }
879- currentPos = i + 1
880- }
883+ // Each element should have a "result" field
884+ for i , obj := range jsonArray {
885+ result , hasResult := obj ["result" ]
886+ assert .True (t , hasResult , "Element %d should have a 'result' field" , i )
887+ assert .NotNil (t , result , "Element %d result should not be nil" , i )
881888 }
882889
883- assert .GreaterOrEqual (t , lines , 1 , "Should receive at least 1 NDJSON line" )
884- assert .GreaterOrEqual (t , len (validChunks ), 1 , "Should have parsed at least 1 valid chunk" )
885-
890+ // Verify all traces are present in the response
886891 assert .Contains (t , bodyStr , "foobar" , "Should contain first trace" )
887892 assert .Contains (t , bodyStr , "client-test-span" , "Should contain second trace" )
888893 assert .Contains (t , bodyStr , "third-span" , "Should contain third trace" )
0 commit comments