Skip to content

Commit 1f3e279

Browse files
add tests for BuildReceiverConfiguration
1 parent 3e71087 commit 1f3e279

File tree

1 file changed

+326
-0
lines changed

1 file changed

+326
-0
lines changed

notify/receivers_test.go

+326
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,37 @@ package notify
22

33
import (
44
"context"
5+
"encoding/base64"
6+
"encoding/json"
57
"errors"
8+
"fmt"
9+
"math/rand"
610
"net/url"
11+
"strings"
712
"testing"
813

914
"github.com/stretchr/testify/require"
15+
16+
"github.com/grafana/alerting/receivers"
17+
"github.com/grafana/alerting/receivers/alertmanager"
18+
"github.com/grafana/alerting/receivers/dinding"
19+
"github.com/grafana/alerting/receivers/discord"
20+
"github.com/grafana/alerting/receivers/email"
21+
"github.com/grafana/alerting/receivers/googlechat"
22+
"github.com/grafana/alerting/receivers/kafka"
23+
"github.com/grafana/alerting/receivers/line"
24+
"github.com/grafana/alerting/receivers/opsgenie"
25+
"github.com/grafana/alerting/receivers/pagerduty"
26+
"github.com/grafana/alerting/receivers/pushover"
27+
"github.com/grafana/alerting/receivers/sensugo"
28+
"github.com/grafana/alerting/receivers/slack"
29+
"github.com/grafana/alerting/receivers/teams"
30+
"github.com/grafana/alerting/receivers/telegram"
31+
"github.com/grafana/alerting/receivers/threema"
32+
"github.com/grafana/alerting/receivers/victorops"
33+
"github.com/grafana/alerting/receivers/webex"
34+
"github.com/grafana/alerting/receivers/webhook"
35+
"github.com/grafana/alerting/receivers/wecom"
1036
)
1137

