Replace clients with app-sdk-generated versions (#116227)

* add GetClientRegistry to user in integration tests to be able to create resource clients
* replace client in alerting notification api tests to generated by app-sdk
This commit is contained in:
Yuri Tseretyan
2026-01-14 16:13:32 -05:00
committed by GitHub
parent 0a66aacfb3
commit d191425f3d
8 changed files with 666 additions and 625 deletions
@@ -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)
})
}
@@ -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, &currentRoute, 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)
}
@@ -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": {}
}
]
}
@@ -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)
}
@@ -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)
@@ -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)
})
}
@@ -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, &currentRoute, 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)
})
+10 -1
View File
@@ -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