package console import ( "context" "fmt" "net/http" "net/url" "strings" "testing" "time" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/rolloutwords" "github.com/carlosframework/platform/internal/status" ) // Astra plan 6 R1 #8: the retry confirmation promises no fallback. A retry // that fails in hold mode leaves the instance down, so "stays on its last // good build" was false there; the host is held again either way. func TestBrowserRetryConfirmationPromisesNoFallback(t *testing.T) { fx := heldFixture(t) c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) code, _, body := postForm(t, c, fx.u("/apps/kass/instances/"+heldHost+"/retry"), url.Values{"csrf": {csrf}}) want := "This clears the failure hold on " + heldHost + ". Its next attempt at v2 runs as a canary. If that fails too, " + heldHost + " is held again." if code != http.StatusOK || !strings.Contains(body, want) { t.Fatalf("confirm = %d, lacks %q", code, want) } if strings.Contains(body, "last good build") { t.Fatal("the confirmation still promises a fallback to the last good build") } } // Astra plan 6 R1 #8: a hold-mode failure leaves nothing serving // (attempt down), so the page's hold row must not say the instance "stays // on" a build there. Both renders: a held instance that serves its good // build keeps the hold text; a down one gets the down text. func TestInstancePageHoldTextTellsDownFromHeld(t *testing.T) { fx := newConsoleFixture(t) const down = "down.kass.carlosapp.dev" for _, h := range []string{heldHost, down} { fx.addRoute(t, registry.Route{Host: h, App: "kass", Account: fx.sqid, Kind: "instance", Status: "ready", Version: "v2", Channel: "stable"}) sibling(t, fx, "kass", h, "stable") } box := status.CollectBox(nil, status.Probes{MachineID: "box1"}, time.Now()) box.Metrics = &status.BoxMetrics{Rollout: &status.RolloutReport{Hosts: map[string]status.HostRollout{ heldHost: {Account: fx.sqid, App: "kass", Installed: "v2", Serving: "v1", Good: "v1", Awake: true, HeldBy: "v2", Reason: status.ReasonHealth, HeldEpoch: heldEpoch, HeldBook: heldBook, RetryV: status.HostRetryV}, down: {Account: fx.sqid, App: "kass", Installed: "v2", Good: "v1", Attempt: status.AttemptDown, AttemptBuild: "v2", HeldBy: "v2", Reason: status.ReasonExit, HeldEpoch: heldEpoch, HeldBook: heldBook, RetryV: status.HostRetryV}, }}} if err := status.WriteBox(context.Background(), fx.rel, box); err != nil { t.Fatal(err) } c := signInPaul(t, fx) _, _, held := get(t, c, fx.u("/apps/kass/instances/"+heldHost)) if want := fmt.Sprintf(swapCopy.HoldText, "v2", rolloutwords.Reason(status.ReasonHealth), "v1"); !strings.Contains(held, want) { t.Errorf("held page lacks %q", want) } _, _, body := get(t, c, fx.u("/apps/kass/instances/"+down)) want := "Build v2 failed in hold mode on this box, and nothing is serving this instance. Roll back with carlos rollback, or retry it." if !strings.Contains(body, want) { t.Errorf("down page lacks %q", want) } if strings.Contains(body, "stays on") { t.Error("the down page says the instance stays on a build") } if !strings.Contains(body, `/instances/`+down+`/retry"`) { t.Error("the down page lost its Retry") } }