Alerting: Migrate notification models to generated by grafnaa-app-sdk (#95430)
* create notifications module and generate models * switch template group to app models * switch time intervals to use app models * switch receiver to use app models * switch routing tree to use app models * move schema registration to resource packages * fix package names to match app * fix codeowners * fix UI to use metadata.name instead of uid * update dockerfile * move generated models to pkg * remove provenance from field selector * move client factories to test files * rename GenericClient to TypedClient
This commit is contained in:
@@ -20,13 +20,14 @@ import (
|
||||
"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/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/resource/receiver/v0alpha1"
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/generated/clientset/versioned"
|
||||
notificationsv0alpha1 "github.com/grafana/grafana/pkg/generated/clientset/versioned/typed/alerting_notifications/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
@@ -72,22 +73,19 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
client := newClient(t, helper.Org1.Admin)
|
||||
newResource := &v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "Test-Receiver",
|
||||
Integrations: nil,
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("create should fail if object name is specified", func(t *testing.T) {
|
||||
resource := newResource.DeepCopy()
|
||||
resource := newResource.Copy().(*v0alpha1.Receiver)
|
||||
resource.Name = "new-receiver"
|
||||
_, err := client.Create(ctx, resource, v1.CreateOptions{})
|
||||
require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err)
|
||||
@@ -113,7 +111,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
existing, err := client.Get(ctx, resourceID, v1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
updated := existing.DeepCopy()
|
||||
updated := existing.Copy().(*v0alpha1.Receiver)
|
||||
updated.Spec.Title = "another-newReceiver"
|
||||
|
||||
actual, err := client.Update(ctx, updated, v1.UpdateOptions{})
|
||||
@@ -150,12 +148,6 @@ func TestIntegrationResourcePermissions(t *testing.T) {
|
||||
),
|
||||
})
|
||||
|
||||
newClient := func(t *testing.T, user apis.User) notificationsv0alpha1.ReceiverInterface {
|
||||
k8sClient, err := versioned.NewForConfig(user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
return k8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
}
|
||||
|
||||
admin := org1.Admin
|
||||
viewer := org1.Viewer
|
||||
editor := org1.Editor
|
||||
@@ -318,7 +310,7 @@ func TestIntegrationResourcePermissions(t *testing.T) {
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "receiver-1",
|
||||
Integrations: nil,
|
||||
},
|
||||
@@ -349,7 +341,7 @@ func TestIntegrationResourcePermissions(t *testing.T) {
|
||||
extractReceiverFromList := func(list *v0alpha1.ReceiverList, name string) *v0alpha1.Receiver {
|
||||
for i := range list.Items {
|
||||
if list.Items[i].Name == name {
|
||||
return list.Items[i].DeepCopy()
|
||||
return list.Items[i].Copy().(*v0alpha1.Receiver)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -362,7 +354,7 @@ func TestIntegrationResourcePermissions(t *testing.T) {
|
||||
require.NotNil(t, expectedGet)
|
||||
|
||||
// Set expected metadata.
|
||||
expectedGetWithMetadata := expectedGet.DeepCopy()
|
||||
expectedGetWithMetadata := expectedGet.Copy().(*v0alpha1.Receiver)
|
||||
// Clear any existing access control metadata.
|
||||
for _, k := range allACMetadata {
|
||||
delete(expectedGetWithMetadata.Annotations, v0alpha1.AccessControlAnnotation(k))
|
||||
@@ -375,7 +367,7 @@ func TestIntegrationResourcePermissions(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
expectedListWithMetadata := extractReceiverFromList(expectedList, created.Name)
|
||||
require.NotNil(t, expectedListWithMetadata)
|
||||
expectedListWithMetadata = expectedListWithMetadata.DeepCopy()
|
||||
expectedListWithMetadata = expectedListWithMetadata.Copy().(*v0alpha1.Receiver)
|
||||
// Clear any existing access control metadata.
|
||||
for _, k := range allACMetadata {
|
||||
delete(expectedListWithMetadata.Annotations, v0alpha1.AccessControlAnnotation(k))
|
||||
@@ -575,22 +567,16 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
admin := org1.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) {
|
||||
k8sClient, err := versioned.NewForConfig(tc.user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := k8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
client := newClient(t, tc.user)
|
||||
|
||||
var expected = &v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: fmt.Sprintf("receiver-1-%s", tc.user.Identity.GetLogin()),
|
||||
Integrations: nil,
|
||||
},
|
||||
@@ -598,7 +584,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
d, err := json.Marshal(expected)
|
||||
require.NoError(t, err)
|
||||
|
||||
newReceiver := expected.DeepCopy()
|
||||
newReceiver := expected.Copy().(*v0alpha1.Receiver)
|
||||
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) {
|
||||
@@ -630,7 +616,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
|
||||
if tc.canRead {
|
||||
// Set expected metadata.
|
||||
expectedWithMetadata := expected.DeepCopy()
|
||||
expectedWithMetadata := expected.Copy().(*v0alpha1.Receiver)
|
||||
expectedWithMetadata.SetInUse(0, nil)
|
||||
if tc.canUpdate {
|
||||
expectedWithMetadata.SetAccessControl("canWrite")
|
||||
@@ -678,7 +664,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
updatedExpected := expected.DeepCopy()
|
||||
updatedExpected := expected.Copy().(*v0alpha1.Receiver)
|
||||
updatedExpected.Spec.Integrations = append(updatedExpected.Spec.Integrations, createIntegration(t, "email"))
|
||||
|
||||
d, err = json.Marshal(updatedExpected)
|
||||
@@ -692,7 +678,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
expected = updated
|
||||
|
||||
t.Run("should get NotFound if name does not exist", func(t *testing.T) {
|
||||
up := updatedExpected.DeepCopy()
|
||||
up := updatedExpected.Copy().(*v0alpha1.Receiver)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err)
|
||||
@@ -704,7 +690,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
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.DeepCopy()
|
||||
up := updatedExpected.Copy().(*v0alpha1.Receiver)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
||||
@@ -759,10 +745,7 @@ func TestIntegrationInUseMetadata(t *testing.T) {
|
||||
cliCfg := helper.Org1.Admin.NewRestConfig()
|
||||
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(cliCfg)
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
// 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)
|
||||
@@ -884,10 +867,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
org := helper.Org1
|
||||
|
||||
admin := org.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
env := helper.GetEnv()
|
||||
ac := acimpl.ProvideAccessControl(env.FeatureToggles, zanzana.NewNoopClient())
|
||||
db, err := store.ProvideDBStore(env.Cfg, env.FeatureToggles, env.SQLStore, &foldertest.FakeService{}, &dashboards.FakeDashboardService{}, ac, bus.ProvideBus(tracing.InitializeTracerForTest()))
|
||||
@@ -897,7 +877,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "test-receiver-1",
|
||||
Integrations: []v0alpha1.Integration{
|
||||
createIntegration(t, "email"),
|
||||
@@ -920,7 +900,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
t.Run("should not let update if provisioned", func(t *testing.T) {
|
||||
got, err := adminClient.Get(ctx, created.Name, v1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
updated := got.DeepCopy()
|
||||
updated := got.Copy().(*v0alpha1.Receiver)
|
||||
updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "email"))
|
||||
|
||||
_, err = adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
@@ -941,15 +921,12 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
receiver := v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "receiver-1",
|
||||
Integrations: nil,
|
||||
},
|
||||
@@ -961,13 +938,13 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
require.NotEmpty(t, created.ResourceVersion)
|
||||
|
||||
t.Run("should forbid if version does not match", func(t *testing.T) {
|
||||
updated := created.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.Receiver)
|
||||
updated.ResourceVersion = "test"
|
||||
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
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.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.Receiver)
|
||||
updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "email"))
|
||||
actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -978,7 +955,7 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
require.NotEqual(t, updated.ResourceVersion, actualUpdated.ResourceVersion)
|
||||
})
|
||||
t.Run("should fail to update if version is empty", func(t *testing.T) {
|
||||
updated := created.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.Receiver)
|
||||
updated.ResourceVersion = ""
|
||||
updated.Spec.Integrations = append(updated.Spec.Integrations, createIntegration(t, "webhook"))
|
||||
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
@@ -1027,15 +1004,12 @@ func TestIntegrationPatch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
receiver := v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "receiver",
|
||||
Integrations: []v0alpha1.Integration{
|
||||
createIntegration(t, "email"),
|
||||
@@ -1083,9 +1057,9 @@ func TestIntegrationPatch(t *testing.T) {
|
||||
}
|
||||
|
||||
expected := current.Spec.Integrations[index]
|
||||
expected.Settings.Remove("username")
|
||||
expected.Settings.Remove("password")
|
||||
expected.Settings.Set("authorization_scheme", "bearer")
|
||||
delete(expected.Settings, "username")
|
||||
delete(expected.Settings, "password")
|
||||
expected.Settings["authorization_scheme"] = "bearer"
|
||||
delete(expected.SecureFields, "password")
|
||||
expected.SecureFields["authorization_credentials"] = true
|
||||
|
||||
@@ -1128,9 +1102,7 @@ func TestIntegrationRejectConfigApiReceiverModification(t *testing.T) {
|
||||
cliCfg := helper.Org1.Admin.NewRestConfig()
|
||||
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(cliCfg)
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
alertmanagerRaw, err := testData.ReadFile(path.Join("test-data", "notification-settings.json"))
|
||||
require.NoError(t, err)
|
||||
@@ -1205,10 +1177,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) {
|
||||
cliCfg := helper.Org1.Admin.NewRestConfig()
|
||||
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(cliCfg)
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
// 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)
|
||||
@@ -1240,7 +1209,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) {
|
||||
|
||||
t.Run("Update", func(t *testing.T) {
|
||||
t.Run("should rename all references if name changes", func(t *testing.T) {
|
||||
renamed := receiver.DeepCopy()
|
||||
renamed := receiver.Copy().(*v0alpha1.Receiver)
|
||||
expectedTitle := renamed.Spec.Title + "-new"
|
||||
renamed.Spec.Title = expectedTitle
|
||||
|
||||
@@ -1265,7 +1234,7 @@ func TestIntegrationReferentialIntegrity(t *testing.T) {
|
||||
|
||||
t.Run("should fail if at least one resource is provisioned", func(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
renamed := receiver.DeepCopy()
|
||||
renamed := receiver.Copy().(*v0alpha1.Receiver)
|
||||
renamed.Spec.Title += util.GenerateShortUID()
|
||||
|
||||
t.Run("provisioned route", func(t *testing.T) {
|
||||
@@ -1318,10 +1287,7 @@ func TestIntegrationCRUD(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
var defaultReceiver *v0alpha1.Receiver
|
||||
t.Run("should list the default receiver", func(t *testing.T) {
|
||||
items, err := adminClient.List(ctx, v1.ListOptions{})
|
||||
@@ -1343,19 +1309,19 @@ func TestIntegrationCRUD(t *testing.T) {
|
||||
|
||||
t.Run("should be able to update default receiver", func(t *testing.T) {
|
||||
require.NotNil(t, defaultReceiver)
|
||||
newDefault := defaultReceiver.DeepCopy()
|
||||
newDefault := defaultReceiver.Copy().(*v0alpha1.Receiver)
|
||||
newDefault.Spec.Integrations = append(newDefault.Spec.Integrations, createIntegration(t, "line"))
|
||||
|
||||
updatedReceiver, err := adminClient.Update(ctx, newDefault, v1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := newDefault.DeepCopy()
|
||||
expected := newDefault.Copy().(*v0alpha1.Receiver)
|
||||
expected.Spec.Integrations[0].Uid = updatedReceiver.Spec.Integrations[0].Uid // default integration does not have UID before first update
|
||||
lineIntegration := expected.Spec.Integrations[1]
|
||||
lineIntegration.SecureFields = map[string]bool{
|
||||
"token": true,
|
||||
}
|
||||
lineIntegration.Settings.Remove("token")
|
||||
delete(lineIntegration.Settings, "token")
|
||||
assert.Equal(t, "LINE", updatedReceiver.Spec.Integrations[1].Type) // this type is in the schema but not in backend
|
||||
lineIntegration.Type = "LINE"
|
||||
lineIntegration.Uid = updatedReceiver.Spec.Integrations[1].Uid
|
||||
@@ -1369,7 +1335,7 @@ func TestIntegrationCRUD(t *testing.T) {
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: defaultReceiver.Spec.Title,
|
||||
Integrations: nil,
|
||||
},
|
||||
@@ -1392,12 +1358,12 @@ func TestIntegrationCRUD(t *testing.T) {
|
||||
for _, key := range keys {
|
||||
integrations = append(integrations, createIntegration(t, key))
|
||||
}
|
||||
|
||||
var err error
|
||||
receiver, err = adminClient.Create(ctx, &v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "all-receivers",
|
||||
Integrations: integrations,
|
||||
},
|
||||
@@ -1436,7 +1402,7 @@ func TestIntegrationCRUD(t *testing.T) {
|
||||
assert.Contains(t, integration.SecureFields, field)
|
||||
assert.Truef(t, integration.SecureFields[field], "secure field should be always true")
|
||||
|
||||
value, ok, err := unstructured.NestedString(integration.Settings.Object, strings.Split(field, ".")...)
|
||||
value, ok, err := unstructured.NestedString(integration.Settings, strings.Split(field, ".")...)
|
||||
assert.NoErrorf(t, err, "failed to read field %s from settings", field)
|
||||
assert.Falsef(t, ok, "secret field %s should not be in settings, value [%s]", field, value)
|
||||
}
|
||||
@@ -1453,17 +1419,17 @@ func TestIntegrationCRUD(t *testing.T) {
|
||||
t.Run(key, func(t *testing.T) {
|
||||
integration := createIntegration(t, key)
|
||||
// Make the integration invalid, so it fails to create. This is usually done by sending empty settings.
|
||||
clear(integration.Settings.Object)
|
||||
clear(integration.Settings)
|
||||
if key == "webex" {
|
||||
// Webex integration is special case and passes validation without any settings so we instead set an invalid URL.
|
||||
integration.Settings.Set("api_url", "(*^$*^%!@#$*()")
|
||||
integration.Settings["api_url"] = "(*^$*^%!@#$*()"
|
||||
}
|
||||
|
||||
receiver, err = adminClient.Create(ctx, &v0alpha1.Receiver{
|
||||
receiver, err := adminClient.Create(ctx, &v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: fmt.Sprintf("invalid-%s", key),
|
||||
Integrations: []v0alpha1.Integration{integration},
|
||||
},
|
||||
@@ -1483,30 +1449,26 @@ func TestIntegrationReceiverListSelector(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().Receivers("default")
|
||||
|
||||
require.NoError(t, err)
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
recv1 := &v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "test-receiver-1",
|
||||
Integrations: []v0alpha1.Integration{
|
||||
createIntegration(t, "email"),
|
||||
},
|
||||
},
|
||||
}
|
||||
recv1, err = adminClient.Create(ctx, recv1, v1.CreateOptions{})
|
||||
recv1, err := adminClient.Create(ctx, recv1, v1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
recv2 := &v0alpha1.Receiver{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "test-receiver-2",
|
||||
Integrations: []v0alpha1.Integration{
|
||||
createIntegration(t, "email"),
|
||||
@@ -1551,7 +1513,7 @@ func TestIntegrationReceiverListSelector(t *testing.T) {
|
||||
|
||||
t.Run("should filter by multiple filters", func(t *testing.T) {
|
||||
list, err := adminClient.List(ctx, v1.ListOptions{
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s,metadata.provenance=%s", recv2.Name, "API"),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s,spec.title=%s", recv2.Name, recv2.Spec.Title),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list.Items, 1)
|
||||
@@ -1560,7 +1522,7 @@ 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,metadata.provenance=%s", recv2.Name, "unknown"),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s", "unknown"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, list.Items)
|
||||
@@ -1569,7 +1531,7 @@ func TestIntegrationReceiverListSelector(t *testing.T) {
|
||||
|
||||
// persistInitialConfig helps create an initial config with new receivers using legacy json. Config API blocks receiver
|
||||
// modifications, so we need to use k8s API to create new receivers before posting the config.
|
||||
func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig, adminClient notificationsv0alpha1.ReceiverInterface, legacyCli alerting.LegacyApiClient) {
|
||||
func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig, adminClient *apis.TypedClient[v0alpha1.Receiver, v0alpha1.ReceiverList], legacyCli alerting.LegacyApiClient) {
|
||||
ctx := context.Background()
|
||||
|
||||
var defaultReceiver *definitions.PostableApiReceiver
|
||||
@@ -1583,7 +1545,7 @@ func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig,
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.ReceiverSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: receiver.Name,
|
||||
Integrations: []v0alpha1.Integration{},
|
||||
},
|
||||
@@ -1593,7 +1555,7 @@ func persistInitialConfig(t *testing.T, amConfig definitions.PostableUserConfig,
|
||||
settings := common.Unstructured{}
|
||||
require.NoError(t, settings.UnmarshalJSON(integration.Settings))
|
||||
toCreate.Spec.Integrations = append(toCreate.Spec.Integrations, v0alpha1.Integration{
|
||||
Settings: settings,
|
||||
Settings: settings.Object,
|
||||
Type: integration.Type,
|
||||
DisableResolveMessage: util.Pointer(false),
|
||||
})
|
||||
@@ -1631,7 +1593,7 @@ func createIntegrationWithSettings(t *testing.T, integrationType string, setting
|
||||
settings := common.Unstructured{}
|
||||
require.NoError(t, settings.UnmarshalJSON([]byte(settingsJson)))
|
||||
return v0alpha1.Integration{
|
||||
Settings: settings,
|
||||
Settings: settings.Object,
|
||||
Type: integrationType,
|
||||
DisableResolveMessage: util.Pointer(false),
|
||||
}
|
||||
@@ -1645,3 +1607,19 @@ func createWildcardPermission(actions ...string) resourcepermissions.SetResource
|
||||
ResourceID: "*",
|
||||
}
|
||||
}
|
||||
|
||||
func newClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1.Receiver, v0alpha1.ReceiverList] {
|
||||
t.Helper()
|
||||
|
||||
client, err := dynamic.NewForConfig(user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
|
||||
return &apis.TypedClient[v0alpha1.Receiver, v0alpha1.ReceiverList]{
|
||||
Client: client.Resource(
|
||||
schema.GroupVersionResource{
|
||||
Group: v0alpha1.Kind().Group(),
|
||||
Version: v0alpha1.Kind().Version(),
|
||||
Resource: v0alpha1.Kind().Plural(),
|
||||
}).Namespace("default"),
|
||||
}
|
||||
}
|
||||
|
||||
+37
-32
@@ -1,4 +1,4 @@
|
||||
package routing_tree
|
||||
package routingtree
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -16,10 +16,11 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/resource/routingtree/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/generated/clientset/versioned"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
@@ -57,21 +58,19 @@ func TestIntegrationNotAllowedMethods(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := adminK8sClient.NotificationsV0alpha1().RoutingTrees("default")
|
||||
client := newClient(t, helper.Org1.Admin)
|
||||
|
||||
route := &v0alpha1.RoutingTree{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.RoutingTreeSpec{},
|
||||
Spec: v0alpha1.Spec{},
|
||||
}
|
||||
_, err = client.Create(ctx, route, v1.CreateOptions{})
|
||||
_, 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.DeleteCollection(ctx, v1.DeleteOptions{}, v1.ListOptions{})
|
||||
err = client.Client.DeleteCollection(ctx, v1.DeleteOptions{}, v1.ListOptions{})
|
||||
assert.Error(t, err)
|
||||
require.Truef(t, errors.IsMethodNotSupported(err), "Expected MethodNotSupported but got %s", err)
|
||||
}
|
||||
@@ -163,15 +162,11 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
}
|
||||
|
||||
admin := org1.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().RoutingTrees("default")
|
||||
adminClient := newClient(t, admin)
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) {
|
||||
k8sClient, err := versioned.NewForConfig(tc.user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := k8sClient.NotificationsV0alpha1().RoutingTrees("default")
|
||||
client := newClient(t, tc.user)
|
||||
|
||||
if tc.canRead {
|
||||
t.Run("should be able to list routing trees", func(t *testing.T) {
|
||||
@@ -212,7 +207,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
|
||||
current, err := adminClient.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
expected := current.DeepCopy()
|
||||
expected := current.Copy().(*v0alpha1.RoutingTree)
|
||||
expected.Spec.Routes = []v0alpha1.Route{
|
||||
{
|
||||
Matchers: []v0alpha1.Matcher{
|
||||
@@ -236,7 +231,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
expected = updated
|
||||
|
||||
t.Run("should get NotFound if name does not exist", func(t *testing.T) {
|
||||
up := expected.DeepCopy()
|
||||
up := expected.Copy().(*v0alpha1.RoutingTree)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
@@ -250,7 +245,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
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.DeepCopy()
|
||||
up := expected.Copy().(*v0alpha1.RoutingTree)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
@@ -286,7 +281,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
err = adminClient.Delete(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.DeleteOptions{})
|
||||
err := adminClient.Delete(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
@@ -302,9 +297,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
org := helper.Org1
|
||||
|
||||
admin := org.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().RoutingTrees("default")
|
||||
adminClient := newClient(t, admin)
|
||||
|
||||
env := helper.GetEnv()
|
||||
ac := acimpl.ProvideAccessControl(env.FeatureToggles, zanzana.NewNoopClient())
|
||||
@@ -323,7 +316,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, "API", got.GetProvenanceStatus())
|
||||
})
|
||||
t.Run("should not let update if provisioned", func(t *testing.T) {
|
||||
updated := current.DeepCopy()
|
||||
updated := current.Copy().(*v0alpha1.RoutingTree)
|
||||
updated.Spec.Routes = []v0alpha1.Route{
|
||||
{
|
||||
Matchers: []v0alpha1.Matcher{
|
||||
@@ -355,23 +348,21 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().RoutingTrees("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
current, err := adminClient.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, current.ResourceVersion)
|
||||
|
||||
t.Run("should forbid if version does not match", func(t *testing.T) {
|
||||
updated := current.DeepCopy()
|
||||
updated := current.Copy().(*v0alpha1.RoutingTree)
|
||||
updated.ResourceVersion = "test"
|
||||
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
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.DeepCopy()
|
||||
updated := current.Copy().(*v0alpha1.RoutingTree)
|
||||
updated.Spec.Defaults.GroupBy = append(updated.Spec.Defaults.GroupBy, "data")
|
||||
actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -381,7 +372,7 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
t.Run("should update if version is empty", func(t *testing.T) {
|
||||
current, err = adminClient.Get(ctx, v0alpha1.UserDefinedRoutingTreeName, v1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
updated := current.DeepCopy()
|
||||
updated := current.Copy().(*v0alpha1.RoutingTree)
|
||||
updated.ResourceVersion = ""
|
||||
updated.Spec.Routes = append(updated.Spec.Routes, v0alpha1.Route{Continue: true})
|
||||
|
||||
@@ -403,9 +394,7 @@ func TestIntegrationDataConsistency(t *testing.T) {
|
||||
cliCfg := helper.Org1.Admin.NewRestConfig()
|
||||
legacyCli := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(cliCfg)
|
||||
require.NoError(t, err)
|
||||
client := adminK8sClient.NotificationsV0alpha1().RoutingTrees("default")
|
||||
client := newClient(t, helper.Org1.Admin)
|
||||
|
||||
receiver := "grafana-default-email"
|
||||
timeInterval := "test-time-interval"
|
||||
@@ -641,3 +630,19 @@ func TestIntegrationDataConsistency(t *testing.T) {
|
||||
require.Equal(t, before, after)
|
||||
})
|
||||
}
|
||||
|
||||
func newClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1.RoutingTree, v0alpha1.RoutingTreeList] {
|
||||
t.Helper()
|
||||
|
||||
client, err := dynamic.NewForConfig(user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
|
||||
return &apis.TypedClient[v0alpha1.RoutingTree, v0alpha1.RoutingTreeList]{
|
||||
Client: client.Resource(
|
||||
schema.GroupVersionResource{
|
||||
Group: v0alpha1.Kind().Group(),
|
||||
Version: v0alpha1.Kind().Version(),
|
||||
Resource: v0alpha1.Kind().Plural(),
|
||||
}).Namespace("default"),
|
||||
}
|
||||
}
|
||||
+46
-45
@@ -10,11 +10,12 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/resource/templategroup/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/generated/clientset/versioned"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
@@ -51,22 +52,20 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := adminK8sClient.NotificationsV0alpha1().TemplateGroups("default")
|
||||
client := newClient(t, helper.Org1.Admin)
|
||||
|
||||
newTemplate := &v0alpha1.TemplateGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "templateGroup",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("create should fail if object name is specified", func(t *testing.T) {
|
||||
template := newTemplate.DeepCopy()
|
||||
template := newTemplate.Copy().(*v0alpha1.TemplateGroup)
|
||||
template.Name = "new-templateGroup"
|
||||
_, err := client.Create(ctx, template, v1.CreateOptions{})
|
||||
assert.Error(t, err)
|
||||
@@ -95,7 +94,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
if existingTemplateGroup == nil {
|
||||
t.Skip()
|
||||
}
|
||||
updated := existingTemplateGroup.DeepCopy()
|
||||
updated := existingTemplateGroup.Copy().(*v0alpha1.TemplateGroup)
|
||||
updated.Spec.Title = "another-templateGroup"
|
||||
actual, err := client.Update(ctx, updated, v1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -187,22 +186,17 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
admin := org1.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TemplateGroups("default")
|
||||
adminClient := newClient(t, org1.Admin)
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) {
|
||||
k8sClient, err := versioned.NewForConfig(tc.user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := k8sClient.NotificationsV0alpha1().TemplateGroups("default")
|
||||
client := newClient(t, tc.user)
|
||||
|
||||
var expected = &v0alpha1.TemplateGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: fmt.Sprintf("template-group-1-%s", tc.user.Identity.GetLogin()),
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
},
|
||||
@@ -270,7 +264,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
updatedExpected := expected.DeepCopy()
|
||||
updatedExpected := expected.Copy().(*v0alpha1.TemplateGroup)
|
||||
updatedExpected.Spec.Content = `{{ define "another-test" }} test {{ end }}`
|
||||
|
||||
d, err = json.Marshal(updatedExpected)
|
||||
@@ -284,7 +278,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
expected = updated
|
||||
|
||||
t.Run("should get NotFound if name does not exist", func(t *testing.T) {
|
||||
up := updatedExpected.DeepCopy()
|
||||
up := updatedExpected.Copy().(*v0alpha1.TemplateGroup)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err)
|
||||
@@ -296,7 +290,7 @@ func TestIntegrationAccessControl(t *testing.T) {
|
||||
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.DeepCopy()
|
||||
up := updatedExpected.Copy().(*v0alpha1.TemplateGroup)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
||||
@@ -351,9 +345,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
org := helper.Org1
|
||||
|
||||
admin := org.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TemplateGroups("default")
|
||||
adminClient := newClient(t, admin)
|
||||
|
||||
env := helper.GetEnv()
|
||||
ac := acimpl.ProvideAccessControl(env.FeatureToggles, zanzana.NewNoopClient())
|
||||
@@ -364,7 +356,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "template-group-1",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
},
|
||||
@@ -382,7 +374,7 @@ func TestIntegrationProvisioning(t *testing.T) {
|
||||
require.Equal(t, "API", got.GetProvenanceStatus())
|
||||
})
|
||||
t.Run("should not let update if provisioned", func(t *testing.T) {
|
||||
updated := created.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.TemplateGroup)
|
||||
updated.Spec.Content = `{{ define "another-test" }} test {{ end }}`
|
||||
|
||||
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
@@ -403,15 +395,13 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TemplateGroups("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
template := v0alpha1.TemplateGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "template-group-1",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
},
|
||||
@@ -423,13 +413,13 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
require.NotEmpty(t, created.ResourceVersion)
|
||||
|
||||
t.Run("should forbid if version does not match", func(t *testing.T) {
|
||||
updated := created.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.TemplateGroup)
|
||||
updated.ResourceVersion = "test"
|
||||
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
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.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.TemplateGroup)
|
||||
updated.Spec.Content = `{{ define "test-another" }} test {{ end }}`
|
||||
actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -437,7 +427,7 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) {
|
||||
require.NotEqual(t, updated.ResourceVersion, actualUpdated.ResourceVersion)
|
||||
})
|
||||
t.Run("should update if version is empty", func(t *testing.T) {
|
||||
updated := created.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.TemplateGroup)
|
||||
updated.ResourceVersion = ""
|
||||
updated.Spec.Content = `{{ define "test-another-2" }} test {{ end }}`
|
||||
|
||||
@@ -489,15 +479,13 @@ func TestIntegrationPatch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TemplateGroups("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
template := v0alpha1.TemplateGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "template-group",
|
||||
Content: `{{ define "test" }} test {{ end }}`,
|
||||
},
|
||||
@@ -537,7 +525,7 @@ func TestIntegrationPatch(t *testing.T) {
|
||||
|
||||
result, err := adminClient.Patch(ctx, current.Name, types.JSONPatchType, patchData, v1.PatchOptions{})
|
||||
require.NoError(t, err)
|
||||
expectedSpec := *current.Spec.DeepCopy()
|
||||
expectedSpec := current.Spec
|
||||
expectedSpec.Content = expected
|
||||
require.EqualValues(t, expectedSpec, result.Spec)
|
||||
current = result
|
||||
@@ -551,28 +539,25 @@ func TestIntegrationListSelector(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TemplateGroups("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
template1 := &v0alpha1.TemplateGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "test1",
|
||||
Content: `{{ define "test1" }} test {{ end }}`,
|
||||
},
|
||||
}
|
||||
template1, err = adminClient.Create(ctx, template1, v1.CreateOptions{})
|
||||
template1, err := adminClient.Create(ctx, template1, v1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
template2 := &v0alpha1.TemplateGroup{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TemplateGroupSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Title: "test2",
|
||||
Content: `{{ define "test2" }} test {{ end }}`,
|
||||
},
|
||||
@@ -614,7 +599,7 @@ func TestIntegrationListSelector(t *testing.T) {
|
||||
|
||||
t.Run("should filter by multiple filters", func(t *testing.T) {
|
||||
list, err := adminClient.List(ctx, v1.ListOptions{
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s,metadata.provenance=%s", template2.Name, "API"),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s,spec.title=%s", template2.Name, template2.Spec.Title),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list.Items, 1)
|
||||
@@ -623,9 +608,25 @@ 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,metadata.provenance=%s", template2.Name, "unknown"),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s", "unknown"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, list.Items)
|
||||
})
|
||||
}
|
||||
|
||||
func newClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1.TemplateGroup, v0alpha1.TemplateGroupList] {
|
||||
t.Helper()
|
||||
|
||||
client, err := dynamic.NewForConfig(user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
|
||||
return &apis.TypedClient[v0alpha1.TemplateGroup, v0alpha1.TemplateGroupList]{
|
||||
Client: client.Resource(
|
||||
schema.GroupVersionResource{
|
||||
Group: v0alpha1.Kind().Group(),
|
||||
Version: v0alpha1.Kind().Version(),
|
||||
Resource: v0alpha1.Kind().Plural(),
|
||||
}).Namespace("default"),
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,13 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/dynamic"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/alerting_notifications/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/resource/timeinterval/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/resource/timeinterval/v0alpha1/fakes"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/generated/clientset/versioned"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
|
||||
@@ -61,22 +63,20 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
client := newClient(t, helper.Org1.Admin)
|
||||
|
||||
newInterval := &v0alpha1.TimeInterval{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TimeIntervalSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Name: "time-newInterval",
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2),
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("create should fail if object name is specified", func(t *testing.T) {
|
||||
interval := newInterval.DeepCopy()
|
||||
interval := newInterval.Copy().(*v0alpha1.TimeInterval)
|
||||
interval.Name = "time-newInterval"
|
||||
_, err := client.Create(ctx, interval, v1.CreateOptions{})
|
||||
require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest but got %s", err)
|
||||
@@ -104,7 +104,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) {
|
||||
if existingInterval == nil {
|
||||
t.Skip()
|
||||
}
|
||||
updated := existingInterval.DeepCopy()
|
||||
updated := existingInterval.Copy().(*v0alpha1.TimeInterval)
|
||||
updated.Spec.Name = "another-newInterval"
|
||||
actual, err := client.Update(ctx, updated, v1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -197,24 +197,18 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
admin := org1.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("user '%s'", tc.user.Identity.GetLogin()), func(t *testing.T) {
|
||||
k8sClient, err := versioned.NewForConfig(tc.user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
client := k8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
|
||||
client := newClient(t, tc.user)
|
||||
var expected = &v0alpha1.TimeInterval{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TimeIntervalSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Name: fmt.Sprintf("time-interval-1-%s", tc.user.Identity.GetLogin()),
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2),
|
||||
},
|
||||
}
|
||||
expected.SetProvenanceStatus("")
|
||||
@@ -280,8 +274,8 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
updatedExpected := expected.DeepCopy()
|
||||
updatedExpected.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2)
|
||||
updatedExpected := expected.Copy().(*v0alpha1.TimeInterval)
|
||||
updatedExpected.Spec.TimeIntervals = fakes.IntervalGenerator{}.GenerateMany(2)
|
||||
|
||||
d, err = json.Marshal(updatedExpected)
|
||||
require.NoError(t, err)
|
||||
@@ -294,7 +288,7 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) {
|
||||
expected = updated
|
||||
|
||||
t.Run("should get NotFound if name does not exist", func(t *testing.T) {
|
||||
up := updatedExpected.DeepCopy()
|
||||
up := updatedExpected.Copy().(*v0alpha1.TimeInterval)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err)
|
||||
@@ -306,7 +300,7 @@ func TestIntegrationTimeIntervalAccessControl(t *testing.T) {
|
||||
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.DeepCopy()
|
||||
up := updatedExpected.Copy().(*v0alpha1.TimeInterval)
|
||||
up.Name = "notFound"
|
||||
_, err := client.Update(ctx, up, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
||||
@@ -361,9 +355,7 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) {
|
||||
org := helper.Org1
|
||||
|
||||
admin := org.Admin
|
||||
adminK8sClient, err := versioned.NewForConfig(admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
env := helper.GetEnv()
|
||||
ac := acimpl.ProvideAccessControl(env.FeatureToggles, zanzana.NewNoopClient())
|
||||
@@ -374,9 +366,9 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) {
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TimeIntervalSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Name: "time-interval-1",
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2),
|
||||
},
|
||||
}, v1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -394,8 +386,8 @@ func TestIntegrationTimeIntervalProvisioning(t *testing.T) {
|
||||
require.Equal(t, "API", got.GetProvenanceStatus())
|
||||
})
|
||||
t.Run("should not let update if provisioned", func(t *testing.T) {
|
||||
updated := created.DeepCopy()
|
||||
updated.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2)
|
||||
updated := created.Copy().(*v0alpha1.TimeInterval)
|
||||
updated.Spec.TimeIntervals = fakes.IntervalGenerator{}.GenerateMany(2)
|
||||
|
||||
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err)
|
||||
@@ -415,17 +407,15 @@ func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
interval := v0alpha1.TimeInterval{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TimeIntervalSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Name: "time-interval",
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -435,23 +425,23 @@ func TestIntegrationTimeIntervalOptimisticConcurrency(t *testing.T) {
|
||||
require.NotEmpty(t, created.ResourceVersion)
|
||||
|
||||
t.Run("should forbid if version does not match", func(t *testing.T) {
|
||||
updated := created.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.TimeInterval)
|
||||
updated.ResourceVersion = "test"
|
||||
_, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
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.DeepCopy()
|
||||
updated.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2)
|
||||
updated := created.Copy().(*v0alpha1.TimeInterval)
|
||||
updated.Spec.TimeIntervals = fakes.IntervalGenerator{}.GenerateMany(2)
|
||||
actualUpdated, err := adminClient.Update(ctx, updated, v1.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) {
|
||||
updated := created.DeepCopy()
|
||||
updated := created.Copy().(*v0alpha1.TimeInterval)
|
||||
updated.ResourceVersion = ""
|
||||
updated.Spec.TimeIntervals = v0alpha1.IntervalGenerator{}.GenerateMany(2)
|
||||
updated.Spec.TimeIntervals = fakes.IntervalGenerator{}.GenerateMany(2)
|
||||
|
||||
actualUpdated, err := adminClient.Update(ctx, updated, v1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -501,17 +491,15 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
interval := v0alpha1.TimeInterval{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TimeIntervalSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Name: "time-interval",
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -534,7 +522,7 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("should patch with json patch", func(t *testing.T) {
|
||||
expected := v0alpha1.IntervalGenerator{}.Generate()
|
||||
expected := fakes.IntervalGenerator{}.Generate()
|
||||
|
||||
patch := []map[string]interface{}{
|
||||
{
|
||||
@@ -549,9 +537,11 @@ func TestIntegrationTimeIntervalPatch(t *testing.T) {
|
||||
|
||||
result, err := adminClient.Patch(ctx, current.Name, types.JSONPatchType, patchData, v1.PatchOptions{})
|
||||
require.NoError(t, err)
|
||||
expectedSpec := *current.Spec.DeepCopy()
|
||||
expectedSpec.TimeIntervals = []v0alpha1.Interval{
|
||||
expected,
|
||||
expectedSpec := v0alpha1.Spec{
|
||||
Name: current.Spec.Name,
|
||||
TimeIntervals: []v0alpha1.Interval{
|
||||
expected,
|
||||
},
|
||||
}
|
||||
require.EqualValues(t, expectedSpec, result.Spec)
|
||||
current = result
|
||||
@@ -566,29 +556,27 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
interval1 := &v0alpha1.TimeInterval{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TimeIntervalSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Name: "test1",
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2),
|
||||
},
|
||||
}
|
||||
interval1, err = adminClient.Create(ctx, interval1, v1.CreateOptions{})
|
||||
interval1, err := adminClient.Create(ctx, interval1, v1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
interval2 := &v0alpha1.TimeInterval{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: v0alpha1.TimeIntervalSpec{
|
||||
Spec: v0alpha1.Spec{
|
||||
Name: "test2",
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(2),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(2),
|
||||
},
|
||||
}
|
||||
interval2, err = adminClient.Create(ctx, interval2, v1.CreateOptions{})
|
||||
@@ -630,7 +618,7 @@ func TestIntegrationTimeIntervalListSelector(t *testing.T) {
|
||||
|
||||
t.Run("should filter by multiple filters", func(t *testing.T) {
|
||||
list, err := adminClient.List(ctx, v1.ListOptions{
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s,metadata.provenance=%s", interval2.Name, "API"),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s,spec.name=%s", interval2.Name, interval2.Spec.Name),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list.Items, 1)
|
||||
@@ -639,7 +627,7 @@ 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,metadata.provenance=%s", interval2.Name, "unknown"),
|
||||
FieldSelector: fmt.Sprintf("metadata.name=%s", "unknown"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, list.Items)
|
||||
@@ -684,9 +672,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) {
|
||||
currentRoute := legacyCli.GetRoute(t)
|
||||
currentRuleGroup := legacyCli.GetRulesGroup(t, folderUID, ruleGroup.Name)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(cliCfg)
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
intervals, err := adminClient.List(ctx, v1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
@@ -710,7 +696,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) {
|
||||
|
||||
t.Run("Update", func(t *testing.T) {
|
||||
t.Run("should rename all references if name changes", func(t *testing.T) {
|
||||
renamed := interval.DeepCopy()
|
||||
renamed := interval.Copy().(*v0alpha1.TimeInterval)
|
||||
renamed.Spec.Name += "-new"
|
||||
|
||||
actual, err := adminClient.Update(ctx, renamed, v1.UpdateOptions{})
|
||||
@@ -734,7 +720,7 @@ func TestIntegrationTimeIntervalReferentialIntegrity(t *testing.T) {
|
||||
|
||||
t.Run("should fail if at least one resource is provisioned", func(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
renamed := interval.DeepCopy()
|
||||
renamed := interval.Copy().(*v0alpha1.TimeInterval)
|
||||
renamed.Spec.Name += util.GenerateShortUID()
|
||||
|
||||
t.Run("provisioned route", func(t *testing.T) {
|
||||
@@ -787,24 +773,22 @@ func TestIntegrationTimeIntervalValidation(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helper := getTestHelper(t)
|
||||
|
||||
adminK8sClient, err := versioned.NewForConfig(helper.Org1.Admin.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
adminClient := adminK8sClient.NotificationsV0alpha1().TimeIntervals("default")
|
||||
adminClient := newClient(t, helper.Org1.Admin)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
interval v0alpha1.TimeIntervalSpec
|
||||
interval v0alpha1.Spec
|
||||
}{
|
||||
{
|
||||
name: "missing name",
|
||||
interval: v0alpha1.TimeIntervalSpec{
|
||||
interval: v0alpha1.Spec{
|
||||
Name: "",
|
||||
TimeIntervals: v0alpha1.IntervalGenerator{}.GenerateMany(1),
|
||||
TimeIntervals: fakes.IntervalGenerator{}.GenerateMany(1),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid interval",
|
||||
interval: v0alpha1.TimeIntervalSpec{
|
||||
interval: v0alpha1.Spec{
|
||||
Name: "test",
|
||||
TimeIntervals: []v0alpha1.Interval{
|
||||
{
|
||||
@@ -823,9 +807,25 @@ func TestIntegrationTimeIntervalValidation(t *testing.T) {
|
||||
},
|
||||
Spec: tc.interval,
|
||||
}
|
||||
_, err = adminClient.Create(ctx, i, v1.CreateOptions{})
|
||||
_, err := adminClient.Create(ctx, i, v1.CreateOptions{})
|
||||
require.Error(t, err)
|
||||
require.Truef(t, errors.IsBadRequest(err), "Expected BadRequest, got: %s", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1.TimeInterval, v0alpha1.TimeIntervalList] {
|
||||
t.Helper()
|
||||
|
||||
client, err := dynamic.NewForConfig(user.NewRestConfig())
|
||||
require.NoError(t, err)
|
||||
|
||||
return &apis.TypedClient[v0alpha1.TimeInterval, v0alpha1.TimeIntervalList]{
|
||||
Client: client.Resource(
|
||||
schema.GroupVersionResource{
|
||||
Group: v0alpha1.Kind().Group(),
|
||||
Version: v0alpha1.Kind().Version(),
|
||||
Resource: v0alpha1.Kind().Plural(),
|
||||
}).Namespace("default"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
yamlutil "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
@@ -645,3 +646,87 @@ func (c *K8sTestHelper) CreateTeam(name, email string, orgID int64) team.Team {
|
||||
require.NoError(c.t, err)
|
||||
return team
|
||||
}
|
||||
|
||||
// TypedClient is the struct that implements a typed interface for resource operations
|
||||
type TypedClient[T any, L any] struct {
|
||||
Client dynamic.ResourceInterface
|
||||
}
|
||||
|
||||
func (c *TypedClient[T, L]) Create(ctx context.Context, resource *T, opts metav1.CreateOptions) (*T, error) {
|
||||
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := &unstructured.Unstructured{Object: unstructuredObj}
|
||||
result, err := c.Client.Create(ctx, u, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createdObj := new(T)
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(result.Object, createdObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return createdObj, nil
|
||||
}
|
||||
|
||||
func (c *TypedClient[T, L]) Update(ctx context.Context, resource *T, opts metav1.UpdateOptions) (*T, error) {
|
||||
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := &unstructured.Unstructured{Object: unstructuredObj}
|
||||
result, err := c.Client.Update(ctx, u, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updatedObj := new(T)
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(result.Object, updatedObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return updatedObj, nil
|
||||
}
|
||||
|
||||
func (c *TypedClient[T, L]) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error {
|
||||
return c.Client.Delete(ctx, name, opts)
|
||||
}
|
||||
|
||||
func (c *TypedClient[T, L]) Get(ctx context.Context, name string, opts metav1.GetOptions) (*T, error) {
|
||||
result, err := c.Client.Get(ctx, name, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retrievedObj := new(T)
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(result.Object, retrievedObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return retrievedObj, nil
|
||||
}
|
||||
|
||||
func (c *TypedClient[T, L]) List(ctx context.Context, opts metav1.ListOptions) (*L, error) {
|
||||
result, err := c.Client.List(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
listObj := new(L)
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(result.UnstructuredContent(), listObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listObj, nil
|
||||
}
|
||||
|
||||
func (c *TypedClient[T, L]) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*T, error) {
|
||||
result, err := c.Client.Patch(ctx, name, pt, data, opts, subresources...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
patchedObj := new(T)
|
||||
err = runtime.DefaultUnstructuredConverter.FromUnstructured(result.Object, patchedObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return patchedObj, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user