Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
147 lines
4.1 KiB
Go
147 lines
4.1 KiB
Go
package processing
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
func TestCleanupExpiredSyncJobsKeepsLatestHashAndDeletesAged(t *testing.T) {
|
|
dsn := 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, "retention-"+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)
|
|
})
|
|
|
|
insertFeed := func(name string) uuid.UUID {
|
|
t.Helper()
|
|
var id uuid.UUID
|
|
err := pg.QueryRow(ctx, `
|
|
INSERT INTO input_feeds (company_id, name, url, feed_type, status, sync_interval_minutes, options)
|
|
VALUES ($1, $2, '', 'csv', 'active', 60, '{}'::jsonb)
|
|
RETURNING id`, companyID, name).Scan(&id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return id
|
|
}
|
|
|
|
insertSync := func(feedID uuid.UUID, status, age, hash string) uuid.UUID {
|
|
t.Helper()
|
|
var id uuid.UUID
|
|
q := `
|
|
INSERT INTO feed_sync_jobs (
|
|
feed_id, company_id, status, started_at, completed_at,
|
|
updated_at, created_at, content_hash
|
|
) VALUES (
|
|
$1, $2, $3,
|
|
now() - interval '` + age + `',
|
|
now() - interval '` + age + `',
|
|
now() - interval '` + age + `',
|
|
now() - interval '` + age + `',
|
|
NULLIF($4, '')
|
|
) RETURNING id`
|
|
if err := pg.QueryRow(ctx, q, feedID, companyID, status, hash).Scan(&id); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return id
|
|
}
|
|
|
|
assertGone := func(id uuid.UUID, label string) {
|
|
t.Helper()
|
|
var n int
|
|
if err := pg.QueryRow(ctx, `SELECT COUNT(*) FROM feed_sync_jobs WHERE id = $1`, id).Scan(&n); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != 0 {
|
|
t.Fatalf("%s still present", label)
|
|
}
|
|
}
|
|
assertPresent := func(id uuid.UUID, label string) {
|
|
t.Helper()
|
|
var n int
|
|
if err := pg.QueryRow(ctx, `SELECT COUNT(*) FROM feed_sync_jobs WHERE id = $1`, id).Scan(&n); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != 1 {
|
|
t.Fatalf("%s missing", label)
|
|
}
|
|
}
|
|
|
|
t.Run("deletesAgedWhenFresherHashExists", func(t *testing.T) {
|
|
feedID := insertFeed("retention-fresh")
|
|
olderHash := insertSync(feedID, "completed", "60 days", "hash-old")
|
|
midHash := insertSync(feedID, "completed", "45 days", "hash-mid")
|
|
oldFailed := insertSync(feedID, "failed", "45 days", "")
|
|
freshCompleted := insertSync(feedID, "completed", "1 day", "hash-fresh")
|
|
oldRunning := insertSync(feedID, "running", "45 days", "")
|
|
|
|
res, err := CleanupExpiredSyncJobs(ctx, pg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if res.SyncJobsDeleted < 3 {
|
|
t.Fatalf("sync_jobs_deleted=%d want >= 3", res.SyncJobsDeleted)
|
|
}
|
|
|
|
assertGone(olderHash, "older completed hash")
|
|
assertGone(midHash, "mid completed hash")
|
|
assertGone(oldFailed, "old failed")
|
|
assertPresent(freshCompleted, "fresh completed")
|
|
assertPresent(oldRunning, "old running")
|
|
})
|
|
|
|
t.Run("keepsNewestAgedHashWhenNoFresher", func(t *testing.T) {
|
|
feedID := insertFeed("retention-stale")
|
|
olderHash := insertSync(feedID, "completed", "60 days", "hash-old")
|
|
keepHash := insertSync(feedID, "completed", "45 days", "hash-keep")
|
|
oldFailed := insertSync(feedID, "failed", "45 days", "")
|
|
|
|
res, err := CleanupExpiredSyncJobs(ctx, pg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if res.SyncJobsDeleted < 2 {
|
|
t.Fatalf("sync_jobs_deleted=%d want >= 2", res.SyncJobsDeleted)
|
|
}
|
|
|
|
assertGone(olderHash, "older completed hash")
|
|
assertGone(oldFailed, "old failed")
|
|
assertPresent(keepHash, "newest aged completed with hash")
|
|
|
|
var hash string
|
|
err = pg.QueryRow(ctx, `
|
|
SELECT content_hash FROM feed_sync_jobs
|
|
WHERE feed_id = $1 AND status = 'completed' AND content_hash IS NOT NULL AND content_hash <> ''
|
|
ORDER BY completed_at DESC NULLS LAST LIMIT 1`, feedID).Scan(&hash)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if hash != "hash-keep" {
|
|
t.Fatalf("lastContentHash=%q want hash-keep", hash)
|
|
}
|
|
})
|
|
}
|