diff --git a/pkg/tests/apis/alerting/notifications/receivers/imported_test.go b/pkg/tests/apis/alerting/notifications/receivers/imported_test.go index f265834b229..56d19aa0aaf 100644 --- a/pkg/tests/apis/alerting/notifications/receivers/imported_test.go +++ b/pkg/tests/apis/alerting/notifications/receivers/imported_test.go @@ -10,10 +10,10 @@ import ( "github.com/grafana/alerting/notify" "github.com/grafana/alerting/receivers/schema" + "github.com/grafana/grafana-app-sdk/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -21,7 +21,6 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/tests/api/alerting" "github.com/grafana/grafana/pkg/tests/apis" - test_common "github.com/grafana/grafana/pkg/tests/apis/alerting/notifications/common" "github.com/grafana/grafana/pkg/tests/testinfra" ) @@ -34,7 +33,8 @@ func TestIntegrationReadImported_Snapshot(t *testing.T) { }, }) - receiverClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + receiverClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) cliCfg := helper.Org1.Admin.NewRestConfig() alertingApi := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password) @@ -58,9 +58,9 @@ func TestIntegrationReadImported_Snapshot(t *testing.T) { response := alertingApi.ConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers) require.Equal(t, "success", response.Status) - receiversRaw, err := receiverClient.Client.List(ctx, v1.ListOptions{}) + receiversRaw, err := receiverClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) - raw, err := receiversRaw.MarshalJSON() + raw, err := json.Marshal(receiversRaw) require.NoError(t, err) expectedBytes, err := os.ReadFile(path.Join("test-data", "imported-expected-snapshot.json")) @@ -74,7 +74,7 @@ func TestIntegrationReadImported_Snapshot(t *testing.T) { require.NoError(t, err) } - receivers, err := receiverClient.List(ctx, v1.ListOptions{}) + receivers, err := receiverClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) t.Run("secure fields should be properly masked", func(t *testing.T) { for _, receiver := range receivers.Items { @@ -114,14 +114,14 @@ func TestIntegrationReadImported_Snapshot(t *testing.T) { toUpdate := receivers.Items[1] toUpdate.Spec.Title = "another title" - _, err = receiverClient.Update(ctx, &toUpdate, v1.UpdateOptions{}) + _, err = receiverClient.Update(ctx, &toUpdate, resource.UpdateOptions{}) require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err) }) t.Run("should not be able to delete", func(t *testing.T) { toDelete := receivers.Items[1] - err = receiverClient.Delete(ctx, toDelete.Name, v1.DeleteOptions{}) + err = receiverClient.Delete(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: toDelete.Name}, resource.DeleteOptions{}) require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err) }) } diff --git a/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go b/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go index 5497c8f1685..52fc1fe1a21 100644 --- a/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go +++ b/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go @@ -15,12 +15,12 @@ import ( "github.com/grafana/alerting/notify/notifytest" "github.com/grafana/alerting/receivers/line" "github.com/grafana/alerting/receivers/schema" + "github.com/grafana/grafana-app-sdk/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/types" "github.com/grafana/alerting/notify" @@ -65,7 +65,8 @@ func TestIntegrationResourceIdentifier(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - client := test_common.NewReceiverClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) newResource := &v0alpha1.Receiver{ ObjectMeta: v1.ObjectMeta{ Namespace: "default", @@ -77,42 +78,42 @@ func TestIntegrationResourceIdentifier(t *testing.T) { } t.Run("create should fail if object name is specified", func(t *testing.T) { - resource := newResource.Copy().(*v0alpha1.Receiver) - resource.Name = "new-receiver" - _, err := client.Create(ctx, resource, v1.CreateOptions{}) + receiver := newResource.Copy().(*v0alpha1.Receiver) + receiver.Name = "new-receiver" + _, err := client.Create(ctx, receiver, resource.CreateOptions{}) require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err) }) - var resourceID string + var resourceID resource.Identifier t.Run("create should succeed and provide resource name", func(t *testing.T) { - actual, err := client.Create(ctx, newResource, v1.CreateOptions{}) + actual, err := client.Create(ctx, newResource, resource.CreateOptions{}) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") require.NotEmptyf(t, actual.UID, "Resource UID should not be empty") - resourceID = actual.Name + resourceID = actual.GetStaticMetadata().Identifier() }) t.Run("resource should be available by the identifier", func(t *testing.T) { - actual, err := client.Get(ctx, resourceID, v1.GetOptions{}) + actual, err := client.Get(ctx, resourceID) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") require.Equal(t, newResource.Spec, actual.Spec) }) t.Run("update should rename receiver if name in the specification changes", func(t *testing.T) { - existing, err := client.Get(ctx, resourceID, v1.GetOptions{}) + existing, err := client.Get(ctx, resourceID) require.NoError(t, err) updated := existing.Copy().(*v0alpha1.Receiver) updated.Spec.Title = "another-newReceiver" - actual, err := client.Update(ctx, updated, v1.UpdateOptions{}) + actual, err := client.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.Equal(t, updated.Spec, actual.Spec) require.NotEqualf(t, updated.Name, actual.Name, "Update should change the resource name but it didn't") require.NotEqualf(t, updated.ResourceVersion, actual.ResourceVersion, "Update should change the resource version but it didn't") - resource, err := client.Get(ctx, actual.Name, v1.GetOptions{}) + resource, err := client.Get(ctx, actual.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, actual.Spec, resource.Spec) require.Equal(t, actual.Name, resource.Name) @@ -140,7 +141,8 @@ func TestIntegrationResourcePermissions(t *testing.T) { admin := org1.Admin viewer := org1.Viewer editor := org1.Editor - adminClient := test_common.NewReceiverClient(t, admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(admin.GetClientRegistry()) + require.NoError(t, err) writeACMetadata := []string{"canWrite", "canDelete"} allACMetadata := []string{"canWrite", "canDelete", "canReadSecrets", "canAdmin", "canModifyProtected"} @@ -292,8 +294,10 @@ func TestIntegrationResourcePermissions(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - createClient := test_common.NewReceiverClient(t, tc.creatingUser) - client := test_common.NewReceiverClient(t, tc.testUser) + createClient, err := v0alpha1.NewReceiverClientFromGenerator(tc.creatingUser.GetClientRegistry()) + require.NoError(t, err) + client, err := v0alpha1.NewReceiverClientFromGenerator(tc.testUser.GetClientRegistry()) + require.NoError(t, err) var created = &v0alpha1.Receiver{ ObjectMeta: v1.ObjectMeta{ @@ -308,12 +312,12 @@ func TestIntegrationResourcePermissions(t *testing.T) { require.NoError(t, err) // Create receiver with creatingUser - created, err = createClient.Create(ctx, created, v1.CreateOptions{}) + created, err = createClient.Create(ctx, created, resource.CreateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.NotNil(t, created) defer func() { - _ = adminClient.Delete(ctx, created.Name, v1.DeleteOptions{}) + _ = adminClient.Delete(ctx, created.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) }() // Assign resource permissions @@ -338,7 +342,7 @@ func TestIntegrationResourcePermissions(t *testing.T) { // Obtain expected responses using admin client as source of truth. expectedGetWithMetadata, expectedListWithMetadata := func() (*v0alpha1.Receiver, *v0alpha1.Receiver) { - expectedGet, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + expectedGet, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) require.NotNil(t, expectedGet) @@ -352,7 +356,7 @@ func TestIntegrationResourcePermissions(t *testing.T) { expectedGetWithMetadata.SetAccessControl(ac) } - expectedList, err := adminClient.List(ctx, v1.ListOptions{}) + expectedList, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) expectedListWithMetadata := extractReceiverFromList(expectedList, created.Name) require.NotNil(t, expectedListWithMetadata) @@ -368,26 +372,26 @@ func TestIntegrationResourcePermissions(t *testing.T) { }() t.Run("should be able to list receivers", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) listedReceiver := extractReceiverFromList(list, created.Name) assert.Equalf(t, expectedListWithMetadata, listedReceiver, "Expected %v but got %v", expectedListWithMetadata, listedReceiver) }) t.Run("should be able to read receiver by resource identifier", func(t *testing.T) { - got, err := client.Get(ctx, expectedGetWithMetadata.Name, v1.GetOptions{}) + got, err := client.Get(ctx, expectedGetWithMetadata.GetStaticMetadata().Identifier()) require.NoError(t, err) assert.Equalf(t, expectedGetWithMetadata, got, "Expected %v but got %v", expectedGetWithMetadata, got) }) } else { t.Run("list receivers should be empty", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Emptyf(t, list.Items, "Expected no receivers but got %v", list.Items) }) t.Run("should be forbidden to read receiver by name", func(t *testing.T) { - _, err := client.Get(ctx, created.Name, v1.GetOptions{}) + _, err := client.Get(ctx, created.GetStaticMetadata().Identifier()) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) } @@ -559,10 +563,12 @@ func TestIntegrationAccessControl(t *testing.T) { }, } - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) for _, tc := range testCases { t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) { - client := test_common.NewReceiverClient(t, tc.user) + client, err := v0alpha1.NewReceiverClientFromGenerator(tc.user.GetClientRegistry()) + require.NoError(t, err) var expected = &v0alpha1.Receiver{ ObjectMeta: v1.ObjectMeta{ @@ -580,29 +586,29 @@ func TestIntegrationAccessControl(t *testing.T) { newReceiver.Spec.Title = fmt.Sprintf("receiver-2-%s", tc.user.Identity.GetLogin()) if tc.canCreate { t.Run("should be able to create receiver", func(t *testing.T) { - actual, err := client.Create(ctx, newReceiver, v1.CreateOptions{}) + actual, err := client.Create(ctx, newReceiver, resource.CreateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.Equal(t, newReceiver.Spec, actual.Spec) t.Run("should fail if already exists", func(t *testing.T) { - _, err := client.Create(ctx, newReceiver, v1.CreateOptions{}) + _, err := client.Create(ctx, newReceiver, resource.CreateOptions{}) require.Truef(t, errors.IsConflict(err), "expected bad request but got %s", err) }) // Cleanup. - require.NoError(t, adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{})) + require.NoError(t, adminClient.Delete(ctx, actual.GetStaticMetadata().Identifier(), resource.DeleteOptions{})) }) } else { t.Run("should be forbidden to create", func(t *testing.T) { - _, err := client.Create(ctx, newReceiver, v1.CreateOptions{}) + _, err := client.Create(ctx, newReceiver, resource.CreateOptions{}) require.Truef(t, errors.IsForbidden(err), "Payload %s", string(d)) }) } // create resource to proceed with other tests. We don't use the one created above because the user will always // have admin permissions on it. - expected, err = adminClient.Create(ctx, expected, v1.CreateOptions{}) + expected, err = adminClient.Create(ctx, expected, resource.CreateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.NotNil(t, expected) @@ -627,34 +633,34 @@ func TestIntegrationAccessControl(t *testing.T) { expectedWithMetadata.SetAccessControl("canAdmin") } t.Run("should be able to list receivers", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, list.Items, 2) // default + created }) t.Run("should be able to read receiver by resource identifier", func(t *testing.T) { - got, err := client.Get(ctx, expected.Name, v1.GetOptions{}) + got, err := client.Get(ctx, expected.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, expectedWithMetadata, got) t.Run("should get NotFound if resource does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("list receivers should be empty", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Emptyf(t, list.Items, "Expected no receivers but got %v", list.Items) }) t.Run("should be forbidden to read receiver by name", func(t *testing.T) { - _, err := client.Get(ctx, expected.Name, v1.GetOptions{}) + _, err := client.Get(ctx, expected.GetStaticMetadata().Identifier()) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if name does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) @@ -668,7 +674,7 @@ func TestIntegrationAccessControl(t *testing.T) { if tc.canUpdate { t.Run("should be able to update receiver", func(t *testing.T) { - updated, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) + updated, err := client.Update(ctx, updatedExpected, resource.UpdateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) expected = updated @@ -676,7 +682,7 @@ func TestIntegrationAccessControl(t *testing.T) { t.Run("should get NotFound if name does not exist", func(t *testing.T) { up := updatedExpected.Copy().(*v0alpha1.Receiver) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) @@ -686,7 +692,7 @@ func TestIntegrationAccessControl(t *testing.T) { createIntegration(t, "webhook"), } - expected, err = adminClient.Update(ctx, updatedExpected, v1.UpdateOptions{}) + expected, err = adminClient.Update(ctx, updatedExpected, resource.UpdateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.NotNil(t, expected) @@ -695,60 +701,62 @@ func TestIntegrationAccessControl(t *testing.T) { if tc.canUpdateProtected { t.Run("should be able to update protected fields of the receiver", func(t *testing.T) { - updated, err := client.Update(ctx, updatedProtected, v1.UpdateOptions{}) + updated, err := client.Update(ctx, updatedProtected, resource.UpdateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.NotNil(t, updated) expected = updated }) } else { t.Run("should be forbidden to edit protected fields of the receiver", func(t *testing.T) { - _, err := client.Update(ctx, updatedProtected, v1.UpdateOptions{}) + _, err := client.Update(ctx, updatedProtected, resource.UpdateOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) } } else { t.Run("should be forbidden to update receiver", func(t *testing.T) { - _, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) + _, err := client.Update(ctx, updatedExpected, resource.UpdateOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if resource does not exist", func(t *testing.T) { up := updatedExpected.Copy().(*v0alpha1.Receiver) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{ + ResourceVersion: up.ResourceVersion, + }) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) require.Falsef(t, tc.canUpdateProtected, "Invalid combination of assertions. CanUpdateProtected should be false") } - deleteOptions := v1.DeleteOptions{Preconditions: &v1.Preconditions{ResourceVersion: util.Pointer(expected.ResourceVersion)}} + deleteOptions := resource.DeleteOptions{Preconditions: resource.DeleteOptionsPreconditions{ResourceVersion: expected.ResourceVersion}} if tc.canDelete { t.Run("should be able to delete receiver", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, deleteOptions) + err := client.Delete(ctx, expected.GetStaticMetadata().Identifier(), deleteOptions) require.NoError(t, err) t.Run("should get NotFound if name does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := client.Delete(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "notfound"}, resource.DeleteOptions{}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to delete receiver", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, deleteOptions) + err := client.Delete(ctx, expected.GetStaticMetadata().Identifier(), deleteOptions) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should be forbidden even if resource does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := client.Delete(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "notfound"}, resource.DeleteOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) - require.NoError(t, adminClient.Delete(ctx, expected.Name, v1.DeleteOptions{})) + require.NoError(t, adminClient.Delete(ctx, expected.GetStaticMetadata().Identifier(), resource.DeleteOptions{})) } if tc.canRead { t.Run("should get empty list if no receivers", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, list.Items, 1) }) @@ -766,7 +774,8 @@ func TestIntegrationInUseMetadata(t *testing.T) { cliCfg := helper.Org1.Admin.NewRestConfig() legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password) - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) // Prepare environment and create notification policy and rule that use receiver alertmanagerRaw, err := testData.ReadFile(path.Join("test-data", "notification-settings.json")) require.NoError(t, err) @@ -813,7 +822,7 @@ func TestIntegrationInUseMetadata(t *testing.T) { requestReceivers := func(t *testing.T, title string) (v0alpha1.Receiver, v0alpha1.Receiver) { t.Helper() - receivers, err := adminClient.List(ctx, v1.ListOptions{}) + receivers, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, receivers.Items, 2) idx := slices.IndexFunc(receivers.Items, func(interval v0alpha1.Receiver) bool { @@ -821,7 +830,7 @@ func TestIntegrationInUseMetadata(t *testing.T) { }) receiverListed := receivers.Items[idx] - receiverGet, err := adminClient.Get(ctx, receiverListed.Name, v1.GetOptions{}) + receiverGet, err := adminClient.Get(ctx, receiverListed.GetStaticMetadata().Identifier()) require.NoError(t, err) return receiverListed, *receiverGet @@ -846,8 +855,9 @@ func TestIntegrationInUseMetadata(t *testing.T) { amConfig.AlertmanagerConfig.Route.Routes = amConfig.AlertmanagerConfig.Route.Routes[:1] v1Route, err := routingtree.ConvertToK8sResource(helper.Org1.AdminServiceAccount.OrgId, *amConfig.AlertmanagerConfig.Route, "", func(int64) string { return "default" }) require.NoError(t, err) - routeAdminClient := test_common.NewRoutingTreeClient(t, helper.Org1.Admin) - _, err = routeAdminClient.Update(ctx, v1Route, v1.UpdateOptions{}) + routeAdminClient, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) + _, err = routeAdminClient.Update(ctx, v1Route, resource.UpdateOptions{}) require.NoError(t, err) receiverListed, receiverGet = requestReceivers(t, "user-defined") @@ -868,7 +878,7 @@ func TestIntegrationInUseMetadata(t *testing.T) { amConfig.AlertmanagerConfig.Route.Routes = nil v1route, err := routingtree.ConvertToK8sResource(1, *amConfig.AlertmanagerConfig.Route, "", func(int64) string { return "default" }) require.NoError(t, err) - _, err = routeAdminClient.Update(ctx, v1route, v1.UpdateOptions{}) + _, err = routeAdminClient.Update(ctx, v1route, resource.UpdateOptions{}) require.NoError(t, err) // Remove the remaining rules. @@ -892,7 +902,8 @@ func TestIntegrationProvisioning(t *testing.T) { org := helper.Org1 admin := org.Admin - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) env := helper.GetEnv() ac := acimpl.ProvideAccessControl(env.FeatureToggles) db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac, bus.ProvideBus(tracing.InitializeTracerForTest())) @@ -908,7 +919,7 @@ func TestIntegrationProvisioning(t *testing.T) { createIntegration(t, "email"), }, }, - }, v1.CreateOptions{}) + }, resource.CreateOptions{}) require.NoError(t, err) require.Equal(t, "none", created.GetProvenanceStatus()) @@ -917,23 +928,23 @@ func TestIntegrationProvisioning(t *testing.T) { UID: *created.Spec.Integrations[0].Uid, }, admin.Identity.GetOrgID(), "API")) - got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + got, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, "API", got.GetProvenanceStatus()) }) t.Run("should not let update if provisioned", func(t *testing.T) { - got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + got, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) updated := got.Copy().(*v0alpha1.Receiver) updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "email")) - _, err = adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err = adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) t.Run("should not let delete if provisioned", func(t *testing.T) { - err := adminClient.Delete(ctx, created.Name, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, created.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) } @@ -944,7 +955,10 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) + oldClient := test_common.NewReceiverClient(t, helper.Org1.Admin) // TODO replace with regular client once Delete works + receiver := v0alpha1.Receiver{ ObjectMeta: v1.ObjectMeta{ Namespace: "default", @@ -955,21 +969,22 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { }, } - created, err := adminClient.Create(ctx, &receiver, v1.CreateOptions{}) + created, err := adminClient.Create(ctx, &receiver, resource.CreateOptions{}) require.NoError(t, err) require.NotNil(t, created) require.NotEmpty(t, created.ResourceVersion) - t.Run("should forbid if version does not match", func(t *testing.T) { + t.Run("should conflict if version does not match", func(t *testing.T) { updated := created.Copy().(*v0alpha1.Receiver) - updated.ResourceVersion = "test" - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := adminClient.Update(ctx, updated, resource.UpdateOptions{ + ResourceVersion: "test", + }) require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) }) t.Run("should update if version matches", func(t *testing.T) { updated := created.Copy().(*v0alpha1.Receiver) updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "email")) - actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + actualUpdated, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) for i, integration := range actualUpdated.Spec.Integrations { updated.Spec.Integrations[i].Uid = integration.Uid @@ -981,25 +996,25 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { updated := created.Copy().(*v0alpha1.Receiver) updated.ResourceVersion = "" updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "webhook")) - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := oldClient.Update(ctx, updated, v1.UpdateOptions{}) require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) // TODO Change that? K8s returns 400 instead. }) t.Run("should fail to delete if version does not match", func(t *testing.T) { - actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + actual, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer("something"), }, }) - require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) + require.Truef(t, errors.IsConflict(err), "should get conflict error but got %s", err) }) t.Run("should succeed if version matches", func(t *testing.T) { - actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + actual, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer(actual.ResourceVersion), }, @@ -1007,10 +1022,10 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { require.NoError(t, err) }) t.Run("should succeed if version is empty", func(t *testing.T) { - actual, err := adminClient.Create(ctx, &receiver, v1.CreateOptions{}) + actual, err := adminClient.Create(ctx, &receiver, resource.CreateOptions{}) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer(actual.ResourceVersion), }, @@ -1025,7 +1040,8 @@ func TestIntegrationPatch(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) receiver := v0alpha1.Receiver{ ObjectMeta: v1.ObjectMeta{ Namespace: "default", @@ -1040,40 +1056,40 @@ func TestIntegrationPatch(t *testing.T) { }, } - current, err := adminClient.Create(ctx, &receiver, v1.CreateOptions{}) + current, err := adminClient.Create(ctx, &receiver, resource.CreateOptions{}) require.NoError(t, err) require.NotNil(t, current) t.Run("should patch with json patch", func(t *testing.T) { - current, err := adminClient.Get(ctx, current.Name, v1.GetOptions{}) + current, err := adminClient.Get(ctx, current.GetStaticMetadata().Identifier()) require.NoError(t, err) index := slices.IndexFunc(current.Spec.Integrations, func(t v0alpha1.ReceiverIntegration) bool { return t.Type == "webhook" }) - patch := []map[string]any{ + patch := []resource.PatchOperation{ { - "op": "remove", - "path": fmt.Sprintf("/spec/integrations/%d/settings/username", index), + Operation: "remove", + Path: fmt.Sprintf("/spec/integrations/%d/settings/username", index), }, { - "op": "remove", - "path": fmt.Sprintf("/spec/integrations/%d/secureFields/password", index), + Operation: "remove", + Path: fmt.Sprintf("/spec/integrations/%d/secureFields/password", index), }, { - "op": "replace", - "path": fmt.Sprintf("/spec/integrations/%d/settings/authorization_scheme", index), - "value": "bearer", + Operation: "replace", + Path: fmt.Sprintf("/spec/integrations/%d/settings/authorization_scheme", index), + Value: "bearer", }, { - "op": "add", - "path": fmt.Sprintf("/spec/integrations/%d/settings/authorization_credentials", index), - "value": "authz-token", + Operation: "add", + Path: fmt.Sprintf("/spec/integrations/%d/settings/authorization_credentials", index), + Value: "authz-token", }, { - "op": "remove", - "path": fmt.Sprintf("/spec/integrations/%d/secureFields/authorization_credentials", index), + Operation: "remove", + Path: fmt.Sprintf("/spec/integrations/%d/secureFields/authorization_credentials", index), }, } @@ -1084,10 +1100,7 @@ func TestIntegrationPatch(t *testing.T) { delete(expected.SecureFields, "password") expected.SecureFields["authorization_credentials"] = true - patchData, err := json.Marshal(patch) - require.NoError(t, err) - - result, err := adminClient.Patch(ctx, current.Name, types.JSONPatchType, patchData, v1.PatchOptions{}) + result, err := adminClient.Patch(ctx, current.GetStaticMetadata().Identifier(), resource.PatchRequest{Operations: patch}, resource.PatchOptions{}) require.NoError(t, err) require.EqualValues(t, expected, result.Spec.Integrations[index]) @@ -1127,7 +1140,8 @@ func TestIntegrationReferentialIntegrity(t *testing.T) { cliCfg := helper.Org1.Admin.NewRestConfig() legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password) - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) // Prepare environment and create notification policy and rule that use time receiver alertmanagerRaw, err := testData.ReadFile(path.Join("test-data", "notification-settings.json")) require.NoError(t, err) @@ -1146,7 +1160,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) { _, status, data := legacyCli.PostRulesGroupWithStatus(t, folderUID, &ruleGroup, false) require.Equalf(t, http.StatusAccepted, status, "Failed to post Rule: %s", data) - receivers, err := adminClient.List(ctx, v1.ListOptions{}) + receivers, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, receivers.Items, 2) idx := slices.IndexFunc(receivers.Items, func(interval v0alpha1.Receiver) bool { @@ -1164,7 +1178,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) { expectedTitle := renamed.Spec.Title + "-new" renamed.Spec.Title = expectedTitle - actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{}) + actual, err := adminClient.Update(ctx, renamed, resource.UpdateOptions{}) require.NoError(t, err) updatedRuleGroup, status := legacyCli.GetRulesGroup(t, folderUID, ruleGroup.Name) @@ -1178,7 +1192,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) { assert.Equalf(t, expectedTitle, route.Receiver, "time receiver in routes should have been renamed but it did not") } - actual, err = adminClient.Get(ctx, actual.Name, v1.GetOptions{}) + actual, err = adminClient.Get(ctx, actual.GetStaticMetadata().Identifier()) require.NoError(t, err) receiver = *actual @@ -1194,20 +1208,20 @@ func TestIntegrationReferentialIntegrity(t *testing.T) { t.Cleanup(func() { require.NoError(t, db.DeleteProvenance(ctx, ¤tRoute, orgID)) }) - actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{}) + actual, err := adminClient.Update(ctx, renamed, resource.UpdateOptions{}) require.Errorf(t, err, "Expected error but got successful result: %v", actual) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) t.Run("provisioned rules", func(t *testing.T) { ruleUid := currentRuleGroup.Rules[0].GrafanaManagedAlert.UID - resource := &ngmodels.AlertRule{UID: ruleUid} - require.NoError(t, db.SetProvenance(ctx, resource, orgID, "API")) + rule := &ngmodels.AlertRule{UID: ruleUid} + require.NoError(t, db.SetProvenance(ctx, rule, orgID, "API")) t.Cleanup(func() { - require.NoError(t, db.DeleteProvenance(ctx, resource, orgID)) + require.NoError(t, db.DeleteProvenance(ctx, rule, orgID)) }) - actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{}) + actual, err := adminClient.Update(ctx, renamed, resource.UpdateOptions{}) require.Errorf(t, err, "Expected error but got successful result: %v", actual) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) @@ -1216,7 +1230,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) { t.Run("Delete", func(t *testing.T) { t.Run("should fail to delete if receiver is used in rule and routes", func(t *testing.T) { - err := adminClient.Delete(ctx, receiver.Name, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, receiver.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) @@ -1225,7 +1239,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) { route.Routes[0].Receiver = "" legacyCli.UpdateRoute(t, route, true) - err = adminClient.Delete(ctx, receiver.Name, v1.DeleteOptions{}) + err = adminClient.Delete(ctx, receiver.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) }) @@ -1237,10 +1251,11 @@ func TestIntegrationCRUD(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) var defaultReceiver *v0alpha1.Receiver t.Run("should list the default receiver", func(t *testing.T) { - items, err := adminClient.List(ctx, v1.ListOptions{}) + items, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) assert.Len(t, items.Items, 1) defaultReceiver = &items.Items[0] @@ -1249,7 +1264,7 @@ func TestIntegrationCRUD(t *testing.T) { assert.NotEmpty(t, defaultReceiver.Name) assert.NotEmpty(t, defaultReceiver.ResourceVersion) - defaultReceiver, err = adminClient.Get(ctx, defaultReceiver.Name, v1.GetOptions{}) + defaultReceiver, err = adminClient.Get(ctx, defaultReceiver.GetStaticMetadata().Identifier()) require.NoError(t, err) assert.NotEmpty(t, defaultReceiver.UID) assert.NotEmpty(t, defaultReceiver.Name) @@ -1262,7 +1277,7 @@ func TestIntegrationCRUD(t *testing.T) { newDefault := defaultReceiver.Copy().(*v0alpha1.Receiver) newDefault.Spec.Integrations = append(newDefault.Spec.Integrations, createIntegration(t, line.Type)) - updatedReceiver, err := adminClient.Update(ctx, newDefault, v1.UpdateOptions{}) + updatedReceiver, err := adminClient.Update(ctx, newDefault, resource.UpdateOptions{}) require.NoError(t, err) expected := newDefault.Copy().(*v0alpha1.Receiver) @@ -1290,12 +1305,12 @@ func TestIntegrationCRUD(t *testing.T) { Integrations: []v0alpha1.ReceiverIntegration{}, }, } - _, err := adminClient.Create(ctx, newReceiver, v1.CreateOptions{}) + _, err := adminClient.Create(ctx, newReceiver, resource.CreateOptions{}) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) t.Run("should not let delete default receiver", func(t *testing.T) { - err := adminClient.Delete(ctx, defaultReceiver.Name, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, defaultReceiver.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) @@ -1317,7 +1332,7 @@ func TestIntegrationCRUD(t *testing.T) { Title: "all-receivers", Integrations: integrations, }, - }, v1.CreateOptions{}) + }, resource.CreateOptions{}) require.NoError(t, err) require.Len(t, receiver.Spec.Integrations, len(integrations)) @@ -1342,7 +1357,7 @@ func TestIntegrationCRUD(t *testing.T) { }) t.Run("should be able read what it is created", func(t *testing.T) { - get, err := adminClient.Get(ctx, receiver.Name, v1.GetOptions{}) + get, err := adminClient.Get(ctx, receiver.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, receiver, get) t.Run("should return secrets in secureFields but not settings", func(t *testing.T) { @@ -1394,7 +1409,7 @@ func TestIntegrationCRUD(t *testing.T) { Title: fmt.Sprintf("invalid-%s", key), Integrations: []v0alpha1.ReceiverIntegration{integration}, }, - }, v1.CreateOptions{}) + }, resource.CreateOptions{}) require.Errorf(t, err, "Expected error but got successful result: %v", receiver) require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest, got: %s", err) }) @@ -1408,7 +1423,8 @@ func TestIntegrationReceiverListSelector(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) recv1 := &v0alpha1.Receiver{ ObjectMeta: v1.ObjectMeta{ Namespace: "default", @@ -1420,7 +1436,7 @@ func TestIntegrationReceiverListSelector(t *testing.T) { }, }, } - recv1, err := adminClient.Create(ctx, recv1, v1.CreateOptions{}) + recv1, err = adminClient.Create(ctx, recv1, resource.CreateOptions{}) require.NoError(t, err) recv2 := &v0alpha1.Receiver{ @@ -1434,7 +1450,7 @@ func TestIntegrationReceiverListSelector(t *testing.T) { }, }, } - recv2, err = adminClient.Create(ctx, recv2, v1.CreateOptions{}) + recv2, err = adminClient.Create(ctx, recv2, resource.CreateOptions{}) require.NoError(t, err) env := helper.GetEnv() @@ -1444,18 +1460,20 @@ func TestIntegrationReceiverListSelector(t *testing.T) { require.NoError(t, db.SetProvenance(ctx, &definitions.EmbeddedContactPoint{ UID: *recv2.Spec.Integrations[0].Uid, }, helper.Org1.Admin.Identity.GetOrgID(), "API")) - recv2, err = adminClient.Get(ctx, recv2.Name, v1.GetOptions{}) + recv2, err = adminClient.Get(ctx, recv2.GetStaticMetadata().Identifier()) require.NoError(t, err) - receivers, err := adminClient.List(ctx, v1.ListOptions{}) + receivers, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, receivers.Items, 3) // Includes default. t.Run("should filter by receiver name", func(t *testing.T) { t.Skip("disabled until app installer supports it") // TODO revisit when custom field selectors are supported - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "spec.title=" + recv1.Spec.Title, + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{ + "spec.title=" + recv1.Spec.Title, + }, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -1463,8 +1481,10 @@ func TestIntegrationReceiverListSelector(t *testing.T) { }) t.Run("should filter by metadata name", func(t *testing.T) { - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "metadata.name=" + recv2.Name, + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{ + "metadata.name=" + recv2.Name, + }, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -1473,8 +1493,10 @@ func TestIntegrationReceiverListSelector(t *testing.T) { t.Run("should filter by multiple filters", func(t *testing.T) { t.Skip("disabled until app installer supports it") // TODO revisit when custom field selectors are supported - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s,spec.title=%s", recv2.Name, recv2.Spec.Title), + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{ + fmt.Sprintf("metadata.name=%s,spec.title=%s", recv2.Name, recv2.Spec.Title), + }, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -1482,8 +1504,10 @@ func TestIntegrationReceiverListSelector(t *testing.T) { }) t.Run("should be empty when filter does not match", func(t *testing.T) { - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s", "unknown"), + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{ + fmt.Sprintf("metadata.name=%s", "unknown"), + }, }) require.NoError(t, err) require.Empty(t, list.Items) @@ -1497,7 +1521,8 @@ func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig) helper := getTestHelper(t) - receiverClient := test_common.NewReceiverClient(t, helper.Org1.Admin) + receiverClient, err := v0alpha1.NewReceiverClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) for _, receiver := range amConfig.AlertmanagerConfig.Receivers { if receiver.Name == "grafana-default-email" { continue @@ -1523,7 +1548,7 @@ func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig) }) } - created, err := receiverClient.Create(ctx, &toCreate, v1.CreateOptions{}) + created, err := receiverClient.Create(ctx, &toCreate, resource.CreateOptions{}) require.NoError(t, err) for i, integration := range created.Spec.Integrations { @@ -1533,10 +1558,11 @@ func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig) nsMapper := func(_ int64) string { return "default" } - routeClient := test_common.NewRoutingTreeClient(t, helper.Org1.Admin) + routeClient, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) v1route, err := routingtree.ConvertToK8sResource(helper.Org1.AdminServiceAccount.OrgId, *amConfig.AlertmanagerConfig.Route, "", nsMapper) require.NoError(t, err) - _, err = routeClient.Update(ctx, v1route, v1.UpdateOptions{}) + _, err = routeClient.Update(ctx, v1route, resource.UpdateOptions{}) require.NoError(t, err) } diff --git a/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json b/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json index f092d8980f7..60d8333e7b8 100644 --- a/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json +++ b/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json @@ -1,10 +1,14 @@ { + "kind": "ReceiverList", "apiVersion": "notifications.alerting.grafana.app/v0alpha1", + "metadata": {}, "items": [ { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "Z3JhZmFuYS1kZWZhdWx0LWVtYWls", + "namespace": "default", + "uid": "zyXFk301pvwNz4HRPrTMKPMFO2934cPB7H1ZXmyM1TUX", + "resourceVersion": "a82b34036bdabbc4", "annotations": { "grafana.com/access/canAdmin": "true", "grafana.com/access/canDelete": "true", @@ -15,53 +19,29 @@ "grafana.com/inUse/routes": "1", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "none" - }, - "name": "Z3JhZmFuYS1kZWZhdWx0LWVtYWls", - "namespace": "default", - "resourceVersion": "a82b34036bdabbc4", - "uid": "zyXFk301pvwNz4HRPrTMKPMFO2934cPB7H1ZXmyM1TUX" + } }, "spec": { + "title": "grafana-default-email", "integrations": [ { + "uid": "", + "type": "email", + "version": "v1", "disableResolveMessage": false, "settings": { "addresses": "\u003cexample@email.com\u003e" - }, - "type": "email", - "uid": "", - "version": "v1" + } } - ], - "title": "grafana-default-email" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { - "annotations": { - "grafana.com/access/canModifyProtected": "true", - "grafana.com/access/canReadSecrets": "true", - "grafana.com/canUse": "false", - "grafana.com/inUse/routes": "0", - "grafana.com/inUse/rules": "0", - "grafana.com/provenance": "converted_prometheus" - }, "name": "Z3JhZmFuYS1kZWZhdWx0LWVtYWlsdGVzdC1jcmVhdGUtZ2V0LWNvbmZpZw", "namespace": "default", + "uid": "JzW6DIlcxj4sRN8A2ULcwTXAmm0Vs0Z68aEBqXSvxK0X", "resourceVersion": "b2823b50ffa1eff6", - "uid": "JzW6DIlcxj4sRN8A2ULcwTXAmm0Vs0Z68aEBqXSvxK0X" - }, - "spec": { - "integrations": [], - "title": "grafana-default-emailtest-create-get-config" - } - }, - { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", - "metadata": { "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -69,19 +49,36 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "ZGlzY29yZA", - "namespace": "default", - "resourceVersion": "06e437697f62ac59", - "uid": "8cH8Ql2S6VhPEVUhwlQEKYWyPbRJS7YKj2lEXdrehH8X" + } }, "spec": { + "title": "grafana-default-emailtest-create-get-config", + "integrations": [] + } + }, + { + "metadata": { + "name": "ZGlzY29yZA", + "namespace": "default", + "uid": "8cH8Ql2S6VhPEVUhwlQEKYWyPbRJS7YKj2lEXdrehH8X", + "resourceVersion": "06e437697f62ac59", + "annotations": { + "grafana.com/access/canModifyProtected": "true", + "grafana.com/access/canReadSecrets": "true", + "grafana.com/canUse": "false", + "grafana.com/inUse/routes": "0", + "grafana.com/inUse/rules": "0", + "grafana.com/provenance": "converted_prometheus" + } + }, + "spec": { + "title": "discord", "integrations": [ { + "uid": "", + "type": "discord", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "webhook_url": true - }, "settings": { "http_config": { "enable_http2": true, @@ -95,18 +92,19 @@ "send_resolved": true, "title": "{{ template \"discord.default.title\" . }}" }, - "type": "discord", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "webhook_url": true + } } - ], - "title": "discord" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "ZW1haWw", + "namespace": "default", + "uid": "bhlvlN758xmnwVrHVPX0c5XvFHepenUbOXP0fuE6eUMX", + "resourceVersion": "9b3ffed277cee189", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -114,19 +112,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "ZW1haWw", - "namespace": "default", - "resourceVersion": "9b3ffed277cee189", - "uid": "bhlvlN758xmnwVrHVPX0c5XvFHepenUbOXP0fuE6eUMX" + } }, "spec": { + "title": "email", "integrations": [ { + "uid": "", + "type": "email", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "auth_password": true - }, "settings": { "auth_username": "alertmanager", "from": "alertmanager@example.com", @@ -144,18 +139,19 @@ }, "to": "team@example.com" }, - "type": "email", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "auth_password": true + } } - ], - "title": "email" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "amlyYQ", + "namespace": "default", + "uid": "7Pu4xcRXbvw4XEX279SoqyO8Ibo8cMl0vAJyYTsJ0NEX", + "resourceVersion": "deae9d34f8554205", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -163,19 +159,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "amlyYQ", - "namespace": "default", - "resourceVersion": "deae9d34f8554205", - "uid": "7Pu4xcRXbvw4XEX279SoqyO8Ibo8cMl0vAJyYTsJ0NEX" + } }, "spec": { + "title": "jira", "integrations": [ { + "uid": "", + "type": "jira", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "http_config.basic_auth.password": true - }, "settings": { "api_url": "http://localhost/jira", "custom_fields": { @@ -203,18 +196,19 @@ "send_resolved": true, "summary": "{{ template \"jira.default.summary\" . }}" }, - "type": "jira", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "http_config.basic_auth.password": true + } } - ], - "title": "jira" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "bXN0ZWFtcw", + "namespace": "default", + "uid": "z7xTMDjrk1HAHXPEx78tQb63LXYA6ivXLOtz2Z09ucIX", + "resourceVersion": "95c8d082d65466a3", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -222,19 +216,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "bXN0ZWFtcw", - "namespace": "default", - "resourceVersion": "95c8d082d65466a3", - "uid": "z7xTMDjrk1HAHXPEx78tQb63LXYA6ivXLOtz2Z09ucIX" + } }, "spec": { + "title": "msteams", "integrations": [ { + "uid": "", + "type": "teams", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "webhook_url": true - }, "settings": { "http_config": { "enable_http2": true, @@ -249,18 +240,19 @@ "text": "{{ template \"msteams.default.text\" . }}", "title": "{{ template \"msteams.default.title\" . }}" }, - "type": "teams", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "webhook_url": true + } } - ], - "title": "msteams" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "b3BzZ2VuaWU", + "namespace": "default", + "uid": "XmkZ214Dj030hvynYiwNLq8i6uRCjUYXMXjE5m19OKAX", + "resourceVersion": "8ee2957ba150ba16", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -268,19 +260,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "b3BzZ2VuaWU", - "namespace": "default", - "resourceVersion": "8ee2957ba150ba16", - "uid": "XmkZ214Dj030hvynYiwNLq8i6uRCjUYXMXjE5m19OKAX" + } }, "spec": { + "title": "opsgenie", "integrations": [ { + "uid": "", + "type": "opsgenie", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "api_key": true - }, "settings": { "actions": "test actions", "api_url": "http://localhost/opsgenie/", @@ -311,18 +300,19 @@ "tags": "test-tags", "update_alerts": true }, - "type": "opsgenie", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "api_key": true + } } - ], - "title": "opsgenie" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "cGFnZXJkdXR5", + "namespace": "default", + "uid": "QNitkUCkwzrIc7WVCCJGGDyvXLyo9csSUVqfyStyctQX", + "resourceVersion": "fe673d5dcd67ccf0", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -330,20 +320,16 @@ "grafana.com/inUse/routes": "1", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "cGFnZXJkdXR5", - "namespace": "default", - "resourceVersion": "fe673d5dcd67ccf0", - "uid": "QNitkUCkwzrIc7WVCCJGGDyvXLyo9csSUVqfyStyctQX" + } }, "spec": { + "title": "pagerduty", "integrations": [ { + "uid": "", + "type": "pagerduty", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "routing_key": true, - "service_key": true - }, "settings": { "class": "test class", "client": "Alertmanager", @@ -383,18 +369,20 @@ "source": "test source", "url": "http://localhost/pagerduty" }, - "type": "pagerduty", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "routing_key": true, + "service_key": true + } } - ], - "title": "pagerduty" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "cHVzaG92ZXI", + "namespace": "default", + "uid": "t2TJSktI6vyGfdbLOKmxH4eBqgcIGsAuW8Qm9m0HRycX", + "resourceVersion": "6ae076725ab463e0", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -402,21 +390,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "cHVzaG92ZXI", - "namespace": "default", - "resourceVersion": "6ae076725ab463e0", - "uid": "t2TJSktI6vyGfdbLOKmxH4eBqgcIGsAuW8Qm9m0HRycX" + } }, "spec": { + "title": "pushover", "integrations": [ { + "uid": "", + "type": "pushover", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "http_config.authorization.credentials": true, - "token": true, - "user_key": true - }, "settings": { "expire": "1h0m0s", "http_config": { @@ -437,18 +420,21 @@ "title": "{{ template \"pushover.default.title\" . }}", "url": "http://localhost/pushover" }, - "type": "pushover", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "http_config.authorization.credentials": true, + "token": true, + "user_key": true + } } - ], - "title": "pushover" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "c2xhY2s", + "namespace": "default", + "uid": "xSB0hnoc9j1CnLCHR3VgeVGXdVXILM0p2dM64bbHN9oX", + "resourceVersion": "ec0e343029ff5d8b", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -456,19 +442,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "c2xhY2s", - "namespace": "default", - "resourceVersion": "ec0e343029ff5d8b", - "uid": "xSB0hnoc9j1CnLCHR3VgeVGXdVXILM0p2dM64bbHN9oX" + } }, "spec": { + "title": "slack", "integrations": [ { + "uid": "", + "type": "slack", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "api_url": true - }, "settings": { "actions": [ { @@ -522,18 +505,19 @@ "title_link": "http://localhost", "username": "Alerting Team" }, - "type": "slack", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "api_url": true + } } - ], - "title": "slack" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "c25z", + "namespace": "default", + "uid": "vSP8NtFr23hnqZqLxRgzUKfr1wOemOvZm1S6MYkfRI4X", + "resourceVersion": "77d734ad4c196d36", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -541,19 +525,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "c25z", - "namespace": "default", - "resourceVersion": "77d734ad4c196d36", - "uid": "vSP8NtFr23hnqZqLxRgzUKfr1wOemOvZm1S6MYkfRI4X" + } }, "spec": { + "title": "sns", "integrations": [ { + "uid": "", + "type": "sns", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "sigv4.SecretKey": true - }, "settings": { "attributes": { "key1": "value1" @@ -577,18 +558,19 @@ "subject": "{{ template \"sns.default.subject\" . }}", "topic_arn": "arn:aws:sns:us-east-1:123456789012:alerts" }, - "type": "sns", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "sigv4.SecretKey": true + } } - ], - "title": "sns" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "dGVsZWdyYW0", + "namespace": "default", + "uid": "XLWjtmYcjP5PiqBCwZXX3YKHV1G8niRtpCakIpcHqoYX", + "resourceVersion": "d9850878a33e302e", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -596,19 +578,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "dGVsZWdyYW0", - "namespace": "default", - "resourceVersion": "d9850878a33e302e", - "uid": "XLWjtmYcjP5PiqBCwZXX3YKHV1G8niRtpCakIpcHqoYX" + } }, "spec": { + "title": "telegram", "integrations": [ { + "uid": "", + "type": "telegram", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "token": true - }, "settings": { "api_url": "http://localhost/telegram-default", "chat": -1001234567890, @@ -624,18 +603,19 @@ "parse_mode": "MarkdownV2", "send_resolved": true }, - "type": "telegram", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "token": true + } } - ], - "title": "telegram" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "dmljdG9yb3Bz", + "namespace": "default", + "uid": "EWiwQ6TIW0GpEo46WusW7Nvg0HuD4QAbHf0JZ2OSOhEX", + "resourceVersion": "1e6886531440afc2", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -643,19 +623,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "dmljdG9yb3Bz", - "namespace": "default", - "resourceVersion": "1e6886531440afc2", - "uid": "EWiwQ6TIW0GpEo46WusW7Nvg0HuD4QAbHf0JZ2OSOhEX" + } }, "spec": { + "title": "victorops", "integrations": [ { + "uid": "", + "type": "victorops", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "api_key": true - }, "settings": { "api_url": "http://localhost/victorops-default/", "entity_display_name": "{{ template \"victorops.default.entity_display_name\" . }}", @@ -674,18 +651,19 @@ "send_resolved": true, "state_message": "{{ template \"victorops.default.state_message\" . }}" }, - "type": "victorops", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "api_key": true + } } - ], - "title": "victorops" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "d2ViZXg", + "namespace": "default", + "uid": "wDNufI44UXHWq4ERRYenZ7XgXVV3Tjxaokz9IjMRZ54X", + "resourceVersion": "08fc955a08dfe9c0", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -693,19 +671,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "d2ViZXg", - "namespace": "default", - "resourceVersion": "08fc955a08dfe9c0", - "uid": "wDNufI44UXHWq4ERRYenZ7XgXVV3Tjxaokz9IjMRZ54X" + } }, "spec": { + "title": "webex", "integrations": [ { + "uid": "", + "type": "webex", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "http_config.authorization.credentials": true - }, "settings": { "api_url": "http://localhost/webes-default", "http_config": { @@ -723,18 +698,19 @@ "room_id": "Y2lzY29zcGFyazovL3VzL1JPT00v12345678", "send_resolved": true }, - "type": "webex", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "http_config.authorization.credentials": true + } } - ], - "title": "webex" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "d2ViaG9vaw", + "namespace": "default", + "uid": "aKzigXATPp6HOh20yTrlTcuF2Y9IrPHridGIcWrJygsX", + "resourceVersion": "494392f899a7b410", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -742,19 +718,16 @@ "grafana.com/inUse/routes": "1", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "d2ViaG9vaw", - "namespace": "default", - "resourceVersion": "494392f899a7b410", - "uid": "aKzigXATPp6HOh20yTrlTcuF2Y9IrPHridGIcWrJygsX" + } }, "spec": { + "title": "webhook", "integrations": [ { + "uid": "", + "type": "webhook", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "url": true - }, "settings": { "http_config": { "enable_http2": true, @@ -769,18 +742,19 @@ "timeout": "0s", "url_file": "" }, - "type": "webhook", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "url": true + } } - ], - "title": "webhook" + ] } }, { - "apiVersion": "notifications.alerting.grafana.app/v0alpha1", - "kind": "Receiver", "metadata": { + "name": "d2VjaGF0", + "namespace": "default", + "uid": "jkXCvNrNVw7XX5nmYFyrGiA4ckAvJ282u2scW8KZq7IX", + "resourceVersion": "135913515cbc156b", "annotations": { "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", @@ -788,19 +762,16 @@ "grafana.com/inUse/routes": "0", "grafana.com/inUse/rules": "0", "grafana.com/provenance": "converted_prometheus" - }, - "name": "d2VjaGF0", - "namespace": "default", - "resourceVersion": "135913515cbc156b", - "uid": "jkXCvNrNVw7XX5nmYFyrGiA4ckAvJ282u2scW8KZq7IX" + } }, "spec": { + "title": "wechat", "integrations": [ { + "uid": "", + "type": "wechat", + "version": "v0mimir1", "disableResolveMessage": false, - "secureFields": { - "api_secret": true - }, "settings": { "agent_id": "1000002", "api_url": "http://localhost/wechat/", @@ -820,15 +791,12 @@ "to_tag": "tag1", "to_user": "user1" }, - "type": "wechat", - "uid": "", - "version": "v0mimir1" + "secureFields": { + "api_secret": true + } } - ], - "title": "wechat" + ] } } - ], - "kind": "ReceiverList", - "metadata": {} -} + ] +} \ No newline at end of file diff --git a/pkg/tests/apis/alerting/notifications/routingtree/routing_tree_test.go b/pkg/tests/apis/alerting/notifications/routingtree/routing_tree_test.go index 00bae878f6d..bbbcd3ecfc0 100644 --- a/pkg/tests/apis/alerting/notifications/routingtree/routing_tree_test.go +++ b/pkg/tests/apis/alerting/notifications/routingtree/routing_tree_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/grafana/grafana-app-sdk/resource" "github.com/prometheus/alertmanager/config" "github.com/prometheus/alertmanager/pkg/labels" "github.com/prometheus/common/model" @@ -39,6 +40,11 @@ import ( "github.com/grafana/grafana/pkg/util/testutil" ) +var defaultTreeIdentifier = resource.Identifier{ + Namespace: apis.DefaultNamespace, + Name: v0alpha1.UserDefinedRoutingTreeName, +} + func TestMain(m *testing.M) { testsuite.Run(m) } @@ -52,7 +58,8 @@ func TestIntegrationNotAllowedMethods(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - client := common.NewRoutingTreeClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) route := &v0alpha1.RoutingTree{ ObjectMeta: v1.ObjectMeta{ @@ -60,11 +67,7 @@ func TestIntegrationNotAllowedMethods(t *testing.T) { }, Spec: v0alpha1.RoutingTreeSpec{}, } - _, err := client.Create(ctx, route, v1.CreateOptions{}) - assert.Error(t, err) - require.Truef(t, errors.IsMethodNotSupported(err), "Expected MethodNotSupported but got %s", err) - - err = client.Client.DeleteCollection(ctx, v1.DeleteOptions{}, v1.ListOptions{}) + _, err = client.Create(ctx, route, resource.CreateOptions{}) assert.Error(t, err) require.Truef(t, errors.IsMethodNotSupported(err), "Expected MethodNotSupported but got %s", err) } @@ -154,50 +157,52 @@ func TestIntegrationAccessControl(t *testing.T) { } admin := org1.Admin - adminClient := common.NewRoutingTreeClient(t, admin) + adminClient, err := v0alpha1.NewRoutingTreeClientFromGenerator(admin.GetClientRegistry()) + require.NoError(t, err) for _, tc := range testCases { t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) { - client := common.NewRoutingTreeClient(t, tc.user) + client, err := v0alpha1.NewRoutingTreeClientFromGenerator(tc.user.GetClientRegistry()) + require.NoError(t, err) if tc.canRead { t.Run("should be able to list routing trees", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, list.Items, 1) require.Equal(t, v0alpha1.UserDefinedRoutingTreeName, list.Items[0].Name) }) t.Run("should be able to read routing trees by resource identifier", func(t *testing.T) { - _, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + _, err := client.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) t.Run("should get NotFound if resource does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to list routing trees", func(t *testing.T) { - _, err := client.List(ctx, v1.ListOptions{}) + _, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) t.Run("should be forbidden to read routing tree by name", func(t *testing.T) { - _, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + _, err := client.Get(ctx, defaultTreeIdentifier) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if name does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) } - current, err := adminClient.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + current, err := adminClient.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) expected := current.Copy().(*v0alpha1.RoutingTree) expected.Spec.Routes = []v0alpha1.RoutingTreeRoute{ @@ -217,7 +222,7 @@ func TestIntegrationAccessControl(t *testing.T) { if tc.canUpdate { t.Run("should be able to update routing tree", func(t *testing.T) { - updated, err := client.Update(ctx, expected, v1.UpdateOptions{}) + updated, err := client.Update(ctx, expected, resource.UpdateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) expected = updated @@ -225,21 +230,23 @@ func TestIntegrationAccessControl(t *testing.T) { t.Run("should get NotFound if name does not exist", func(t *testing.T) { up := expected.Copy().(*v0alpha1.RoutingTree) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{}) require.Error(t, err) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to update routing tree", func(t *testing.T) { - _, err := client.Update(ctx, expected, v1.UpdateOptions{}) + _, err := client.Update(ctx, expected, resource.UpdateOptions{}) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if resource does not exist", func(t *testing.T) { up := expected.Copy().(*v0alpha1.RoutingTree) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{ + ResourceVersion: up.ResourceVersion, + }) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) @@ -248,32 +255,32 @@ func TestIntegrationAccessControl(t *testing.T) { if tc.canUpdate { t.Run("should be able to reset routing tree", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, v1.DeleteOptions{}) + err := client.Delete(ctx, expected.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.NoError(t, err) t.Run("should get NotFound if name does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := client.Delete(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "notfound"}, resource.DeleteOptions{}) require.Error(t, err) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to reset routing tree", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, v1.DeleteOptions{}) + err := client.Delete(ctx, expected.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should be forbidden even if resource does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := client.Delete(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "notfound"}, resource.DeleteOptions{}) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) - require.NoError(t, adminClient.Delete(ctx, expected.Name, v1.DeleteOptions{})) + require.NoError(t, adminClient.Delete(ctx, expected.GetStaticMetadata().Identifier(), resource.DeleteOptions{})) } }) - err := adminClient.Delete(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, defaultTreeIdentifier, resource.DeleteOptions{}) require.NoError(t, err) } } @@ -287,21 +294,22 @@ func TestIntegrationProvisioning(t *testing.T) { org := helper.Org1 admin := org.Admin - adminClient := common.NewRoutingTreeClient(t, admin) + adminClient, err := v0alpha1.NewRoutingTreeClientFromGenerator(admin.GetClientRegistry()) + require.NoError(t, err) env := helper.GetEnv() ac := acimpl.ProvideAccessControl(env.FeatureToggles) db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac, bus.ProvideBus(tracing.InitializeTracerForTest())) require.NoError(t, err) - current, err := adminClient.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + current, err := adminClient.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) require.Equal(t, "none", current.GetProvenanceStatus()) t.Run("should provide provenance status", func(t *testing.T) { require.NoError(t, db.SetProvenance(ctx, &definitions.Route{}, admin.Identity.GetOrgID(), "API")) - got, err := adminClient.Get(ctx, current.Name, v1.GetOptions{}) + got, err := adminClient.Get(ctx, current.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, "API", got.GetProvenanceStatus()) }) @@ -319,13 +327,13 @@ func TestIntegrationProvisioning(t *testing.T) { }, } - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.Error(t, err) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) t.Run("should not let delete if provisioned", func(t *testing.T) { - err := adminClient.Delete(ctx, current.Name, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, current.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) } @@ -336,35 +344,37 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewRoutingTreeClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) - current, err := adminClient.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + current, err := adminClient.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) require.NotEmpty(t, current.ResourceVersion) t.Run("should forbid if version does not match", func(t *testing.T) { updated := current.Copy().(*v0alpha1.RoutingTree) - updated.ResourceVersion = "test" - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := adminClient.Update(ctx, updated, resource.UpdateOptions{ + ResourceVersion: "test", + }) require.Error(t, err) require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) }) t.Run("should update if version matches", func(t *testing.T) { updated := current.Copy().(*v0alpha1.RoutingTree) updated.Spec.Defaults.GroupBy = append(updated.Spec.Defaults.GroupBy, "data") - actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + actualUpdated, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.EqualValues(t, updated.Spec, actualUpdated.Spec) require.NotEqual(t, updated.ResourceVersion, actualUpdated.ResourceVersion) }) t.Run("should update if version is empty", func(t *testing.T) { - current, err = adminClient.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + current, err = adminClient.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) updated := current.Copy().(*v0alpha1.RoutingTree) updated.ResourceVersion = "" updated.Spec.Routes = append(updated.Spec.Routes, v0alpha1.RoutingTreeRoute{Continue: true}) - actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + actualUpdated, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.EqualValues(t, updated.Spec, actualUpdated.Spec) require.NotEqual(t, current.ResourceVersion, actualUpdated.ResourceVersion) @@ -380,20 +390,22 @@ func TestIntegrationDataConsistency(t *testing.T) { cliCfg := helper.Org1.Admin.NewRestConfig() legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password) - client := common.NewRoutingTreeClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) receiver := "grafana-default-email" timeInterval := "test-time-interval" createRoute := func(t *testing.T, route definitions.Route) { t.Helper() - routeClient := common.NewRoutingTreeClient(t, helper.Org1.Admin) + routeClient, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) v1Route, err := routingtree.ConvertToK8sResource(helper.Org1.Admin.Identity.GetOrgID(), route, "", func(int64) string { return "default" }) require.NoError(t, err) - _, err = routeClient.Update(ctx, v1Route, v1.UpdateOptions{}) + _, err = routeClient.Update(ctx, v1Route, resource.UpdateOptions{}) require.NoError(t, err) } - _, err := common.NewTimeIntervalClient(t, helper.Org1.Admin).Create(ctx, &v0alpha1.TimeInterval{ + _, err = common.NewTimeIntervalClient(t, helper.Org1.Admin).Create(ctx, &v0alpha1.TimeInterval{ ObjectMeta: v1.ObjectMeta{ Namespace: "default", }, @@ -435,7 +447,7 @@ func TestIntegrationDataConsistency(t *testing.T) { }, } createRoute(t, route) - tree, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + tree, err := client.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) expected := []v0alpha1.RoutingTreeMatcher{ { @@ -503,9 +515,9 @@ func TestIntegrationDataConsistency(t *testing.T) { ensureMatcher(t, labels.MatchNotEqual, "matchers", "v"), } - tree, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + tree, err := client.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) - _, err = client.Update(ctx, tree, v1.UpdateOptions{}) + _, err = client.Update(ctx, tree, resource.UpdateOptions{}) require.NoError(t, err) cfg, _, _ = legacyCli.GetAlertmanagerConfigWithStatus(t) @@ -542,7 +554,7 @@ func TestIntegrationDataConsistency(t *testing.T) { createRoute(t, route) t.Run("correctly reads all fields", func(t *testing.T) { - tree, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + tree, err := client.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) assert.Equal(t, v0alpha1.RoutingTreeRouteDefaults{ Receiver: receiver, @@ -589,10 +601,10 @@ func TestIntegrationDataConsistency(t *testing.T) { t.Run("correctly save all fields", func(t *testing.T) { before, status, body := legacyCli.GetAlertmanagerConfigWithStatus(t) require.Equalf(t, http.StatusOK, status, body) - tree, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + tree, err := client.Get(ctx, defaultTreeIdentifier) tree.Spec.Defaults.GroupBy = []string{"test-123", "test-456", "test-789"} require.NoError(t, err) - _, err = client.Update(ctx, tree, v1.UpdateOptions{}) + _, err = client.Update(ctx, tree, resource.UpdateOptions{}) require.NoError(t, err) before.AlertmanagerConfig.Route.GroupByStr = []string{"test-123", "test-456", "test-789"} @@ -640,7 +652,7 @@ func TestIntegrationDataConsistency(t *testing.T) { } createRoute(t, route) - tree, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + tree, err := client.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) assert.Equal(t, "foo🙂", tree.Spec.Routes[0].GroupBy[0]) expected := []v0alpha1.RoutingTreeMatcher{ @@ -666,7 +678,8 @@ func TestIntegrationExtraConfigsConflicts(t *testing.T) { cliCfg := helper.Org1.Admin.NewRestConfig() legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password) - client := common.NewRoutingTreeClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) // Now upload a new extra config testAlertmanagerConfigYAML := ` @@ -691,7 +704,7 @@ receivers: }, headers) require.Equal(t, "success", response.Status) - current, err := client.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{}) + current, err := client.Get(ctx, defaultTreeIdentifier) require.NoError(t, err) updated := current.Copy().(*v0alpha1.RoutingTree) updated.Spec.Routes = append(updated.Spec.Routes, v0alpha1.RoutingTreeRoute{ @@ -704,7 +717,7 @@ receivers: }, }) - _, err = client.Update(ctx, updated, v1.UpdateOptions{}) + _, err = client.Update(ctx, updated, resource.UpdateOptions{}) require.Error(t, err) require.Truef(t, errors.IsBadRequest(err), "Should get BadRequest error but got: %s", err) @@ -712,6 +725,6 @@ receivers: legacyCli.ConvertPrometheusDeleteAlertmanagerConfig(t, headers) // and try again - _, err = client.Update(ctx, updated, v1.UpdateOptions{}) + _, err = client.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) } diff --git a/pkg/tests/apis/alerting/notifications/templategroup/imported_test.go b/pkg/tests/apis/alerting/notifications/templategroup/imported_test.go index 9a3e88f3e46..1c7dbe6cb4d 100644 --- a/pkg/tests/apis/alerting/notifications/templategroup/imported_test.go +++ b/pkg/tests/apis/alerting/notifications/templategroup/imported_test.go @@ -6,6 +6,7 @@ import ( "path" "testing" + "github.com/grafana/grafana-app-sdk/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.yaml.in/yaml/v3" @@ -18,7 +19,6 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/tests/api/alerting" "github.com/grafana/grafana/pkg/tests/apis" - "github.com/grafana/grafana/pkg/tests/apis/alerting/notifications/common" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/grafana/grafana/pkg/util/testutil" ) @@ -35,7 +35,8 @@ func TestIntegrationImportedTemplates(t *testing.T) { }, }) - client := common.NewTemplateGroupClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewTemplateGroupClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) cliCfg := helper.Org1.Admin.NewRestConfig() alertingApi := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password) @@ -57,7 +58,7 @@ func TestIntegrationImportedTemplates(t *testing.T) { response := alertingApi.ConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers) require.Equal(t, "success", response.Status) - templates, err := client.List(context.Background(), metav1.ListOptions{}) + templates, err := client.List(context.Background(), apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, templates.Items, 3) @@ -90,12 +91,12 @@ func TestIntegrationImportedTemplates(t *testing.T) { t.Run("should not be able to update", func(t *testing.T) { tpl := templates.Items[1] tpl.Spec.Content = "new content" - _, err := client.Update(context.Background(), &tpl, metav1.UpdateOptions{}) + _, err := client.Update(context.Background(), &tpl, resource.UpdateOptions{}) require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) }) t.Run("should not be able to delete", func(t *testing.T) { - err := client.Delete(context.Background(), templates.Items[1].Name, metav1.DeleteOptions{}) + err := client.Delete(context.Background(), templates.Items[1].GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) }) @@ -108,14 +109,14 @@ func TestIntegrationImportedTemplates(t *testing.T) { } tpl.Spec.Kind = v0alpha1.TemplateGroupTemplateKindGrafana - created, err := client.Create(context.Background(), &tpl, metav1.CreateOptions{}) + created, err := client.Create(context.Background(), &tpl, resource.CreateOptions{}) require.NoError(t, err) assert.NotEqual(t, templates.Items[1].Name, created.Name) }) t.Run("sort by kind and then name", func(t *testing.T) { - templates, err := client.List(context.Background(), metav1.ListOptions{}) + templates, err := client.List(context.Background(), apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, templates.Items, 4) diff --git a/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go b/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go index 146bccd5f11..ea21d66fc14 100644 --- a/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go +++ b/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/grafana/alerting/templates" + "github.com/grafana/grafana-app-sdk/resource" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/errors" @@ -45,7 +46,8 @@ func TestIntegrationResourceIdentifier(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - client := common.NewTemplateGroupClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewTemplateGroupClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) newTemplate := &v0alpha1.TemplateGroup{ ObjectMeta: v1.ObjectMeta{ @@ -61,23 +63,23 @@ func TestIntegrationResourceIdentifier(t *testing.T) { t.Run("create should fail if object name is specified", func(t *testing.T) { template := newTemplate.Copy().(*v0alpha1.TemplateGroup) template.Name = "new-templateGroup" - _, err := client.Create(ctx, template, v1.CreateOptions{}) + _, err := client.Create(ctx, template, resource.CreateOptions{}) assert.Error(t, err) require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err) }) - var resourceID string + var resourceID resource.Identifier t.Run("create should succeed and provide resource name", func(t *testing.T) { - actual, err := client.Create(ctx, newTemplate, v1.CreateOptions{}) + actual, err := client.Create(ctx, newTemplate, resource.CreateOptions{}) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") require.NotEmptyf(t, actual.UID, "Resource UID should not be empty") - resourceID = actual.Name + resourceID = actual.GetStaticMetadata().Identifier() }) var existingTemplateGroup *v0alpha1.TemplateGroup t.Run("resource should be available by the identifier", func(t *testing.T) { - actual, err := client.Get(ctx, resourceID, v1.GetOptions{}) + actual, err := client.Get(ctx, resourceID) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") require.Equal(t, newTemplate.Spec, actual.Spec) @@ -90,12 +92,12 @@ func TestIntegrationResourceIdentifier(t *testing.T) { } updated := existingTemplateGroup.Copy().(*v0alpha1.TemplateGroup) updated.Spec.Title = "another-templateGroup" - actual, err := client.Update(ctx, updated, v1.UpdateOptions{}) + actual, err := client.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.Equal(t, updated.Spec, actual.Spec) require.NotEqualf(t, updated.Name, actual.Name, "Update should change the resource name but it didn't") - resource, err := client.Get(ctx, actual.Name, v1.GetOptions{}) + resource, err := client.Get(ctx, actual.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, actual, resource) @@ -104,7 +106,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) { var defaultTemplateGroup *v0alpha1.TemplateGroup t.Run("default template should be available by the identifier", func(t *testing.T) { - actual, err := client.Get(ctx, templates.DefaultTemplateName, v1.GetOptions{}) + actual, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: templates.DefaultTemplateName}) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") @@ -122,7 +124,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) { t.Run("create with reserved default title should work", func(t *testing.T) { template := newTemplate.Copy().(*v0alpha1.TemplateGroup) template.Spec.Title = defaultTemplateGroup.Spec.Title - actual, err := client.Create(ctx, template, v1.CreateOptions{}) + actual, err := client.Create(ctx, template, resource.CreateOptions{}) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") require.NotEmptyf(t, actual.UID, "Resource UID should not be empty") @@ -130,7 +132,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) { }) t.Run("default template should not be available by calculated UID", func(t *testing.T) { - actual, err := client.Get(ctx, newTemplateWithOverlappingName.Name, v1.GetOptions{}) + actual, err := client.Get(ctx, newTemplateWithOverlappingName.GetStaticMetadata().Identifier()) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") @@ -215,11 +217,13 @@ func TestIntegrationAccessControl(t *testing.T) { }, } - adminClient := common.NewTemplateGroupClient(t, org1.Admin) + adminClient, err := v0alpha1.NewTemplateGroupClientFromGenerator(org1.Admin.GetClientRegistry()) + require.NoError(t, err) for _, tc := range testCases { t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) { - client := common.NewTemplateGroupClient(t, tc.user) + client, err := v0alpha1.NewTemplateGroupClientFromGenerator(tc.user.GetClientRegistry()) + require.NoError(t, err) var expected = &v0alpha1.TemplateGroup{ ObjectMeta: v1.ObjectMeta{ @@ -237,12 +241,12 @@ func TestIntegrationAccessControl(t *testing.T) { if tc.canCreate { t.Run("should be able to create template group", func(t *testing.T) { - actual, err := client.Create(ctx, expected, v1.CreateOptions{}) + actual, err := client.Create(ctx, expected, resource.CreateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.Equal(t, expected.Spec, actual.Spec) t.Run("should fail if already exists", func(t *testing.T) { - _, err := client.Create(ctx, actual, v1.CreateOptions{}) + _, err := client.Create(ctx, actual, resource.CreateOptions{}) require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) }) @@ -250,45 +254,45 @@ func TestIntegrationAccessControl(t *testing.T) { }) } else { t.Run("should be forbidden to create", func(t *testing.T) { - _, err := client.Create(ctx, expected, v1.CreateOptions{}) + _, err := client.Create(ctx, expected, resource.CreateOptions{}) require.Truef(t, errors.IsForbidden(err), "Payload %s", string(d)) }) // create resource to proceed with other tests - expected, err = adminClient.Create(ctx, expected, v1.CreateOptions{}) + expected, err = adminClient.Create(ctx, expected, resource.CreateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.NotNil(t, expected) } if tc.canRead { t.Run("should be able to list template groups", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, list.Items, 2) // Includes default template. }) t.Run("should be able to read template group by resource identifier", func(t *testing.T) { - got, err := client.Get(ctx, expected.Name, v1.GetOptions{}) + got, err := client.Get(ctx, expected.GetStaticMetadata().Identifier()) require.NoError(t, err) - require.Equal(t, expected, got) + require.Equal(t, expected.Spec, got.Spec) t.Run("should get NotFound if resource does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to list template groups", func(t *testing.T) { - _, err := client.List(ctx, v1.ListOptions{}) + _, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) t.Run("should be forbidden to read template group by name", func(t *testing.T) { - _, err := client.Get(ctx, expected.Name, v1.GetOptions{}) + _, err := client.Get(ctx, expected.GetStaticMetadata().Identifier()) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if name does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) @@ -302,7 +306,7 @@ func TestIntegrationAccessControl(t *testing.T) { if tc.canUpdate { t.Run("should be able to update template group", func(t *testing.T) { - updated, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) + updated, err := client.Update(ctx, updatedExpected, resource.UpdateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) expected = updated @@ -310,52 +314,54 @@ func TestIntegrationAccessControl(t *testing.T) { t.Run("should get NotFound if name does not exist", func(t *testing.T) { up := updatedExpected.Copy().(*v0alpha1.TemplateGroup) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to update template group", func(t *testing.T) { - _, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) + _, err := client.Update(ctx, updatedExpected, resource.UpdateOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if resource does not exist", func(t *testing.T) { up := updatedExpected.Copy().(*v0alpha1.TemplateGroup) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{ + ResourceVersion: up.ResourceVersion, + }) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) } deleteOptions := v1.DeleteOptions{Preconditions: &v1.Preconditions{ResourceVersion: util.Pointer(expected.ResourceVersion)}} - + oldClient := common.NewTemplateGroupClient(t, tc.user) // TODO replace with normal client once delete is fixed if tc.canDelete { t.Run("should be able to delete template group", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, deleteOptions) + err := oldClient.Delete(ctx, expected.GetStaticMetadata().Identifier().Name, deleteOptions) require.NoError(t, err) t.Run("should get NotFound if name does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := oldClient.Delete(ctx, "notfound", v1.DeleteOptions{}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to delete template group", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, deleteOptions) + err := oldClient.Delete(ctx, expected.GetStaticMetadata().Identifier().Name, deleteOptions) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should be forbidden even if resource does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := oldClient.Delete(ctx, "notfound", v1.DeleteOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) - require.NoError(t, adminClient.Delete(ctx, expected.Name, v1.DeleteOptions{})) + require.NoError(t, adminClient.Delete(ctx, expected.GetStaticMetadata().Identifier(), resource.DeleteOptions{})) } if tc.canRead { t.Run("should get list with just default template if no template groups", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, list.Items, 1) require.Equal(t, templates.DefaultTemplateName, list.Items[0].Name) @@ -374,7 +380,8 @@ func TestIntegrationProvisioning(t *testing.T) { org := helper.Org1 admin := org.Admin - adminClient := common.NewTemplateGroupClient(t, admin) + adminClient, err := v0alpha1.NewTemplateGroupClientFromGenerator(admin.GetClientRegistry()) + require.NoError(t, err) env := helper.GetEnv() ac := acimpl.ProvideAccessControl(env.FeatureToggles) @@ -390,7 +397,7 @@ func TestIntegrationProvisioning(t *testing.T) { Content: `{{ define "test" }} test {{ end }}`, Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, - }, v1.CreateOptions{}) + }, resource.CreateOptions{}) require.NoError(t, err) require.Equal(t, "none", created.GetProvenanceStatus()) @@ -399,7 +406,7 @@ func TestIntegrationProvisioning(t *testing.T) { Name: created.Spec.Title, }, admin.Identity.GetOrgID(), "API")) - got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + got, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, "API", got.GetProvenanceStatus()) }) @@ -407,12 +414,12 @@ func TestIntegrationProvisioning(t *testing.T) { updated := created.Copy().(*v0alpha1.TemplateGroup) updated.Spec.Content = `{{ define "another-test" }} test {{ end }}` - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) t.Run("should not let delete if provisioned", func(t *testing.T) { - err := adminClient.Delete(ctx, created.Name, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, created.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) } @@ -423,8 +430,9 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewTemplateGroupClient(t, helper.Org1.Admin) - + adminClient, err := v0alpha1.NewTemplateGroupClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) + oldClient := common.NewTemplateGroupClient(t, helper.Org1.Admin) template := v0alpha1.TemplateGroup{ ObjectMeta: v1.ObjectMeta{ Namespace: "default", @@ -436,21 +444,22 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { }, } - created, err := adminClient.Create(ctx, &template, v1.CreateOptions{}) + created, err := adminClient.Create(ctx, &template, resource.CreateOptions{}) require.NoError(t, err) require.NotNil(t, created) require.NotEmpty(t, created.ResourceVersion) t.Run("should forbid if version does not match", func(t *testing.T) { updated := created.Copy().(*v0alpha1.TemplateGroup) - updated.ResourceVersion = "test" - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := adminClient.Update(ctx, updated, resource.UpdateOptions{ + ResourceVersion: "test", + }) require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) }) t.Run("should update if version matches", func(t *testing.T) { updated := created.Copy().(*v0alpha1.TemplateGroup) updated.Spec.Content = `{{ define "test-another" }} test {{ end }}` - actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + actualUpdated, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.EqualValues(t, updated.Spec, actualUpdated.Spec) require.NotEqual(t, updated.ResourceVersion, actualUpdated.ResourceVersion) @@ -460,16 +469,16 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { updated.ResourceVersion = "" updated.Spec.Content = `{{ define "test-another-2" }} test {{ end }}` - actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + actualUpdated, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.EqualValues(t, updated.Spec, actualUpdated.Spec) require.NotEqual(t, created.ResourceVersion, actualUpdated.ResourceVersion) }) t.Run("should fail to delete if version does not match", func(t *testing.T) { - actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + actual, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.GetStaticMetadata().Identifier().Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer("something"), }, @@ -477,10 +486,10 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) }) t.Run("should succeed if version matches", func(t *testing.T) { - actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + actual, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.GetStaticMetadata().Identifier().Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer(actual.ResourceVersion), }, @@ -488,10 +497,10 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { require.NoError(t, err) }) t.Run("should succeed if version is empty", func(t *testing.T) { - actual, err := adminClient.Create(ctx, &template, v1.CreateOptions{}) + actual, err := adminClient.Create(ctx, &template, resource.CreateOptions{}) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.GetStaticMetadata().Identifier().Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer(actual.ResourceVersion), }, @@ -506,7 +515,8 @@ func TestIntegrationPatch(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewTemplateGroupClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTemplateGroupClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) template := v0alpha1.TemplateGroup{ ObjectMeta: v1.ObjectMeta{ @@ -519,8 +529,10 @@ func TestIntegrationPatch(t *testing.T) { }, } - current, err := adminClient.Create(ctx, &template, v1.CreateOptions{}) + current, err := adminClient.Create(ctx, &template, resource.CreateOptions{}) require.NoError(t, err) + oldClient := common.NewTemplateGroupClient(t, helper.Org1.Admin) + require.NotNil(t, current) require.NotEmpty(t, current.ResourceVersion) @@ -531,7 +543,7 @@ func TestIntegrationPatch(t *testing.T) { } }` - result, err := adminClient.Patch(ctx, current.Name, types.MergePatchType, []byte(patch), v1.PatchOptions{}) + result, err := oldClient.Patch(ctx, current.GetStaticMetadata().Identifier().Name, types.MergePatchType, []byte(patch), v1.PatchOptions{}) require.NoError(t, err) require.Equal(t, `{{ define "test-another" }} test {{ end }}`, result.Spec.Content) current = result @@ -540,18 +552,15 @@ func TestIntegrationPatch(t *testing.T) { t.Run("should patch with json patch", func(t *testing.T) { expected := `{{ define "test-json-patch" }} test {{ end }}` - patch := []map[string]interface{}{ + patch := []resource.PatchOperation{ { - "op": "replace", - "path": "/spec/content", - "value": expected, + Operation: "replace", + Path: "/spec/content", + Value: expected, }, } - patchData, err := json.Marshal(patch) - require.NoError(t, err) - - result, err := adminClient.Patch(ctx, current.Name, types.JSONPatchType, patchData, v1.PatchOptions{}) + result, err := adminClient.Patch(ctx, current.GetStaticMetadata().Identifier(), resource.PatchRequest{Operations: patch}, resource.PatchOptions{}) require.NoError(t, err) expectedSpec := current.Spec expectedSpec.Content = expected @@ -565,7 +574,8 @@ func TestIntegrationListSelector(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewTemplateGroupClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTemplateGroupClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) template1 := &v0alpha1.TemplateGroup{ ObjectMeta: v1.ObjectMeta{ @@ -577,7 +587,7 @@ func TestIntegrationListSelector(t *testing.T) { Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } - template1, err := adminClient.Create(ctx, template1, v1.CreateOptions{}) + template1, err = adminClient.Create(ctx, template1, resource.CreateOptions{}) require.NoError(t, err) template2 := &v0alpha1.TemplateGroup{ @@ -590,7 +600,7 @@ func TestIntegrationListSelector(t *testing.T) { Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } - template2, err = adminClient.Create(ctx, template2, v1.CreateOptions{}) + template2, err = adminClient.Create(ctx, template2, resource.CreateOptions{}) require.NoError(t, err) env := helper.GetEnv() ac := acimpl.ProvideAccessControl(env.FeatureToggles) @@ -599,18 +609,18 @@ func TestIntegrationListSelector(t *testing.T) { require.NoError(t, db.SetProvenance(ctx, &definitions.NotificationTemplate{ Name: template2.Spec.Title, }, helper.Org1.Admin.Identity.GetOrgID(), "API")) - template2, err = adminClient.Get(ctx, template2.Name, v1.GetOptions{}) + template2, err = adminClient.Get(ctx, template2.GetStaticMetadata().Identifier()) require.NoError(t, err) - tmpls, err := adminClient.List(ctx, v1.ListOptions{}) + tmpls, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, tmpls.Items, 3) // Includes default template. t.Run("should filter by template name", func(t *testing.T) { t.Skip("disabled until app installer supports it") // TODO revisit when custom field selectors are supported - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "spec.title=" + template1.Spec.Title, + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{"spec.title=" + template1.Spec.Title}, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -618,8 +628,8 @@ func TestIntegrationListSelector(t *testing.T) { }) t.Run("should filter by template metadata name", func(t *testing.T) { - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "metadata.name=" + template2.Name, + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{"metadata.name=" + template2.Name}, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -628,8 +638,8 @@ func TestIntegrationListSelector(t *testing.T) { t.Run("should filter by multiple filters", func(t *testing.T) { t.Skip("disabled until app installer supports it") // TODO revisit when custom field selectors are supported - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s,spec.title=%s", template2.Name, template2.Spec.Title), + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{fmt.Sprintf("metadata.name=%s,spec.title=%s", template2.Name, template2.Spec.Title)}, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -637,8 +647,8 @@ func TestIntegrationListSelector(t *testing.T) { }) t.Run("should be empty when filter does not match", func(t *testing.T) { - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s", "unknown"), + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{fmt.Sprintf("metadata.name=%s", "unknown")}, }) require.NoError(t, err) require.Empty(t, list.Items) @@ -646,17 +656,17 @@ func TestIntegrationListSelector(t *testing.T) { t.Run("should filter by default template name", func(t *testing.T) { t.Skip("disabled until app installer supports it") // TODO revisit when custom field selectors are supported - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "spec.title=" + v0alpha1.DefaultTemplateTitle, + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{"spec.title=" + v0alpha1.DefaultTemplateTitle}, }) require.NoError(t, err) require.Len(t, list.Items, 1) require.Equal(t, templates.DefaultTemplateName, list.Items[0].Name) // Now just non-default templates - list, err = adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "spec.title!=" + v0alpha1.DefaultTemplateTitle, - }) + list, err = adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{"spec.title!=" + v0alpha1.DefaultTemplateTitle}}, + ) require.NoError(t, err) require.Len(t, list.Items, 2) require.NotEqualf(t, templates.DefaultTemplateName, list.Items[0].Name, "Expected non-default template but got %s", list.Items[0].Name) @@ -669,7 +679,8 @@ func TestIntegrationKinds(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - client := common.NewTemplateGroupClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewTemplateGroupClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) newTemplate := &v0alpha1.TemplateGroup{ ObjectMeta: v1.ObjectMeta{ @@ -683,17 +694,17 @@ func TestIntegrationKinds(t *testing.T) { } t.Run("should not let create Mimir template", func(t *testing.T) { - _, err := client.Create(ctx, newTemplate, v1.CreateOptions{}) + _, err := client.Create(ctx, newTemplate, resource.CreateOptions{}) require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) }) t.Run("should not let change kind", func(t *testing.T) { newTemplate.Spec.Kind = v0alpha1.TemplateGroupTemplateKindGrafana - created, err := client.Create(ctx, newTemplate, v1.CreateOptions{}) + created, err := client.Create(ctx, newTemplate, resource.CreateOptions{}) require.NoError(t, err) created.Spec.Kind = v0alpha1.TemplateGroupTemplateKindMimir - _, err = client.Update(ctx, created, v1.UpdateOptions{}) + _, err = client.Update(ctx, created, resource.UpdateOptions{}) require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) }) } diff --git a/pkg/tests/apis/alerting/notifications/timeinterval/timeinterval_test.go b/pkg/tests/apis/alerting/notifications/timeinterval/timeinterval_test.go index fdac61b048b..a05e108a091 100644 --- a/pkg/tests/apis/alerting/notifications/timeinterval/timeinterval_test.go +++ b/pkg/tests/apis/alerting/notifications/timeinterval/timeinterval_test.go @@ -10,6 +10,7 @@ import ( "slices" "testing" + "github.com/grafana/grafana-app-sdk/resource" "github.com/prometheus/alertmanager/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -57,7 +58,8 @@ func TestIntegrationResourceIdentifier(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - client := common.NewTimeIntervalClient(t, helper.Org1.Admin) + client, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) newInterval := &v0alpha1.TimeInterval{ ObjectMeta: v1.ObjectMeta{ @@ -72,22 +74,22 @@ func TestIntegrationResourceIdentifier(t *testing.T) { t.Run("create should fail if object name is specified", func(t *testing.T) { interval := newInterval.Copy().(*v0alpha1.TimeInterval) interval.Name = "time-newInterval" - _, err := client.Create(ctx, interval, v1.CreateOptions{}) + _, err := client.Create(ctx, interval, resource.CreateOptions{}) require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err) }) - var resourceID string + var resourceID resource.Identifier t.Run("create should succeed and provide resource name", func(t *testing.T) { - actual, err := client.Create(ctx, newInterval, v1.CreateOptions{}) + actual, err := client.Create(ctx, newInterval, resource.CreateOptions{}) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") require.NotEmptyf(t, actual.UID, "Resource UID should not be empty") - resourceID = actual.Name + resourceID = actual.GetStaticMetadata().Identifier() }) var existingInterval *v0alpha1.TimeInterval t.Run("resource should be available by the identifier", func(t *testing.T) { - actual, err := client.Get(ctx, resourceID, v1.GetOptions{}) + actual, err := client.Get(ctx, resourceID) require.NoError(t, err) require.NotEmptyf(t, actual.Name, "Resource name should not be empty") require.Equal(t, newInterval.Spec, actual.Spec) @@ -100,13 +102,13 @@ func TestIntegrationResourceIdentifier(t *testing.T) { } updated := existingInterval.Copy().(*v0alpha1.TimeInterval) updated.Spec.Name = "another-newInterval" - actual, err := client.Update(ctx, updated, v1.UpdateOptions{}) + actual, err := client.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.Equal(t, updated.Spec, actual.Spec) require.NotEqualf(t, updated.Name, actual.Name, "Update should change the resource name but it didn't") require.NotEqualf(t, updated.ResourceVersion, actual.ResourceVersion, "Update should change the resource version but it didn't") - resource, err := client.Get(ctx, actual.Name, v1.GetOptions{}) + resource, err := client.Get(ctx, actual.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, actual, resource) }) @@ -189,11 +191,13 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) { }, } - adminClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) for _, tc := range testCases { t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) { - client := common.NewTimeIntervalClient(t, tc.user) + client, err := v0alpha1.NewTimeIntervalClientFromGenerator(tc.user.GetClientRegistry()) + require.NoError(t, err) var expected = &v0alpha1.TimeInterval{ ObjectMeta: v1.ObjectMeta{ Namespace: "default", @@ -209,12 +213,12 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) { if tc.canCreate { t.Run("should be able to create time interval", func(t *testing.T) { - actual, err := client.Create(ctx, expected, v1.CreateOptions{}) + actual, err := client.Create(ctx, expected, resource.CreateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.Equal(t, expected.Spec, actual.Spec) t.Run("should fail if already exists", func(t *testing.T) { - _, err := client.Create(ctx, actual, v1.CreateOptions{}) + _, err := client.Create(ctx, actual, resource.CreateOptions{}) require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) }) @@ -222,45 +226,45 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) { }) } else { t.Run("should be forbidden to create", func(t *testing.T) { - _, err := client.Create(ctx, expected, v1.CreateOptions{}) + _, err := client.Create(ctx, expected, resource.CreateOptions{}) require.Truef(t, errors.IsForbidden(err), "Payload %s", string(d)) }) // create resource to proceed with other tests - expected, err = adminClient.Create(ctx, expected, v1.CreateOptions{}) + expected, err = adminClient.Create(ctx, expected, resource.CreateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) require.NotNil(t, expected) } if tc.canRead { t.Run("should be able to list time intervals", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, list.Items, 1) }) t.Run("should be able to read time interval by resource identifier", func(t *testing.T) { - got, err := client.Get(ctx, expected.Name, v1.GetOptions{}) + got, err := client.Get(ctx, expected.GetStaticMetadata().Identifier()) require.NoError(t, err) - require.Equal(t, expected, got) + require.Equal(t, expected.Spec, got.Spec) t.Run("should get NotFound if resource does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to list time intervals", func(t *testing.T) { - _, err := client.List(ctx, v1.ListOptions{}) + _, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) t.Run("should be forbidden to read time interval by name", func(t *testing.T) { - _, err := client.Get(ctx, expected.Name, v1.GetOptions{}) + _, err := client.Get(ctx, expected.GetStaticMetadata().Identifier()) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if name does not exist", func(t *testing.T) { - _, err := client.Get(ctx, "Notfound", v1.GetOptions{}) + _, err := client.Get(ctx, resource.Identifier{Namespace: apis.DefaultNamespace, Name: "Notfound"}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) @@ -274,7 +278,7 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) { if tc.canUpdate { t.Run("should be able to update time interval", func(t *testing.T) { - updated, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) + updated, err := client.Update(ctx, updatedExpected, resource.UpdateOptions{}) require.NoErrorf(t, err, "Payload %s", string(d)) expected = updated @@ -282,52 +286,54 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) { t.Run("should get NotFound if name does not exist", func(t *testing.T) { up := updatedExpected.Copy().(*v0alpha1.TimeInterval) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to update time interval", func(t *testing.T) { - _, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) + _, err := client.Update(ctx, updatedExpected, resource.UpdateOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should get forbidden even if resource does not exist", func(t *testing.T) { up := updatedExpected.Copy().(*v0alpha1.TimeInterval) up.Name = "notFound" - _, err := client.Update(ctx, up, v1.UpdateOptions{}) + _, err := client.Update(ctx, up, resource.UpdateOptions{ + ResourceVersion: up.ResourceVersion, + }) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) } deleteOptions := v1.DeleteOptions{Preconditions: &v1.Preconditions{ResourceVersion: util.Pointer(expected.ResourceVersion)}} - + oldClient := common.NewTimeIntervalClient(t, tc.user) if tc.canDelete { t.Run("should be able to delete time interval", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, deleteOptions) + err := oldClient.Delete(ctx, expected.GetStaticMetadata().Identifier().Name, deleteOptions) require.NoError(t, err) t.Run("should get NotFound if name does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := oldClient.Delete(ctx, "notfound", v1.DeleteOptions{}) require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) } else { t.Run("should be forbidden to delete time interval", func(t *testing.T) { - err := client.Delete(ctx, expected.Name, deleteOptions) + err := oldClient.Delete(ctx, expected.GetStaticMetadata().Identifier().Name, deleteOptions) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) t.Run("should be forbidden even if resource does not exist", func(t *testing.T) { - err := client.Delete(ctx, "notfound", v1.DeleteOptions{}) + err := oldClient.Delete(ctx, "notfound", v1.DeleteOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) - require.NoError(t, adminClient.Delete(ctx, expected.Name, v1.DeleteOptions{})) + require.NoError(t, adminClient.Delete(ctx, expected.GetStaticMetadata().Identifier(), resource.DeleteOptions{})) } if tc.canRead { t.Run("should get empty list if no mute timings", func(t *testing.T) { - list, err := client.List(ctx, v1.ListOptions{}) + list, err := client.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, list.Items, 0) }) @@ -345,7 +351,8 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) { org := helper.Org1 admin := org.Admin - adminClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) env := helper.GetEnv() ac := acimpl.ProvideAccessControl(env.FeatureToggles) @@ -360,7 +367,7 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) { Name: "time-interval-1", TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2), }, - }, v1.CreateOptions{}) + }, resource.CreateOptions{}) require.NoError(t, err) require.Equal(t, "none", created.GetProvenanceStatus()) @@ -371,7 +378,7 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) { }, }, admin.Identity.GetOrgID(), "API")) - got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + got, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) require.Equal(t, "API", got.GetProvenanceStatus()) }) @@ -379,12 +386,12 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) { updated := created.Copy().(*v0alpha1.TimeInterval) updated.Spec.TimeIntervals = fakes.IntervalGenerator{}.GenerateMany(2) - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) t.Run("should not let delete if provisioned", func(t *testing.T) { - err := adminClient.Delete(ctx, created.Name, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, created.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) } @@ -395,7 +402,9 @@ func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) + oldClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) interval := v0alpha1.TimeInterval{ ObjectMeta: v1.ObjectMeta{ @@ -407,21 +416,22 @@ func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) { }, } - created, err := adminClient.Create(ctx, &interval, v1.CreateOptions{}) + created, err := adminClient.Create(ctx, &interval, resource.CreateOptions{}) require.NoError(t, err) require.NotNil(t, created) require.NotEmpty(t, created.ResourceVersion) t.Run("should forbid if version does not match", func(t *testing.T) { updated := created.Copy().(*v0alpha1.TimeInterval) - updated.ResourceVersion = "test" - _, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + _, err := adminClient.Update(ctx, updated, resource.UpdateOptions{ + ResourceVersion: "test", + }) require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) }) t.Run("should update if version matches", func(t *testing.T) { updated := created.Copy().(*v0alpha1.TimeInterval) updated.Spec.TimeIntervals = fakes.IntervalGenerator{}.GenerateMany(2) - actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + actualUpdated, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.EqualValues(t, updated.Spec, actualUpdated.Spec) require.NotEqual(t, updated.ResourceVersion, actualUpdated.ResourceVersion) @@ -431,16 +441,16 @@ func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) { updated.ResourceVersion = "" updated.Spec.TimeIntervals = fakes.IntervalGenerator{}.GenerateMany(2) - actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{}) + actualUpdated, err := adminClient.Update(ctx, updated, resource.UpdateOptions{}) require.NoError(t, err) require.EqualValues(t, updated.Spec, actualUpdated.Spec) require.NotEqual(t, created.ResourceVersion, actualUpdated.ResourceVersion) }) t.Run("should fail to delete if version does not match", func(t *testing.T) { - actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + actual, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.GetStaticMetadata().Identifier().Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer("something"), }, @@ -448,10 +458,10 @@ func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) { require.Truef(t, errors.IsConflict(err), "should get Forbidden error but got %s", err) }) t.Run("should succeed if version matches", func(t *testing.T) { - actual, err := adminClient.Get(ctx, created.Name, v1.GetOptions{}) + actual, err := adminClient.Get(ctx, created.GetStaticMetadata().Identifier()) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.GetStaticMetadata().Identifier().Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer(actual.ResourceVersion), }, @@ -459,10 +469,10 @@ func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) { require.NoError(t, err) }) t.Run("should succeed if version is empty", func(t *testing.T) { - actual, err := adminClient.Create(ctx, &interval, v1.CreateOptions{}) + actual, err := adminClient.Create(ctx, &interval, resource.CreateOptions{}) require.NoError(t, err) - err = adminClient.Delete(ctx, actual.Name, v1.DeleteOptions{ + err = oldClient.Delete(ctx, actual.GetStaticMetadata().Identifier().Name, v1.DeleteOptions{ Preconditions: &v1.Preconditions{ ResourceVersion: util.Pointer(actual.ResourceVersion), }, @@ -477,7 +487,9 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) + oldClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) interval := v0alpha1.TimeInterval{ ObjectMeta: v1.ObjectMeta{ @@ -489,7 +501,7 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) { }, } - current, err := adminClient.Create(ctx, &interval, v1.CreateOptions{}) + current, err := adminClient.Create(ctx, &interval, resource.CreateOptions{}) require.NoError(t, err) require.NotNil(t, current) require.NotEmpty(t, current.ResourceVersion) @@ -501,7 +513,7 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) { } }` - result, err := adminClient.Patch(ctx, current.Name, types.MergePatchType, []byte(patch), v1.PatchOptions{}) + result, err := oldClient.Patch(ctx, current.GetStaticMetadata().Identifier().Name, types.MergePatchType, []byte(patch), v1.PatchOptions{}) require.NoError(t, err) require.Empty(t, result.Spec.TimeIntervals) current = result @@ -510,18 +522,15 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) { t.Run("should patch with json patch", func(t *testing.T) { expected := fakes.IntervalGenerator{}.Generate() - patch := []map[string]interface{}{ + patch := []resource.PatchOperation{ { - "op": "add", - "path": "/spec/time_intervals/-", - "value": expected, + Operation: "add", + Path: "/spec/time_intervals/-", + Value: expected, }, } - patchData, err := json.Marshal(patch) - require.NoError(t, err) - - result, err := adminClient.Patch(ctx, current.Name, types.JSONPatchType, patchData, v1.PatchOptions{}) + result, err := adminClient.Patch(ctx, current.GetStaticMetadata().Identifier(), resource.PatchRequest{Operations: patch}, resource.PatchOptions{}) require.NoError(t, err) expectedSpec := v0alpha1.TimeIntervalSpec{ Name: current.Spec.Name, @@ -540,7 +549,8 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) interval1 := &v0alpha1.TimeInterval{ ObjectMeta: v1.ObjectMeta{ @@ -551,7 +561,7 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) { TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2), }, } - interval1, err := adminClient.Create(ctx, interval1, v1.CreateOptions{}) + interval1, err = adminClient.Create(ctx, interval1, resource.CreateOptions{}) require.NoError(t, err) interval2 := &v0alpha1.TimeInterval{ @@ -563,7 +573,7 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) { TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2), }, } - interval2, err = adminClient.Create(ctx, interval2, v1.CreateOptions{}) + interval2, err = adminClient.Create(ctx, interval2, resource.CreateOptions{}) require.NoError(t, err) env := helper.GetEnv() ac := acimpl.ProvideAccessControl(env.FeatureToggles) @@ -574,18 +584,18 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) { Name: interval2.Spec.Name, }, }, helper.Org1.Admin.Identity.GetOrgID(), "API")) - interval2, err = adminClient.Get(ctx, interval2.Name, v1.GetOptions{}) + interval2, err = adminClient.Get(ctx, interval2.GetStaticMetadata().Identifier()) require.NoError(t, err) - intervals, err := adminClient.List(ctx, v1.ListOptions{}) + intervals, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, intervals.Items, 2) t.Run("should filter by interval name", func(t *testing.T) { t.Skip("disabled until app installer supports it") // TODO revisit when custom field selectors are supported - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "spec.name=" + interval1.Spec.Name, + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{"spec.name=" + interval1.Spec.Name}, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -593,8 +603,8 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) { }) t.Run("should filter by interval metadata name", func(t *testing.T) { - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: "metadata.name=" + interval2.Name, + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{"metadata.name=" + interval2.Name}, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -603,8 +613,8 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) { t.Run("should filter by multiple filters", func(t *testing.T) { t.Skip("disabled until app installer supports it") - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s,spec.name=%s", interval2.Name, interval2.Spec.Name), + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{fmt.Sprintf("metadata.name=%s", interval2.Name), fmt.Sprintf("spec.name=%s", interval2.Spec.Name)}, }) require.NoError(t, err) require.Len(t, list.Items, 1) @@ -612,8 +622,8 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) { }) t.Run("should be empty when filter does not match", func(t *testing.T) { - list, err := adminClient.List(ctx, v1.ListOptions{ - FieldSelector: fmt.Sprintf("metadata.name=%s", "unknown"), + list, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{ + FieldSelectors: []string{fmt.Sprintf("metadata.name=%s", "unknown")}, }) require.NoError(t, err) require.Empty(t, list.Items) @@ -647,18 +657,20 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) { }) } - adminClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) v1intervals, err := timeinterval.ConvertToK8sResources(orgID, mtis, func(int64) string { return "default" }, nil) require.NoError(t, err) for _, interval := range v1intervals.Items { - _, err := adminClient.Create(ctx, &interval, v1.CreateOptions{}) + _, err := adminClient.Create(ctx, &interval, resource.CreateOptions{}) require.NoError(t, err) } - routeClient := common.NewRoutingTreeClient(t, helper.Org1.Admin) + routeClient, err := v0alpha1.NewRoutingTreeClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) v1route, err := routingtree.ConvertToK8sResource(helper.Org1.Admin.Identity.GetOrgID(), *amConfig.AlertmanagerConfig.Route, "", func(int64) string { return "default" }) require.NoError(t, err) - _, err = routeClient.Update(ctx, v1route, v1.UpdateOptions{}) + _, err = routeClient.Update(ctx, v1route, resource.UpdateOptions{}) require.NoError(t, err) postGroupRaw, err := testData.ReadFile(path.Join("test-data", "rulegroup-1.json")) @@ -675,7 +687,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) { currentRuleGroup, status := legacyCli.GetRulesGroup(t, folderUID, ruleGroup.Name) require.Equal(t, http.StatusAccepted, status) - intervals, err := adminClient.List(ctx, v1.ListOptions{}) + intervals, err := adminClient.List(ctx, apis.DefaultNamespace, resource.ListOptions{}) require.NoError(t, err) require.Len(t, intervals.Items, 3) intervalIdx := slices.IndexFunc(intervals.Items, func(interval v0alpha1.TimeInterval) bool { @@ -700,7 +712,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) { renamed := interval.Copy().(*v0alpha1.TimeInterval) renamed.Spec.Name += "-new" - actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{}) + actual, err := adminClient.Update(ctx, renamed, resource.UpdateOptions{}) require.NoError(t, err) updatedRuleGroup, status := legacyCli.GetRulesGroup(t, folderUID, ruleGroup.Name) @@ -732,20 +744,20 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) { t.Cleanup(func() { require.NoError(t, db.DeleteProvenance(ctx, ¤tRoute, orgID)) }) - actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{}) + actual, err := adminClient.Update(ctx, renamed, resource.UpdateOptions{}) require.Errorf(t, err, "Expected error but got successful result: %v", actual) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) t.Run("provisioned rules", func(t *testing.T) { ruleUid := currentRuleGroup.Rules[0].GrafanaManagedAlert.UID - resource := &ngmodels.AlertRule{UID: ruleUid} - require.NoError(t, db.SetProvenance(ctx, resource, orgID, "API")) + rule := &ngmodels.AlertRule{UID: ruleUid} + require.NoError(t, db.SetProvenance(ctx, rule, orgID, "API")) t.Cleanup(func() { - require.NoError(t, db.DeleteProvenance(ctx, resource, orgID)) + require.NoError(t, db.DeleteProvenance(ctx, rule, orgID)) }) - actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{}) + actual, err := adminClient.Update(ctx, renamed, resource.UpdateOptions{}) require.Errorf(t, err, "Expected error but got successful result: %v", actual) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) @@ -754,7 +766,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) { t.Run("Delete", func(t *testing.T) { t.Run("should fail to delete if time interval is used in rule and routes", func(t *testing.T) { - err := adminClient.Delete(ctx, interval.Name, v1.DeleteOptions{}) + err := adminClient.Delete(ctx, interval.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) @@ -763,7 +775,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) { route.Routes[0].MuteTimeIntervals = nil legacyCli.UpdateRoute(t, route, true) - err = adminClient.Delete(ctx, interval.Name, v1.DeleteOptions{}) + err = adminClient.Delete(ctx, interval.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) @@ -773,7 +785,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) { }) intervalToDelete := intervals.Items[idx] - err = adminClient.Delete(ctx, intervalToDelete.Name, v1.DeleteOptions{}) + err = adminClient.Delete(ctx, intervalToDelete.GetStaticMetadata().Identifier(), resource.DeleteOptions{}) require.Truef(t, errors.IsConflict(err), "Expected Conflict, got: %s", err) }) }) @@ -785,7 +797,8 @@ func TestIntegrationTimeIntervalValidation(t *testing.T) { ctx := context.Background() helper := getTestHelper(t) - adminClient := common.NewTimeIntervalClient(t, helper.Org1.Admin) + adminClient, err := v0alpha1.NewTimeIntervalClientFromGenerator(helper.Org1.Admin.GetClientRegistry()) + require.NoError(t, err) testCases := []struct { name string @@ -819,7 +832,7 @@ func TestIntegrationTimeIntervalValidation(t *testing.T) { }, Spec: tc.interval, } - _, err := adminClient.Create(ctx, i, v1.CreateOptions{}) + _, err := adminClient.Create(ctx, i, resource.CreateOptions{}) require.Error(t, err) require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest, got: %s", err) }) diff --git a/pkg/tests/apis/helper.go b/pkg/tests/apis/helper.go index 6087b64687d..0f2cb95cc50 100644 --- a/pkg/tests/apis/helper.go +++ b/pkg/tests/apis/helper.go @@ -14,7 +14,7 @@ import ( "testing" "time" - githubConnection "github.com/grafana/grafana/apps/provisioning/pkg/connection/github" + appsdk_k8s "github.com/grafana/grafana-app-sdk/k8s" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/errors" @@ -28,6 +28,8 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" + githubConnection "github.com/grafana/grafana/apps/provisioning/pkg/connection/github" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/configprovider" @@ -57,6 +59,8 @@ import ( const ( Org1 = "Org1" Org2 = "OrgB" + + DefaultNamespace = "default" ) var ( @@ -445,6 +449,11 @@ func (c *User) RESTClient(t *testing.T, gv *schema.GroupVersion) *rest.RESTClien return client } +func (c *User) GetClientRegistry() *appsdk_k8s.ClientRegistry { + restConfig := c.NewRestConfig() + return appsdk_k8s.NewClientRegistry(*restConfig, appsdk_k8s.DefaultClientConfig()) +} + type RequestParams struct { User User Method string // GET, POST, PATCH, etc