spoc-bot-vr/slack_test.go

304 lines
12 KiB
Go

package main
import (
"context"
"encoding/json"
"os"
"path"
"testing"
"time"
"github.com/breel-render/spoc-bot-vr/model"
"gotest.tools/assert"
)
func TestSlackToModelPipeline(t *testing.T) {
t.Parallel()
ctx, can := context.WithTimeout(context.Background(), time.Second*5)
defer can()
pipeline, err := NewSlackToModelPipeline(ctx, Config{
driver: NewTestDriver(t),
AssetPattern: renderAssetPattern,
DatacenterPattern: renderDatacenterPattern,
EventNamePattern: renderEventNamePattern,
})
if err != nil {
t.Fatal(err)
}
go func() {
if err := pipeline.Process(ctx); err != nil && ctx.Err() == nil {
t.Fatal(err)
}
}()
want := Models{
Event: model.NewEvent(
"11071",
"https://renderinc.slack.com/archives/C06U1DDBBU4/p1712927439728409",
1712927439,
"Alertconfig Workflow Failed",
"",
"",
"Datastores Non-Critical",
true,
),
Message: model.NewMessage(
"1712927439.728409/1712927439",
1712927439,
"Opsgenie for Alert Management",
"At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
"1712927439.728409",
),
Thread: model.NewThread(
"1712927439.728409",
"https://renderinc.slack.com/archives/C06U1DDBBU4/p1712927439728409",
1712927439,
"C06U1DDBBU4",
"11071",
),
/*
ID: "1712927439.728409/1712927439",
TS: 1712927439,
Source: "https://renderinc.slack.com/archives/C06U1DDBBU4/p1712927439728409",
Channel: "C06U1DDBBU4",
Thread: "1712927439.728409",
EventName: "",
Event: "11071",
Plaintext: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Asset: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Datacenter: "alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb",
*/
}
b, _ := os.ReadFile("testdata/slack_events/opsgenie_alert.json")
if err := pipeline.reader.Enqueue(ctx, b); err != nil {
t.Fatal("failed to enqueue", err)
}
var got Models
if _, b2, err := pipeline.writer.Syn(ctx); err != nil {
t.Fatal("failed to syn", err)
} else if err := json.Unmarshal(b2, &got); err != nil {
t.Fatal("failed to parse outqueue:", err)
} else {
want.Event.Updated = 0
want.Message.Updated = 0
want.Thread.Updated = 0
got.Event.Updated = 0
got.Message.Updated = 0
got.Thread.Updated = 0
assert.DeepEqual(t, want, got)
}
}
func TestParseSlackTestdata(t *testing.T) {
t.Parallel()
cases := map[string]struct {
slackMessage slackMessage
message parsedSlackMessage
}{
"human_thread_message_from_opsgenie_alert.json": {
slackMessage: slackMessage{
TS: 1712930706,
Event: slackEvent{
ID: "1712930706.598629",
Channel: "C06U1DDBBU4",
ParentID: "1712927439.728409",
Text: "I gotta do this",
Blocks: []slackBlock{{
Elements: []slackElement{{
Elements: []slackElement{{
RichText: "I gotta do this",
}},
}},
}},
Bot: slackBot{
Name: "",
},
Attachments: []slackAttachment{},
},
},
message: parsedSlackMessage{
ID: "1712927439.728409/1712930706",
TS: 1712930706,
Source: "https://renderinc.slack.com/archives/C06U1DDBBU4/p1712927439728409",
Channel: "C06U1DDBBU4",
Thread: "1712927439.728409",
EventName: "",
Event: "",
Plaintext: "I gotta do this",
Asset: "",
Author: "U06868T6ADV",
},
},
"opsgenie_alert.json": {
slackMessage: slackMessage{
TS: 1712927439,
Event: slackEvent{
ID: "1712927439.728409",
Channel: "C06U1DDBBU4",
Bot: slackBot{
Name: "Opsgenie for Alert Management",
},
Attachments: []slackAttachment{{
Color: "2ecc71",
Title: "#11071: [Grafana]: Firing: Alertconfig Workflow Failed",
Text: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Fields: []slackField{
{Value: "P3", Title: "Priority"},
{Value: "alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb", Title: "Tags"},
{Value: "Datastores Non-Critical", Title: "Routed Teams"},
},
Actions: []slackAction{{}, {}, {}},
}},
},
},
message: parsedSlackMessage{
ID: "1712927439.728409/1712927439",
TS: 1712927439,
Source: "https://renderinc.slack.com/archives/C06U1DDBBU4/p1712927439728409",
Channel: "C06U1DDBBU4",
Thread: "1712927439.728409",
EventName: "Alertconfig Workflow Failed",
Event: "11071",
Plaintext: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Asset: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Datacenter: "alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb",
Author: "Opsgenie for Alert Management",
Team: "Datastores Non-Critical",
Resolved: true,
},
},
"opsgenie_alert_resolved.json": {
slackMessage: slackMessage{
TS: 1712916339,
Event: slackEvent{
ID: "1712916339.000300",
Channel: "C06U1DDBBU4",
Bot: slackBot{
Name: "Opsgenie for Alert Management",
},
Attachments: []slackAttachment{{
Color: "2ecc71",
Title: "#11069: [Grafana]: Firing: Alertconfig Workflow Failed",
Text: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Fields: []slackField{
{Value: "P3", Title: "Priority"},
{Value: "alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb", Title: "Tags"},
{Value: "Datastores Non-Critical", Title: "Routed Teams"},
},
Actions: []slackAction{},
}},
},
},
message: parsedSlackMessage{
ID: "1712916339.000300/1712916339",
TS: 1712916339,
Source: "https://renderinc.slack.com/archives/C06U1DDBBU4/p1712916339000300",
Channel: "C06U1DDBBU4",
Thread: "1712916339.000300",
EventName: "Alertconfig Workflow Failed",
Event: "11069",
Plaintext: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Asset: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Resolved: true,
Datacenter: "alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb",
Author: "Opsgenie for Alert Management",
Team: "Datastores Non-Critical",
},
},
"reingested_alert.json": {
message: parsedSlackMessage{
ID: "1712892637.037639/1712892637",
TS: 1712892637,
Source: "https://renderinc.slack.com/archives//p1712892637037639",
//Channel: "C06U1DDBBU4",
Thread: "1712892637.037639",
EventName: "Alertconfig Workflow Failed",
Event: "11061",
Plaintext: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Asset: "At least one alertconfig run has failed unexpectedly.\nDashboard: <https://grafana.render.com/d/VLZU83YVk?orgId=1>\nPanel: <https://grafana.render.com/d/VLZU83YVk?orgId=1&amp;viewPanel=17>\nSource: <https://grafana.render.com/alerting/grafana/fa7b06b8-b4d8-4979-bce7-5e1c432edd81/view?orgId=1>",
Resolved: true,
Datacenter: "alertname:Alertconfig Workflow Failed, grafana_folder:Datastores, rule_uid:a7639f7e-6950-41be-850a-b22119f74cbb",
Author: "Opsgenie for Alert Management",
Team: "Datastores Non-Critical",
},
},
}
for name, d := range cases {
want := d
t.Run(name, func(t *testing.T) {
b, err := os.ReadFile(path.Join("testdata", "slack_events", name))
if err != nil {
t.Fatal(err)
}
t.Run("parseSlack", func(t *testing.T) {
got, err := parseSlack(b)
if err != nil {
t.Fatal(err)
}
if got != want.message {
assert.DeepEqual(t, want.message, got)
t.Errorf("wanted \n\t%+v, got\n\t%+v", want.message, got)
}
if time := got.Time(); time.Unix() != int64(got.TS) {
t.Error("not unix time", got.TS, time)
}
})
})
}
}
func TestWrappedSlack(t *testing.T) {
b, _ := os.ReadFile("testdata/slack_events/human_thread_message_from_opsgenie_alert.json")
b2, _ := json.Marshal(ChannelWrapper{Channel: "X", V: json.RawMessage(b)})
if got, err := _parseSlack(b); err != nil {
t.Fatal(err)
} else if got2, err := _parseSlack(b2); err != nil {
t.Fatal(err)
} else if got2.Event.Channel != "X" {
t.Error(got2.Event.Channel)
} else if got2.Event.ParentID == "" {
t.Error(got2.Event)
} else if got.Event.ParentID != got2.Event.ParentID {
t.Error(got, got2)
}
}
func TestWithPattern(t *testing.T) {
cases := map[string]struct {
given string
pattern string
want string
}{
"pods unavailable on node": {
given: `pods are unavailable on node ip-12-345-67-890.xx-yyyyy-1.compute.internal.`,
pattern: renderAssetPattern,
want: `ip-12-345-67-890.xx-yyyyy-1.compute.internal`,
},
"redis err": {
given: `Redis instance red-abc123 is emitting Some error repeatedly`,
pattern: renderAssetPattern,
want: `red-abc123`,
},
"pg err": {
given: `db dpg-xyz123 is in a pinch`,
pattern: renderAssetPattern,
want: `dpg-xyz123`,
},
}
for name, d := range cases {
c := d
t.Run(name, func(t *testing.T) {
got := withPattern(c.pattern, c.given)
if got != c.want {
t.Errorf("withPattern(%q, %q) expected %q but got %q", c.pattern, c.given, c.want, got)
}
})
}
}