package api import ( "net/http" "strings" "testing" "time" "gitea.dooplex.hu/admin/felhom-hub/internal/store" ) // R-998: the agent's deliberate_off field sets the host row's hold; the next report without it (a new boot — the box // was switched back on) clears it. Each change leaves one info event on the customer's list; a repeat leaves none. func TestHostReport_DeliberateOffSetThenCleared(t *testing.T) { h, st, _ := newTestHandler(t) st.SaveCustomerConfig(&store.CustomerConfig{CustomerID: "c1", APIKey: "ckey", RetrievalPassword: "p"}) st.UpsertHost(&store.Host{HostID: "h1", CustomerID: "c1", APIKey: "HKEY"}) withOff := strings.TrimSuffix(validReportBody("h1"), "}") + `,"deliberate_off":{"requested_at":"2026-10-13T18:00:00Z"}}` for i := 0; i < 2; i++ { // the field rides every report until the box is down; the second must not re-record if rr := do(h, http.MethodPost, "/host-report", "HKEY", withOff); rr.Code != 200 { t.Fatalf("report %d: %d %s", i, rr.Code, rr.Body.String()) } } at := st.HostDeliberateOffAt("h1") if at == nil || !at.Equal(time.Date(2026, 10, 13, 18, 0, 0, 0, time.UTC)) { t.Fatalf("hold = %v, want 2026-10-13 18:00 UTC", at) } evs, _ := st.GetEventsByType("c1", eventHostDeliberateOff, time.Now().Add(-time.Hour)) if len(evs) != 1 || evs[0].Severity != "info" { t.Fatalf("set events = %+v, want exactly one info event", evs) } if rr := do(h, http.MethodPost, "/host-report", "HKEY", validReportBody("h1")); rr.Code != 200 { t.Fatalf("plain report: %d", rr.Code) } if st.HostDeliberateOffAt("h1") != nil { t.Fatal("a report without the field must clear the hold") } ended, _ := st.GetEventsByType("c1", eventHostDeliberateOffEnded, time.Now().Add(-time.Hour)) if len(ended) != 1 { t.Fatalf("ended events = %d, want 1", len(ended)) } }