package errlog
import (
"fmt"
"testing"
"time"
)
// Forgetting a signature discards its count, so the same error arriving
// afterwards is a FIRST sighting — which is the point: a maintainer who
// clears a fault after fixing it wants to be told if it comes back, not
// handed the old total plus one.
func TestForgettingMakesTheNextOccurrenceAFirstSighting(t *testing.T) {
r := New(10)
var firsts []string
r.OnFirst = func(e Entry) { firsts = append(firsts, e.Message) }
for i := 0; i < 5; i++ {
r.Report("web", "/x", fmt.Errorf("disk on fire"))
}
total, distinct, _ := r.Stats()
if total != 5 || distinct != 1 {
t.Fatalf("FAIL: before forgetting, total/distinct = %d/%d, want 5/1", total, distinct)
}
sig := r.Recent(1)[0].Sig()
if !r.Forget(sig) {
t.Fatal("FAIL: Forget said there was nothing to forget")
}
if total, distinct, _ := r.Stats(); total != 0 || distinct != 0 {
t.Errorf("FAIL: after forgetting, total/distinct = %d/%d, want 0/0", total, distinct)
}
r.Report("web", "/x", fmt.Errorf("disk on fire"))
if total, _, _ := r.Stats(); total != 1 {
t.Errorf("FAIL: the returning error counted %d, want 1 — a fresh start", total)
}
if len(firsts) != 2 {
t.Errorf("FAIL: OnFirst fired %d times, want 2 — the return alerts like a first sighting", len(firsts))
}
// Forgetting something that was never there is not an error, it is
// just false: a double-click must not fail.
if r.Forget("nothing-like-this") {
t.Error("FAIL: forgetting an unknown signature claimed to have done something")
}
}
// Age retires what capacity never will. A fault fixed weeks ago sits at
// its final count competing with what is happening now.
func TestPruneDropsOnlyWhatHasStopped(t *testing.T) {
r := New(10)
r.Report("web", "/old", fmt.Errorf("last year's problem"))
r.Report("web", "/new", fmt.Errorf("today's problem"))
// Age the first entry by hand: the ring stamps Last from the clock.
old := r.Recent(10)
var oldSig string
for _, e := range old {
if e.Message == "last year's problem" {
oldSig = e.Sig()
}
}
r.mu.Lock()
r.entries[oldSig].Last = time.Now().Add(-40 * 24 * time.Hour)
r.mu.Unlock()
if n := r.Prune(time.Now().Add(-30 * 24 * time.Hour)); n != 1 {
t.Errorf("FAIL: pruned %d, want 1", n)
}
left := r.Recent(10)
if len(left) != 1 || left[0].Message != "today's problem" {
t.Errorf("FAIL: after pruning the ring holds %+v, want only today's problem", left)
}
// A cutoff before everything must take nothing: pruning is not a
// clear-all with extra steps.
if n := r.Prune(time.Now().Add(-365 * 24 * time.Hour)); n != 0 {
t.Errorf("FAIL: an old cutoff pruned %d, want 0", n)
}
}