feat(http): host mode toggle handler + route (host.mode_updated)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
// ui_host_mode_test.go — covers handleUIHostModeSave: toggling a
|
||||
// host's always-on flag via POST /hosts/{id}/mode.
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
stdhttp "net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHostModeSaveToggle verifies the checkbox-absent ⇒ intermittent
|
||||
// and checkbox-present ⇒ always-on semantics, and that the audit row
|
||||
// lands for each request.
|
||||
func TestHostModeSaveToggle(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, ts, st := rawTestServerWithUI(t)
|
||||
hostID, _ := enrolHostForUI(t, nil, st, "mode-toggle-host")
|
||||
|
||||
cookie := loginAsAdmin(t, st)
|
||||
|
||||
cli := &stdhttp.Client{
|
||||
CheckRedirect: func(*stdhttp.Request, []*stdhttp.Request) error {
|
||||
return stdhttp.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
|
||||
// --- POST with no always_on field => intermittent ---
|
||||
form := url.Values{}
|
||||
req, _ := stdhttp.NewRequest("POST", ts.URL+"/hosts/"+hostID+"/mode",
|
||||
strings.NewReader(form.Encode()))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.AddCookie(cookie)
|
||||
res, err := cli.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("do: %v", err)
|
||||
}
|
||||
_ = res.Body.Close()
|
||||
if res.StatusCode != stdhttp.StatusSeeOther {
|
||||
t.Fatalf("status: got %d, want 303", res.StatusCode)
|
||||
}
|
||||
if loc := res.Header.Get("Location"); loc != "/hosts/"+hostID {
|
||||
t.Errorf("Location: got %q, want /hosts/%s", loc, hostID)
|
||||
}
|
||||
|
||||
got, err := st.GetHost(context.Background(), hostID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetHost: %v", err)
|
||||
}
|
||||
if got.AlwaysOn {
|
||||
t.Errorf("AlwaysOn after empty form: got true, want false")
|
||||
}
|
||||
|
||||
// --- POST with always_on=on => always-on ---
|
||||
form2 := url.Values{"always_on": {"on"}}
|
||||
req2, _ := stdhttp.NewRequest("POST", ts.URL+"/hosts/"+hostID+"/mode",
|
||||
strings.NewReader(form2.Encode()))
|
||||
req2.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req2.AddCookie(cookie)
|
||||
res2, err := cli.Do(req2)
|
||||
if err != nil {
|
||||
t.Fatalf("do: %v", err)
|
||||
}
|
||||
_ = res2.Body.Close()
|
||||
if res2.StatusCode != stdhttp.StatusSeeOther {
|
||||
t.Fatalf("status: got %d, want 303", res2.StatusCode)
|
||||
}
|
||||
|
||||
got2, err := st.GetHost(context.Background(), hostID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetHost: %v", err)
|
||||
}
|
||||
if !got2.AlwaysOn {
|
||||
t.Errorf("AlwaysOn after always_on=on: got false, want true")
|
||||
}
|
||||
|
||||
// Audit rows must exist (one per request).
|
||||
var n int
|
||||
if err := st.DB().QueryRow(
|
||||
`SELECT COUNT(*) FROM audit_log WHERE action = 'host.mode_updated' AND target_id = ?`,
|
||||
hostID).Scan(&n); err != nil {
|
||||
t.Fatalf("count audit: %v", err)
|
||||
}
|
||||
if n != 2 {
|
||||
t.Errorf("audit rows: got %d, want 2", n)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user