package web import ( "bytes" "log" "net/http/httptest" "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/settings" ) // R-234, THE MEASURED CAUSE — a manual run that the single-flight dropped must not be reported as one // that started. // // WHAT WAS MEASURED (Part 4 venue, 2026-08-06). The customer toggled an app on and pressed // „Távoli mentés most". The handler answered „A távoli mentés elindult — az állapot itt frissül.", // `runOffboxBackup` hit `acquireRunning`, logged an INFO and returned **nil**, and the card then // showed the PREVIOUS run's „✓ Rendben · 1 pillanatkép" — which reads as "the app I just selected is // backed up". It was not: the restore refused for that app minutes later, and only a third run // carried it. // // The verdict fix (R-234 part 1) does not cover this: there was no skipped app in that run, because // there was no run. A request that did nothing must say so. // // Handler-level on purpose: the decision now lives in the handler, before the goroutine, and a // manager-level assertion cannot observe what the customer was told. func TestOffboxRunHandler_InFlightRequestIsNotReportedAsStarted(t *testing.T) { s, sett, m := newOffboxWebServer(t) if err := sett.SetOffboxTarget(&settings.OffboxTarget{ Enabled: true, Host: "nas.local", Port: 22, User: "felhom", RepoPath: "/srv/repo", Schedule: "daily", EscrowState: "escrowed", }); err != nil { t.Fatal(err) } if err := m.WriteOffboxSecrets("PRIVATE-KEY-MATERIAL", "nas.local ssh-ed25519 AAAAhostkey"); err != nil { t.Fatal(err) } if !m.OffboxConfigured() || !m.OffboxRunnable() { t.Fatal("fixture: the target must be configured and runnable, or the handler exits earlier") } // Occupy the single-flight exactly as a run in progress would. if err := m.AcquireRunningForTest(); err != nil { t.Fatalf("fixture: %v", err) } defer m.ReleaseRunningForTest() var logbuf bytes.Buffer s.logger = log.New(&logbuf, "", 0) w := httptest.NewRecorder() s.offboxRunHandler(w, httptest.NewRequest("POST", "/backup/offbox/run", nil)) if w.Code != 302 { t.Fatalf("the handler redirects; got %d", w.Code) } loc := w.Header().Get("Location") if strings.Contains(loc, "elind") { t.Errorf("a dropped request must NOT be reported as started — that is the defect. Location: %q", loc) } if !strings.Contains(loc, "flash_error") { t.Errorf("it must reach the customer as a problem, not a success flash. Location: %q", loc) } // It must also say the visible result belongs to the EARLIER run — that is what was misread. if !strings.Contains(loc, "kor%C3%A1bbi") { t.Errorf("the message must say the shown result is the earlier run's. Location: %q", loc) } if !strings.Contains(logbuf.String(), "NOT started") { t.Errorf("the drop must be findable in the log too, got %q", logbuf.String()) } }