- Add comprehensive CLI tests for seed and serve commands - Create README.md with development setup, deployment guide, and environment variable reference - Mark Step 10.3 as complete in PLAN.md This completes the final implementation step. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
242 lines
7.4 KiB
Python
242 lines
7.4 KiB
Python
# ABOUTME: End-to-end tests for seed CLI command.
|
|
# ABOUTME: Tests seeding reference data via subprocess.
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from animaltrack.db import get_db
|
|
from animaltrack.repositories import (
|
|
FeedTypeRepository,
|
|
LocationRepository,
|
|
ProductRepository,
|
|
SpeciesRepository,
|
|
UserRepository,
|
|
)
|
|
|
|
# Get the project root directory (parent of tests/)
|
|
PROJECT_ROOT = Path(__file__).parent.parent
|
|
|
|
|
|
class TestSeedCLI:
|
|
"""End-to-end tests for seed command."""
|
|
|
|
def test_seed_command_success(self, tmp_path):
|
|
"""Should seed data via CLI and exit 0."""
|
|
db_path = tmp_path / "test.db"
|
|
|
|
env = os.environ.copy()
|
|
env["DB_PATH"] = str(db_path)
|
|
env["CSRF_SECRET"] = "test-secret-for-csrf"
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT / "src")
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
|
|
assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}"
|
|
assert "seed data loaded" in result.stdout.lower()
|
|
|
|
def test_seed_creates_users(self, tmp_path):
|
|
"""Should create expected users."""
|
|
db_path = tmp_path / "test.db"
|
|
|
|
env = os.environ.copy()
|
|
env["DB_PATH"] = str(db_path)
|
|
env["CSRF_SECRET"] = "test-secret-for-csrf"
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT / "src")
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
|
|
assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}"
|
|
|
|
# Verify users were created
|
|
db = get_db(str(db_path))
|
|
repo = UserRepository(db)
|
|
users = repo.list_all()
|
|
|
|
usernames = {u.username for u in users}
|
|
assert "ppetru" in usernames
|
|
assert "ines" in usernames
|
|
assert "guest" in usernames
|
|
|
|
def test_seed_creates_locations(self, tmp_path):
|
|
"""Should create expected locations."""
|
|
db_path = tmp_path / "test.db"
|
|
|
|
env = os.environ.copy()
|
|
env["DB_PATH"] = str(db_path)
|
|
env["CSRF_SECRET"] = "test-secret-for-csrf"
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT / "src")
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
|
|
assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}"
|
|
|
|
# Verify locations were created
|
|
db = get_db(str(db_path))
|
|
repo = LocationRepository(db)
|
|
locations = repo.list_all()
|
|
|
|
names = {loc.name for loc in locations}
|
|
assert "Strip 1" in names
|
|
assert "Strip 4" in names
|
|
assert "Nursery 1" in names
|
|
assert "Nursery 4" in names
|
|
assert len(locations) == 8
|
|
|
|
def test_seed_creates_species(self, tmp_path):
|
|
"""Should create expected species."""
|
|
db_path = tmp_path / "test.db"
|
|
|
|
env = os.environ.copy()
|
|
env["DB_PATH"] = str(db_path)
|
|
env["CSRF_SECRET"] = "test-secret-for-csrf"
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT / "src")
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
|
|
assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}"
|
|
|
|
# Verify species were created
|
|
db = get_db(str(db_path))
|
|
repo = SpeciesRepository(db)
|
|
species_list = repo.list_all()
|
|
|
|
codes = {s.code for s in species_list}
|
|
assert "duck" in codes
|
|
assert "goose" in codes
|
|
assert "sheep" in codes
|
|
|
|
def test_seed_creates_products(self, tmp_path):
|
|
"""Should create expected products."""
|
|
db_path = tmp_path / "test.db"
|
|
|
|
env = os.environ.copy()
|
|
env["DB_PATH"] = str(db_path)
|
|
env["CSRF_SECRET"] = "test-secret-for-csrf"
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT / "src")
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
|
|
assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}"
|
|
|
|
# Verify products were created
|
|
db = get_db(str(db_path))
|
|
repo = ProductRepository(db)
|
|
products = repo.list_all()
|
|
|
|
codes = {p.code for p in products}
|
|
assert "egg.duck" in codes
|
|
assert "meat" in codes
|
|
assert "offal" in codes
|
|
assert "fat" in codes
|
|
assert "bones" in codes
|
|
assert "feathers" in codes
|
|
assert "down" in codes
|
|
|
|
def test_seed_creates_feed_types(self, tmp_path):
|
|
"""Should create expected feed types."""
|
|
db_path = tmp_path / "test.db"
|
|
|
|
env = os.environ.copy()
|
|
env["DB_PATH"] = str(db_path)
|
|
env["CSRF_SECRET"] = "test-secret-for-csrf"
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT / "src")
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
|
|
assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}"
|
|
|
|
# Verify feed types were created
|
|
db = get_db(str(db_path))
|
|
repo = FeedTypeRepository(db)
|
|
feed_types = repo.list_all()
|
|
|
|
codes = {f.code for f in feed_types}
|
|
assert "starter" in codes
|
|
assert "grower" in codes
|
|
assert "layer" in codes
|
|
|
|
def test_seed_is_idempotent(self, tmp_path):
|
|
"""Running seed twice should produce same result."""
|
|
db_path = tmp_path / "test.db"
|
|
|
|
env = os.environ.copy()
|
|
env["DB_PATH"] = str(db_path)
|
|
env["CSRF_SECRET"] = "test-secret-for-csrf"
|
|
env["PYTHONPATH"] = str(PROJECT_ROOT / "src")
|
|
|
|
# Run seed first time
|
|
result1 = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
assert result1.returncode == 0, f"stdout: {result1.stdout}, stderr: {result1.stderr}"
|
|
|
|
# Run seed second time
|
|
result2 = subprocess.run(
|
|
[sys.executable, "-m", "animaltrack.cli", "seed"],
|
|
capture_output=True,
|
|
text=True,
|
|
env=env,
|
|
cwd=str(PROJECT_ROOT),
|
|
)
|
|
assert result2.returncode == 0, f"stdout: {result2.stdout}, stderr: {result2.stderr}"
|
|
|
|
# Verify counts haven't doubled
|
|
db = get_db(str(db_path))
|
|
|
|
user_repo = UserRepository(db)
|
|
assert len(user_repo.list_all()) == 3
|
|
|
|
location_repo = LocationRepository(db)
|
|
assert len(location_repo.list_all()) == 8
|
|
|
|
species_repo = SpeciesRepository(db)
|
|
assert len(species_repo.list_all()) == 3
|
|
|
|
product_repo = ProductRepository(db)
|
|
assert len(product_repo.list_all()) == 7
|
|
|
|
feed_repo = FeedTypeRepository(db)
|
|
assert len(feed_repo.list_all()) == 3
|