Skip to content
quarry Artifact [4f603692e7]
Login

Artifact [4f603692e7]

Artifact 4f603692e707b8abc46a4bd299f7643eeb5f1cbb6832d123dab016dea54d9731:


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)
	}
}