readiness_internal_test.go RawHistoryFolder

1package deployment
2
3import (
4	"context"
5	"net"
6	"net/http"
7	"net/http/httptest"
8	"testing"
9	"time"
10
11	"github.com/stretchr/testify/assert"
12	"github.com/stretchr/testify/require"
13
14	"github.com/bnema/gordon/internal/domain"
15)
16
17// TestWaitHTTPReady_ProbeURLKeepsLoopbackAuthority proves the probe URL is
18// built from an immutable loopback host and an escaped path, so no declared
19// path can redirect the request to a different authority. The Host header
20// must name the declared container port, not the random published port.
21func TestWaitHTTPReady_ProbeURLKeepsLoopbackAuthority(t *testing.T) {
22	var gotURL, gotHost string
23	deps := ProbeDeps{httpGet: func(_ context.Context, url, hostAuthority string) (int, error) {
24		gotURL, gotHost = url, hostAuthority
25		return 200, nil
26	}}
27	spec := domain.AppService{
28		Name:      "web",
29		HTTP:      []domain.AppHTTPInterface{{Host: "web.example.com", Port: 8080}},
30		Readiness: domain.AppReadiness{Type: domain.AppReadinessHTTP, Path: "/healthz?probe=1", Timeout: time.Second},
31	}
32	require.NoError(t, waitHTTPReadyWithDeps(context.Background(), deps, spec, map[int]int{8080: 18080}))
33	assert.Equal(t, "http://127.0.0.1:18080/healthz?probe=1", gotURL)
34	assert.Equal(t, "127.0.0.1:8080", gotHost, "the Host header names the declared container port, not the published port")
35}
36
37// TestWaitHTTPReady_SendsContainerPortAsHostAuthority is the qBittorrent
38// regression: readiness dials the random loopback publication, but the
39// workload rejects a Host whose port is not its declared container port
40// with 401 "Invalid Host header, port mismatch". The probe must dial the
41// published port while sending the container port as the Host authority.
42func TestWaitHTTPReady_SendsContainerPortAsHostAuthority(t *testing.T) {
43	const containerPort = 8080
44	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45		if r.Host != "127.0.0.1:8080" {
46			http.Error(w, "Invalid Host header, port mismatch", http.StatusUnauthorized)
47			return
48		}
49		w.WriteHeader(http.StatusOK)
50	}))
51	defer server.Close()
52	publishedPort := server.Listener.Addr().(*net.TCPAddr).Port
53
54	spec := domain.AppService{
55		Name:      "qbittorrent",
56		HTTP:      []domain.AppHTTPInterface{{Host: "qbit.example.com", Port: containerPort}},
57		Readiness: domain.AppReadiness{Type: domain.AppReadinessHTTP, Path: "/api/v2/app/version", Timeout: 2 * time.Second},
58	}
59	require.NoError(t, waitHTTPReadyWithDeps(context.Background(), ProbeDeps{httpGet: httpGetOnce}, spec, map[int]int{containerPort: publishedPort}))
60}
61
62// TestWaitHTTPReady_HangingProbeRespectsDeadline proves a workload that
63// never answers cannot hold the readiness operation open past its bound.
64func TestWaitHTTPReady_HangingProbeRespectsDeadline(t *testing.T) {
65	deps := ProbeDeps{httpGet: func(ctx context.Context, _, _ string) (int, error) {
66		<-ctx.Done()
67		return 0, ctx.Err()
68	}}
69	spec := domain.AppService{
70		Name:      "web",
71		HTTP:      []domain.AppHTTPInterface{{Host: "web.example.com", Port: 8080}},
72		Readiness: domain.AppReadiness{Type: domain.AppReadinessHTTP, Path: "/healthz", Timeout: time.Second},
73	}
74	start := time.Now()
75	err := waitHTTPReadyWithDeps(context.Background(), deps, spec, map[int]int{8080: 18080})
76	require.Error(t, err)
77	assert.Less(t, time.Since(start), 6*time.Second)
78}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close