Files
Gardomatic/internal/storage/postgres/application_settings_integration_test.go
T
kleiax 904d14b64c
CI / test (push) Canceled after 0s
Initial commit
2026-09-12 22:22:17 +02:00

107 lines
5.5 KiB
Go

package postgres
import (
"database/sql"
"os"
"testing"
"time"
_ "github.com/lib/pq"
)
func TestRemoveExpiredPlantsClosesRelatedRecordsAndWritesHistory(t *testing.T) {
dsn := os.Getenv("GARDOMATIC_TEST_DB_DSN")
if dsn == "" {
t.Skip("set GARDOMATIC_TEST_DB_DSN to run PostgreSQL integration tests")
}
db, err := sql.Open("postgres", dsn)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = db.Close() })
if err = db.Ping(); err != nil {
t.Fatal(err)
}
stamp := time.Now().Format("150405.000000000")
var userID, gardenID, categoryID, biennialCategoryID, speciesID, biennialSpeciesID, plantID, biennialPlantID, locationID, templateID, taskID, manualTaskID int
if err = db.QueryRow(`INSERT INTO users (name, email, password_hash, activated) VALUES ('Lifecycle integration', $1, 'hash', true) RETURNING id`, "lifecycle-"+stamp+"@example.com").Scan(&userID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO gardens (name) VALUES ('Lifecycle integration') RETURNING id`).Scan(&gardenID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO species_categories (name, lifecycle) VALUES ($1, 'annual') RETURNING id`, "Annual "+stamp).Scan(&categoryID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO species_categories (name, lifecycle) VALUES ($1, 'biennial') RETURNING id`, "Biennial "+stamp).Scan(&biennialCategoryID); err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
_, _ = db.Exec(`DELETE FROM gardens WHERE id = $1`, gardenID)
_, _ = db.Exec(`DELETE FROM species_categories WHERE id IN ($1, $2)`, categoryID, biennialCategoryID)
_, _ = db.Exec(`DELETE FROM users WHERE id = $1`, userID)
})
if err = db.QueryRow(`INSERT INTO species (garden_id, common_name, category_id) VALUES ($1, 'Sommerblume', $2) RETURNING id`, gardenID, categoryID).Scan(&speciesID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO species (garden_id, common_name, category_id) VALUES ($1, 'Zweijährige Blume', $2) RETURNING id`, gardenID, biennialCategoryID).Scan(&biennialSpeciesID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO species_task_templates (species_id, title, trigger_type, month_from, day_from) VALUES ($1, 'Pflegen', 'month_of_year', 3, 10) RETURNING id`, speciesID).Scan(&templateID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO plants (garden_id, species_id, name, acquired_at) VALUES ($1, $2, 'Sommerblume', '2026-03-10') RETURNING id`, gardenID, speciesID).Scan(&plantID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO plants (garden_id, species_id, name, acquired_at) VALUES ($1, $2, 'Zweijährige Blume', '2026-03-10') RETURNING id`, gardenID, biennialSpeciesID).Scan(&biennialPlantID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO locations (garden_id, name) VALUES ($1, 'Beet') RETURNING id`, gardenID).Scan(&locationID); err != nil {
t.Fatal(err)
}
if _, err = db.Exec(`INSERT INTO plant_locations (plant_id, location_id, planted_at) VALUES ($1, $2, '2026-03-10')`, plantID, locationID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO tasks (garden_id, plant_id, template_id, title, created_by) VALUES ($1, $2, $3, 'Pflegen', $4) RETURNING id`, gardenID, plantID, templateID, userID).Scan(&taskID); err != nil {
t.Fatal(err)
}
if err = db.QueryRow(`INSERT INTO tasks (garden_id, plant_id, title, created_by) VALUES ($1, $2, 'Dokumentieren', $3) RETURNING id`, gardenID, plantID, userID).Scan(&manualTaskID); err != nil {
t.Fatal(err)
}
count, err := (ApplicationSettingsModel{DB: db}).RemoveExpiredPlants(time.Date(2026, 12, 1, 0, 0, 0, 0, time.UTC), 12, 1)
if err != nil || count != 1 {
t.Fatalf("remove expired plants: count=%d err=%v", count, err)
}
var status string
var removedAt time.Time
if err = db.QueryRow(`SELECT status, removed_at FROM plants WHERE id = $1`, plantID).Scan(&status, &removedAt); err != nil || status != "removed" || removedAt.Format("2006-01-02") != "2026-12-01" {
t.Fatalf("plant status=%q removed_at=%v err=%v", status, removedAt, err)
}
var assignmentClosed, taskActive bool
if err = db.QueryRow(`SELECT removed_at IS NOT NULL FROM plant_locations WHERE plant_id = $1`, plantID).Scan(&assignmentClosed); err != nil || !assignmentClosed {
t.Fatalf("assignment closed=%v err=%v", assignmentClosed, err)
}
if err = db.QueryRow(`SELECT active FROM tasks WHERE id = $1`, taskID).Scan(&taskActive); err != nil || taskActive {
t.Fatalf("task active=%v err=%v", taskActive, err)
}
if err = db.QueryRow(`SELECT active FROM tasks WHERE id = $1`, manualTaskID).Scan(&taskActive); err != nil || !taskActive {
t.Fatalf("manual task active=%v err=%v", taskActive, err)
}
var historyCount int
if err = db.QueryRow(`SELECT count(*) FROM plant_status_history WHERE plant_id = $1 AND reason = 'lifecycle_reached'`, plantID).Scan(&historyCount); err != nil || historyCount != 1 {
t.Fatalf("history count=%d err=%v", historyCount, err)
}
if err = db.QueryRow(`SELECT status FROM plants WHERE id = $1`, biennialPlantID).Scan(&status); err != nil || status != "alive" {
t.Fatalf("biennial plant was removed too early: status=%q err=%v", status, err)
}
count, err = (ApplicationSettingsModel{DB: db}).RemoveExpiredPlants(time.Date(2027, 12, 1, 0, 0, 0, 0, time.UTC), 12, 1)
if err != nil || count != 1 {
t.Fatalf("remove biennial plant: count=%d err=%v", count, err)
}
if err = db.QueryRow(`SELECT status FROM plants WHERE id = $1`, biennialPlantID).Scan(&status); err != nil || status != "removed" {
t.Fatalf("biennial plant status=%q err=%v", status, err)
}
}