package oltp
import (
"testing"
"time"
)
// The durable half is the one that survives restarts and seeds the ring
// back up, so it is the one that grew without any bound at all.
func TestPruneDropsStoppedSignaturesAndTheirHits(t *testing.T) {
d := excDB(t)
now := time.Now()
stale := now.Add(-40 * 24 * time.Hour)
for _, e := range []Exception{
{Sig: "old", Message: "fixed weeks ago", Surface: "web", Path: "/a", Count: 9999, First: stale, Last: stale},
{Sig: "live", Message: "happening now", Surface: "web", Path: "/b", Count: 2, First: now, Last: now},
} {
if err := d.RecordException(e); err != nil {
t.Fatal(err)
}
}
n, err := d.PruneExceptions(now.Add(-30 * 24 * time.Hour))
if err != nil {
t.Fatal(err)
}
if n != 1 {
t.Errorf("FAIL: pruned %d, want 1", n)
}
got, _ := d.Exceptions(10)
if len(got) != 1 || got[0].Sig != "live" {
t.Fatalf("FAIL: after pruning the table holds %d rows, want only \"live\"", len(got))
}
// A stale signature's hits go with it: a hit whose count row is
// gone can never be read, because every reader joins through it.
var hits int
d.db.QueryRow(`SELECT count(*) FROM exception_hit WHERE sig = 'old'`).Scan(&hits)
if hits != 0 {
t.Errorf("FAIL: %d orphaned hits survived the prune", hits)
}
}
// Forgetting discards the count. That is the whole point — resolve
// keeps it and reopens, forget starts the reckoning again.
func TestForgettingDiscardsTheCountEntirely(t *testing.T) {
d := excDB(t)
now := time.Now()
e := Exception{Sig: "noisy", Message: "10k times", Surface: "ingest", Path: "/z",
Count: 1, First: now, Last: now}
for i := 0; i < 4; i++ {
if err := d.RecordException(e); err != nil {
t.Fatal(err)
}
}
got, _ := d.Exceptions(10)
if len(got) != 1 || got[0].Count < 4 {
t.Fatalf("FAIL: expected an accumulated count, got %+v", got)
}
if err := d.ForgetException("noisy"); err != nil {
t.Fatal(err)
}
if got, _ := d.Exceptions(10); len(got) != 0 {
t.Fatalf("FAIL: %d rows survived being forgotten", len(got))
}
// And it comes back counting from one, not from where it left off.
if err := d.RecordException(e); err != nil {
t.Fatal(err)
}
got, _ = d.Exceptions(10)
if len(got) != 1 || got[0].Count != 1 {
t.Errorf("FAIL: the returning signature counted %v, want 1", got)
}
// Forgetting nothing is not an error: a double-click must not fail.
if err := d.ForgetException("never-existed"); err != nil {
t.Errorf("FAIL: forgetting an unknown signature errored: %v", err)
}
if err := d.ForgetException(""); err != nil {
t.Errorf("FAIL: forgetting an empty signature errored: %v", err)
}
}