package replays import ( "context" "fmt" "os" "os/exec" "path/filepath" "strings" "testing" "time" ) // **R145 — a web application that accepts TCP and answers nothing is raised within two looks** (novox/hq // ADR 0240 Phase B, "how it is checked", rule 4; issue 145). // // For eleven hours a web application's port was open and its program ran while every request hung, and the // mesh said its machine was healthy; a person found it. Liveness cannot see it and a TCP check cannot either. // The replay is the whole chain, each half at its commit: // // 1. a web server whose application never answers is raised here, as the node-engine raises a module's; // 2. the node-engine at MESH_REPLAY_HOST looks at it with the HTTP check its module declares, two looks, // and writes what it states (its TestReplaySilentWebAppIsSaidUnhealthy) — an engine older than the // declared check states it alive and nothing more; // 3. the controller at MESH_REPLAY_CONTROLLER hears that statement on two looks in a row and raises the // module's condition on the second (its TestReplaySilentWebAppIsRaisedWithinTwoLooks). // // Needs a container runtime, Go, and MESH_TEST_POSTGRES for the controller's store; the container is removed // after, whatever happened. func TestReplaySilentWebApp(t *testing.T) { host := orDefault(os.Getenv("MESH_REPLAY_HOST"), filepath.Join("..", "..", "mesh-host")) controller := orDefault(os.Getenv("MESH_REPLAY_CONTROLLER"), filepath.Join("..", "..", "mesh-controller")) for _, dir := range []string{host, controller} { if _, err := os.Stat(filepath.Join(dir, "go.mod")); err != nil { t.Skipf("no checkout at %s (MESH_REPLAY_HOST and MESH_REPLAY_CONTROLLER name them)", dir) } } if os.Getenv("MESH_TEST_POSTGRES") == "" { t.Skip("no MESH_TEST_POSTGRES: the controller's half raises its condition in a store") } docker, ok := DockerFromEnv() if !ok { t.Skip("no container runtime: the web application is a container") } ctx, cancel := context.WithTimeout(t.Context(), 10*time.Minute) defer cancel() // 1. The silent web application (mesh-host internal/liveness SilentWebImage, SilentWebProgram). const image = "busybox:1.36" if err := docker.Pull(ctx, image); err != nil { t.Fatal(err) } name := fmt.Sprintf("mesh-replay-silent-web-%d", time.Now().UnixNano()) id, address, err := docker.Start(ctx, Run{Image: image, Name: name, Restart: "unless-stopped", Labels: map[string]string{"mesh-host.id": "app.server"}, Cmd: []string{"sh", "-c", "mkdir -p /www/cgi-bin && printf '#!/bin/sh\\nsleep 3600\\n' > /www/cgi-bin/app && " + "chmod +x /www/cgi-bin/app && exec httpd -f -p 8080 -h /www"}}) if err != nil { t.Fatal(err) } defer docker.Remove(context.Background(), id) // 2. The node-engine at its commit looks at it, and says what it states. statement := filepath.Join(t.TempDir(), "statement.json") engine := exec.CommandContext(ctx, "go", "test", "-count=1", "-run", "^TestReplaySilentWebAppIsSaidUnhealthy$", "./internal/liveness/") engine.Dir = host engine.Env = append(os.Environ(), "MESH_REPLAY_CONTAINER="+name, "MESH_REPLAY_ADDRESS="+address, "MESH_REPLAY_STATEMENT="+statement, "GOFLAGS=") out, err := engine.CombinedOutput() switch { case err == nil && !strings.Contains(string(out), "no tests to run"): t.Logf("the node-engine said: %s", firstLineOf(statementOf(statement))) case judgesNothing(string(out)) || strings.Contains(string(out), "no tests to run"): // An engine older than the declared check: it states the application alive, and nothing more. t.Fatalf("the node-engine at this commit does not look at a declared HTTP check") default: t.Fatalf("the node-engine did not say the silent web application unhealthy: %v\n%s", err, lastOf(string(out), 12)) } // 3. The controller at its commit raises the module's condition from what the engine said. raise := exec.CommandContext(ctx, "go", "test", "-count=1", "-run", "^TestReplaySilentWebAppIsRaisedWithinTwoLooks$", "./cmd/mesh-controller/") raise.Dir = controller raise.Env = append(os.Environ(), "MESH_REPLAY_STATEMENT="+statement, "GOFLAGS=-mod=vendor", "GOPROXY=off") out, err = raise.CombinedOutput() if err != nil { t.Fatalf("the controller did not raise the silent web application within two looks: %v\n%s", err, lastOf(string(out), 12)) } if strings.Contains(string(out), "no tests to run") { t.Fatal("the controller at this commit has no half of the replay to run") } }