package feeds import ( "context" "os" "strings" "sync" "testing" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) func TestFindOrCreatePendingSyncJobDedupesSameFeed(t *testing.T) { dsn := strings.TrimSpace(os.Getenv("DATABASE_URL")) if dsn == "" { t.Skip("DATABASE_URL not set") } ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() pg, err := pgxpool.New(ctx, dsn) if err != nil { t.Fatal(err) } defer pg.Close() companyID := uuid.New() _, err = pg.Exec(ctx, `INSERT INTO companies (id, name) VALUES ($1, $2)`, companyID, "sync-dedupe-"+companyID.String()[:8]) if err != nil { t.Fatalf("seed company: %v", err) } t.Cleanup(func() { _, _ = pg.Exec(context.Background(), `DELETE FROM companies WHERE id = $1`, companyID) }) var feedID uuid.UUID err = pg.QueryRow(ctx, ` INSERT INTO input_feeds (company_id, name, url, feed_type, status, sync_interval_minutes, options) VALUES ($1, 'dedupe-feed', 'https://example.com/feed.csv', 'csv', 'active', 60, '{}'::jsonb) RETURNING id`, companyID).Scan(&feedID) if err != nil { t.Fatalf("seed feed: %v", err) } svc := &Service{Pool: pg} first, err := svc.findOrCreatePendingSyncJob(ctx, companyID, feedID) if err != nil { t.Fatalf("first: %v", err) } second, err := svc.findOrCreatePendingSyncJob(ctx, companyID, feedID) if err != nil { t.Fatalf("second: %v", err) } if first != second { t.Fatalf("dedupe failed: first=%s second=%s", first, second) } var pendingCount int if err := pg.QueryRow(ctx, ` SELECT COUNT(*) FROM feed_sync_jobs WHERE feed_id = $1 AND company_id = $2 AND status = 'pending'`, feedID, companyID).Scan(&pendingCount); err != nil { t.Fatal(err) } if pendingCount != 1 { t.Fatalf("pending count=%d want 1", pendingCount) } const n = 8 ids := make([]uuid.UUID, n) var wg sync.WaitGroup wg.Add(n) for i := 0; i < n; i++ { go func(i int) { defer wg.Done() id, err := svc.findOrCreatePendingSyncJob(ctx, companyID, feedID) if err != nil { t.Errorf("concurrent findOrCreate: %v", err) return } ids[i] = id }(i) } wg.Wait() for _, id := range ids { if id != first { t.Fatalf("concurrent id=%s want %s", id, first) } } }