Files
descrybe/apps/api/internal/processing/retention_cleanup_integration_test.go
T

148 lines
3.7 KiB
Go
Raw Normal View History

package processing
import (
"context"
"os"
"testing"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
func TestCleanupExpiredDeletesTerminalJobsAndCascadesProducts(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)
}
insertJob := func(status string, age string) uuid.UUID {
t.Helper()
var id uuid.UUID
err := pg.QueryRow(ctx, `
INSERT INTO processing_jobs (
company_id, user_id, status, total_products, processed_products,
processing_type, started_at, completed_at, updated_at, created_at
) VALUES (
$1, $2, $3, 1, 1, 'full',
now() - interval '`+age+`',
now() - interval '`+age+`',
now() - interval '`+age+`',
now() - interval '`+age+`'
)
RETURNING id`, companyID, userID, status).Scan(&id)
if err != nil {
t.Fatal(err)
}
return id
}
oldCompleted := insertJob("completed", "45 days")
oldFailed := insertJob("failed", "45 days")
oldRunning := insertJob("running", "45 days")
freshCompleted := insertJob("completed", "1 day")
defer func() {
for _, id := range []uuid.UUID{oldCompleted, oldFailed, oldRunning, freshCompleted} {
_, _ = pg.Exec(context.Background(), `DELETE FROM processing_job_products WHERE job_id = $1`, id)
_, _ = pg.Exec(context.Background(), `DELETE FROM processing_jobs WHERE id = $1`, id)
}
}()
if _, err := pg.Exec(ctx, `
INSERT INTO processing_job_products (job_id, raw_product_id, status, updated_at, created_at)
VALUES ($1, $2, 'processed', now() - interval '45 days', now() - interval '45 days')`,
oldCompleted, rawID); err != nil {
t.Fatal(err)
}
res, err := CleanupExpired(ctx, pg)
if err != nil {
t.Fatal(err)
}
if res.JobsDeleted < 2 {
t.Fatalf("jobs_deleted=%d want >= 2", res.JobsDeleted)
}
assertGone := func(id uuid.UUID, label string) {
t.Helper()
var n int
if err := pg.QueryRow(ctx, `SELECT COUNT(*) FROM processing_jobs WHERE id = $1`, id).Scan(&n); err != nil {
t.Fatal(err)
}
if n != 0 {
t.Fatalf("%s job still present", label)
}
}
assertPresent := func(id uuid.UUID, label string) {
t.Helper()
var n int
if err := pg.QueryRow(ctx, `SELECT COUNT(*) FROM processing_jobs WHERE id = $1`, id).Scan(&n); err != nil {
t.Fatal(err)
}
if n != 1 {
t.Fatalf("%s job missing", label)
}
}
assertGone(oldCompleted, "old completed")
assertGone(oldFailed, "old failed")
assertPresent(oldRunning, "old running")
assertPresent(freshCompleted, "fresh completed")
var productCount int
if err := pg.QueryRow(ctx, `
SELECT COUNT(*) FROM processing_job_products WHERE job_id = $1`, oldCompleted).Scan(&productCount); err != nil {
t.Fatal(err)
}
if productCount != 0 {
t.Fatalf("cascaded products remaining=%d want 0", productCount)
}
}