Old kernels removed by the box (R-1368, wrapper mode kernel-cleanup); security profiles refreshed after a kernel change (R-1388, mode profile-refresh); Go 1.27.4 (R-1391)
gates / gates (push) Successful in 40s

This commit is contained in:
admin committed 2026-11-14 12:11:06 +01:00
1 parent 91a2924ad0
commit cc63dd5204
11 files changed
+1542 -10

No files matched your search

+97
View File
@@ -0,0 +1,97 @@
package osupdate
import (
"context"
"encoding/json"
"testing"
"time"
"gitea.dooplex.hu/admin/felhom-agent/internal/hub"
)
// ---- the security-profile refresh (R-1388, R-1301, `11` §5.12) ----
func profileCalls(w *fakeWrapper) []map[string]any {
var m []map[string]any
for _, p := range w.plans {
if p["mode"] == "profile-refresh" {
m = append(m, p)
}
}
return m
}
func refreshed() *WrapperReport {
return &WrapperReport{ProfileRefresh: json.RawMessage(`{"outcome":"refreshed","kernel":"7.0.14-28-pve","rewritten":["f6da0254.0/usr.sbin.chronyd"],` +
`"restarted":[{"unit":"chrony.service","program":"/usr/sbin/chronyd","rc":0,"active":true}],"seconds":0.5}`)}
}
// One call, a host-layer plan that names NOTHING, and nothing to the hub.
// COMPANION RED-PROOF (observed): add "units" to the plan → this test fails; drop the Appliance check → the BYO test fails.
func TestProfileRefresh_OneCallNoNamesNoHubReport(t *testing.T) {
w := &fakeWrapper{t: t, profileRep: refreshed()}
l, h := newLeg(t, w, &hub.WireOSUpdate{Ring: 1, Enabled: true})
if got := l.ProfileRefresh(context.Background(), "agent start", nil, 1, time.Second); got != "refreshed" {
t.Fatalf("outcome = %q", got)
}
pc := profileCalls(w)
if len(pc) != 1 {
t.Fatalf("calls = %d", len(pc))
}
if len(pc[0]) != 3 || pc[0]["layer"] != LayerHost || pc[0]["release_id"] != "profile-refresh" {
t.Fatalf("the plan carries more than release_id, layer and mode: %v", pc[0])
}
if len(h.reports) != 0 {
t.Fatalf("the hub got a report: %+v", h.reports)
}
}
func TestProfileRefresh_ByoHostIsNeverAsked(t *testing.T) {
w := &fakeWrapper{t: t, profileRep: refreshed()}
l, _ := newLeg(t, w, nil)
l.Appliance = false
if got := l.ProfileRefresh(context.Background(), "agent start", nil, 1, time.Second); got != "" || len(profileCalls(w)) != 0 {
t.Fatalf("a BYO host was asked: %q %v", got, profileCalls(w))
}
}
// The heavy-op gate: busy → wait and ask again; still busy after the tries → not run (the next start asks again).
// COMPANION RED-PROOF (observed): ignore `ok` from the gate → the "always busy" half fails.
func TestProfileRefresh_WaitsForTheHeavyOpGate(t *testing.T) {
w := &fakeWrapper{t: t, profileRep: refreshed()}
l, _ := newLeg(t, w, nil)
n, released := 0, 0
gate := func() (func(), string, bool) {
n++
if n < 3 {
return nil, "primary-backup", false
}
return func() { released++ }, "", true
}
if got := l.ProfileRefresh(context.Background(), "agent start", gate, 5, time.Minute); got != "refreshed" {
t.Fatalf("outcome = %q after %d gate tries", got, n)
}
if n != 3 || released != 1 || len(profileCalls(w)) != 1 {
t.Fatalf("gate tries %d, released %d, calls %d", n, released, len(profileCalls(w)))
}
w2 := &fakeWrapper{t: t, profileRep: refreshed()}
l2, _ := newLeg(t, w2, nil)
busy := func() (func(), string, bool) { return nil, "restore-test", false }
if got := l2.ProfileRefresh(context.Background(), "agent start", busy, 3, time.Minute); got != "" || len(profileCalls(w2)) != 0 {
t.Fatalf("ran beside a heavy operation: %q %d call(s)", got, len(profileCalls(w2)))
}
}
// An older wrapper refuses the mode: logged, nothing else. A failure is said as "failed".
func TestProfileRefresh_RefusedAndFailed(t *testing.T) {
w := &fakeWrapper{t: t, profileRep: &WrapperReport{Refused: json.RawMessage(`{"code":"R11","reason":"unknown mode 'profile-refresh'"}`)}}
l, _ := newLeg(t, w, nil)
if got := l.ProfileRefresh(context.Background(), "agent start", nil, 1, time.Second); got != "" {
t.Fatalf("refused → %q", got)
}
w2 := &fakeWrapper{t: t, profileRep: &WrapperReport{Failed: json.RawMessage(`{"rc":1,"step":"profile-refresh"}`)}}
l2, _ := newLeg(t, w2, nil)
if got := l2.ProfileRefresh(context.Background(), "agent start", nil, 1, time.Second); got != "failed" {
t.Fatalf("failed → %q", got)
}
}