carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "net"
5 "net/http"
6 "net/http/httptest"
7 "os/exec"
8 "strings"
9 "testing"
10)
11
12// spec §17 step 6 (codex R4-3, plan-R1 4): the gate fails on a 404 and on a
13// version mismatch, and a proxy in the environment cannot route around the
14// edge it names.
15func TestRegionServiceGate(t *testing.T) {
16 const version = "abc1234"
17 ok := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18 w.Header().Set("X-Carlos-Version", version)
19 }))
20 defer ok.Close()
21 unknown := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22 http.NotFound(w, r)
23 }))
24 defer unknown.Close()
25 hostPort := func(s *httptest.Server) (string, string) {
26 h, p, _ := net.SplitHostPort(s.Listener.Addr().String())
27 return h, p
28 }
29 run := func(srv *httptest.Server, want string, extraEnv ...string) (string, error) {
30 h, p := hostPort(srv)
31 cmd := exec.Command("./scripts/region-service-gate.sh", "probe.example", want, h)
32 cmd.Env = append(cmd.Environ(), append([]string{"GATE_PORT=" + p, "GATE_INSECURE=1", "GATE_SKIP_PUBLIC=1"}, extraEnv...)...)
33 out, err := cmd.CombinedOutput()
34 return string(out), err
35 }
36 if out, err := run(ok, version); err != nil {
37 t.Fatalf("a serving edge failed the gate: %v %s", err, out)
38 }
39 if out, err := run(unknown, version); err == nil || !strings.Contains(out, "FAIL") {
40 t.Fatalf("an unknown-host 404 passed: %s", out)
41 }
42 if out, err := run(ok, "other"); err == nil || !strings.Contains(out, "FAIL") {
43 t.Fatalf("a version mismatch passed: %s", out)
44 }
45 // A proxy that refuses everything: honoured, it would fail every check.
46 dead := "http://127.0.0.1:9"
47 if out, err := run(ok, version, "HTTPS_PROXY="+dead, "https_proxy="+dead, "ALL_PROXY="+dead, "all_proxy="+dead); err != nil {
48 t.Fatalf("the gate went through a proxy: %v %s", err, out)
49 }
50}
51
52// Review fix round 1: the gate judges the final response only. The status is
53// the final status line, not any header that starts with "HTTP", and
54// X-Carlos-Version is read from the final response's header block, not from
55// an informational response ahead of it.
56func TestRegionServiceGateJudgesTheFinalResponse(t *testing.T) {
57 const version = "abc1234"
58 gate := func(h http.HandlerFunc) (string, error) {
59 srv := httptest.NewTLSServer(h)
60 defer srv.Close()
61 host, port, _ := net.SplitHostPort(srv.Listener.Addr().String())
62 cmd := exec.Command("./scripts/region-service-gate.sh", "probe.example", version, host)
63 cmd.Env = append(cmd.Environ(), "GATE_PORT="+port, "GATE_INSECURE=1", "GATE_SKIP_PUBLIC=1")
64 out, err := cmd.CombinedOutput()
65 return string(out), err
66 }
67 // A 500 that carries a header looking like a status line and the right version.
68 if out, err := gate(func(w http.ResponseWriter, r *http.Request) {
69 w.Header().Set("X-Carlos-Version", version)
70 w.Header().Set("HTTP-Debug", "200")
71 w.WriteHeader(http.StatusInternalServerError)
72 }); err == nil || !strings.Contains(out, "FAIL") {
73 t.Errorf("a 500 with an HTTP-Debug header passed: %s", out)
74 }
75 // 103 Early Hints carries the version; the final 200 does not.
76 if out, err := gate(func(w http.ResponseWriter, r *http.Request) {
77 w.Header().Set("X-Carlos-Version", version)
78 w.WriteHeader(http.StatusEarlyHints)
79 w.Header().Del("X-Carlos-Version")
80 w.WriteHeader(http.StatusOK)
81 }); err == nil || !strings.Contains(out, "FAIL") {
82 t.Errorf("a version only on the 103 passed: %s", out)
83 }
84 // Two version headers in the final response: an empty one and the right
85 // one. A duplicate fails whatever either value is.
86 if out, err := gate(func(w http.ResponseWriter, r *http.Request) {
87 w.Header()["X-Carlos-Version"] = []string{"", version}
88 w.WriteHeader(http.StatusOK)
89 }); err == nil || !strings.Contains(out, "FAIL") {
90 t.Errorf("an empty and a correct version header on the final 200 passed: %s", out)
91 }
92 // The same duplicate with identical values is still a duplicate.
93 if out, err := gate(func(w http.ResponseWriter, r *http.Request) {
94 w.Header()["X-Carlos-Version"] = []string{version, version}
95 w.WriteHeader(http.StatusOK)
96 }); err == nil || !strings.Contains(out, "FAIL") {
97 t.Errorf("two identical version headers on the final 200 passed: %s", out)
98 }
99 // Both blocks carry the version: the final one is right, so it passes.
100 if out, err := gate(func(w http.ResponseWriter, r *http.Request) {
101 w.Header().Set("X-Carlos-Version", version)
102 w.WriteHeader(http.StatusEarlyHints)
103 w.WriteHeader(http.StatusOK)
104 }); err != nil {
105 t.Errorf("a 103 and a 200 that both carry the version failed: %v %s", err, out)
106 }
107}
108