package host import ( "bytes" "context" "encoding/json" "errors" "log" "strings" "testing" "github.com/carlosframework/platform/internal/alerting" ) // TestPageOperatorUsesTheArmedSinks: the paging primitive goes out through // the same webhook (and SNS topic) the agent's alerts use, its failures are // counted where the alert failures are, and the package function pages on // whatever the metrics loop armed. With no sinks it returns nil and says so // once. func TestPageOperatorUsesTheArmedSinks(t *testing.T) { type page struct{ Kind, Level, Subject, Body string } var pages []page var fail error post := func(url string, body []byte) error { var p page if err := json.Unmarshal(body, &p); err != nil { t.Fatalf("webhook body %s: %v", body, err) } if url != "http://example.test/hook" { t.Fatalf("posted to %s", url) } pages = append(pages, p) return fail } counts := &alertCounters{} pub := &fakeSNS{} sinks := newAlertSinks("http://example.test/hook", post, testTopicARN, pub, counts) ctx := context.Background() if err := sinks.PageOperator(ctx, alerting.LevelIncident, "carlos move stuck: shop.example", "the body"); err != nil { t.Fatal(err) } want := page{"page", "incident", "carlos move stuck: shop.example", "the body"} if len(pages) != 1 || pages[0] != want { t.Fatalf("pages %+v, want %+v", pages, want) } if len(pub.in) != 1 || deref(pub.in[0].Subject) != want.Subject || deref(pub.in[0].Message) != want.Body { t.Fatalf("sns: %+v", pub.in) } // The package function pages on the armed sinks. armPaging(sinks) t.Cleanup(func() { armPaging(nil) }) if err := PageOperator(ctx, alerting.LevelWarning, "second", "body two"); err != nil { t.Fatal(err) } if len(pages) != 2 || pages[1].Subject != "second" || pages[1].Level != "warning" { t.Fatalf("pages %+v", pages) } // A failed send is returned and counted with the alert failures. fail = errors.New("boom") if err := PageOperator(ctx, alerting.LevelIncident, "third", "body"); err == nil { t.Fatal("a failed webhook post returned nil") } if counts.webhook.Load() != 1 || counts.sns.Load() != 0 { t.Fatalf("failures webhook=%d sns=%d", counts.webhook.Load(), counts.sns.Load()) } // No sinks: nil, and one line in the journal however often it is asked. var buf bytes.Buffer prev := log.Writer() log.SetOutput(&buf) t.Cleanup(func() { log.SetOutput(prev) }) armPaging(nil) var none *alertSinks for range 2 { if err := PageOperator(ctx, alerting.LevelIncident, "s", "b"); err != nil { t.Fatal(err) } if err := none.PageOperator(ctx, alerting.LevelIncident, "s", "b"); err != nil { t.Fatal(err) } } if n := strings.Count(buf.String(), "no sink configured"); n != 1 { t.Fatalf("no-sink notice logged %d times, want once:\n%s", n, buf.String()) } if len(pages) != 3 { t.Fatalf("an unarmed page reached the old sinks: %+v", pages) } }