package store import ( "context" "testing" "time" "github.com/alicebob/miniredis/v2" "github.com/cosmic-clash/cosmic-clash/server/domain" "github.com/redis/go-redis/v9" ) func TestRedisCandidateIndexRebuildSnapshotAndRemove(t *testing.T) { mini, err := miniredis.Run() if err != nil { t.Fatal(err) } defer mini.Close() client := redis.NewClient(&redis.Options{Addr: mini.Addr()}) defer client.Close() index := RedisCandidateIndex{Client: client, Prefix: "integration", TTL: time.Minute} now := time.Unix(1000, 0).UTC() candidates := []domain.Candidate{ {TicketID: "ticket-b", PlayerID: "player-b", EnqueuedAt: now.Add(time.Second)}, {TicketID: "ticket-a", PlayerID: "player-a", EnqueuedAt: now}, } if err := index.Rebuild(context.Background(), candidates); err != nil { t.Fatal(err) } got, err := index.Snapshot(context.Background(), now) if err != nil { t.Fatal(err) } if len(got) != 1 || got[0].TicketID != "ticket-a" { t.Fatalf("snapshot before future candidate = %+v", got) } if err := index.Remove(context.Background(), "ticket-a"); err != nil { t.Fatal(err) } got, err = index.Snapshot(context.Background(), now.Add(2*time.Second)) if err != nil { t.Fatal(err) } if len(got) != 1 || got[0].TicketID != "ticket-b" { t.Fatalf("snapshot after remove = %+v", got) } if ttl, err := client.TTL(context.Background(), "integration:queue:candidates:data").Result(); err != nil || ttl <= 0 { t.Fatalf("candidate data TTL = %v, err = %v", ttl, err) } } func TestRedisCandidateIndexRejectsInvalidAndDuplicateRebuilds(t *testing.T) { index := RedisCandidateIndex{TTL: time.Minute} if err := index.Rebuild(context.Background(), nil); err == nil { t.Fatal("nil Redis client accepted") } mini, err := miniredis.Run() if err != nil { t.Fatal(err) } defer mini.Close() client := redis.NewClient(&redis.Options{Addr: mini.Addr()}) defer client.Close() index.Client = client candidate := domain.Candidate{TicketID: "ticket-a", PlayerID: "player-a", EnqueuedAt: time.Unix(1000, 0)} if err := index.Rebuild(context.Background(), []domain.Candidate{candidate, candidate}); err == nil { t.Fatal("duplicate candidate accepted") } if err := index.Upsert(context.Background(), domain.Candidate{TicketID: "", PlayerID: "player-a", EnqueuedAt: candidate.EnqueuedAt}); err == nil { t.Fatal("invalid candidate accepted") } }