1238
func TestInvalidReceiverError_Error(t *testing.T) {
@@ -78,3 +104,303 @@ func TestProcessNotifierError(t *testing.T) {
78104
require.Equal(t, err, ProcessNotifierError(r, err))
79105
})
80106
}
107+
108+
func TestBuildReceiverConfiguration(t *testing.T) {
109+
var decrypt receivers.GetDecryptedValueFn = func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string {
110+
v, ok := sjd[key]
111+
if !ok {
112+
return fallback
113+
}
114+
return string(v)
115+
}
116+
117+
t.Run("should decode secrets from base64", func(t *testing.T) {
118+
recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}}
119+
for notifierType, cfg := range allKnownConfigs {
120+
recCfg.Receivers = append(recCfg.Receivers, cfg.getRawNotifierConfig(notifierType))
121+
}
122+
counter := 0
123+
decryptCount := func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string {
124+
counter++
125+
return decrypt(ctx, sjd, key, fallback)
126+
}
127+
_, _ = BuildReceiverConfiguration(context.Background(), recCfg, decryptCount)
128+
require.Greater(t, counter, 0)
129+
})
130+
t.Run("should fail if at least one config is invalid", func(t *testing.T) {
131+
recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}}
132+
for notifierType, cfg := range allKnownConfigs {
133+
recCfg.Receivers = append(recCfg.Receivers, cfg.getRawNotifierConfig(notifierType))
134+
}
135+
bad := &GrafanaReceiver{
136+
UID: "invalid-test",
137+
Name: "invalid-test",
138+
Type: "slack",
139+
Settings: json.RawMessage(`{ "test" : "test" }`),
140+
}
141+
recCfg.Receivers = append(recCfg.Receivers, bad)
142+
143+
parsed, err := BuildReceiverConfiguration(context.Background(), recCfg, decrypt)
144+
require.NotNil(t, err)
145+
require.Equal(t, GrafanaReceiverConfig{}, parsed)
146+
require.IsType(t, &ReceiverValidationError{}, err)
147+
typedError := err.(*ReceiverValidationError)
148+
require.NotNil(t, typedError.Cfg)
149+
require.Equal(t, bad, typedError.Cfg)
150+
require.ErrorContains(t, err, fmt.Sprintf(`failed to validate receiver "%s" of type "%s"`, bad.Name, bad.Type))
151+
})
152+
t.Run("should accept empty config", func(t *testing.T) {
153+
recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}}
154+
parsed, err := BuildReceiverConfiguration(context.Background(), recCfg, decrypt)
155+
require.NoError(t, err)
156+
require.Equal(t, recCfg.Name, parsed.Name)
157+
})
158+
t.Run("should fail if secrets decoding fails", func(t *testing.T) {
159+
recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}}
160+
for notifierType, cfg := range allKnownConfigs {
161+
notifierRaw := cfg.getRawNotifierConfig(notifierType)
162+
if len(notifierRaw.SecureSettings) == 0 {
163+
continue
164+
}
165+
for key := range notifierRaw.SecureSettings {
166+
notifierRaw.SecureSettings[key] = "bad base-64"
167+
}
168+
recCfg.Receivers = append(recCfg.Receivers, notifierRaw)
169+
}
170+
171+
parsed, err := BuildReceiverConfiguration(context.Background(), recCfg, decrypt)
172+
require.NotNil(t, err)
173+
require.Equal(t, GrafanaReceiverConfig{}, parsed)
174+
require.IsType(t, &ReceiverValidationError{}, err)
175+
typedError := err.(*ReceiverValidationError)
176+
require.NotNil(t, typedError.Cfg)
177+
require.ErrorContains(t, err, "failed to decode secure settings")
178+
})
179+
t.Run("should fail if notifier type is unknown", func(t *testing.T) {
180+
recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}}
181+
for notifierType, cfg := range allKnownConfigs {
182+
recCfg.Receivers = append(recCfg.Receivers, cfg.getRawNotifierConfig(notifierType))
183+
}
184+
bad := &GrafanaReceiver{
185+
UID: "test",
186+
Name: "test",
187+
Type: fmt.Sprintf("invalid-%d", rand.Uint32()),
188+
Settings: json.RawMessage(`{ "test" : "test" }`),
189+
}
190+
recCfg.Receivers = append(recCfg.Receivers, bad)
191+
192+
parsed, err := BuildReceiverConfiguration(context.Background(), recCfg, decrypt)
193+
require.NotNil(t, err)
194+
require.Equal(t, GrafanaReceiverConfig{}, parsed)
195+
require.IsType(t, &ReceiverValidationError{}, err)
196+
typedError := err.(*ReceiverValidationError)
197+
require.NotNil(t, typedError.Cfg)
198+
require.Equal(t, bad, typedError.Cfg)
199+
require.ErrorContains(t, err, fmt.Sprintf("notifier %s is not supported", bad.Type))
200+
})
201+
t.Run("should recognize all known types", func(t *testing.T) {
202+
recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}}
203+
for notifierType, cfg := range allKnownConfigs {
204+
recCfg.Receivers = append(recCfg.Receivers, cfg.getRawNotifierConfig(notifierType))
205+
}
206+
parsed, err := BuildReceiverConfiguration(context.Background(), recCfg, decrypt)
207+
require.NoError(t, err)
208+
require.Equal(t, recCfg.Name, parsed.Name)
209+
require.Len(t, parsed.AlertmanagerConfigs, 1)
210+
require.Len(t, parsed.DingdingConfigs, 1)
211+
require.Len(t, parsed.DiscordConfigs, 1)
212+
require.Len(t, parsed.EmailConfigs, 1)
213+
require.Len(t, parsed.GooglechatConfigs, 1)
214+
require.Len(t, parsed.KafkaConfigs, 1)
215+
require.Len(t, parsed.LineConfigs, 1)
216+
require.Len(t, parsed.OpsgenieConfigs, 1)
217+
require.Len(t, parsed.PagerdutyConfigs, 1)
218+
require.Len(t, parsed.PushoverConfigs, 1)
219+
require.Len(t, parsed.SensugoConfigs, 1)
220+
require.Len(t, parsed.SlackConfigs, 1)
221+
require.Len(t, parsed.TeamsConfigs, 1)
222+
require.Len(t, parsed.TelegramConfigs, 1)
223+
require.Len(t, parsed.ThreemaConfigs, 1)
224+
require.Len(t, parsed.VictoropsConfigs, 1)
225+
require.Len(t, parsed.WebhookConfigs, 1)
226+
require.Len(t, parsed.WecomConfigs, 1)
227+
require.Len(t, parsed.WebexConfigs, 1)
228+
229+
t.Run("should populate metadata", func(t *testing.T) {
230+
var all []receivers.Metadata
231+
all = append(all, getMetadata(parsed.AlertmanagerConfigs)...)
232+
all = append(all, getMetadata(parsed.DingdingConfigs)...)
233+
all = append(all, getMetadata(parsed.DiscordConfigs)...)
234+
all = append(all, getMetadata(parsed.EmailConfigs)...)
235+
all = append(all, getMetadata(parsed.GooglechatConfigs)...)
236+
all = append(all, getMetadata(parsed.KafkaConfigs)...)
237+
all = append(all, getMetadata(parsed.LineConfigs)...)
238+
all = append(all, getMetadata(parsed.OpsgenieConfigs)...)
239+
all = append(all, getMetadata(parsed.PagerdutyConfigs)...)
240+
all = append(all, getMetadata(parsed.PushoverConfigs)...)
241+
all = append(all, getMetadata(parsed.SensugoConfigs)...)
242+
all = append(all, getMetadata(parsed.SlackConfigs)...)
243+
all = append(all, getMetadata(parsed.TeamsConfigs)...)
244+
all = append(all, getMetadata(parsed.TelegramConfigs)...)
245+
all = append(all, getMetadata(parsed.ThreemaConfigs)...)
246+
all = append(all, getMetadata(parsed.VictoropsConfigs)...)
247+
all = append(all, getMetadata(parsed.WebhookConfigs)...)
248+
all = append(all, getMetadata(parsed.WecomConfigs)...)
249+
all = append(all, getMetadata(parsed.WebexConfigs)...)
250+
251+
for idx, meta := range all {
252+
require.NotEmptyf(t, meta.Type, "%s notifier (idx: %d) '%s' uid: '%s'.", meta.Type, idx, meta.Name, meta.UID)
253+
require.NotEmptyf(t, meta.UID, "%s notifier (idx: %d) '%s' uid: '%s'.", meta.Type, idx, meta.Name, meta.UID)
254+
require.NotEmptyf(t, meta.Name, "%s notifier (idx: %d) '%s' uid: '%s'.", meta.Type, idx, meta.Name, meta.UID)
255+
var notifierRaw *GrafanaReceiver
256+
for _, receiver := range recCfg.Receivers {
257+
if receiver.Type == meta.Type && receiver.UID == meta.UID && receiver.Name == meta.Name {
258+
notifierRaw = receiver
259+
break
260+
}
261+
}
262+
require.NotNilf(t, notifierRaw, "cannot find raw settings for %s notifier '%s' uid: '%s'.", meta.Type, meta.Name, meta.UID)
263+
require.Equalf(t, notifierRaw.DisableResolveMessage, meta.DisableResolveMessage, "%s notifier '%s' uid: '%s'.", meta.Type, meta.Name, meta.UID)
264+
}
265+
})
266+
})
267+
t.Run("should recognize type in any case", func(t *testing.T) {
268+
recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}}
269+
for notifierType, cfg := range allKnownConfigs {
270+
notifierRaw := cfg.getRawNotifierConfig(notifierType)
271+
notifierRaw.Type = strings.ToUpper(notifierRaw.Type)
272+
recCfg.Receivers = append(recCfg.Receivers, cfg.getRawNotifierConfig(notifierType))
273+
}
274+
parsed, err := BuildReceiverConfiguration(context.Background(), recCfg, decrypt)
275+
require.NoError(t, err)
276+
require.Len(t, parsed.AlertmanagerConfigs, 1)
277+
require.Len(t, parsed.DingdingConfigs, 1)
278+
require.Len(t, parsed.DiscordConfigs, 1)
279+
require.Len(t, parsed.EmailConfigs, 1)
280+
require.Len(t, parsed.GooglechatConfigs, 1)
281+
require.Len(t, parsed.KafkaConfigs, 1)
282+
require.Len(t, parsed.LineConfigs, 1)
283+
require.Len(t, parsed.OpsgenieConfigs, 1)
284+
require.Len(t, parsed.PagerdutyConfigs, 1)
285+
require.Len(t, parsed.PushoverConfigs, 1)
286+
require.Len(t, parsed.SensugoConfigs, 1)
287+
require.Len(t, parsed.SlackConfigs, 1)
288+
require.Len(t, parsed.TeamsConfigs, 1)
289+
require.Len(t, parsed.TelegramConfigs, 1)
290+
require.Len(t, parsed.ThreemaConfigs, 1)
291+
require.Len(t, parsed.VictoropsConfigs, 1)
292+
require.Len(t, parsed.WebhookConfigs, 1)
293+
require.Len(t, parsed.WecomConfigs, 1)
294+
require.Len(t, parsed.WebexConfigs, 1)
295+
296+
})
297+
}
298+
299+
func getMetadata[T any](notifiers []*NotifierConfig[T]) []receivers.Metadata {
300+
result := make([]receivers.Metadata, 0, len(notifiers))
301+
for _, notifier := range notifiers {
302+
result = append(result, notifier.Metadata)
303+
}
304+
return result
305+
}
306+
307+
var allKnownConfigs = map[string]notifierConfigTest{
308+
"prometheus-alertmanager": {
309+
notifierType: "prometheus-alertmanager",
310+
config: alertmanager.FullValidConfigForTesting,
311+
secrets: alertmanager.FullValidSecretsForTesting,
312+
},
313+
"dingding": {notifierType: "dingding",
314+
config: dinding.FullValidConfigForTesting,
315+
},
316+
"discord": {notifierType: "discord",
317+
config: discord.FullValidConfigForTesting,
318+
},
319+
"email": {notifierType: "email",
320+
config: email.FullValidConfigForTesting,
321+
},
322+
"googlechat": {notifierType: "googlechat",
323+
config: googlechat.FullValidConfigForTesting,
324+
},
325+
"kafka": {notifierType: "kafka",
326+
config: kafka.FullValidConfigForTesting,
327+
secrets: kafka.FullValidSecretsForTesting,
328+
},
329+
"line": {notifierType: "line",
330+
config: line.FullValidConfigForTesting,
331+
secrets: line.FullValidSecretsForTesting,
332+
},
333+
"opsgenie": {notifierType: "opsgenie",
334+
config: opsgenie.FullValidConfigForTesting,
335+
secrets: opsgenie.FullValidSecretsForTesting,
336+
},
337+
"pagerduty": {notifierType: "pagerduty",
338+
config: pagerduty.FullValidConfigForTesting,
339+
secrets: pagerduty.FullValidSecretsForTesting,
340+
},
341+
"pushover": {notifierType: "pushover",
342+
config: pushover.FullValidConfigForTesting,
343+
secrets: pushover.FullValidSecretsForTesting,
344+
},
345+
"sensugo": {notifierType: "sensugo",
346+
config: sensugo.FullValidConfigForTesting,
347+
secrets: sensugo.FullValidSecretsForTesting,
348+
},
349+
"slack": {notifierType: "slack",
350+
config: slack.FullValidConfigForTesting,
351+
secrets: slack.FullValidSecretsForTesting,
352+
},
353+
"teams": {notifierType: "teams",
354+
config: teams.FullValidConfigForTesting,
355+
},
356+
"telegram": {notifierType: "telegram",
357+
config: telegram.FullValidConfigForTesting,
358+
secrets: telegram.FullValidSecretsForTesting,
359+
},
360+
"threema": {notifierType: "threema",
361+
config: threema.FullValidConfigForTesting,
362+
secrets: threema.FullValidSecretsForTesting,
363+
},
364+
"victorops": {notifierType: "victorops",
365+
config: victorops.FullValidConfigForTesting,
366+
},
367+
"webhook": {notifierType: "webhook",
368+
config: webhook.FullValidConfigForTesting,
369+
secrets: webhook.FullValidSecretsForTesting,
370+
},
371+
"wecom": {notifierType: "wecom",
372+
config: wecom.FullValidConfigForTesting,
373+
secrets: wecom.FullValidSecretsForTesting,
374+
},
375+
"webex": {notifierType: "webex",
376+
config: webex.FullValidConfigForTesting,
377+
secrets: webex.FullValidSecretsForTesting,
378+
},
379+
}
380+
381+
type notifierConfigTest struct {
382+
notifierType string
383+
config string
384+
secrets string
385+
}
386+
387+
func (n notifierConfigTest) getRawNotifierConfig(name string) *GrafanaReceiver {
388+
secrets := make(map[string]string)
389+
if n.secrets != "" {
390+
err := json.Unmarshal([]byte(n.secrets), &secrets)
391+
if err != nil {
392+
panic(err)
393+
}
394+
for key, value := range secrets {
395+
secrets[key] = base64.StdEncoding.EncodeToString([]byte(value))
396+
}
397+
}
398+
return &GrafanaReceiver{
399+
UID: fmt.Sprintf("%s-%d", name, rand.Uint32()),
400+
Name: name,
401+
Type: n.notifierType,
402+
DisableResolveMessage: rand.Int()%2 == 0,
403+
Settings: json.RawMessage(n.config),
404+
SecureSettings: secrets,
405+
}
406+
}

0 commit comments

Comments
 (0)