| 1 | package utils |
| 2 | |
| 3 | import ( |
| 4 | "crypto/tls" |
| 5 | "net/http" |
| 6 | "testing" |
| 7 | ) |
| 8 | |
| 9 | func TestNewHTTPClientTransportIsolation(t *testing.T) { |
| 10 | t.Parallel() |
| 11 | |
| 12 | a := NewHTTPClient() |
| 13 | b := NewHTTPClient() |
| 14 | |
| 15 | ta := mustTransportOf(a) |
| 16 | tb := mustTransportOf(b) |
| 17 | |
| 18 | if ta == tb { |
| 19 | t.Fatalf("NewHTTPClient() returned clients sharing the same *http.Transport") |
| 20 | } |
| 21 | if ta == baseTransport { |
| 22 | t.Fatalf("NewHTTPClient() transport aliases baseTransport; mutations would leak across all clients") |
| 23 | } |
| 24 | if ta == mustTransportOf(DefaultHTTPClient) { |
| 25 | t.Fatalf("NewHTTPClient() transport aliases DefaultHTTPClient's transport") |
| 26 | } |
| 27 | |
| 28 | // Mutating one client's transport must not affect the other. |
| 29 | ta.MaxIdleConns = 7 |
| 30 | if tb.MaxIdleConns == 7 { |
| 31 | t.Fatalf("mutation on client A leaked into client B (MaxIdleConns)") |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | func TestWithHTTPTLSConfigClonesInput(t *testing.T) { |
| 36 | t.Parallel() |
| 37 | |
| 38 | original := &tls.Config{ServerName: "before", InsecureSkipVerify: false} |
| 39 | c := NewHTTPClient(WithHTTPTLSConfig(original)) |
| 40 | |
| 41 | // Mutate the caller's config after the option was applied; the transport |
| 42 | // must not observe the change because WithHTTPTLSConfig clones the input. |
| 43 | original.ServerName = "after" |
| 44 | original.InsecureSkipVerify = true |
| 45 | |
| 46 | got := mustTransportOf(c).TLSClientConfig |
| 47 | if got == original { |
| 48 | t.Fatalf("WithHTTPTLSConfig stored the caller's *tls.Config by reference") |
| 49 | } |
| 50 | if got.ServerName != "before" || got.InsecureSkipVerify { |
| 51 | t.Fatalf("WithHTTPTLSConfig did not clone tls.Config: got %+v", got) |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | func TestWithHTTPTLSConfigNilClearsTransportConfig(t *testing.T) { |
| 56 | t.Parallel() |
| 57 | |
| 58 | c := NewHTTPClient(WithHTTPTLSConfig(&tls.Config{ServerName: "x"})) |
| 59 | WithHTTPTLSConfig(nil)(c) |
| 60 | |
| 61 | if mustTransportOf(c).TLSClientConfig != nil { |
| 62 | t.Fatalf("WithHTTPTLSConfig(nil) did not clear TLSClientConfig") |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | func TestMustTransportOfPanicsOnForeignTransport(t *testing.T) { |
| 67 | t.Parallel() |
| 68 | |
| 69 | defer func() { |
| 70 | if r := recover(); r == nil { |
| 71 | t.Fatalf("mustTransportOf did not panic on non-*http.Transport RoundTripper") |
| 72 | } |
| 73 | }() |
| 74 | |
| 75 | c := &http.Client{Transport: roundTripperFunc(func(*http.Request) (*http.Response, error) { |
| 76 | return nil, nil |
| 77 | })} |
| 78 | _ = mustTransportOf(c) |
| 79 | } |
| 80 | |
| 81 | type roundTripperFunc func(*http.Request) (*http.Response, error) |
| 82 | |
| 83 | func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) } |