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}