Initial commit of Descrybe v2 without local scratch artifacts.

Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
@@ -0,0 +1,261 @@
package processing
import (
"context"
"encoding/json"
"os"
"testing"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
func TestRetryJobResetsCompletedJobForFullRerun(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)
}
rows, err := pg.Query(ctx, `
SELECT id
FROM raw_products
WHERE company_id = $1
ORDER BY updated_at DESC
LIMIT 2`, companyID)
if err != nil {
t.Fatal(err)
}
defer rows.Close()
rawIDs := make([]uuid.UUID, 0, 2)
for rows.Next() {
var rawID uuid.UUID
if err := rows.Scan(&rawID); err != nil {
t.Fatal(err)
}
rawIDs = append(rawIDs, rawID)
}
if err := rows.Err(); err != nil {
t.Fatal(err)
}
if len(rawIDs) == 0 {
t.Skip("no raw_products for selected company")
}
progress := InitialStepProgress("full")
progressJSON, err := json.Marshal(progress)
if err != nil {
t.Fatal(err)
}
firstStep := ""
if len(progress) > 0 {
firstStep = progress[0].Step
}
var jobID uuid.UUID
err = pg.QueryRow(ctx, `
INSERT INTO processing_jobs (
company_id, user_id, status, total_products, processed_products,
processing_type, current_step, step_progress, started_at, completed_at
) VALUES ($1, $2, 'completed', $3, $3, 'full', $4, $5::jsonb, now(), now())
RETURNING id`,
companyID, userID, len(rawIDs), firstStep, progressJSON,
).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)
}()
for _, rawID := range rawIDs {
if _, err := pg.Exec(ctx, `
INSERT INTO processing_job_products (job_id, raw_product_id, status)
VALUES ($1, $2, 'processed')`, jobID, rawID); err != nil {
t.Fatal(err)
}
}
p := NewPipeline(pg)
p.Billing = nil
job, err := p.RetryJob(ctx, companyID, jobID)
if err != nil {
t.Fatal(err)
}
if job.Status != "pending" {
t.Fatalf("status=%q", job.Status)
}
if job.ProcessedProducts != 0 {
t.Fatalf("processed_products=%d", job.ProcessedProducts)
}
if job.StartedAt != nil {
t.Fatalf("started_at should be reset, got %v", *job.StartedAt)
}
if job.CompletedAt != nil {
t.Fatalf("completed_at should be reset, got %v", *job.CompletedAt)
}
var pendingCount, processedCount int
err = pg.QueryRow(ctx, `
SELECT
COUNT(*) FILTER (WHERE status = 'pending'),
COUNT(*) FILTER (WHERE status = 'processed')
FROM processing_job_products
WHERE job_id = $1`, jobID).Scan(&pendingCount, &processedCount)
if err != nil {
t.Fatal(err)
}
if pendingCount != len(rawIDs) {
t.Fatalf("pending_count=%d want %d", pendingCount, len(rawIDs))
}
if processedCount != 0 {
t.Fatalf("processed_count=%d want 0", processedCount)
}
}
func TestCancelJobCancelsPendingProducts(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)
}
progress := InitialStepProgress("full")
progressJSON, err := marshalStepProgress(progress)
if err != nil {
t.Fatal(err)
}
firstStep := ""
if len(progress) > 0 {
firstStep = progress[0].Step
}
var jobID uuid.UUID
err = pg.QueryRow(ctx, `
INSERT INTO processing_jobs (
company_id, user_id, status, total_products, processed_products,
processing_type, current_step, step_progress, started_at
) VALUES ($1, $2, 'running', 1, 0, 'full', $3, $4::jsonb, now())
RETURNING id`,
companyID, userID, firstStep, progressJSON,
).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)
VALUES ($1, $2, 'pending')`, jobID, rawID); err != nil {
t.Fatal(err)
}
p := NewPipeline(pg)
p.Billing = nil
job, err := p.CancelJob(ctx, companyID, jobID)
if err != nil {
t.Fatal(err)
}
if job.Status != "cancelled" {
t.Fatalf("status=%q", job.Status)
}
var productStatus string
err = pg.QueryRow(ctx, `
SELECT status FROM processing_job_products WHERE job_id = $1`, jobID).Scan(&productStatus)
if err != nil {
t.Fatal(err)
}
if productStatus != "cancelled" {
t.Fatalf("product status=%q want cancelled", productStatus)
}
}
func errorsIsNoRows(err error) bool {
return err == pgx.ErrNoRows
}