From 036760df0293cc0d06af9b1cd9487953ed03cd2e Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Wed, 24 Jun 2026 08:16:17 +0000 Subject: [PATCH] hscontrol: collapse key and settings asserts into cmp.Diff --- hscontrol/apiv2_keys_test.go | 42 ++++++++++++++++++++------------ hscontrol/apiv2_settings_test.go | 20 +++++++++------ 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/hscontrol/apiv2_keys_test.go b/hscontrol/apiv2_keys_test.go index 679eb40f..c71b18cf 100644 --- a/hscontrol/apiv2_keys_test.go +++ b/hscontrol/apiv2_keys_test.go @@ -8,6 +8,8 @@ import ( "time" "github.com/danielgtaylor/huma/v2/humatest" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" apiv2 "github.com/juanfont/headscale/hscontrol/api/v2" "github.com/juanfont/headscale/hscontrol/types" "github.com/stretchr/testify/assert" @@ -131,17 +133,21 @@ func TestAPIv2Key_Create_Tagged(t *testing.T) { }) // (a) create response — Tailscale Key shape, exact seconds (int64 wire). - assert.Equal(t, "auth", created.KeyType) + // ID/Key/Created/Expires are server-assigned; assert their presence apart. + want := apiv2.Key{ + KeyType: "auth", + Description: "dev access", + ExpirySeconds: 86400, + Capabilities: taggedCaps("tag:test"), + Tags: []string{"tag:test"}, + } + if diff := cmp.Diff(want, created, cmpopts.IgnoreFields(apiv2.Key{}, "ID", "Key", "Created", "Expires")); diff != "" { + t.Errorf("created key mismatch (-want +got):\n%s", diff) + } + assert.NotEmpty(t, created.ID) assert.NotEmpty(t, created.Key, "secret returned on create") - assert.Equal(t, "dev access", created.Description) - assert.Equal(t, int64(86400), created.ExpirySeconds, "seconds, not nanoseconds") - assert.Empty(t, created.UserID, "tagged key presents no owner") - assert.Equal(t, []string{"tag:test"}, created.Capabilities.Devices.Create.Tags) - assert.True(t, created.Capabilities.Devices.Create.Reusable) - assert.True(t, created.Capabilities.Devices.Create.Preauthorized, "echoed on create") assert.NotNil(t, created.Expires) - assert.False(t, created.Invalid) // (c) server-side — the stored key. pak := srvKey(t, app, created.ID) @@ -234,14 +240,18 @@ func TestAPIv2Key_Get(t *testing.T) { }) got := getKey(t, api, created.ID) - assert.Equal(t, created.ID, got.ID) - assert.Empty(t, got.Key, "secret omitted on get") - assert.Equal(t, "dev access", got.Description) - assert.Equal(t, int64(86400), got.ExpirySeconds, "stable across get") - assert.True(t, got.Capabilities.Devices.Create.Reusable) - assert.True(t, got.Capabilities.Devices.Create.Preauthorized, "Headscale always preauthorizes") - assert.Equal(t, []string{"tag:test"}, got.Capabilities.Devices.Create.Tags) - assert.False(t, got.Invalid) + // Get omits the secret (empty Key) and is stable across the round-trip. + want := apiv2.Key{ + ID: created.ID, + KeyType: "auth", + Description: "dev access", + ExpirySeconds: 86400, + Capabilities: taggedCaps("tag:test"), + Tags: []string{"tag:test"}, + } + if diff := cmp.Diff(want, got, cmpopts.IgnoreFields(apiv2.Key{}, "Created", "Expires")); diff != "" { + t.Errorf("got key mismatch (-want +got):\n%s", diff) + } // Unknown id and bad tailnet both 404 with the Tailscale error body. assert.Equal(t, http.StatusNotFound, api.Get("/api/v2/tailnet/-/keys/999999").Code) diff --git a/hscontrol/apiv2_settings_test.go b/hscontrol/apiv2_settings_test.go index a46e83d7..62b88bd7 100644 --- a/hscontrol/apiv2_settings_test.go +++ b/hscontrol/apiv2_settings_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/danielgtaylor/huma/v2/humatest" + "github.com/google/go-cmp/cmp" apiv2 "github.com/juanfont/headscale/hscontrol/api/v2" "github.com/juanfont/headscale/hscontrol/types" "github.com/stretchr/testify/assert" @@ -102,7 +103,7 @@ func TestAPIv2SettingsComputedFields(t *testing.T) { } } -// TestAPIv2SettingsConstantOffFields pins the honestly-hardcoded-off fields: +// TestAPIv2SettingsConstantOffFields pins the hardcoded-off fields: // even with every config knob set, they must not pick up signal. func TestAPIv2SettingsConstantOffFields(t *testing.T) { cfg := types.Config{ @@ -113,13 +114,16 @@ func TestAPIv2SettingsConstantOffFields(t *testing.T) { s := getSettings(t, settingsAPIWithConfig(t, &cfg)) - assert.False(t, s.DevicesApprovalOn) - assert.False(t, s.DevicesAutoUpdatesOn) - assert.False(t, s.UsersApprovalOn) - assert.False(t, s.NetworkFlowLoggingOn) - assert.False(t, s.RegionalRoutingOn) - assert.False(t, s.PostureIdentityCollectionOn) - assert.Empty(t, s.ACLsExternalLink) + // Only the four computed fields reflect cfg; everything else stays off. + want := apiv2.TailnetSettings{ + ACLsExternallyManagedOn: true, + DevicesKeyDurationDays: 90, + HTTPSEnabled: true, + UsersRoleAllowedToJoinExternalTailnets: "none", + } + if diff := cmp.Diff(want, s); diff != "" { + t.Errorf("settings mismatch (-want +got):\n%s", diff) + } } // TestAPIv2SettingsPatchUnsupported confirms writes are rejected and inert.