From 7cdecd4e78c4ede4202bb0d8aec7944f915168f9 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Tue, 20 Oct 2026 12:22:51 +0000 Subject: [PATCH] servertest: fail on skip entries no lifecycle replay reads Consumers check entries under their own capture only, so a bare or misspelled key never went stale. --- hscontrol/servertest/lifecycle_compat_test.go | 7 +++++++ hscontrol/servertest/via_ha_compat_test.go | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/hscontrol/servertest/lifecycle_compat_test.go b/hscontrol/servertest/lifecycle_compat_test.go index 0e9459943..1e843eaa7 100644 --- a/hscontrol/servertest/lifecycle_compat_test.go +++ b/hscontrol/servertest/lifecycle_compat_test.go @@ -106,6 +106,13 @@ func TestRouteApprovalCompat(t *testing.T) { }) } +func TestLifecycleSkipEntriesNameCaptures(t *testing.T) { + t.Parallel() + + requireSkipCaptures(t, lifecycleSkipReasons, "route-approval", "ephemeral-lifecycle") + requireSkipCaptures(t, reauthSkipReasons, append([]string{"owner-routes", "ephemeral-lifecycle"}, reauthCompatTests...)...) +} + // stepCheck is one rendering of a step outcome: SaaS's, and how to read // headscale's. type stepCheck struct { diff --git a/hscontrol/servertest/via_ha_compat_test.go b/hscontrol/servertest/via_ha_compat_test.go index f69642af3..72b7c8592 100644 --- a/hscontrol/servertest/via_ha_compat_test.go +++ b/hscontrol/servertest/via_ha_compat_test.go @@ -622,6 +622,20 @@ func readStepCapture(t *testing.T, id string) *testcapture.Capture { return c } +// requireSkipCaptures fails on a skip entry that is not +// //.../ for one of ids, the captures the map's consumers +// replay. Each consumer checks only the entries under its own capture, so +// such an entry would never go stale. +func requireSkipCaptures(t *testing.T, skips map[string]string, ids ...string) { + t.Helper() + + for k := range skips { + id, rest, _ := strings.Cut(k, "/") + assert.True(t, slices.Contains(ids, id) && strings.Contains(rest, "/"), + "skip entry %q names no replayed capture and step", k) + } +} + // stepReplay drives a step capture's actions against headscale: policy // pushes, key mints and revokes, joins, relogins, profile switches, // restarts, kills, shutdowns, route announcements, logouts, retires and admin