Skip to content

Commit 424942d

Browse files
committed
chore(config): test previewHeaderInjectorTransport.RoundTrip
Per request of @deiga (#2514 (comment)), this adds tests for previewHeaderInjectorTransport.RoundTrip logic around application/octest-stream header handling. See google/go-github#3392 for context. Signed-off-by: Mike Ball <mikedball@gmail.com>
1 parent 1448f3c commit 424942d

File tree

1 file changed

+215
-0
lines changed

1 file changed

+215
-0
lines changed

github/config_test.go

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package github
22

33
import (
44
"context"
5+
"net/http"
6+
"net/http/httptest"
57
"testing"
68

79
"github.com/shurcooL/githubv4"
@@ -300,3 +302,216 @@ func TestAccConfigMeta(t *testing.T) {
300302
}
301303
})
302304
}
305+
306+
func TestPreviewHeaderInjectorTransport_RoundTrip(t *testing.T) {
307+
tests := []struct {
308+
name string
309+
previewHeaders map[string]string
310+
existingHeaders map[string]string
311+
expectedHeaders map[string]string
312+
expectRoundTripCall bool
313+
}{
314+
{
315+
name: "empty preview headers",
316+
previewHeaders: map[string]string{},
317+
existingHeaders: map[string]string{"User-Agent": "test"},
318+
expectedHeaders: map[string]string{"User-Agent": "test"},
319+
expectRoundTripCall: true,
320+
},
321+
{
322+
name: "add new preview header",
323+
previewHeaders: map[string]string{
324+
"Accept": "application/vnd.github.v3+json",
325+
},
326+
existingHeaders: map[string]string{},
327+
expectedHeaders: map[string]string{
328+
"Accept": "application/vnd.github.v3+json",
329+
},
330+
expectRoundTripCall: true,
331+
},
332+
{
333+
name: "append to existing header",
334+
previewHeaders: map[string]string{
335+
"Accept": "application/vnd.github.preview+json",
336+
},
337+
existingHeaders: map[string]string{
338+
"Accept": "application/json",
339+
},
340+
expectedHeaders: map[string]string{
341+
"Accept": "application/json,application/vnd.github.preview+json",
342+
},
343+
expectRoundTripCall: true,
344+
},
345+
{
346+
name: "preserve existing Accept application/octet-stream",
347+
previewHeaders: map[string]string{
348+
"Accept": "application/vnd.github.preview+json",
349+
},
350+
existingHeaders: map[string]string{
351+
"Accept": "application/octet-stream",
352+
},
353+
expectedHeaders: map[string]string{
354+
"Accept": "application/octet-stream",
355+
},
356+
expectRoundTripCall: true,
357+
},
358+
{
359+
name: "preserve existing accept application/octet-stream (lowercase)",
360+
previewHeaders: map[string]string{
361+
"accept": "application/vnd.github.preview+json",
362+
},
363+
existingHeaders: map[string]string{
364+
"accept": "application/octet-stream",
365+
},
366+
expectedHeaders: map[string]string{
367+
"Accept": "application/octet-stream",
368+
},
369+
expectRoundTripCall: true,
370+
},
371+
{
372+
name: "preserve existing Accept application/octet-stream (mixed case)",
373+
previewHeaders: map[string]string{
374+
"AcCePt": "application/vnd.github.preview+json",
375+
},
376+
existingHeaders: map[string]string{
377+
"Accept": "application/octet-stream",
378+
},
379+
expectedHeaders: map[string]string{
380+
"Accept": "application/octet-stream",
381+
},
382+
expectRoundTripCall: true,
383+
},
384+
{
385+
name: "multiple preview headers",
386+
previewHeaders: map[string]string{
387+
"Accept": "application/vnd.github.v3+json",
388+
"X-GitHub-Api-Version": "2022-11-28",
389+
},
390+
existingHeaders: map[string]string{},
391+
expectedHeaders: map[string]string{
392+
"Accept": "application/vnd.github.v3+json",
393+
"X-GitHub-Api-Version": "2022-11-28",
394+
},
395+
expectRoundTripCall: true,
396+
},
397+
{
398+
name: "append multiple preview headers to existing",
399+
previewHeaders: map[string]string{
400+
"Accept": "application/vnd.github.v3+json",
401+
"X-GitHub-Api-Version": "2022-11-28",
402+
},
403+
existingHeaders: map[string]string{
404+
"Accept": "application/json",
405+
"X-GitHub-Api-Version": "2021-01-01",
406+
},
407+
expectedHeaders: map[string]string{
408+
"Accept": "application/json,application/vnd.github.v3+json",
409+
"X-GitHub-Api-Version": "2021-01-01,2022-11-28",
410+
},
411+
expectRoundTripCall: true,
412+
},
413+
{
414+
name: "non-accept headers always append",
415+
previewHeaders: map[string]string{
416+
"X-Custom-Header": "preview-value",
417+
},
418+
existingHeaders: map[string]string{
419+
"X-Custom-Header": "application/octet-stream",
420+
},
421+
expectedHeaders: map[string]string{
422+
"X-Custom-Header": "application/octet-stream,preview-value",
423+
},
424+
expectRoundTripCall: true,
425+
},
426+
{
427+
name: "accept header with different value appends",
428+
previewHeaders: map[string]string{
429+
"Accept": "application/vnd.github.preview+json",
430+
},
431+
existingHeaders: map[string]string{
432+
"Accept": "application/json",
433+
},
434+
expectedHeaders: map[string]string{
435+
"Accept": "application/json,application/vnd.github.preview+json",
436+
},
437+
expectRoundTripCall: true,
438+
},
439+
}
440+
441+
for _, tt := range tests {
442+
t.Run(tt.name, func(t *testing.T) {
443+
// Create a mock RoundTripper that records the request
444+
var capturedRequest *http.Request
445+
mockRT := &mockRoundTripper{
446+
roundTripFunc: func(req *http.Request) (*http.Response, error) {
447+
capturedRequest = req
448+
return &http.Response{
449+
StatusCode: http.StatusOK,
450+
Body: http.NoBody,
451+
}, nil
452+
},
453+
}
454+
455+
injector := &previewHeaderInjectorTransport{
456+
rt: mockRT,
457+
previewHeaders: tt.previewHeaders,
458+
}
459+
460+
// Create a test request with existing headers
461+
req := httptest.NewRequest(http.MethodGet, "https://api.github.com/test", nil)
462+
for name, value := range tt.existingHeaders {
463+
req.Header.Set(name, value)
464+
}
465+
466+
// Execute RoundTrip
467+
resp, err := injector.RoundTrip(req)
468+
469+
// Verify no error
470+
if err != nil {
471+
t.Fatalf("unexpected error: %v", err)
472+
}
473+
474+
// Verify response
475+
if resp == nil {
476+
t.Fatal("expected non-nil response")
477+
}
478+
479+
// Verify RoundTrip was called on the underlying transport
480+
if tt.expectRoundTripCall && capturedRequest == nil {
481+
t.Fatal("expected RoundTrip to be called on underlying transport")
482+
}
483+
484+
// Verify headers in the captured request
485+
if capturedRequest != nil {
486+
for name, expectedValue := range tt.expectedHeaders {
487+
actualValue := capturedRequest.Header.Get(name)
488+
if actualValue != expectedValue {
489+
t.Errorf("header %q: expected %q, got %q", name, expectedValue, actualValue)
490+
}
491+
}
492+
493+
// Verify no unexpected headers were added
494+
for name := range capturedRequest.Header {
495+
if _, exists := tt.expectedHeaders[name]; !exists {
496+
// Allow headers that were in existingHeaders but not in expectedHeaders
497+
if _, wasExisting := tt.existingHeaders[name]; !wasExisting {
498+
t.Errorf("unexpected header %q: %q", name, capturedRequest.Header.Get(name))
499+
}
500+
}
501+
}
502+
}
503+
})
504+
}
505+
}
506+
507+
// mockRoundTripper is a mock implementation of http.RoundTripper for testing
508+
type mockRoundTripper struct {
509+
roundTripFunc func(*http.Request) (*http.Response, error)
510+
}
511+
512+
func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
513+
if m.roundTripFunc != nil {
514+
return m.roundTripFunc(req)
515+
}
516+
return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody}, nil
517+
}

0 commit comments

Comments
 (0)