dedupe_test.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package dedupe
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/redis/go-redis/v9"
  7. "git3.techno-world.net/lrosales/broad-announce/internal/store"
  8. )
  9. // These tests need a real Redis. They use a short window and a
  10. // test-prefix so they don't collide with prod data.
  11. //
  12. // In CI: run with `go test -tags=redis ./...` (the integration
  13. // build tag) and ensure Redis is on localhost:6379.
  14. //
  15. // In the M0 docker-compose, `make test-redis` runs the same suite
  16. // against the dev container.
  17. func newRedis(t *testing.T) *store.Redis {
  18. t.Helper()
  19. r, err := store.ConnectRedis(context.Background(), "redis://localhost:6379/0")
  20. if err != nil {
  21. t.Skipf("redis not available, skipping: %v", err)
  22. }
  23. return r
  24. }
  25. func TestCheck_FirstAndDuplicate(t *testing.T) {
  26. r := newRedis(t)
  27. d := New(r.Client, 2*time.Second)
  28. isNew, n, err := d.Check(context.Background(), "src-A", "key-1")
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. if !isNew || n != 1 {
  33. t.Fatalf("first: want new/1, got new=%v n=%d", isNew, n)
  34. }
  35. isNew, n, err = d.Check(context.Background(), "src-A", "key-1")
  36. if err != nil {
  37. t.Fatal(err)
  38. }
  39. if isNew || n != 2 {
  40. t.Fatalf("second: want dup/2, got new=%v n=%d", isNew, n)
  41. }
  42. }
  43. func TestCheck_DifferentSourcesDoNotCollide(t *testing.T) {
  44. r := newRedis(t)
  45. d := New(r.Client, 2*time.Second)
  46. if isNew, _, _ := d.Check(context.Background(), "src-A", "shared"); !isNew {
  47. t.Fatal("src-A first should be new")
  48. }
  49. if isNew, _, _ := d.Check(context.Background(), "src-B", "shared"); !isNew {
  50. t.Fatal("src-B first should be new (different source)")
  51. }
  52. }
  53. func TestCheck_EmptyDedupeKeyIsNeverDeduped(t *testing.T) {
  54. r := newRedis(t)
  55. d := New(r.Client, 2*time.Second)
  56. for i := 0; i < 5; i++ {
  57. isNew, n, err := d.Check(context.Background(), "src-A", "")
  58. if err != nil {
  59. t.Fatal(err)
  60. }
  61. if !isNew || n != 1 {
  62. t.Fatalf("empty dedupe_key should always be new, got new=%v n=%d", isNew, n)
  63. }
  64. }
  65. }
  66. func TestCheck_WindowExpires(t *testing.T) {
  67. r := newRedis(t)
  68. d := New(r.Client, 500*time.Millisecond)
  69. if isNew, _, _ := d.Check(context.Background(), "src-A", "expiring"); !isNew {
  70. t.Fatal("first should be new")
  71. }
  72. time.Sleep(600 * time.Millisecond)
  73. isNew, n, err := d.Check(context.Background(), "src-A", "expiring")
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. if !isNew || n != 1 {
  78. t.Fatalf("after window: want new/1, got new=%v n=%d", isNew, n)
  79. }
  80. }
  81. // Sanity: ensure the package compiles when redis isn't around.
  82. var _ = redis.Nil