package replays import ( "context" "fmt" "os" "os/exec" "path/filepath" "strings" "testing" "time" ) // **The catalogue's bed** (novox/hq ADR 0240 rule 7, to-be 48 §8, Phase D): every long-running resource whose // declared `health` or image the change touches is started alone and its check must see the program within // its grace. Run by every merge check of the catalogue on the build seat, with the change's catalogue at // MESH_REPLAY_CATALOGUE; by hand against the catalogue beside the lab. What changed is against // MESH_BED_BASE (origin/main by default) in that checkout. func TestBedProvesEveryChangedHealthCheck(t *testing.T) { root := orDefault(os.Getenv("MESH_REPLAY_CATALOGUE"), filepath.Join("..", "..", "mesh-catalog")) if _, err := os.Stat(filepath.Join(root, "modules")); err != nil { t.Skipf("no catalogue at %s (MESH_REPLAY_CATALOGUE names it)", root) } base := orDefault(os.Getenv("MESH_BED_BASE"), "origin/main") show := func(ref, path string) ([]byte, error) { return exec.Command("git", "-c", "safe.directory=*", "-C", root, "show", ref+":"+path).Output() } if _, err := exec.Command("git", "-c", "safe.directory=*", "-C", root, "rev-parse", "--verify", base).Output(); err != nil { // What changed cannot be told, so every declared check is proved: the bed never passes what it did // not look at. t.Logf("%s is not in the catalogue at %s (%v): every declared check is proved", base, root, err) } changed, err := ChangedHealth(root, base, show) if err != nil { t.Fatal(err) } if len(changed) == 0 { t.Logf("no declared check or image of a long-running resource changed against %s: nothing to prove", base) return } docker, ok := DockerFromEnv() if !ok { t.Fatalf("%d changed check(s) and no container runtime to prove them on", len(changed)) } ctx, cancel := context.WithTimeout(t.Context(), 30*time.Minute) defer cancel() for _, r := range changed { manifest, _ := os.ReadFile(filepath.Join(root, "modules", r.Module, "module.json")) v := docker.Prove(ctx, r, FilesOf(manifest)) switch { case v.Failed: t.Errorf("FAILS ON THE BED: %s", v.Said) case v.Proved: t.Logf("proved: %s", v.Said) default: t.Logf("NOT PROVED HERE: %s", v.Said) } } } // **R-studio — a check that asks an address the program does not bind fails the bed, not a machine** // (novox/hq ADR 0240 Phase D, done when). The hosted database suite's studio binds the address the runtime // puts in HOSTNAME, so it answered only on its network address while its image's own check asked localhost: // unhealthy for ever while working, until the module set HOSTNAME=0.0.0.0. Adopted by name without proof, it // would have put back a good build. // // The replay is that image in miniature: a web server that binds $HOSTNAME's address, and an image check that // asks localhost. Adopted as the module declared it before the fix, the bed fails it; with the fix, it proves // it. The image is built here and removed after, with everything the bed made. func TestBedFailsTheStudiosFalseUnhealthy(t *testing.T) { docker, ok := DockerFromEnv() if !ok { t.Skip("no container runtime: the studio is a container") } ctx, cancel := context.WithTimeout(t.Context(), 5*time.Minute) defer cancel() if err := docker.Pull(ctx, "busybox:1.36"); err != nil { t.Fatal(err) } tag := fmt.Sprintf("mesh-replay-studio:%d", time.Now().UnixNano()) if err := docker.Build(ctx, tag, StudioDockerfile); err != nil { t.Fatal(err) } defer docker.RemoveImage(context.Background(), tag) was := BedFloor BedFloor = 15 * time.Second defer func() { BedFloor = was }() studio := func(env map[string]any) BedResource { r := map[string]any{"id": "studio", "type": "container", "name": "supabase-studio", "image": tag, "health": map[string]any{"kind": "runtime", "grace": "10s"}} if env != nil { r["env"] = env } return BedResource{Module: "supabase", ID: "studio", Resource: r, Listens: map[string]int{}} } before := docker.Prove(ctx, studio(nil), nil) if !before.Failed || !strings.Contains(before.Said, "does not see it") { t.Fatalf("the studio's false unhealthy was not failed on the bed: %+v", before) } t.Logf("before the fix: %s", before.Said) after := docker.Prove(ctx, studio(map[string]any{"HOSTNAME": "0.0.0.0"}), nil) if !after.Proved { t.Fatalf("the studio with HOSTNAME=0.0.0.0 was not proved: %+v", after) } t.Logf("with the fix: %s", after.Said) } // StudioDockerfile is the studio in miniature: it serves on the address HOSTNAME names, and its own check // asks localhost, as the studio's image does. const StudioDockerfile = `FROM busybox:1.36 RUN mkdir -p /www && echo studio > /www/index.html HEALTHCHECK --interval=5s --timeout=2s --retries=2 CMD wget -q -O /dev/null http://localhost:3000/ || exit 1 CMD addr=$(grep -w "$HOSTNAME" /etc/hosts | head -n 1 | cut -f 1); exec httpd -f -p "${addr:-$HOSTNAME}:3000" -h /www ` // What the bed proves is what the change touches: a long-running container whose declared check or image // changed, or that is new; never a step, never one left as it was. func TestTheBedProvesWhatTheChangeTouches(t *testing.T) { root := t.TempDir() git := func(args ...string) { t.Helper() cmd := exec.Command("git", append([]string{"-C", root, "-c", "user.email=lab@example", "-c", "user.name=lab"}, args...)...) if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("git %v: %v %s", args, err, out) } } write := func(module, body string) { t.Helper() if err := os.MkdirAll(filepath.Join(root, "modules", module), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(root, "modules", module, "module.json"), []byte(body), 0o644); err != nil { t.Fatal(err) } } git("init", "-q", "-b", "main") write("web", `{"module":"web","resources":[{"id":"server","type":"container","image":"web@sha256:a","health":{"kind":"runtime"}}, {"id":"seed","type":"container","image":"web@sha256:a","run-once":true,"health":{"kind":"runtime"}}]}`) write("db", `{"module":"db","resources":[{"id":"server","type":"container","image":"db@sha256:a","health":{"kind":"runtime"}}]}`) git("add", "-A") git("commit", "-qm", "base") write("web", `{"module":"web","resources":[{"id":"server","type":"container","image":"web@sha256:b","health":{"kind":"runtime"}}, {"id":"seed","type":"container","image":"web@sha256:b","run-once":true,"health":{"kind":"runtime"}}]}`) write("cache", `{"module":"cache","resources":[{"id":"server","type":"container","image":"cache@sha256:a","health":{"kind":"tcp","endpoint":"redis"}}, {"id":"plain","type":"container","image":"cache@sha256:a"}]}`) show := func(ref, path string) ([]byte, error) { return exec.Command("git", "-C", root, "show", ref+":"+path).Output() } changed, err := ChangedHealth(root, "main", show) if err != nil { t.Fatal(err) } var got []string for _, r := range changed { got = append(got, r.Module+"."+r.ID) } if strings.Join(got, ",") != "cache.server,web.server" { t.Fatalf("the bed would prove %v; want the new module's checked container and the one whose image moved", got) } }