v0.238.0: the page follows the update, and a held app offers no way to start it (update arc slice 4 Part 4)
gates / gates (push) Successful in 13s
gates / gates (push) Successful in 13s
No behaviour change on the box — the surface only.
- Frissítés follows the job: the button shows the phase label (polling GET /api/stacks/{name}
every 3 s) and the page reloads when updating goes false.
- An updating card offers no lifecycle button; a held card (failed update OR failed restore) shows
the hold sentence with a Mentések link and nothing that would start it; a failed update that held
nothing shows its sentence above the buttons. app_info shows the same three notices.
- The updating/held checks run BEFORE isOperational, which counts `restarting` as operational — how
the 2026-09-01 spike saw a green Frissítés beside a crash loop. Pinned with StateRestarting
fixtures; red-proofed by moving the checks after it (both tests fail).
- No new CSS, no version number.
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
||||
)
|
||||
|
||||
// Slice 4 Part 4 — the card while an update runs, while an app is held, and after an update that
|
||||
// failed without a hold. Rendered through the REAL stacks template.
|
||||
//
|
||||
// THE TRAP THESE PIN: isOperationalState counts `restarting` as operational — that is how the
|
||||
// 2026-09-01 spike saw a green Frissítés beside a crash loop. Both fixtures below are in
|
||||
// StateRestarting on purpose, so a template that checked isOperational FIRST would render all three
|
||||
// lifecycle buttons and fail here.
|
||||
//
|
||||
// COMPANION RED-PROOF (REPORT.md): move the `{{if .Updating}}…{{else if .HoldReason}}` branches below
|
||||
// `isOperational` in stacks.html — the held and updating tests fail with the buttons present.
|
||||
|
||||
var slice4LifecycleButtons = []string{
|
||||
`stackAction(event, 'bookstack', 'update')`,
|
||||
`stackAction(event, 'bookstack', 'restart')`,
|
||||
`stackAction(event, 'bookstack', 'stop')`,
|
||||
`stackAction(event, 'bookstack', 'start')`,
|
||||
}
|
||||
|
||||
func TestSlice4_Page_UpdatingCardShowsThePhaseAndNoLifecycleButton(t *testing.T) {
|
||||
st := ubStack(nil, map[string]string{"web": "nginx:1.27"}, "2026-07-18")
|
||||
st.State = stacks.StateRestarting
|
||||
st.Updating, st.UpdatePhase, st.UpdatePhaseLabel = true, stacks.UpdatePhasePulling, stacks.UpdatePhaseLabel(stacks.UpdatePhasePulling)
|
||||
h := renderBackupPage(t, "stacks", ubStacksData(st))
|
||||
if !strings.Contains(h, `data-update-phase="pulling"`) || !strings.Contains(h, stacks.UpdatePhaseLabel(stacks.UpdatePhasePulling)) {
|
||||
t.Error("an updating card must show its phase label")
|
||||
}
|
||||
for _, b := range slice4LifecycleButtons {
|
||||
if strings.Contains(h, b) {
|
||||
t.Errorf("an updating card must offer no lifecycle button, found %q", b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlice4_Page_HeldCardShowsTheHoldAndTheWayBack(t *testing.T) {
|
||||
st := ubStack(nil, map[string]string{"web": "nginx:1.27"}, "2026-07-18")
|
||||
st.State = stacks.StateRestarting
|
||||
st.HoldReason = "A(z) bookstack frissítése 2026-09-13 10:00-kor nem sikerült — HOLD"
|
||||
h := renderBackupPage(t, "stacks", ubStacksData(st))
|
||||
if !strings.Contains(h, `data-held="true"`) || !strings.Contains(h, "HOLD") || !strings.Contains(h, `href="/backups/apps"`) {
|
||||
t.Error("a held card must show the hold sentence and link Mentések")
|
||||
}
|
||||
for _, b := range slice4LifecycleButtons {
|
||||
if strings.Contains(h, b) {
|
||||
t.Errorf("a held card must offer nothing that starts or updates it, found %q", b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlice4_Page_FailedUpdateWithoutHoldKeepsTheButtonsAndSaysWhy(t *testing.T) {
|
||||
st := ubStack(nil, map[string]string{"web": "nginx:1.27"}, "2026-07-18")
|
||||
st.UpdateError = stacks.MsgUpdatePullFailed
|
||||
h := renderBackupPage(t, "stacks", ubStacksData(st))
|
||||
if !strings.Contains(h, `data-update-error="true"`) || !strings.Contains(h, stacks.MsgUpdatePullFailed) {
|
||||
t.Error("a failed update that held nothing must still say what happened")
|
||||
}
|
||||
for _, b := range slice4LifecycleButtons[:3] {
|
||||
if !strings.Contains(h, b) {
|
||||
t.Errorf("positive control: a running, unheld app keeps %q", b)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user