From ee85b245dae98a6287045814236c19b1fbdcf460 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sat, 29 Aug 2026 00:34:27 +0200 Subject: [PATCH] test(models): restore api token route maps after each test --- pkg/models/api_routes_test.go | 43 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/pkg/models/api_routes_test.go b/pkg/models/api_routes_test.go index 9cce9753f..c095c98f5 100644 --- a/pkg/models/api_routes_test.go +++ b/pkg/models/api_routes_test.go @@ -27,6 +27,19 @@ import ( "github.com/stretchr/testify/require" ) +// resetAPITokenRoutes empties both route tables for a test and restores the +// collected ones afterwards, so tests that read the real tables don't depend +// on running first. +func resetAPITokenRoutes(t *testing.T) { + t.Helper() + v1, v2 := apiTokenRoutes, apiTokenRoutesV2 + t.Cleanup(func() { + apiTokenRoutes, apiTokenRoutesV2 = v1, v2 + }) + apiTokenRoutes = make(map[string]APITokenRoute) + apiTokenRoutesV2 = make(map[string]APITokenRoute) +} + func TestAPITokenRoutes_MCPAccessRegistered(t *testing.T) { routes := GetAPITokenRoutes() @@ -46,8 +59,7 @@ func TestPermissionsAreValid_MCPAccess(t *testing.T) { } func TestCanDoAPIRoute_BulkLabelTask(t *testing.T) { - // Reset apiTokenRoutes to isolate this test - apiTokenRoutes = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) // Register the standard CRUD routes for tasks_labels first CollectRoutesForAPITokenUsage(echo.RouteInfo{ @@ -116,8 +128,7 @@ func TestStripAPIVersion(t *testing.T) { // would use. This is what lets a token scoped on `labels.read_one` authorise // both /api/v1/labels/{id} and /api/v2/labels/{id}. func TestCollectRoutesV2(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v2/labels"}, true) CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v2/labels/:id"}, true) @@ -145,8 +156,7 @@ func TestCollectRoutesV2(t *testing.T) { // snake_case "time_entries" group (not the "other" catch-all, not a hyphenated // key the frontend's snake_case transform would mangle on save). func TestCollectRoutes_TimeEntriesV2(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v2/time-entries"}, true) CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v2/time-entries/:id"}, true) @@ -174,8 +184,7 @@ func TestCollectRoutes_TimeEntriesV2(t *testing.T) { // v2-only groups (time_entries has no v1 counterpart) so token clients can // discover and grant them, without mutating the v1 table itself. func TestGetAPITokenRoutes_ExposesV2Only(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) license.SetForTests([]license.Feature{license.FeatureTimeTracking}) defer license.ResetForTests() @@ -200,8 +209,7 @@ func TestGetAPITokenRoutes_ExposesV2Only(t *testing.T) { // inside always-available groups (tasks.time_entries) — while validation and // authorisation of existing tokens stay unfiltered. func TestGetAPITokenRoutes_LicenseFilter(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v1/labels"}, true) CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v1/admin/users"}, true) @@ -242,8 +250,7 @@ func TestGetAPITokenRoutes_LicenseFilter(t *testing.T) { // TestCanDoAPIRoute_TimeEntriesHyphenLegacy proves a token stored under the old // hyphenated "time-entries" key still validates and authorises — no migration. func TestCanDoAPIRoute_TimeEntriesHyphenLegacy(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) CollectRoutesForAPITokenUsage(echo.RouteInfo{Method: "GET", Path: "/api/v2/time-entries"}, true) @@ -288,8 +295,7 @@ func TestGetRouteDetail_V2Verbs(t *testing.T) { // PATCH for every PUT — the matcher accepts it as an alias so token // holders aren't forced to use PUT exclusively. func TestCanDoAPIRoute_V2PatchAliasesPut(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) apiTokenRoutes["caldav"] = APITokenRoute{ "access": &RouteDetail{Path: "/dav/*", Method: "ANY"}, } @@ -342,8 +348,7 @@ func TestCanDoAPIRoute_V2PatchAliasesPut(t *testing.T) { // one RouteDetail survives in the map — the special case in CanDoAPIRoute must // accept either path. func TestCanDoAPIRoute_V2TasksReadAll(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) apiTokenRoutes["caldav"] = APITokenRoute{ "access": &RouteDetail{Path: "/dav/*", Method: "ANY"}, } @@ -372,8 +377,7 @@ func TestCanDoAPIRoute_V2TasksReadAll(t *testing.T) { // TestCollectRoutes_V2TasksBulkCreate pins the bulk create route to tasks.create_bulk instead of projects.tasks_bulk. func TestCollectRoutes_V2TasksBulkCreate(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) CollectRoutesForAPITokenUsage(echo.RouteInfo{ Method: "POST", @@ -394,8 +398,7 @@ func TestCollectRoutes_V2TasksBulkCreate(t *testing.T) { // TestCanDoAPIRoute_V2TasksBulkCreate verifies that tasks.create_bulk, not tasks.create, authorises the bulk create route. func TestCanDoAPIRoute_V2TasksBulkCreate(t *testing.T) { - apiTokenRoutes = make(map[string]APITokenRoute) - apiTokenRoutesV2 = make(map[string]APITokenRoute) + resetAPITokenRoutes(t) CollectRoutesForAPITokenUsage(echo.RouteInfo{ Method: "POST",