package memory import ( "context" "testing" "time" "keel/internal/aw" ) func TestFakeRecordThenRecentNewestFirstByKind(t *testing.T) { f := NewFake() ctx := context.Background() _ = f.Record(ctx, Event{Kind: "proposal_made", At: time.Unix(1, 0), Data: map[string]any{"n": "a"}}) _ = f.Record(ctx, Event{Kind: "action_taken", At: time.Unix(2, 0)}) _ = f.Record(ctx, Event{Kind: "proposal_made", At: time.Unix(3, 0), Data: map[string]any{"n": "b"}}) got, err := f.Recent(ctx, "proposal_made", 5) if err != nil { t.Fatalf("Recent: %v", err) } if len(got) != 2 || got[0].Data["n"] != "b" { t.Fatalf("want newest-first [b,a], got %+v", got) } } func TestFakeRecentRespectsLimit(t *testing.T) { f := NewFake() ctx := context.Background() for i := 0; i < 4; i++ { _ = f.Record(ctx, Event{Kind: "proposal_made", At: time.Unix(int64(i), 0)}) } got, _ := f.Recent(ctx, "proposal_made", 2) if len(got) != 2 { t.Fatalf("limit not honored: %d", len(got)) } } func TestNopStoreIsInert(t *testing.T) { s := NewNop() if err := s.Record(context.Background(), Event{Kind: "x"}); err != nil { t.Fatalf("nop Record: %v", err) } got, err := s.Recent(context.Background(), "x", 5) if err != nil || len(got) != 0 { t.Fatalf("nop Recent = %+v, %v", got, err) } } // fakeAWClient is the AWClient subset, recording inserts and replaying a fixed // recent list so we can test mapping and over-fetch filtering without HTTP. type fakeAWClient struct { inserted []aw.Event recent []aw.Event // newest-first, mixed kinds lastLimit int } func (f *fakeAWClient) Insert(_ context.Context, _ string, e aw.Event) error { f.inserted = append(f.inserted, e) return nil } func (f *fakeAWClient) Recent(_ context.Context, _ string, limit int) ([]aw.Event, error) { f.lastLimit = limit return f.recent, nil } func TestAWStoreRecordMapsKindIntoData(t *testing.T) { fc := &fakeAWClient{} s := NewAWStore(fc, "keel.events") at := time.Unix(1000, 0).UTC() if err := s.Record(context.Background(), Event{Kind: "proposal_made", At: at, Data: map[string]any{"proposal_id": "x"}}); err != nil { t.Fatalf("Record: %v", err) } if len(fc.inserted) != 1 { t.Fatalf("inserted %d", len(fc.inserted)) } got := fc.inserted[0] if !got.Timestamp.Equal(at) || got.Data["_kind"] != "proposal_made" || got.Data["proposal_id"] != "x" { t.Fatalf("mapped event = %+v", got) } } func TestAWStoreRecentOverfetchesAndFiltersByKind(t *testing.T) { fc := &fakeAWClient{recent: []aw.Event{ {Timestamp: time.Unix(3, 0), Data: map[string]any{"_kind": "proposal_made", "n": "b"}}, {Timestamp: time.Unix(2, 0), Data: map[string]any{"_kind": "action_taken"}}, {Timestamp: time.Unix(1, 0), Data: map[string]any{"_kind": "proposal_made", "n": "a"}}, }} s := NewAWStore(fc, "keel.events") got, err := s.Recent(context.Background(), "proposal_made", 5) if err != nil { t.Fatalf("Recent: %v", err) } if fc.lastLimit != overfetch { t.Fatalf("over-fetch limit = %d, want %d", fc.lastLimit, overfetch) } if len(got) != 2 || got[0].Kind != "proposal_made" || got[0].Data["n"] != "b" { t.Fatalf("filtered = %+v", got) } if _, leaked := got[0].Data["_kind"]; leaked { t.Fatalf("_kind leaked into returned Data: %+v", got[0].Data) } } func TestAWStoreRecentCapsAtN(t *testing.T) { var recent []aw.Event for i := 0; i < 5; i++ { recent = append(recent, aw.Event{Timestamp: time.Unix(int64(i), 0), Data: map[string]any{"_kind": "proposal_made"}}) } s := NewAWStore(&fakeAWClient{recent: recent}, "keel.events") got, _ := s.Recent(context.Background(), "proposal_made", 2) if len(got) != 2 { t.Fatalf("cap not applied: %d", len(got)) } }