Skip to content
quarry Artifact [f611393808]
Login

Artifact [f611393808]

Artifact f6113938084313a691bbd2aa58010562da7385022146cb4274a7e0d917da4e14:


package errlog

import (
	"errors"
	"testing"
)

// The ring's whole value is what it does under repetition: one
// signature is one row with a count (a hot loop must not flood), the
// first sighting fires the alert hook exactly once, and eviction
// removes what STOPPED happening, never what is still happening.
func TestDedupFirstSightingAndEviction(t *testing.T) {
	r := New(2)
	var fired []string
	r.OnFirst = func(e Entry) { fired = append(fired, e.Message) }

	boom := errors.New("boom")
	for i := 0; i < 5; i++ {
		r.Report("web", "/x", boom)
	}
	if got := r.Recent(0); len(got) != 1 || got[0].Count != 5 {
		t.Fatalf("recent = %+v, want one row counted 5", got)
	}
	if len(fired) != 1 {
		t.Fatalf("OnFirst fired %d times, want once", len(fired))
	}

	r.Report("api", "/y", errors.New("crash"))
	r.Report("web", "/x", boom) // boom is STILL happening
	r.Report("panic", "/z", errors.New("bang")) // full: evict the stalest
	got := r.Recent(0)
	if len(got) != 2 {
		t.Fatalf("ring exceeded its cap: %+v", got)
	}
	for _, e := range got {
		if e.Message == "crash" {
			t.Fatalf("evicted the still-happening error instead of the stopped one: %+v", got)
		}
	}
	if got[0].Message != "bang" {
		t.Fatalf("recent not newest-first: %+v", got)
	}
	total, distinct, lastAt := r.Stats()
	if total != 7 || distinct != 2 || lastAt.IsZero() {
		t.Fatalf("stats = %d %d %v", total, distinct, lastAt)
	}
	r.Report("web", "/x", nil) // a nil error is not an error
	if tot, _, _ := r.Stats(); tot != 7 {
		t.Fatal("nil error was counted")
	}
}