Skip to content

Commit d5e51a6

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 2407ae3 commit d5e51a6

1 file changed

Lines changed: 215 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)