package web import ( "io" "log" "net/http/httptest" "net/url" "path/filepath" "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/settings" ) // Group D (Scenario D): with the seam unset (hub reporting off / nil trigger), the helper // is a strict nil-safe no-op — a handler calling it must never panic. func TestReportTriggerNow_NilSeamIsNoOp(t *testing.T) { s := &Server{} s.reportTriggerNow() // must not panic with reportTriggerFn == nil } // The wired seam fires on a SUCCESSFUL local commit and does NOT fire on the error path // (§Part 3: after the successful local commit — never before, never on error). Exercised // through a real handler (offbox per-app toggle) so deleting the call site fails this test. func TestReportTriggerNow_FiresAfterSuccessfulCommitOnly(t *testing.T) { tmp := t.TempDir() lg := log.New(io.Discard, "", 0) sett, err := settings.Load(filepath.Join(tmp, "settings.json"), lg) if err != nil { t.Fatal(err) } fired := 0 s := &Server{settings: sett, logger: lg} s.SetReportTrigger(func() { fired++ }) // Error path: missing app param → refused, trigger must NOT fire. w := httptest.NewRecorder() req := httptest.NewRequest("POST", "/backup/offbox/toggle", strings.NewReader(url.Values{"enabled": {"on"}}.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") s.offboxToggleHandler(w, req) if fired != 0 { t.Fatalf("trigger fired %d time(s) on the refused save, want 0 (never on the error path)", fired) } // Success path: the setting commits → the trigger fires exactly once. w2 := httptest.NewRecorder() req2 := httptest.NewRequest("POST", "/backup/offbox/toggle", strings.NewReader(url.Values{"app": {"immich"}, "enabled": {"on"}}.Encode())) req2.Header.Set("Content-Type", "application/x-www-form-urlencoded") s.offboxToggleHandler(w2, req2) if !sett.IsAppOffbox("immich") { t.Fatal("toggle did not commit — precondition for the trigger assertion") } if fired != 1 { t.Fatalf("trigger fired %d time(s) after the successful save, want exactly 1", fired) } }