@@ -2,6 +2,7 @@ package graphql
22
33import (
44 "bytes"
5+ "context"
56 "io"
67 "net/http"
78 "net/url"
@@ -590,6 +591,84 @@ func TestRead_GraphQLErrorWithoutMessage_FallsBackToJSON(t *testing.T) {
590591 }
591592}
592593
594+ // TestRead_EmitsRequestBodyToHTTPLogWhenEnabled asserts that when a context
595+ // logger is attached, the rendered GraphQL request body and wire URL are
596+ // surfaced before the Do() call — closing the gap where --http.log.enabled
597+ // previously only showed the post-transform projection.
598+ func TestRead_EmitsRequestBodyToHTTPLogWhenEnabled (t * testing.T ) {
599+ var buf bytes.Buffer
600+ c := & fakeAnySdkClient {bodyJSON : `{"data": {"rows": [{"id": 1}]}}` }
601+ req := newTestRequest (t )
602+ req = req .WithContext (ContextWithHTTPLogger (context .Background (), & buf ))
603+
604+ r , err := NewStandardGQLReader (
605+ c , req , 0 , `query { rows { id } }` , map [string ]interface {}{}, "" ,
606+ "$.data.rows[*]" , "$.data.__no_cursor[*]" ,
607+ )
608+ if err != nil {
609+ t .Fatalf ("NewStandardGQLReader: %v" , err )
610+ }
611+ if _ , err := r .Read (); err != nil && err != io .EOF {
612+ t .Fatalf ("Read: %v" , err )
613+ }
614+
615+ out := buf .String ()
616+ if ! strings .Contains (out , "query { rows { id } }" ) {
617+ t .Errorf ("expected rendered request body in log, got:\n %s" , out )
618+ }
619+ if ! strings .Contains (out , "https://api.example.test/graphql" ) {
620+ t .Errorf ("expected wire URL in log, got:\n %s" , out )
621+ }
622+ }
623+
624+ // TestRead_EmitsRawResponseToHTTPLogWhenEnabled asserts that the naked
625+ // pre-transform response body is surfaced when a context logger is attached.
626+ // This is the diagnostic that was missing for transform / templating failures.
627+ func TestRead_EmitsRawResponseToHTTPLogWhenEnabled (t * testing.T ) {
628+ var buf bytes.Buffer
629+ c := & fakeAnySdkClient {bodyJSON : `{"data":{"rows":[{"id":1}]}}` }
630+ req := newTestRequest (t )
631+ req = req .WithContext (ContextWithHTTPLogger (context .Background (), & buf ))
632+
633+ r , err := NewStandardGQLReader (
634+ c , req , 0 , `{ ignored }` , map [string ]interface {}{}, "" ,
635+ "$.data.rows[*]" , "$.data.__no_cursor[*]" ,
636+ )
637+ if err != nil {
638+ t .Fatalf ("NewStandardGQLReader: %v" , err )
639+ }
640+ if _ , err := r .Read (); err != nil && err != io .EOF {
641+ t .Fatalf ("Read: %v" , err )
642+ }
643+
644+ out := buf .String ()
645+ if ! strings .Contains (out , `"id":1` ) {
646+ t .Errorf ("expected raw response body in log, got:\n %s" , out )
647+ }
648+ }
649+
650+ // TestRead_DoesNotLogWhenHTTPLogDisabled asserts that with no logger attached
651+ // to the request context, Read() emits nothing — the opt-in shape mirrors the
652+ // REST acquire path's gating on runtimeCtx.HTTPLogEnabled.
653+ func TestRead_DoesNotLogWhenHTTPLogDisabled (t * testing.T ) {
654+ c := & fakeAnySdkClient {bodyJSON : `{"data":{"rows":[]}}` }
655+ req := newTestRequest (t ) // no logger in context
656+
657+ r , err := NewStandardGQLReader (
658+ c , req , 0 , `{ ignored }` , map [string ]interface {}{}, "" ,
659+ "$.data.rows[*]" , "$.data.__no_cursor[*]" ,
660+ )
661+ if err != nil {
662+ t .Fatalf ("NewStandardGQLReader: %v" , err )
663+ }
664+ if _ , err := r .Read (); err != nil && err != io .EOF {
665+ t .Fatalf ("Read: %v" , err )
666+ }
667+ // nothing to assert beyond "no panic and no log sink to fill" — the
668+ // negative case is covered by the structural check that nil-logger
669+ // branches in Read() are short-circuit.
670+ }
671+
593672// TestNewStandardGQLReaderWithCursor_KeysetRequiresFormat ensures a keyset
594673// configuration without a format template is rejected at construction time.
595674func TestNewStandardGQLReaderWithCursor_KeysetRequiresFormat (t * testing.T ) {
0 commit comments