fixes
This commit is contained in:
1 parent
2cf2cebf5c
commit
23243ddbdc
13 files changed
+906
-55
No files matched your search
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.tornberg.me/go-otel/internal/features"
|
||||
"git.tornberg.me/go-otel/internal/topology"
|
||||
)
|
||||
|
||||
func burst(sig string, n int, at time.Time, status int, route string) []features.Event {
|
||||
@@ -124,9 +125,23 @@ func TestTelegramTruncates(t *testing.T) {
|
||||
if err := (&Telegram{Token: "t", ChatID: "1", API: srv.URL}).Send(context.Background(), NewAlert(spike, time.Now())); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n := len([]rune(body["text"].(string))); n > 4096 {
|
||||
text := body["text"].(string)
|
||||
if n := plainLen(text); n > 4096 {
|
||||
t.Fatalf("message too long: %d", n)
|
||||
}
|
||||
if body["parse_mode"] != "HTML" || !strings.Contains(text, "more pattern") || strings.Count(text, "<b>") != strings.Count(text, "</b>") {
|
||||
t.Fatalf("bad html message: %.200s", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTelegramHTMLEscapesDynamicText(t *testing.T) {
|
||||
at := time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)
|
||||
ev := burst("x", 12, at.Add(-2*time.Minute), 500, "/a<b>&c")
|
||||
sp := DetectAlerts(ev, at, features.SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, MinExcess: 5})
|
||||
out := NewAlert(sp[0], at).HTML("https://otel.k6n.net", 4000)
|
||||
if strings.Contains(out, "/a<b>") || !strings.Contains(out, "/a<b>&c") {
|
||||
t.Fatalf("route not escaped:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScannerClientIsMutedEntirely(t *testing.T) {
|
||||
@@ -163,3 +178,104 @@ func TestMinExcessAppliesAfterTriage(t *testing.T) {
|
||||
t.Fatalf("paged on excess that was mostly probes: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientErrorsRankBelowServerErrors(t *testing.T) {
|
||||
at := time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)
|
||||
cur := at.Add(-2 * time.Minute)
|
||||
cfg := features.SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, MinExcess: 10}
|
||||
// 40 x 422 discounted to 8 excess: below MinExcess 10, no page
|
||||
if got := DetectAlerts(burst("bad-input", 40, cur, 422, "/api/order"), at, cfg); len(got) != 0 {
|
||||
t.Fatalf("4xx alone paged: %+v", got)
|
||||
}
|
||||
// 5xx of the same volume does page
|
||||
if got := DetectAlerts(burst("boom", 40, cur, 500, "/api/order"), at, cfg); len(got) != 1 {
|
||||
t.Fatalf("5xx did not page")
|
||||
}
|
||||
// mixed: the 5xx is listed first and the alert is high priority
|
||||
events := append(burst("bad-input", 40, cur, 422, "/api/order"), burst("boom", 8, cur, 500, "/api/pay")...)
|
||||
got := DetectAlerts(events, at, cfg)
|
||||
if len(got) != 1 {
|
||||
t.Fatalf("mixed spike: %+v", got)
|
||||
}
|
||||
a := NewAlert(got[0], at)
|
||||
if a.Priority() != PriorityHigh || a.Patterns[0].Priority != PriorityHigh || a.Patterns[1].Priority != PriorityLow {
|
||||
t.Fatalf("priority order wrong: %+v", a.Patterns)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertLinksToIssue(t *testing.T) {
|
||||
at := time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)
|
||||
ev := burst("boom", 12, at.Add(-2*time.Minute), 500, "/api")
|
||||
for i := range ev {
|
||||
ev[i].IssueFingerprint = "00ab12cd34ef5678"
|
||||
}
|
||||
sp := DetectAlerts(ev, at, features.SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, MinExcess: 5})
|
||||
txt := NewAlert(sp[0], at).Text("https://otel.k6n.net/")
|
||||
if !strings.Contains(txt, "https://otel.k6n.net/issues/00ab12cd34ef5678") {
|
||||
t.Fatalf("no issue link:\n%s", txt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrawlerClientErrorsNeverAlert(t *testing.T) {
|
||||
at := time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)
|
||||
ev := burst("crawl", 100, at.Add(-2*time.Minute), 403, "/members")
|
||||
for i := range ev {
|
||||
ev[i].UAClass = "ai_crawler"
|
||||
}
|
||||
if got := DetectAlerts(ev, at, features.SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, MinExcess: 5}); len(got) != 0 {
|
||||
t.Fatalf("crawler 4xx alerted: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertListsAffectedServices(t *testing.T) {
|
||||
at := time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)
|
||||
ev := burst("boom", 12, at.Add(-2*time.Minute), 500, "/api")
|
||||
for i := range ev {
|
||||
ev[i].TraceServices = []string{"payments", "api"}
|
||||
}
|
||||
sp := DetectAlerts(ev, at, features.SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, MinExcess: 5})
|
||||
a := NewAlert(sp[0], at)
|
||||
if got := strings.Join(a.Patterns[0].Services, ","); got != "api,payments" {
|
||||
t.Fatalf("services = %q", got)
|
||||
}
|
||||
if !strings.Contains(a.Text(""), "Services with errors in the same requests: api, payments") {
|
||||
t.Fatalf("text lacks services:\n%s", a.Text(""))
|
||||
}
|
||||
}
|
||||
|
||||
type fakeResolver struct{ got [2]string }
|
||||
|
||||
func (f *fakeResolver) Resolve(host, path string) []topology.Target {
|
||||
f.got = [2]string{host, path}
|
||||
return []topology.Target{
|
||||
{Host: host, Path: "/api", Namespace: "shop", Service: "orders", Deployments: []string{"orders-v2"}},
|
||||
{Host: host, Path: "/api", Namespace: "shop", Service: "gone", Missing: true},
|
||||
}
|
||||
}
|
||||
|
||||
func TestEdgeAlertShowsIngressBackends(t *testing.T) {
|
||||
at := time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)
|
||||
ev := burst("bad-gw", 16, at.Add(-2*time.Minute), 502, "/api/order")
|
||||
for i := range ev {
|
||||
ev[i].Service, ev[i].Host = "nginx", "shop.example.com"
|
||||
}
|
||||
sp := DetectAlerts(ev, at, features.SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, MinExcess: 5})
|
||||
a := NewAlert(sp[0], at)
|
||||
r := &fakeResolver{}
|
||||
a.Enrich(r)
|
||||
if r.got != [2]string{"shop.example.com", "/api/order"} {
|
||||
t.Fatalf("resolved %v", r.got)
|
||||
}
|
||||
txt := a.Text("")
|
||||
for _, want := range []string{"service shop/orders -> deployment orders-v2", "may not be instrumented", "kubectl -n shop", "this Service does not exist"} {
|
||||
if !strings.Contains(txt, want) {
|
||||
t.Fatalf("missing %q in:\n%s", want, txt)
|
||||
}
|
||||
}
|
||||
// a non-edge service is never enriched
|
||||
b := NewAlert(DetectAlerts(burst("x", 12, at.Add(-2*time.Minute), 500, "/"), at, features.SpikeConfig{Window: 5 * time.Minute, BaselineWindows: 12, MinExcess: 5})[0], at)
|
||||
b.Enrich(r)
|
||||
if len(b.Patterns[0].Routes) != 0 {
|
||||
t.Fatalf("non-edge alert enriched")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user