108 lines
2.2 KiB
Go
108 lines
2.2 KiB
Go
|
|
package auditlog
|
||
|
|
|
||
|
|
import (
|
||
|
|
"path/filepath"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func newTestStore(t *testing.T) *Store {
|
||
|
|
t.Helper()
|
||
|
|
s, err := New(filepath.Join(t.TempDir(), "audit.db"))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
return s
|
||
|
|
}
|
||
|
|
|
||
|
|
// eventually polls List until at least want entries are persisted (writes are
|
||
|
|
// async) or it times out.
|
||
|
|
func eventually(t *testing.T, s *Store, want int) []Entry {
|
||
|
|
t.Helper()
|
||
|
|
deadline := time.Now().Add(time.Second)
|
||
|
|
for {
|
||
|
|
got, err := s.List(100)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if len(got) >= want {
|
||
|
|
return got
|
||
|
|
}
|
||
|
|
if time.Now().After(deadline) {
|
||
|
|
t.Fatalf("timed out waiting for %d entries, have %d", want, len(got))
|
||
|
|
}
|
||
|
|
time.Sleep(5 * time.Millisecond)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRecordAndList(t *testing.T) {
|
||
|
|
s := newTestStore(t)
|
||
|
|
s.Record("alice", "POST", "/api/users", "users", 200)
|
||
|
|
s.Record("bob", "DELETE", "/api/users/x", "users", 403)
|
||
|
|
|
||
|
|
got := eventually(t, s, 2)
|
||
|
|
// Newest first.
|
||
|
|
if got[0].Username != "bob" || got[0].Status != 403 {
|
||
|
|
t.Errorf("newest entry wrong: %+v", got[0])
|
||
|
|
}
|
||
|
|
if got[1].Username != "alice" || got[1].Method != "POST" {
|
||
|
|
t.Errorf("oldest entry wrong: %+v", got[1])
|
||
|
|
}
|
||
|
|
if got[0].Time == "" {
|
||
|
|
t.Error("time not populated")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestListLimit(t *testing.T) {
|
||
|
|
s := newTestStore(t)
|
||
|
|
for range 5 {
|
||
|
|
s.Record("u", "POST", "/api/x", "system", 200)
|
||
|
|
}
|
||
|
|
eventually(t, s, 5)
|
||
|
|
got, err := s.List(3)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if len(got) != 3 {
|
||
|
|
t.Errorf("limit not honored: got %d, want 3", len(got))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestCloseDrains(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "audit.db")
|
||
|
|
s, err := New(path)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
for range 50 {
|
||
|
|
s.Record("u", "POST", "/api/x", "system", 200)
|
||
|
|
}
|
||
|
|
// Close must flush everything still buffered before returning.
|
||
|
|
if err := s.Close(); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Reopen and confirm all 50 made it to disk.
|
||
|
|
s2, err := New(path)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
got, err := s2.List(100)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if len(got) != 50 {
|
||
|
|
t.Errorf("Close did not drain: got %d entries, want 50", len(got))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestListEmpty(t *testing.T) {
|
||
|
|
got, err := newTestStore(t).List(10)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if len(got) != 0 {
|
||
|
|
t.Errorf("fresh store should be empty, got %d", len(got))
|
||
|
|
}
|
||
|
|
}
|