Skip to content
quarry Artifact [dede1dc544]
Login

Artifact [dede1dc544]

Artifact dede1dc544a58743a3485b56fa17ad45d43bb16541c13bebc13f48c9c97bd181:


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