test(http): cover transport isolation, TLS clone, and must-style panic

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

oesni committed May 4, 2026 at 14:28 UTC 385463c5ef05b96f24463a6d5efc37d2d9aef53d
1 file changed +83
utils/http_test.go new
+83
@@ -0,0 +1,83 @@
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) }