|
|
package alertmanager
import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/http" "net/http/httptest" "net/url" "regexp" "strings" "testing"
"github.com/matrix-org/go-neb/database" "github.com/matrix-org/go-neb/testutils" "github.com/matrix-org/go-neb/types" "maunium.net/go/mautrix" mevt "maunium.net/go/mautrix/event" )
func TestNotify(t *testing.T) { database.SetServiceDB(&database.NopStorage{})
// Intercept message sending to Matrix and mock responses
msgs := []mevt.MessageEventContent{} matrixCli := buildTestClient(&msgs)
// create the service
srv := buildTestService(t)
// send a notification
req, err := http.NewRequest( "POST", "", bytes.NewBufferString(` { "externalURL": "http://alertmanager", "alerts": [ { "labels": { "alertname": "alert 1", "severity": "huge" }, "generatorURL": "http://x" }, { "labels": { "alertname": "alert 2", "severity": "tiny" }, "generatorURL": "http://y" } ] } `), ) if err != nil { t.Fatalf("Failed to create webhook request: %s", err) } mockWriter := httptest.NewRecorder() srv.OnReceiveWebhook(mockWriter, req, matrixCli)
// check response
if mockWriter.Code != 200 { t.Fatalf("Expected response 200 OK, got %d", mockWriter.Code) } if len(msgs) != 1 { t.Fatalf("Expected sent 1 msgs, sent %d", len(msgs)) } msg := msgs[0] if msg.MsgType != "m.text" { t.Errorf("Wrong msgtype: got %s want m.text", msg.MsgType) }
lines := strings.Split(msg.FormattedBody, "\n")
// <a href="http://alertmanager#silences/new?filter=%7balertname%3D%22alert%202%22,severity%3D%22tiny%22%7d">silence</a>
matchedSilence := 0 for _, line := range lines { if !strings.Contains(line, "silence") { continue }
matchedSilence++ checkSilenceLine(t, line, map[string]string{ "alertname": "\"alert 1\"", "severity": "\"huge\"", }) break }
if matchedSilence == 0 { t.Errorf("Did not find any silence lines") } }
func buildTestClient(msgs *[]mevt.MessageEventContent) types.MatrixClient { matrixTrans := struct{ testutils.MockTransport }{} matrixTrans.RT = func(req *http.Request) (*http.Response, error) { if !strings.Contains(req.URL.String(), "/send/m.room.message") { return nil, fmt.Errorf("Unhandled URL: %s", req.URL.String()) } var msg mevt.MessageEventContent if err := json.NewDecoder(req.Body).Decode(&msg); err != nil { return nil, fmt.Errorf("Failed to decode request JSON: %s", err) } *msgs = append(*msgs, msg) return &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBufferString(`{"event_id":"$yup:event"}`)), }, nil } matrixCli, _ := mautrix.NewClient("https://hs", "@neb:hs", "its_a_secret") matrixCli.Client = &http.Client{Transport: matrixTrans} return matrixCli }
func buildTestService(t *testing.T) types.Service { htmlTemplate, err := json.Marshal( `{{range .Alerts}} {{index .Labels "severity" }} : {{- index .Labels "alertname" -}} <a href="{{ .GeneratorURL }}">source</a> <a href="{{ .SilenceURL }}">silence</a> {{- end }} `, )
if err != nil { t.Fatal(err) }
textTemplate, err := json.Marshal(`{{range .Alerts}}{{index .Labels "alertname"}} {{end}}`) if err != nil { t.Fatal(err) }
config := fmt.Sprintf(`{ "rooms":{ "!testroom:id" : { "text_template":%s, "html_template":%s, "msg_type":"m.text" }} }`, textTemplate, htmlTemplate, )
srv, err := types.CreateService("id", "alertmanager", "@neb:hs", []byte(config))
if err != nil { t.Fatal(err) }
return srv }
func checkSilenceLine(t *testing.T, line string, expectedKeys map[string]string) { silenceRegexp := regexp.MustCompile(`<a href="http://alertmanager#silences/new\?filter=%7b([^"]*)%7d">silence</a>`) m := silenceRegexp.FindStringSubmatch(line) if m == nil { t.Errorf("silence line %s had bad format", line) return }
unesc, err := url.QueryUnescape(m[1]) if err != nil { t.Errorf("Unable to decode filter, %v", err) return }
matched := 0 for _, f := range strings.Split(unesc, ",") { splits := strings.SplitN(f, "=", 2) key := splits[0] exp, ok := expectedKeys[key] if !ok { t.Errorf("unexpected key in filter: %v", key) } else if exp != splits[1] { t.Errorf("bad value for filter key %v: got %q, want %q", key, splits[1], exp) } else { matched++ } }
if matched != len(expectedKeys) { t.Errorf("number of filter fields got %d, want %d", matched, len(expectedKeys)) } }
|