package dedupe import ( "context" "testing" "time" "github.com/redis/go-redis/v9" "git3.techno-world.net/lrosales/broad-announce/internal/store" ) // These tests need a real Redis. They use a short window and a // test-prefix so they don't collide with prod data. // // In CI: run with `go test -tags=redis ./...` (the integration // build tag) and ensure Redis is on localhost:6379. // // In the M0 docker-compose, `make test-redis` runs the same suite // against the dev container. func newRedis(t *testing.T) *store.Redis { t.Helper() r, err := store.ConnectRedis(context.Background(), "redis://localhost:6379/0") if err != nil { t.Skipf("redis not available, skipping: %v", err) } return r } func TestCheck_FirstAndDuplicate(t *testing.T) { r := newRedis(t) d := New(r.Client, 2*time.Second) isNew, n, err := d.Check(context.Background(), "src-A", "key-1") if err != nil { t.Fatal(err) } if !isNew || n != 1 { t.Fatalf("first: want new/1, got new=%v n=%d", isNew, n) } isNew, n, err = d.Check(context.Background(), "src-A", "key-1") if err != nil { t.Fatal(err) } if isNew || n != 2 { t.Fatalf("second: want dup/2, got new=%v n=%d", isNew, n) } } func TestCheck_DifferentSourcesDoNotCollide(t *testing.T) { r := newRedis(t) d := New(r.Client, 2*time.Second) if isNew, _, _ := d.Check(context.Background(), "src-A", "shared"); !isNew { t.Fatal("src-A first should be new") } if isNew, _, _ := d.Check(context.Background(), "src-B", "shared"); !isNew { t.Fatal("src-B first should be new (different source)") } } func TestCheck_EmptyDedupeKeyIsNeverDeduped(t *testing.T) { r := newRedis(t) d := New(r.Client, 2*time.Second) for i := 0; i < 5; i++ { isNew, n, err := d.Check(context.Background(), "src-A", "") if err != nil { t.Fatal(err) } if !isNew || n != 1 { t.Fatalf("empty dedupe_key should always be new, got new=%v n=%d", isNew, n) } } } func TestCheck_WindowExpires(t *testing.T) { r := newRedis(t) d := New(r.Client, 500*time.Millisecond) if isNew, _, _ := d.Check(context.Background(), "src-A", "expiring"); !isNew { t.Fatal("first should be new") } time.Sleep(600 * time.Millisecond) isNew, n, err := d.Check(context.Background(), "src-A", "expiring") if err != nil { t.Fatal(err) } if !isNew || n != 1 { t.Fatalf("after window: want new/1, got new=%v n=%d", isNew, n) } } // Sanity: ensure the package compiles when redis isn't around. var _ = redis.Nil