# ABOUTME: End-to-end tests for migration CLI commands. # ABOUTME: Tests migrate and create-migration commands via subprocess. import os import subprocess import sys from pathlib import Path # Get the project root directory (parent of tests/) PROJECT_ROOT = Path(__file__).parent.parent class TestMigrateCLI: """End-to-end tests for migrate command.""" def test_migrate_command_success(self, tmp_path, temp_migrations_dir): """Should run migrations via CLI and exit 0.""" # Use a path that doesn't exist yet db_path = tmp_path / "test.db" # Create a migration file migration_file = temp_migrations_dir / "0001-test.sql" migration_file.write_text("CREATE TABLE test (id INTEGER PRIMARY KEY);") # Set required env vars with PYTHONPATH to find the package # Note: Settings uses no env_prefix, so use DB_PATH not AT_DB_PATH env = os.environ.copy() env["DB_PATH"] = str(db_path) env["CSRF_SECRET"] = "test-secret-for-csrf" env["PYTHONPATH"] = str(PROJECT_ROOT / "src") # Run migrate command result = subprocess.run( [sys.executable, "-m", "animaltrack.cli", "migrate"], capture_output=True, text=True, env=env, cwd=str(temp_migrations_dir.parent), ) assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}" assert "success" in result.stdout.lower() or "completed" in result.stdout.lower() def test_migrate_command_no_migrations(self, tmp_path, temp_migrations_dir): """Should succeed when no migrations to run.""" # Use a path that doesn't exist yet db_path = tmp_path / "test.db" # Set required env vars env = os.environ.copy() env["DB_PATH"] = str(db_path) env["CSRF_SECRET"] = "test-secret-for-csrf" env["PYTHONPATH"] = str(PROJECT_ROOT / "src") # Run migrate command with empty migrations dir result = subprocess.run( [sys.executable, "-m", "animaltrack.cli", "migrate"], capture_output=True, text=True, env=env, cwd=str(temp_migrations_dir.parent), ) assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}" def test_migrate_command_failure(self, tmp_path, temp_migrations_dir): """Should exit 1 on migration failure.""" # Use a path that doesn't exist yet db_path = tmp_path / "test.db" # Create a broken migration file migration_file = temp_migrations_dir / "0001-broken.sql" migration_file.write_text("THIS IS INVALID SQL;") # Set required env vars env = os.environ.copy() env["DB_PATH"] = str(db_path) env["CSRF_SECRET"] = "test-secret-for-csrf" env["PYTHONPATH"] = str(PROJECT_ROOT / "src") # Run migrate command result = subprocess.run( [sys.executable, "-m", "animaltrack.cli", "migrate"], capture_output=True, text=True, env=env, cwd=str(temp_migrations_dir.parent), ) assert result.returncode == 1 class TestCreateMigrationCLI: """End-to-end tests for create-migration command.""" def test_create_migration_command(self, temp_migrations_dir): """Should create migration file via CLI.""" # Set required env vars env = os.environ.copy() env["CSRF_SECRET"] = "test-secret-for-csrf" env["PYTHONPATH"] = str(PROJECT_ROOT / "src") # Run create-migration command result = subprocess.run( [sys.executable, "-m", "animaltrack.cli", "create-migration", "add users table"], capture_output=True, text=True, env=env, cwd=str(temp_migrations_dir.parent), ) assert result.returncode == 0, f"stdout: {result.stdout}, stderr: {result.stderr}" # Verify file was created created_files = list(temp_migrations_dir.glob("0001-*.sql")) assert len(created_files) == 1 assert "add-users-table" in created_files[0].name def test_create_migration_shows_path(self, temp_migrations_dir): """Should print path to created migration.""" # Set required env vars env = os.environ.copy() env["CSRF_SECRET"] = "test-secret-for-csrf" env["PYTHONPATH"] = str(PROJECT_ROOT / "src") # Run create-migration command result = subprocess.run( [sys.executable, "-m", "animaltrack.cli", "create-migration", "test migration"], capture_output=True, text=True, env=env, cwd=str(temp_migrations_dir.parent), ) assert result.returncode == 0 assert "0001-test-migration.sql" in result.stdout def test_create_migration_increments_index(self, temp_migrations_dir): """Should create migrations with incrementing indexes.""" # Set required env vars env = os.environ.copy() env["CSRF_SECRET"] = "test-secret-for-csrf" env["PYTHONPATH"] = str(PROJECT_ROOT / "src") # Create first migration subprocess.run( [sys.executable, "-m", "animaltrack.cli", "create-migration", "first"], capture_output=True, env=env, cwd=str(temp_migrations_dir.parent), ) # Create second migration result = subprocess.run( [sys.executable, "-m", "animaltrack.cli", "create-migration", "second"], capture_output=True, text=True, env=env, cwd=str(temp_migrations_dir.parent), ) assert result.returncode == 0 assert "0002-second.sql" in result.stdout def test_create_migration_requires_description(self, temp_migrations_dir): """Should fail when description not provided.""" env = os.environ.copy() env["CSRF_SECRET"] = "test-secret-for-csrf" env["PYTHONPATH"] = str(PROJECT_ROOT / "src") result = subprocess.run( [sys.executable, "-m", "animaltrack.cli", "create-migration"], capture_output=True, text=True, env=env, cwd=str(temp_migrations_dir.parent), ) # argparse should reject missing required argument assert result.returncode != 0