Delete replays/merge-check.sh; tests that raise containers or a bus move to the integration level (issue 1295, S5 replays; ADR 0529)
gofmt and vet are the Go build module's; the unit level keeps the register and the bed's reading of a change.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
//go:build integration
|
||||
|
||||
package replays
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// **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
|
||||
`
|
||||
+7
-57
@@ -2,7 +2,6 @@ package replays
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -58,62 +57,6 @@ func TestBedProvesEveryChangedHealthCheck(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// **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) {
|
||||
@@ -159,3 +102,10 @@ func TestTheBedProvesWhatTheChangeTouches(t *testing.T) {
|
||||
t.Fatalf("the bed would prove %v; want the new module's checked container and the one whose image moved", got)
|
||||
}
|
||||
}
|
||||
|
||||
func orDefault(s, fallback string) string {
|
||||
if s == "" {
|
||||
return fallback
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build integration
|
||||
|
||||
package replays
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build integration
|
||||
|
||||
package replays
|
||||
|
||||
import (
|
||||
@@ -111,13 +113,6 @@ func statementOf(path string) string {
|
||||
return string(raw)
|
||||
}
|
||||
|
||||
func orDefault(s, fallback string) string {
|
||||
if s == "" {
|
||||
return fallback
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func firstLineOf(s string) string {
|
||||
line, _, _ := strings.Cut(strings.TrimSpace(s), "\n")
|
||||
if len(line) > 400 {
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
# mesh-check-toolchain: go
|
||||
#
|
||||
# The Go part of the lab's own check (novox/hq issue 302): the replays register and its prover, run by the
|
||||
# build seat in the mesh's Go toolchain, its own container, because the lab's merge-check.sh declares it
|
||||
# (`# mesh-check-also: go replays/merge-check.sh`) — and by hand, from anywhere:
|
||||
# `sh replays/merge-check.sh`.
|
||||
#
|
||||
# 1. formatted and vetted — the register, the replays and the prover compile, tests included;
|
||||
# 2. the tests that need nothing but Go and git: every replay registered whole (TestEveryReplayIsWhole),
|
||||
# and the bed's reading of what a change touches.
|
||||
#
|
||||
# **Said, never passed silently**: the replays themselves raise containers and a bus of the release the mesh
|
||||
# runs; this container holds no container runtime, so they are not run here. They run from the lab's main,
|
||||
# reviewed, in the gate of every core change, and a change to one is proven by `go run ./cmd/prove` before
|
||||
# it merges.
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
unformatted=$(gofmt -l .)
|
||||
if [ -n "$unformatted" ]; then
|
||||
echo "not gofmt'd:"
|
||||
echo "$unformatted"
|
||||
exit 1
|
||||
fi
|
||||
go vet ./...
|
||||
go test -count=1 -run '^(TestEveryReplayIsWhole|TestTheBedProvesWhatTheChangeTouches)$' .
|
||||
echo "NOT RUN HERE: the replays themselves — they raise containers, and this container holds no container runtime"
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build integration
|
||||
|
||||
package replays
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build integration
|
||||
|
||||
package replays
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build integration
|
||||
|
||||
package replays
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user