package console import ( "context" "crypto/sha256" "encoding/hex" "net/http" "testing" "github.com/carlosframework/platform/internal/release" ) // Issue #316: system status compares bootstrap/carlos, the binary a new box // boots, with stable's signed linux-arm64 artifact. func TestSystemStatusReportsWhetherBootstrapIsStablesBuild(t *testing.T) { fx := newConsoleFixture(t) owner := cliToken(t, fx, "paul@keymail.dev", "code-sys-bootstrap") seedBox(t, fx, "ie", "linux-arm64", "stable", "v0.28.0") ctx := context.Background() build := []byte("stable build") sum := sha256.Sum256(build) if _, err := release.PromoteSystem(ctx, fx.rel, release.RootSigner(fx.priv), "router", "stable", release.SystemRelease{ Version: "v0.28.0", Artifacts: map[string]release.SystemArtifact{"linux-arm64": { Key: release.SystemArtifactKey("v0.28.0", "linux-arm64"), SHA256: hex.EncodeToString(sum[:])}}, }, release.SystemPromoteOptions{}); err != nil { t.Fatal(err) } bootstrap := func() any { t.Helper() st, out := getJSON(t, fx.ts.URL+"/api/cli/system/status", owner) if st != http.StatusOK { t.Fatalf("status = %d %v", st, out) } v, ok := out["bootstrap"] if !ok { t.Fatalf("no bootstrap field in %v", out) } return v } if got := bootstrap(); got != nil { t.Fatalf("absent bootstrap object: bootstrap = %v, want null", got) } put := func(data []byte) { t.Helper() _, etag, err := fx.rel.Get(ctx, bootstrapKey) if err != nil { etag = "" } if _, err := fx.rel.Put(ctx, bootstrapKey, data, etag); err != nil { t.Fatal(err) } } put([]byte("an older build")) row, _ := bootstrap().(map[string]any) if row["state"] != "behind" || row["version"] != "v0.28.0" || row["key"] != "bootstrap/router/v0.28.0/carlos-linux-arm64" { t.Fatalf("stale bootstrap: row = %v, want behind v0.28.0 with the mirror key", row) } put(build) if row, _ := bootstrap().(map[string]any); row["state"] != "current" { t.Fatalf("matching bootstrap: row = %v, want current", row) } // Past its budget the comparison reads unreadable, and the status read // still answers (Astra review: a slow store must not time the CLI out). was := bootstrapReadBudget bootstrapReadBudget = 0 t.Cleanup(func() { bootstrapReadBudget = was }) if row, _ := bootstrap().(map[string]any); row["state"] != "unreadable" || row["error"] == "" { t.Fatalf("over budget: row = %v, want unreadable with the error", row) } }