package oltp
import (
"path/filepath"
"testing"
"time"
)
func excDB(t *testing.T) *DB {
t.Helper()
d, err := Open(filepath.Join(t.TempDir(), "t.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { d.Close() })
return d
}
// The whole point of persisting: the panel can answer for more than the
// process that is running now.
func TestExceptionSurvivesAndCounts(t *testing.T) {
d := excDB(t)
first := time.Now().Add(-time.Hour)
e := Exception{Sig: "abc12345", Message: "boom", Surface: "web", Path: "/x",
Count: 1, First: first, Last: first}
if err := d.RecordException(e); err != nil {
t.Fatal(err)
}
e.Last = time.Now()
if err := d.RecordException(e); err != nil {
t.Fatal(err)
}
got, err := d.Exceptions(10)
if err != nil {
t.Fatal(err)
}
if len(got) != 1 {
t.Fatalf("stored %d rows, want 1 — a repeat is the same signature", len(got))
}
if got[0].Count != 2 {
t.Errorf("count %d, want 2", got[0].Count)
}
// The FIRST sighting keeps its date; only the clock on "last" moves.
if !got[0].First.Truncate(time.Second).Equal(first.UTC().Truncate(time.Second)) {
t.Errorf("first moved to %v, want %v", got[0].First, first.UTC())
}
sigs, occ, err := d.ExceptionTotals()
if err != nil {
t.Fatal(err)
}
if sigs != 1 || occ != 2 {
t.Errorf("totals = %d signatures / %d occurrences, want 1/2", sigs, occ)
}
}
// An error that comes back is not resolved, whatever anybody clicked.
func TestRecurrenceReopensAResolvedException(t *testing.T) {
d := excDB(t)
now := time.Now()
e := Exception{Sig: "s", Message: "flaky", Surface: "ingest", Path: "/y",
Count: 1, First: now, Last: now}
if err := d.RecordException(e); err != nil {
t.Fatal(err)
}
if err := d.ResolveException("s"); err != nil {
t.Fatal(err)
}
got, _ := d.Exceptions(10)
if !got[0].Resolved {
t.Fatal("resolve did not take")
}
e.Last = now.Add(time.Minute)
if err := d.RecordException(e); err != nil {
t.Fatal(err)
}
got, _ = d.Exceptions(10)
if got[0].Resolved {
t.Error("a signature that recurred is still marked resolved")
}
}