fix
This commit is contained in:
@@ -200,6 +200,138 @@ func TestCleanupStuckResetsJobsAndProducts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReclaimOrphanedRunningRequeuesImmediately(t *testing.T) {
|
||||
dsn := os.Getenv("DATABASE_URL")
|
||||
if dsn == "" {
|
||||
t.Skip("DATABASE_URL not set")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
pg, err := pgxpool.New(ctx, dsn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer pg.Close()
|
||||
|
||||
var companyID uuid.UUID
|
||||
err = pg.QueryRow(ctx, `
|
||||
SELECT company_id
|
||||
FROM raw_products
|
||||
WHERE company_id IS NOT NULL
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1`).Scan(&companyID)
|
||||
if errorsIsNoRows(err) {
|
||||
t.Skip("no raw_products rows available")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var userID uuid.UUID
|
||||
err = pg.QueryRow(ctx, `SELECT id FROM users ORDER BY created_at DESC LIMIT 1`).Scan(&userID)
|
||||
if errorsIsNoRows(err) {
|
||||
t.Skip("no users rows available")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var rawID uuid.UUID
|
||||
err = pg.QueryRow(ctx, `
|
||||
SELECT id
|
||||
FROM raw_products
|
||||
WHERE company_id = $1
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1`, companyID).Scan(&rawID)
|
||||
if errorsIsNoRows(err) {
|
||||
t.Skip("no raw_products for selected company")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var jobID uuid.UUID
|
||||
err = pg.QueryRow(ctx, `
|
||||
INSERT INTO processing_jobs (
|
||||
company_id, user_id, status, total_products, processed_products,
|
||||
processing_type, started_at, updated_at
|
||||
) VALUES ($1, $2, 'running', 1, 0, 'full', now(), now())
|
||||
RETURNING id`,
|
||||
companyID, userID,
|
||||
).Scan(&jobID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_, _ = pg.Exec(context.Background(), `DELETE FROM processing_job_products WHERE job_id = $1`, jobID)
|
||||
_, _ = pg.Exec(context.Background(), `DELETE FROM processing_jobs WHERE id = $1`, jobID)
|
||||
}()
|
||||
|
||||
if _, err := pg.Exec(ctx, `
|
||||
INSERT INTO processing_job_products (job_id, raw_product_id, status, updated_at)
|
||||
VALUES ($1, $2, 'processing', now())`, jobID, rawID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var syncFeedID uuid.UUID
|
||||
err = pg.QueryRow(ctx, `
|
||||
INSERT INTO input_feeds (company_id, name, url, feed_type, status, sync_interval_minutes, options)
|
||||
VALUES ($1, 'orphan-reclaim-feed', 'https://example.com/orphan.csv', 'csv', 'active', 60, '{}'::jsonb)
|
||||
RETURNING id`, companyID).Scan(&syncFeedID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
_, _ = pg.Exec(context.Background(), `DELETE FROM feed_sync_jobs WHERE feed_id = $1`, syncFeedID)
|
||||
_, _ = pg.Exec(context.Background(), `DELETE FROM input_feeds WHERE id = $1`, syncFeedID)
|
||||
}()
|
||||
|
||||
var syncID uuid.UUID
|
||||
err = pg.QueryRow(ctx, `
|
||||
INSERT INTO feed_sync_jobs (feed_id, company_id, status, started_at, updated_at)
|
||||
VALUES ($1, $2, 'running', now(), now())
|
||||
RETURNING id`, syncFeedID, companyID).Scan(&syncID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
res, err := ReclaimOrphanedRunning(ctx, pg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.JobsRequeued < 1 {
|
||||
t.Fatalf("jobs_requeued=%d want >= 1", res.JobsRequeued)
|
||||
}
|
||||
if res.ProductsReset < 1 {
|
||||
t.Fatalf("products_reset=%d want >= 1", res.ProductsReset)
|
||||
}
|
||||
if res.SyncJobsRequeued < 1 {
|
||||
t.Fatalf("sync_requeued=%d want >= 1", res.SyncJobsRequeued)
|
||||
}
|
||||
|
||||
var jobStatus, productStatus, syncStatus string
|
||||
if err := pg.QueryRow(ctx, `SELECT status FROM processing_jobs WHERE id = $1`, jobID).Scan(&jobStatus); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if jobStatus != "pending" {
|
||||
t.Fatalf("job status=%q want pending", jobStatus)
|
||||
}
|
||||
if err := pg.QueryRow(ctx, `SELECT status FROM processing_job_products WHERE job_id = $1`, jobID).Scan(&productStatus); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if productStatus != "pending" {
|
||||
t.Fatalf("product status=%q want pending", productStatus)
|
||||
}
|
||||
if err := pg.QueryRow(ctx, `SELECT status FROM feed_sync_jobs WHERE id = $1`, syncID).Scan(&syncStatus); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if syncStatus != "pending" {
|
||||
t.Fatalf("sync status=%q want pending", syncStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadPendingItemsReclaimsAgedProcessing(t *testing.T) {
|
||||
dsn := os.Getenv("DATABASE_URL")
|
||||
if dsn == "" {
|
||||
|
||||
Reference in New Issue
Block a user