1
2
3
4
5
6
7
8
9
10
11
12
13
14 package victorops
15
16 import (
17 "context"
18 "encoding/json"
19 "fmt"
20 "net/http"
21 "net/http/httptest"
22 "net/url"
23 "os"
24 "testing"
25 "time"
26
27 "github.com/go-kit/log"
28 commoncfg "github.com/prometheus/common/config"
29 "github.com/prometheus/common/model"
30 "github.com/stretchr/testify/require"
31
32 "github.com/prometheus/alertmanager/config"
33 "github.com/prometheus/alertmanager/notify"
34 "github.com/prometheus/alertmanager/notify/test"
35 "github.com/prometheus/alertmanager/types"
36 )
37
38 func TestVictorOpsCustomFields(t *testing.T) {
39 logger := log.NewNopLogger()
40 tmpl := test.CreateTmpl(t)
41
42 url, err := url.Parse("http://nowhere.com")
43
44 require.NoError(t, err, "unexpected error parsing mock url")
45
46 conf := &config.VictorOpsConfig{
47 APIKey: `12345`,
48 APIURL: &config.URL{URL: url},
49 EntityDisplayName: `{{ .CommonLabels.Message }}`,
50 StateMessage: `{{ .CommonLabels.Message }}`,
51 RoutingKey: `test`,
52 MessageType: ``,
53 MonitoringTool: `AM`,
54 CustomFields: map[string]string{
55 "Field_A": "{{ .CommonLabels.Message }}",
56 },
57 HTTPConfig: &commoncfg.HTTPClientConfig{},
58 }
59
60 notifier, err := New(conf, tmpl, logger)
61 require.NoError(t, err)
62
63 ctx := context.Background()
64 ctx = notify.WithGroupKey(ctx, "1")
65
66 alert := &types.Alert{
67 Alert: model.Alert{
68 Labels: model.LabelSet{
69 "Message": "message",
70 },
71 StartsAt: time.Now(),
72 EndsAt: time.Now().Add(time.Hour),
73 },
74 }
75
76 msg, err := notifier.createVictorOpsPayload(ctx, alert)
77 require.NoError(t, err)
78
79 var m map[string]string
80 err = json.Unmarshal(msg.Bytes(), &m)
81
82 require.NoError(t, err)
83
84
85 require.Equal(t, "message", m["Field_A"])
86 }
87
88 func TestVictorOpsRetry(t *testing.T) {
89 notifier, err := New(
90 &config.VictorOpsConfig{
91 APIKey: config.Secret("secret"),
92 HTTPConfig: &commoncfg.HTTPClientConfig{},
93 },
94 test.CreateTmpl(t),
95 log.NewNopLogger(),
96 )
97 require.NoError(t, err)
98 for statusCode, expected := range test.RetryTests(test.DefaultRetryCodes()) {
99 actual, _ := notifier.retrier.Check(statusCode, nil)
100 require.Equal(t, expected, actual, fmt.Sprintf("error on status %d", statusCode))
101 }
102 }
103
104 func TestVictorOpsRedactedURL(t *testing.T) {
105 ctx, u, fn := test.GetContextWithCancelingURL()
106 defer fn()
107
108 secret := "secret"
109 notifier, err := New(
110 &config.VictorOpsConfig{
111 APIURL: &config.URL{URL: u},
112 APIKey: config.Secret(secret),
113 HTTPConfig: &commoncfg.HTTPClientConfig{},
114 },
115 test.CreateTmpl(t),
116 log.NewNopLogger(),
117 )
118 require.NoError(t, err)
119
120 test.AssertNotifyLeaksNoSecret(ctx, t, notifier, secret)
121 }
122
123 func TestVictorOpsReadingApiKeyFromFile(t *testing.T) {
124 key := "key"
125 f, err := os.CreateTemp("", "victorops_test")
126 require.NoError(t, err, "creating temp file failed")
127 _, err = f.WriteString(key)
128 require.NoError(t, err, "writing to temp file failed")
129
130 ctx, u, fn := test.GetContextWithCancelingURL()
131 defer fn()
132
133 notifier, err := New(
134 &config.VictorOpsConfig{
135 APIURL: &config.URL{URL: u},
136 APIKeyFile: f.Name(),
137 HTTPConfig: &commoncfg.HTTPClientConfig{},
138 },
139 test.CreateTmpl(t),
140 log.NewNopLogger(),
141 )
142 require.NoError(t, err)
143
144 test.AssertNotifyLeaksNoSecret(ctx, t, notifier, key)
145 }
146
147 func TestVictorOpsTemplating(t *testing.T) {
148 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
149 dec := json.NewDecoder(r.Body)
150 out := make(map[string]interface{})
151 err := dec.Decode(&out)
152 if err != nil {
153 panic(err)
154 }
155 }))
156 defer srv.Close()
157 u, _ := url.Parse(srv.URL)
158
159 tests := []struct {
160 name string
161 cfg *config.VictorOpsConfig
162 errMsg string
163 }{
164 {
165 name: "default valid templates",
166 cfg: &config.VictorOpsConfig{},
167 },
168 {
169 name: "invalid message_type",
170 cfg: &config.VictorOpsConfig{
171 MessageType: "{{ .CommonLabels.alertname }",
172 },
173 errMsg: "templating error",
174 },
175 {
176 name: "invalid entity_display_name",
177 cfg: &config.VictorOpsConfig{
178 EntityDisplayName: "{{ .CommonLabels.alertname }",
179 },
180 errMsg: "templating error",
181 },
182 {
183 name: "invalid state_message",
184 cfg: &config.VictorOpsConfig{
185 StateMessage: "{{ .CommonLabels.alertname }",
186 },
187 errMsg: "templating error",
188 },
189 {
190 name: "invalid monitoring tool",
191 cfg: &config.VictorOpsConfig{
192 MonitoringTool: "{{ .CommonLabels.alertname }",
193 },
194 errMsg: "templating error",
195 },
196 {
197 name: "invalid routing_key",
198 cfg: &config.VictorOpsConfig{
199 RoutingKey: "{{ .CommonLabels.alertname }",
200 },
201 errMsg: "templating error",
202 },
203 }
204
205 for _, tc := range tests {
206 t.Run(tc.name, func(t *testing.T) {
207 tc.cfg.HTTPConfig = &commoncfg.HTTPClientConfig{}
208 tc.cfg.APIURL = &config.URL{URL: u}
209 tc.cfg.APIKey = "test"
210 vo, err := New(tc.cfg, test.CreateTmpl(t), log.NewNopLogger())
211 require.NoError(t, err)
212 ctx := context.Background()
213 ctx = notify.WithGroupKey(ctx, "1")
214
215 _, err = vo.Notify(ctx, []*types.Alert{
216 {
217 Alert: model.Alert{
218 Labels: model.LabelSet{
219 "lbl1": "val1",
220 },
221 StartsAt: time.Now(),
222 EndsAt: time.Now().Add(time.Hour),
223 },
224 },
225 }...)
226 if tc.errMsg == "" {
227 require.NoError(t, err)
228 } else {
229 require.Contains(t, err.Error(), tc.errMsg)
230 }
231 })
232 }
233 }
234
View as plain text