50e47e29af
gates / gates (push) Successful in 6m40s
hosts.deliberate_off_at follows the agent's deliberate_off field (set, then cleared by the first report of a new boot; one info event each way). While held, every silence alarm is held: host and node staleness, the 05:00 backup deadlines, off-site and restore-test freshness, the OS alarms and the kernel notice. After 14 days the usual alarms fire once, naming the power-off. Pages show KIKAPCSOLVA and the time. Consequence tests with controls; each guard red-proofed.
64 lines
2.2 KiB
Go
64 lines
2.2 KiB
Go
package web
|
|
|
|
import (
|
|
"database/sql"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
|
)
|
|
|
|
// R-998: a box the household switched off reads KIKAPCSOLVA with the power-off line on the hosts page — not DOWN —
|
|
// exactly while the alarms are held; after the 14-day hold it reads DOWN again.
|
|
func TestHostsPage_DeliberatelyOffBox(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "t.db")
|
|
st, err := store.New(path, log.New(io.Discard, "", 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { st.Close() })
|
|
s := New(st, "", "", "test", 30*time.Minute, log.New(io.Discard, "", 0))
|
|
st.SaveCustomerConfig(&store.CustomerConfig{CustomerID: "c1", APIKey: "ck", RetrievalPassword: "p"})
|
|
st.UpsertHost(&store.Host{HostID: "h1", CustomerID: "c1", APIKey: "k1"})
|
|
st.SaveHostReport("h1", "c1", []byte(`{}`), store.HostReportDenorm{})
|
|
age := func(d time.Duration) {
|
|
db, _ := sql.Open("sqlite", path)
|
|
defer db.Close()
|
|
db.Exec(`UPDATE hosts SET last_report_at = ? WHERE host_id = 'h1'`, time.Now().UTC().Add(-d).Format("2006-01-02 15:04:05"))
|
|
}
|
|
page := func() string {
|
|
rr := httptest.NewRecorder()
|
|
s.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/hosts", nil))
|
|
if rr.Code != 200 {
|
|
t.Fatalf("/hosts: %d", rr.Code)
|
|
}
|
|
return rr.Body.String()
|
|
}
|
|
|
|
age(3 * time.Hour)
|
|
if p := page(); !strings.Contains(p, ">DOWN<") || strings.Contains(p, "data-deliberate-off") {
|
|
t.Fatal("CONTROL: a silent box without a power-off must read DOWN")
|
|
}
|
|
at := time.Now().UTC().Add(-3 * time.Hour).Truncate(time.Second)
|
|
st.SetHostDeliberateOff("h1", &at)
|
|
p := page()
|
|
if !strings.Contains(p, ">KIKAPCSOLVA<") || strings.Contains(p, ">DOWN<") {
|
|
t.Fatal("a box switched off by the household must read KIKAPCSOLVA, not DOWN")
|
|
}
|
|
if !strings.Contains(p, "Kikapcsolva a háztartás által, "+at.Format("2006-01-02 15:04")) {
|
|
t.Fatal("the hosts page does not name the household power-off and its time")
|
|
}
|
|
old := time.Now().UTC().Add(-15 * 24 * time.Hour)
|
|
st.SetHostDeliberateOff("h1", &old)
|
|
age(15 * 24 * time.Hour)
|
|
if p := page(); !strings.Contains(p, ">DOWN<") {
|
|
t.Fatal("after the 14-day hold the box must read DOWN again")
|
|
}
|
|
}
|