grafana/pkg/services/ngalert/api/compat_contact_points_test.go
Yuri Tseretyan 372082d254
Alerting: Export of contact points to HCL (#75849)
* add compat layer to convert from Export model to "new" API models
2023-10-12 22:33:57 +01:00

188 lines
6.3 KiB
Go

package api
import (
"context"
"encoding/base64"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/grafana/alerting/notify"
receiversTesting "github.com/grafana/alerting/receivers/testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
)
// Test that conversion notify.APIReceiver -> definitions.ContactPoint -> notify.APIReceiver does not lose data
func TestContactPointFromContactPointExports(t *testing.T) {
getContactPointExport := func(t *testing.T, receiver *notify.APIReceiver) definitions.ContactPointExport {
export := make([]definitions.ReceiverExport, 0, len(receiver.Integrations))
for _, integrationConfig := range receiver.Integrations {
postable := &definitions.PostableGrafanaReceiver{
UID: integrationConfig.UID,
Name: integrationConfig.Name,
Type: integrationConfig.Type,
DisableResolveMessage: integrationConfig.DisableResolveMessage,
Settings: definitions.RawMessage(integrationConfig.Settings),
SecureSettings: integrationConfig.SecureSettings,
}
emb, err := provisioning.PostableGrafanaReceiverToEmbeddedContactPoint(
postable,
models.ProvenanceNone,
func(s string) string { // test configs are not encrypted but encoded
d, err := base64.StdEncoding.DecodeString(s)
require.NoError(t, err)
return string(d)
})
require.NoError(t, err)
ex, err := ReceiverExportFromEmbeddedContactPoint(emb)
require.NoError(t, err)
export = append(export, ex)
}
return definitions.ContactPointExport{
OrgID: 1,
Name: receiver.Name,
Receivers: export,
}
}
// use the configs for testing because they have all fields supported by integrations
for integrationType, cfg := range notify.AllKnownConfigsForTesting {
t.Run(integrationType, func(t *testing.T) {
recCfg := &notify.APIReceiver{
ConfigReceiver: notify.ConfigReceiver{Name: "test-receiver"},
GrafanaIntegrations: notify.GrafanaIntegrations{
Integrations: []*notify.GrafanaIntegrationConfig{
cfg.GetRawNotifierConfig("test"),
},
},
}
expected, err := notify.BuildReceiverConfiguration(context.Background(), recCfg, func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string {
return receiversTesting.DecryptForTesting(sjd)(key, fallback)
})
require.NoError(t, err)
result, err := ContactPointFromContactPointExport(getContactPointExport(t, recCfg))
require.NoError(t, err)
back, err := ContactPointToContactPointExport(result)
require.NoError(t, err)
actual, err := notify.BuildReceiverConfiguration(context.Background(), &back, func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string {
return receiversTesting.DecryptForTesting(sjd)(key, fallback)
})
require.NoError(t, err)
diff := cmp.Diff(expected, actual, cmp.FilterPath(func(path cmp.Path) bool {
return strings.Contains(path.String(), "Metadata.UID") ||
strings.Contains(path.String(), "Metadata.Name") ||
strings.Contains(path.String(), "WecomConfigs.Settings.EndpointURL") // This field is not exposed to user
}, cmp.Ignore()))
if len(diff) != 0 {
require.Failf(t, "The re-marshalled configuration does not match the expected one", diff)
}
})
}
t.Run("pushover optional numbers as string", func(t *testing.T) {
export := definitions.ContactPointExport{
Name: "test",
Receivers: []definitions.ReceiverExport{
{
Type: "pushover",
Settings: definitions.RawMessage(
`{
"priority": 1,
"okPriority": "2",
"expire": null,
"retry": "invalid"
}`),
},
},
}
result, err := ContactPointFromContactPointExport(export)
require.NoError(t, err)
require.Len(t, result.Pushover, 1)
require.Equal(t, int64(1), *result.Pushover[0].AlertingPriority)
require.Equal(t, int64(2), *result.Pushover[0].OKPriority)
require.Nil(t, result.Pushover[0].Expire)
require.Nil(t, result.Pushover[0].Retry)
})
t.Run("email with multiple addresses", func(t *testing.T) {
export := definitions.ContactPointExport{
Name: "test",
Receivers: []definitions.ReceiverExport{
{
Type: "email",
Settings: definitions.RawMessage(`{"addresses": "test@grafana.com,test2@grafana.com;test3@grafana.com\ntest4@granafa.com"}`),
},
},
}
result, err := ContactPointFromContactPointExport(export)
require.NoError(t, err)
require.Len(t, result.Email, 1)
require.EqualValues(t, []string{
"test@grafana.com",
"test2@grafana.com",
"test3@grafana.com",
"test4@granafa.com",
}, result.Email[0].Addresses)
})
t.Run("webhook with optional numbers as string", func(t *testing.T) {
export := definitions.ContactPointExport{
Name: "test",
Receivers: []definitions.ReceiverExport{
{
Type: "webhook",
Settings: definitions.RawMessage(`{ "maxAlerts" : "112" }`),
},
{
Type: "webhook",
Settings: definitions.RawMessage(`{ "maxAlerts" : "test" }`),
},
{
Type: "webhook",
Settings: definitions.RawMessage(`{ "maxAlerts" : null }`),
},
},
}
result, err := ContactPointFromContactPointExport(export)
require.NoError(t, err)
require.Len(t, result.Webhook, 3)
require.Equal(t, int64(112), *result.Webhook[0].MaxAlerts)
require.Nil(t, result.Webhook[1].MaxAlerts)
require.Nil(t, result.Webhook[2].MaxAlerts)
})
t.Run("oncall with optional numbers as string", func(t *testing.T) {
export := definitions.ContactPointExport{
Name: "test",
Receivers: []definitions.ReceiverExport{
{
Type: "oncall",
Settings: definitions.RawMessage(`{ "maxAlerts" : "112" }`),
},
{
Type: "oncall",
Settings: definitions.RawMessage(`{ "maxAlerts" : "test" }`),
},
{
Type: "oncall",
Settings: definitions.RawMessage(`{ "maxAlerts" : null }`),
},
},
}
result, err := ContactPointFromContactPointExport(export)
require.NoError(t, err)
require.Len(t, result.OnCall, 3)
require.Equal(t, int64(112), *result.OnCall[0].MaxAlerts)
require.Nil(t, result.OnCall[1].MaxAlerts)
require.Nil(t, result.OnCall[2].MaxAlerts)
})
}