//go:build integration // +build integration package integration import ( "context" "encoding/json" "net/http" "net/http/httptest" "sort" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/handlers/setup_keys" "github.com/netbirdio/netbird/management/server/http/testing/testing_tools" ) func Test_SetupKeys_Create(t *testing.T) { truePointer := true users := []struct { name string userId string expectResponse bool }{ { name: "Regular user", userId: testing_tools.TestUserId, expectResponse: false, }, { name: "Admin user", userId: testing_tools.TestAdminId, expectResponse: true, }, { name: "Owner user", userId: testing_tools.TestOwnerId, expectResponse: true, }, { name: "Regular service user", userId: testing_tools.TestServiceUserId, expectResponse: false, }, { name: "Admin service user", userId: testing_tools.TestServiceAdminId, expectResponse: true, }, { name: "Blocked user", userId: testing_tools.BlockedUserId, expectResponse: false, }, { name: "Other user", userId: testing_tools.OtherUserId, expectResponse: false, }, { name: "Invalid token", userId: testing_tools.InvalidToken, expectResponse: false, }, } tt := []struct { name string expectedStatus int expectedResponse *api.SetupKey requestBody *api.CreateSetupKeyRequest requestType string requestPath string userId string }{ { name: "Create Setup Key", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: nil, ExpiresIn: testing_tools.ExpiresIn, Name: testing_tools.NewKeyName, Type: "reusable", UsageLimit: 0, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.NewKeyName, Revoked: false, State: "valid", Type: "reusable", UpdatedAt: time.Now(), UsageLimit: 0, UsedTimes: 0, Valid: true, }, }, { name: "Create Setup Key with already existing name", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: nil, ExpiresIn: testing_tools.ExpiresIn, Name: testing_tools.ExistingKeyName, Type: "one-off", UsageLimit: 0, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "valid", Type: "one-off", UpdatedAt: time.Now(), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Create Setup Key as on-off with more than one usage", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: nil, ExpiresIn: testing_tools.ExpiresIn, Name: testing_tools.NewKeyName, Type: "one-off", UsageLimit: 3, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.NewKeyName, Revoked: false, State: "valid", Type: "one-off", UpdatedAt: time.Now(), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Create Setup Key with expiration in the past", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: nil, ExpiresIn: -testing_tools.ExpiresIn, Name: testing_tools.NewKeyName, Type: "one-off", UsageLimit: 0, }, expectedStatus: http.StatusUnprocessableEntity, expectedResponse: nil, }, { name: "Create Setup Key with AutoGroups that do exist", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId}, ExpiresIn: testing_tools.ExpiresIn, Name: testing_tools.NewKeyName, Type: "reusable", UsageLimit: 1, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.NewKeyName, Revoked: false, State: "valid", Type: "reusable", UpdatedAt: time.Now(), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Create Setup Key for ephemeral peers", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: []string{}, ExpiresIn: testing_tools.ExpiresIn, Name: testing_tools.NewKeyName, Type: "reusable", Ephemeral: &truePointer, UsageLimit: 1, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{}, Ephemeral: true, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.NewKeyName, Revoked: false, State: "valid", Type: "reusable", UpdatedAt: time.Now(), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Create Setup Key with AutoGroups that do not exist", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: []string{"someGroupID"}, ExpiresIn: testing_tools.ExpiresIn, Name: testing_tools.NewKeyName, Type: "reusable", UsageLimit: 0, }, expectedStatus: http.StatusUnprocessableEntity, expectedResponse: nil, }, { name: "Create Setup Key", requestType: http.MethodPost, requestPath: "/api/setup-keys", requestBody: &api.CreateSetupKeyRequest{ AutoGroups: nil, ExpiresIn: testing_tools.ExpiresIn, Name: testing_tools.NewKeyName, Type: "reusable", UsageLimit: 0, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.NewKeyName, Revoked: false, State: "valid", Type: "reusable", UpdatedAt: time.Now(), UsageLimit: 0, UsedTimes: 0, Valid: true, }, }, } for _, tc := range tt { for _, user := range users { t.Run(user.name+" - "+tc.name, func(t *testing.T) { apiHandler, am, done := testing_tools.BuildApiBlackBoxWithDBState(t, "../testdata/setup_keys.sql", nil, true) body, err := json.Marshal(tc.requestBody) if err != nil { t.Fatalf("Failed to marshal request body: %v", err) } req := testing_tools.BuildRequest(t, body, tc.requestType, tc.requestPath, user.userId) recorder := httptest.NewRecorder() apiHandler.ServeHTTP(recorder, req) content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse) if !expectResponse { return } got := &api.SetupKey{} if err := json.Unmarshal(content, &got); err != nil { t.Fatalf("Sent content is not in correct json format; %v", err) } validateCreatedKey(t, tc.expectedResponse, got) key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id) if err != nil { return } validateCreatedKey(t, tc.expectedResponse, setup_keys.ToResponseBody(key)) select { case <-done: case <-time.After(time.Second): t.Error("timeout waiting for peerShouldNotReceiveUpdate") } }) } } } func Test_SetupKeys_Update(t *testing.T) { users := []struct { name string userId string expectResponse bool }{ { name: "Regular user", userId: testing_tools.TestUserId, expectResponse: false, }, { name: "Admin user", userId: testing_tools.TestAdminId, expectResponse: true, }, { name: "Owner user", userId: testing_tools.TestOwnerId, expectResponse: true, }, { name: "Regular service user", userId: testing_tools.TestServiceUserId, expectResponse: false, }, { name: "Admin service user", userId: testing_tools.TestServiceAdminId, expectResponse: true, }, { name: "Blocked user", userId: testing_tools.BlockedUserId, expectResponse: false, }, { name: "Other user", userId: testing_tools.OtherUserId, expectResponse: false, }, { name: "Invalid token", userId: testing_tools.InvalidToken, expectResponse: false, }, } tt := []struct { name string expectedStatus int expectedResponse *api.SetupKey requestBody *api.SetupKeyRequest requestType string requestPath string requestId string }{ { name: "Add existing Group to existing Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.TestKeyId, requestBody: &api.SetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId, testing_tools.NewGroupId}, Revoked: false, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId, testing_tools.NewGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "valid", Type: "one-off", UpdatedAt: time.Now(), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Add non-existing Group to existing Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.TestKeyId, requestBody: &api.SetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId, "someGroupId"}, Revoked: false, }, expectedStatus: http.StatusUnprocessableEntity, expectedResponse: nil, }, { name: "Add existing Group to non-existing Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: "someId", requestBody: &api.SetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId, testing_tools.NewGroupId}, Revoked: false, }, expectedStatus: http.StatusNotFound, expectedResponse: nil, }, { name: "Remove existing Group from existing Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.TestKeyId, requestBody: &api.SetupKeyRequest{ AutoGroups: []string{}, Revoked: false, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "valid", Type: "one-off", UpdatedAt: time.Now(), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Remove existing Group to non-existing Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: "someID", requestBody: &api.SetupKeyRequest{ AutoGroups: []string{}, Revoked: false, }, expectedStatus: http.StatusNotFound, expectedResponse: nil, }, { name: "Revoke existing valid Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.TestKeyId, requestBody: &api.SetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId}, Revoked: true, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: true, State: "revoked", Type: "one-off", UpdatedAt: time.Now(), UsageLimit: 1, UsedTimes: 0, Valid: false, }, }, { name: "Revoke existing revoked Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.RevokedKeyId, requestBody: &api.SetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId}, Revoked: true, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: true, State: "revoked", Type: "reusable", UpdatedAt: time.Now(), UsageLimit: 3, UsedTimes: 0, Valid: false, }, }, { name: "Un-Revoke existing revoked Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.RevokedKeyId, requestBody: &api.SetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId}, Revoked: false, }, expectedStatus: http.StatusUnprocessableEntity, expectedResponse: nil, }, { name: "Revoke existing expired Setup Key", requestType: http.MethodPut, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.ExpiredKeyId, requestBody: &api.SetupKeyRequest{ AutoGroups: []string{testing_tools.TestGroupId}, Revoked: true, }, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: true, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: true, State: "expired", Type: "reusable", UpdatedAt: time.Now(), UsageLimit: 5, UsedTimes: 1, Valid: false, }, }, } for _, tc := range tt { for _, user := range users { t.Run(tc.name, func(t *testing.T) { apiHandler, am, done := testing_tools.BuildApiBlackBoxWithDBState(t, "../testdata/setup_keys.sql", nil, true) body, err := json.Marshal(tc.requestBody) if err != nil { t.Fatalf("Failed to marshal request body: %v", err) } req := testing_tools.BuildRequest(t, body, tc.requestType, strings.Replace(tc.requestPath, "{id}", tc.requestId, 1), user.userId) recorder := httptest.NewRecorder() apiHandler.ServeHTTP(recorder, req) content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse) if !expectResponse { return } got := &api.SetupKey{} if err := json.Unmarshal(content, &got); err != nil { t.Fatalf("Sent content is not in correct json format; %v", err) } validateCreatedKey(t, tc.expectedResponse, got) key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id) if err != nil { return } validateCreatedKey(t, tc.expectedResponse, setup_keys.ToResponseBody(key)) select { case <-done: case <-time.After(time.Second): t.Error("timeout waiting for peerShouldNotReceiveUpdate") } }) } } } func Test_SetupKeys_Get(t *testing.T) { users := []struct { name string userId string expectResponse bool }{ { name: "Regular user", userId: testing_tools.TestUserId, expectResponse: false, }, { name: "Admin user", userId: testing_tools.TestAdminId, expectResponse: true, }, { name: "Owner user", userId: testing_tools.TestOwnerId, expectResponse: true, }, { name: "Regular service user", userId: testing_tools.TestServiceUserId, expectResponse: false, }, { name: "Admin service user", userId: testing_tools.TestServiceAdminId, expectResponse: true, }, { name: "Blocked user", userId: testing_tools.BlockedUserId, expectResponse: false, }, { name: "Other user", userId: testing_tools.OtherUserId, expectResponse: false, }, { name: "Invalid token", userId: testing_tools.InvalidToken, expectResponse: false, }, } tt := []struct { name string expectedStatus int expectedResponse *api.SetupKey requestType string requestPath string requestId string }{ { name: "Get existing valid Setup Key", requestType: http.MethodGet, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.TestKeyId, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "valid", Type: "one-off", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Get existing expired Setup Key", requestType: http.MethodGet, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.ExpiredKeyId, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: true, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "expired", Type: "reusable", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 5, UsedTimes: 1, Valid: false, }, }, { name: "Get existing revoked Setup Key", requestType: http.MethodGet, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.RevokedKeyId, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: true, State: "revoked", Type: "reusable", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 3, UsedTimes: 0, Valid: false, }, }, { name: "Get non-existing Setup Key", requestType: http.MethodGet, requestPath: "/api/setup-keys/{id}", requestId: "someId", expectedStatus: http.StatusNotFound, expectedResponse: nil, }, } for _, tc := range tt { for _, user := range users { t.Run(tc.name, func(t *testing.T) { apiHandler, am, done := testing_tools.BuildApiBlackBoxWithDBState(t, "../testdata/setup_keys.sql", nil, true) req := testing_tools.BuildRequest(t, []byte{}, tc.requestType, strings.Replace(tc.requestPath, "{id}", tc.requestId, 1), user.userId) recorder := httptest.NewRecorder() apiHandler.ServeHTTP(recorder, req) content, expectRespnose := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse) if !expectRespnose { return } got := &api.SetupKey{} if err := json.Unmarshal(content, &got); err != nil { t.Fatalf("Sent content is not in correct json format; %v", err) } validateCreatedKey(t, tc.expectedResponse, got) key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id) if err != nil { return } validateCreatedKey(t, tc.expectedResponse, setup_keys.ToResponseBody(key)) select { case <-done: case <-time.After(time.Second): t.Error("timeout waiting for peerShouldNotReceiveUpdate") } }) } } } func Test_SetupKeys_GetAll(t *testing.T) { users := []struct { name string userId string expectResponse bool }{ { name: "Regular user", userId: testing_tools.TestUserId, expectResponse: false, }, { name: "Admin user", userId: testing_tools.TestAdminId, expectResponse: true, }, { name: "Owner user", userId: testing_tools.TestOwnerId, expectResponse: true, }, { name: "Regular service user", userId: testing_tools.TestServiceUserId, expectResponse: false, }, { name: "Admin service user", userId: testing_tools.TestServiceAdminId, expectResponse: true, }, { name: "Blocked user", userId: testing_tools.BlockedUserId, expectResponse: false, }, { name: "Other user", userId: testing_tools.OtherUserId, expectResponse: false, }, { name: "Invalid token", userId: testing_tools.InvalidToken, expectResponse: false, }, } tt := []struct { name string expectedStatus int expectedResponse []*api.SetupKey requestType string requestPath string }{ { name: "Get all Setup Keys", requestType: http.MethodGet, requestPath: "/api/setup-keys", expectedStatus: http.StatusOK, expectedResponse: []*api.SetupKey{ { AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "valid", Type: "one-off", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 1, UsedTimes: 0, Valid: true, }, { AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: true, State: "revoked", Type: "reusable", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 3, UsedTimes: 0, Valid: false, }, { AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: true, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "expired", Type: "reusable", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 5, UsedTimes: 1, Valid: false, }, }, }, } for _, tc := range tt { for _, user := range users { t.Run(tc.name, func(t *testing.T) { apiHandler, am, done := testing_tools.BuildApiBlackBoxWithDBState(t, "../testdata/setup_keys.sql", nil, true) req := testing_tools.BuildRequest(t, []byte{}, tc.requestType, tc.requestPath, user.userId) recorder := httptest.NewRecorder() apiHandler.ServeHTTP(recorder, req) content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse) if !expectResponse { return } got := []api.SetupKey{} if err := json.Unmarshal(content, &got); err != nil { t.Fatalf("Sent content is not in correct json format; %v", err) } sort.Slice(got, func(i, j int) bool { return got[i].UsageLimit < got[j].UsageLimit }) sort.Slice(tc.expectedResponse, func(i, j int) bool { return tc.expectedResponse[i].UsageLimit < tc.expectedResponse[j].UsageLimit }) for i := range tc.expectedResponse { validateCreatedKey(t, tc.expectedResponse[i], &got[i]) key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got[i].Id) if err != nil { return } validateCreatedKey(t, tc.expectedResponse[i], setup_keys.ToResponseBody(key)) } select { case <-done: case <-time.After(time.Second): t.Error("timeout waiting for peerShouldNotReceiveUpdate") } }) } } } func Test_SetupKeys_Delete(t *testing.T) { users := []struct { name string userId string expectResponse bool }{ { name: "Regular user", userId: testing_tools.TestUserId, expectResponse: false, }, { name: "Admin user", userId: testing_tools.TestAdminId, expectResponse: true, }, { name: "Owner user", userId: testing_tools.TestOwnerId, expectResponse: true, }, { name: "Regular service user", userId: testing_tools.TestServiceUserId, expectResponse: false, }, { name: "Admin service user", userId: testing_tools.TestServiceAdminId, expectResponse: true, }, { name: "Blocked user", userId: testing_tools.BlockedUserId, expectResponse: false, }, { name: "Other user", userId: testing_tools.OtherUserId, expectResponse: false, }, { name: "Invalid token", userId: testing_tools.InvalidToken, expectResponse: false, }, } tt := []struct { name string expectedStatus int expectedResponse *api.SetupKey requestType string requestPath string requestId string }{ { name: "Delete existing valid Setup Key", requestType: http.MethodDelete, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.TestKeyId, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "valid", Type: "one-off", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 1, UsedTimes: 0, Valid: true, }, }, { name: "Delete existing expired Setup Key", requestType: http.MethodDelete, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.ExpiredKeyId, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: true, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: false, State: "expired", Type: "reusable", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 5, UsedTimes: 1, Valid: false, }, }, { name: "Delete existing revoked Setup Key", requestType: http.MethodDelete, requestPath: "/api/setup-keys/{id}", requestId: testing_tools.RevokedKeyId, expectedStatus: http.StatusOK, expectedResponse: &api.SetupKey{ AutoGroups: []string{testing_tools.TestGroupId}, Ephemeral: false, Expires: time.Time{}, Id: "", Key: "", LastUsed: time.Time{}, Name: testing_tools.ExistingKeyName, Revoked: true, State: "revoked", Type: "reusable", UpdatedAt: time.Date(2021, time.August, 19, 20, 46, 20, 0, time.UTC), UsageLimit: 3, UsedTimes: 0, Valid: false, }, }, { name: "Delete non-existing Setup Key", requestType: http.MethodDelete, requestPath: "/api/setup-keys/{id}", requestId: "someId", expectedStatus: http.StatusNotFound, expectedResponse: nil, }, } for _, tc := range tt { for _, user := range users { t.Run(tc.name, func(t *testing.T) { apiHandler, am, done := testing_tools.BuildApiBlackBoxWithDBState(t, "../testdata/setup_keys.sql", nil, true) req := testing_tools.BuildRequest(t, []byte{}, tc.requestType, strings.Replace(tc.requestPath, "{id}", tc.requestId, 1), user.userId) recorder := httptest.NewRecorder() apiHandler.ServeHTTP(recorder, req) content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse) if !expectResponse { return } got := &api.SetupKey{} if err := json.Unmarshal(content, &got); err != nil { t.Fatalf("Sent content is not in correct json format; %v", err) } _, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id) assert.Errorf(t, err, "Expected error when trying to get deleted key") select { case <-done: case <-time.After(time.Second): t.Error("timeout waiting for peerShouldNotReceiveUpdate") } }) } } } func validateCreatedKey(t *testing.T, expectedKey *api.SetupKey, got *api.SetupKey) { t.Helper() if got.Expires.After(time.Now().Add(-1*time.Minute)) && got.Expires.Before(time.Now().Add(testing_tools.ExpiresIn*time.Second)) || got.Expires.After(time.Date(2300, 01, 01, 0, 0, 0, 0, time.Local)) || got.Expires.Before(time.Date(1950, 01, 01, 0, 0, 0, 0, time.Local)) { got.Expires = time.Time{} expectedKey.Expires = time.Time{} } if got.Id == "" { t.Fatalf("Expected key to have an ID") } got.Id = "" if got.Key == "" { t.Fatalf("Expected key to have a key") } got.Key = "" if got.UpdatedAt.After(time.Now().Add(-1*time.Minute)) && got.UpdatedAt.Before(time.Now().Add(+1*time.Minute)) { got.UpdatedAt = time.Time{} expectedKey.UpdatedAt = time.Time{} } expectedKey.UpdatedAt = expectedKey.UpdatedAt.In(time.UTC) got.UpdatedAt = got.UpdatedAt.In(time.UTC) assert.Equal(t, expectedKey, got) }