httpclient_test.go

 1package httpclient
 2
 3import (
 4	"net/http"
 5	"net/http/httptest"
 6	"strings"
 7	"testing"
 8	"time"
 9)
10
11func TestTimeoutConstants(t *testing.T) {
12	cases := []struct {
13		name string
14		got  time.Duration
15		min  time.Duration
16	}{
17		{"PluginCallTimeout", PluginCallTimeout, time.Second},
18		{"RegistryFetchTimeout", RegistryFetchTimeout, time.Second},
19		{"RemoteImageTimeout", RemoteImageTimeout, time.Second},
20		{"InstallTimeout", InstallTimeout, time.Second},
21		{"UpdateCheckTimeout", UpdateCheckTimeout, time.Second},
22	}
23	for _, c := range cases {
24		if c.got < c.min {
25			t.Errorf("%s = %s, want at least %s", c.name, c.got, c.min)
26		}
27	}
28}
29
30func TestNew_AppliesTimeout(t *testing.T) {
31	c := New(7 * time.Second)
32	if c.Timeout != 7*time.Second {
33		t.Errorf("New(7s).Timeout = %s, want 7s", c.Timeout)
34	}
35}
36
37func TestNewWithRedirectCap_AppliesTimeoutAndRedirects(t *testing.T) {
38	c := NewWithRedirectCap(11*time.Second, 3)
39	if c.Timeout != 11*time.Second {
40		t.Errorf("Timeout = %s, want 11s", c.Timeout)
41	}
42	if c.CheckRedirect == nil {
43		t.Fatal("CheckRedirect is nil; want a redirect-cap function")
44	}
45
46	// Build a stubbed redirect chain and verify the cap fires at the
47	// configured maxRedirects.
48	req, _ := http.NewRequest(http.MethodGet, "http://example.invalid/", nil)
49	via := []*http.Request{}
50	for i := 0; i < 3; i++ {
51		if err := c.CheckRedirect(req, via); err != nil {
52			t.Fatalf("CheckRedirect rejected %d-redirect chain: %v", i, err)
53		}
54		via = append(via, req)
55	}
56	if err := c.CheckRedirect(req, via); err == nil {
57		t.Error("CheckRedirect(via len=3) returned nil; want stopped error")
58	} else if !strings.Contains(err.Error(), "stopped after 3 redirects") {
59		t.Errorf("CheckRedirect error = %q, want 'stopped after 3 redirects' substring", err.Error())
60	}
61}
62
63// TestNewWithRedirectCap_LiveServer is a defense-in-depth integration check
64// that the redirect cap is actually honored by net/http when wired up. It
65// uses an in-process server so it stays hermetic.
66func TestNewWithRedirectCap_LiveServer(t *testing.T) {
67	hops := 0
68	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
69		hops++
70		http.Redirect(w, r, "/next", http.StatusFound)
71	}))
72	defer server.Close()
73
74	c := NewWithRedirectCap(2*time.Second, 2)
75	resp, err := c.Get(server.URL + "/start")
76	if err == nil {
77		resp.Body.Close()
78		t.Fatal("expected redirect-cap error, got nil")
79	}
80	if !strings.Contains(err.Error(), "stopped after 2 redirects") {
81		t.Errorf("redirect error = %v, want substring 'stopped after 2 redirects'", err)
82	}
83}