From 23ab2c54b0052ecb53394a48b8d2f437ea571ad0 Mon Sep 17 00:00:00 2001 From: Ivan Skvortsov Date: Tue, 19 May 2026 13:03:22 +0200 Subject: [PATCH 1/7] feat(backend): improve dev experience with auto-seeding and long-lived sessions --- backend/app/core/startup.py | 49 +++++++++++++++++++++++++++++++ backend/app/factory.py | 10 ++----- backend/app/modules/auth/token.py | 12 ++++++-- 3 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 backend/app/core/startup.py diff --git a/backend/app/core/startup.py b/backend/app/core/startup.py new file mode 100644 index 0000000..a21f988 --- /dev/null +++ b/backend/app/core/startup.py @@ -0,0 +1,49 @@ +import logging + +from fastapi import HTTPException +from sqlalchemy.orm import Session + +from app.modules.admin.seed.service import seed_all +from app.modules.auth.schemas import UserCreate +from app.modules.auth.service import create_user_if_not_exists +from app.settings import Settings + +logger = logging.getLogger(__name__) + +TEST_USERS = [ + {"email": "user@example.com", "password": "12345678"}, +] + + +def setup_test_users(db: Session): + """Create initial test users if they don't exist.""" + for user_data in TEST_USERS: + logger.info(f"Ensuring test user exists: {user_data['email']}") + create_user_if_not_exists( + db, UserCreate(email=user_data["email"], password=user_data["password"]) + ) + + +def auto_seed_data(db: Session): + """Seed the database with initial data if it's empty.""" + try: + seed_all(db, n_tags=7, n_fields=12, n_events=30) + logger.info("Auto-seeding completed successfully.") + except HTTPException as e: + if e.status_code == 405: + logger.info("Database already contains data. Skipping auto-seeding.") + else: + logger.error(f"Auto-seeding failed with unexpected error: {e.detail}") + except Exception as e: + logger.error(f"Auto-seeding failed: {e}") + + +def run_startup_tasks(db: Session, settings: Settings): + """Run all necessary startup tasks for development environment.""" + if settings.is_dev: + setup_test_users(db) + auto_seed_data(db) + elif settings.is_demo: + create_user_if_not_exists( + db, UserCreate(email="demo@evsy.dev", password="bestructured") + ) diff --git a/backend/app/factory.py b/backend/app/factory.py index 58173ba..c97472a 100644 --- a/backend/app/factory.py +++ b/backend/app/factory.py @@ -10,8 +10,7 @@ from app.api.v1.routes import admin, auth, events, fields, generic, tags from app.core.handlers import http_exception_handler, validation_exception_handler -from app.modules.auth.schemas import UserCreate -from app.modules.auth.service import create_user_if_not_exists +from app.core.startup import run_startup_tasks from app.settings import Settings logger = logging.getLogger(__name__) @@ -24,11 +23,8 @@ def create_app( @asynccontextmanager async def lifespan(app: FastAPI): logger.info(f"Starting application in {settings.env} mode") - if settings.is_demo: - with SessionLocal() as db: - create_user_if_not_exists( - db, UserCreate(email="demo@evsy.dev", password="bestructured") - ) + with SessionLocal() as db: + run_startup_tasks(db, settings) yield logger.info("Shutting down application") engine.dispose() diff --git a/backend/app/modules/auth/token.py b/backend/app/modules/auth/token.py index 3377e64..2dc349d 100644 --- a/backend/app/modules/auth/token.py +++ b/backend/app/modules/auth/token.py @@ -17,9 +17,15 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: settings = get_settings() to_encode = data.copy() - expire = datetime.now(UTC) + ( - expires_delta or timedelta(minutes=settings.access_token_expire_minutes) - ) + if expires_delta: + expire = datetime.now(UTC) + expires_delta + elif settings.is_dev: + # 100 years for dev mode + expire = datetime.now(UTC) + timedelta(days=365 * 100) + else: + expire = datetime.now(UTC) + timedelta( + minutes=settings.access_token_expire_minutes + ) to_encode.update({"exp": expire}) return jwt.encode(to_encode, settings.secret_key, algorithm=settings.jwt_algorithm) From d26a7da49d63682f3768276e3c857fc784ac75ca Mon Sep 17 00:00:00 2001 From: Ivan Skvortsov Date: Tue, 19 May 2026 13:21:04 +0200 Subject: [PATCH 2/7] test(backend): add unit tests for startup tasks and dev session expiry --- backend/tests/test_startup.py | 82 +++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 backend/tests/test_startup.py diff --git a/backend/tests/test_startup.py b/backend/tests/test_startup.py new file mode 100644 index 0000000..ab15fe9 --- /dev/null +++ b/backend/tests/test_startup.py @@ -0,0 +1,82 @@ +import pytest +from unittest.mock import MagicMock, patch +from datetime import UTC, datetime, timedelta +from jose import jwt +from app.modules.auth.token import create_access_token +from app.core.startup import run_startup_tasks, setup_test_users, auto_seed_data +from app.modules.auth.models import User +from fastapi import HTTPException + +def test_create_access_token_dev_long_expiry(): + """Test that tokens in dev mode have a very long expiry.""" + mock_settings = MagicMock() + mock_settings.is_dev = True + mock_settings.secret_key = "test_secret" + mock_settings.jwt_algorithm = "HS256" + + with patch("app.modules.auth.token.get_settings", return_value=mock_settings): + token = create_access_token({"sub": "user@example.com"}) + payload = jwt.decode(token, "test_secret", algorithms=["HS256"]) + + exp = payload["exp"] + expected_min_exp = (datetime.now(UTC) + timedelta(days=365 * 99)).timestamp() + assert exp > expected_min_exp + +def test_create_access_token_prod_normal_expiry(): + """Test that tokens in prod mode have normal expiry.""" + mock_settings = MagicMock() + mock_settings.is_dev = False + mock_settings.access_token_expire_minutes = 60 + mock_settings.secret_key = "test_secret" + mock_settings.jwt_algorithm = "HS256" + + with patch("app.modules.auth.token.get_settings", return_value=mock_settings): + token = create_access_token({"sub": "user@example.com"}) + payload = jwt.decode(token, "test_secret", algorithms=["HS256"]) + + exp = payload["exp"] + # Should be roughly 60 minutes from now + expected_exp = (datetime.now(UTC) + timedelta(minutes=60)).timestamp() + assert abs(exp - expected_exp) < 10 # Allow 10s difference + +def test_setup_test_users(db): + """Test that test users are created if they don't exist.""" + # Ensure user doesn't exist in the current transaction + user = db.query(User).filter(User.email == "user@example.com").first() + if user: + db.delete(user) + db.flush() + + setup_test_users(db) + + user = db.query(User).filter(User.email == "user@example.com").first() + assert user is not None + assert user.email == "user@example.com" + +@patch("app.core.startup.seed_all") +def test_auto_seed_data_empty_db(mock_seed_all, db): + """Test that seeding is called when DB is empty.""" + mock_seed_all.return_value = None + auto_seed_data(db) + mock_seed_all.assert_called_once() + +@patch("app.core.startup.seed_all") +def test_auto_seed_data_already_seeded(mock_seed_all, db): + """Test that seeding is skipped if DB already has data (simulated by HTTPException 405).""" + mock_seed_all.side_effect = HTTPException(status_code=405, detail="Action is only allowed on empty database") + + # This should not raise an exception, just log and return + auto_seed_data(db) + mock_seed_all.assert_called_once() + +def test_run_startup_tasks_dev_calls_subtasks(db): + """Test that all dev startup tasks are triggered in dev mode.""" + mock_settings = MagicMock() + mock_settings.is_dev = True + mock_settings.is_demo = False + + with patch("app.core.startup.setup_test_users") as mock_setup_users, \ + patch("app.core.startup.auto_seed_data") as mock_auto_seed: + run_startup_tasks(db, mock_settings) + mock_setup_users.assert_called_once_with(db) + mock_auto_seed.assert_called_once_with(db) From 23fe913ee92290898281941c0f3fbf3995785c3b Mon Sep 17 00:00:00 2001 From: Ivan Skvortsov Date: Tue, 19 May 2026 13:31:44 +0200 Subject: [PATCH 3/7] refactor(backend): use logging.exception for better error tracking --- backend/app/core/startup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/app/core/startup.py b/backend/app/core/startup.py index a21f988..9423abf 100644 --- a/backend/app/core/startup.py +++ b/backend/app/core/startup.py @@ -33,9 +33,9 @@ def auto_seed_data(db: Session): if e.status_code == 405: logger.info("Database already contains data. Skipping auto-seeding.") else: - logger.error(f"Auto-seeding failed with unexpected error: {e.detail}") - except Exception as e: - logger.error(f"Auto-seeding failed: {e}") + logger.exception(f"Auto-seeding failed with unexpected error: {e.detail}") + except Exception: + logger.exception("Auto-seeding failed") def run_startup_tasks(db: Session, settings: Settings): From 87d45bf98b68e575d4eeec4afbe82d6d0cf59b73 Mon Sep 17 00:00:00 2001 From: Ivan Skvortsov Date: Tue, 19 May 2026 13:40:48 +0200 Subject: [PATCH 4/7] feat(backend): make dev and demo user credentials configurable --- backend/app/core/startup.py | 24 ++++++++++++------------ backend/app/settings.py | 6 ++++++ backend/tests/test_startup.py | 12 ++++++------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/backend/app/core/startup.py b/backend/app/core/startup.py index 9423abf..92b7019 100644 --- a/backend/app/core/startup.py +++ b/backend/app/core/startup.py @@ -10,18 +10,15 @@ logger = logging.getLogger(__name__) -TEST_USERS = [ - {"email": "user@example.com", "password": "12345678"}, -] - -def setup_test_users(db: Session): +def setup_test_users(db: Session, settings: Settings): """Create initial test users if they don't exist.""" - for user_data in TEST_USERS: - logger.info(f"Ensuring test user exists: {user_data['email']}") - create_user_if_not_exists( - db, UserCreate(email=user_data["email"], password=user_data["password"]) - ) + # Ensure test user exists + logger.info(f"Ensuring test user exists: {settings.dev_user_email}") + create_user_if_not_exists( + db, + UserCreate(email=settings.dev_user_email, password=settings.dev_user_password), + ) def auto_seed_data(db: Session): @@ -41,9 +38,12 @@ def auto_seed_data(db: Session): def run_startup_tasks(db: Session, settings: Settings): """Run all necessary startup tasks for development environment.""" if settings.is_dev: - setup_test_users(db) + setup_test_users(db, settings) auto_seed_data(db) elif settings.is_demo: create_user_if_not_exists( - db, UserCreate(email="demo@evsy.dev", password="bestructured") + db, + UserCreate( + email=settings.demo_user_email, password=settings.demo_user_password + ), ) diff --git a/backend/app/settings.py b/backend/app/settings.py index 5cd5244..cf8f284 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -57,6 +57,12 @@ def __init__(self, _env_file: Optional[str] = None, **kwargs: Any): default=None, alias="GOOGLE_CLIENT_SECRET" ) + dev_user_email: str = Field(default="user@example.com", alias="DEV_USER_EMAIL") + dev_user_password: str = Field(default="12345678", alias="DEV_USER_PASSWORD") + + demo_user_email: str = Field(default="demo@evsy.dev", alias="DEMO_USER_EMAIL") + demo_user_password: str = Field(default="bestructured", alias="DEMO_USER_PASSWORD") + model_config = SettingsConfigDict( env_file_encoding="utf-8", case_sensitive=False, diff --git a/backend/tests/test_startup.py b/backend/tests/test_startup.py index ab15fe9..1bc53b4 100644 --- a/backend/tests/test_startup.py +++ b/backend/tests/test_startup.py @@ -39,19 +39,19 @@ def test_create_access_token_prod_normal_expiry(): expected_exp = (datetime.now(UTC) + timedelta(minutes=60)).timestamp() assert abs(exp - expected_exp) < 10 # Allow 10s difference -def test_setup_test_users(db): +def test_setup_test_users(db, test_settings): """Test that test users are created if they don't exist.""" # Ensure user doesn't exist in the current transaction - user = db.query(User).filter(User.email == "user@example.com").first() + user = db.query(User).filter(User.email == test_settings.dev_user_email).first() if user: db.delete(user) db.flush() - setup_test_users(db) + setup_test_users(db, test_settings) - user = db.query(User).filter(User.email == "user@example.com").first() + user = db.query(User).filter(User.email == test_settings.dev_user_email).first() assert user is not None - assert user.email == "user@example.com" + assert user.email == test_settings.dev_user_email @patch("app.core.startup.seed_all") def test_auto_seed_data_empty_db(mock_seed_all, db): @@ -78,5 +78,5 @@ def test_run_startup_tasks_dev_calls_subtasks(db): with patch("app.core.startup.setup_test_users") as mock_setup_users, \ patch("app.core.startup.auto_seed_data") as mock_auto_seed: run_startup_tasks(db, mock_settings) - mock_setup_users.assert_called_once_with(db) + mock_setup_users.assert_called_once_with(db, mock_settings) mock_auto_seed.assert_called_once_with(db) From 827aa8e17859bd4cd289c8190fa946f1e9fafc88 Mon Sep 17 00:00:00 2001 From: Ivan Skvortsov Date: Tue, 19 May 2026 13:52:51 +0200 Subject: [PATCH 5/7] refactor(backend): use extendable dev_users list in settings --- backend/app/core/startup.py | 15 ++++++--------- backend/app/settings.py | 6 ++++-- backend/tests/test_startup.py | 12 +++++++----- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/backend/app/core/startup.py b/backend/app/core/startup.py index 92b7019..b805ca5 100644 --- a/backend/app/core/startup.py +++ b/backend/app/core/startup.py @@ -11,14 +11,11 @@ logger = logging.getLogger(__name__) -def setup_test_users(db: Session, settings: Settings): - """Create initial test users if they don't exist.""" - # Ensure test user exists - logger.info(f"Ensuring test user exists: {settings.dev_user_email}") - create_user_if_not_exists( - db, - UserCreate(email=settings.dev_user_email, password=settings.dev_user_password), - ) +def setup_test_users(db: Session, users: list[dict[str, str]]): + """Create initial test users if they don't exist. Easily extendable.""" + for user_info in users: + logger.info(f"Ensuring test user exists: {user_info['email']}") + create_user_if_not_exists(db, UserCreate(**user_info)) def auto_seed_data(db: Session): @@ -38,7 +35,7 @@ def auto_seed_data(db: Session): def run_startup_tasks(db: Session, settings: Settings): """Run all necessary startup tasks for development environment.""" if settings.is_dev: - setup_test_users(db, settings) + setup_test_users(db, settings.dev_users) auto_seed_data(db) elif settings.is_demo: create_user_if_not_exists( diff --git a/backend/app/settings.py b/backend/app/settings.py index cf8f284..7df738f 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -57,8 +57,10 @@ def __init__(self, _env_file: Optional[str] = None, **kwargs: Any): default=None, alias="GOOGLE_CLIENT_SECRET" ) - dev_user_email: str = Field(default="user@example.com", alias="DEV_USER_EMAIL") - dev_user_password: str = Field(default="12345678", alias="DEV_USER_PASSWORD") + dev_users: list[dict[str, str]] = Field( + default=[{"email": "user@example.com", "password": "12345678"}], + alias="DEV_USERS", + ) demo_user_email: str = Field(default="demo@evsy.dev", alias="DEMO_USER_EMAIL") demo_user_password: str = Field(default="bestructured", alias="DEMO_USER_PASSWORD") diff --git a/backend/tests/test_startup.py b/backend/tests/test_startup.py index 1bc53b4..b446fdd 100644 --- a/backend/tests/test_startup.py +++ b/backend/tests/test_startup.py @@ -42,16 +42,17 @@ def test_create_access_token_prod_normal_expiry(): def test_setup_test_users(db, test_settings): """Test that test users are created if they don't exist.""" # Ensure user doesn't exist in the current transaction - user = db.query(User).filter(User.email == test_settings.dev_user_email).first() + primary_dev_user = test_settings.dev_users[0] + user = db.query(User).filter(User.email == primary_dev_user["email"]).first() if user: db.delete(user) db.flush() - setup_test_users(db, test_settings) + setup_test_users(db, test_settings.dev_users) - user = db.query(User).filter(User.email == test_settings.dev_user_email).first() + user = db.query(User).filter(User.email == primary_dev_user["email"]).first() assert user is not None - assert user.email == test_settings.dev_user_email + assert user.email == primary_dev_user["email"] @patch("app.core.startup.seed_all") def test_auto_seed_data_empty_db(mock_seed_all, db): @@ -74,9 +75,10 @@ def test_run_startup_tasks_dev_calls_subtasks(db): mock_settings = MagicMock() mock_settings.is_dev = True mock_settings.is_demo = False + mock_settings.dev_users = [{"email": "user@example.com", "password": "password"}] with patch("app.core.startup.setup_test_users") as mock_setup_users, \ patch("app.core.startup.auto_seed_data") as mock_auto_seed: run_startup_tasks(db, mock_settings) - mock_setup_users.assert_called_once_with(db, mock_settings) + mock_setup_users.assert_called_once_with(db, mock_settings.dev_users) mock_auto_seed.assert_called_once_with(db) From 264326bf5bc4f3266d1fa3749f6a32723e946625 Mon Sep 17 00:00:00 2001 From: Ivan Skvortsov Date: Tue, 19 May 2026 14:02:19 +0200 Subject: [PATCH 6/7] fix(backend): fix missing Any import and refine startup tasks --- backend/app/core/startup.py | 14 ++++++++++---- backend/app/settings.py | 5 +++-- backend/tests/test_startup.py | 7 ++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/backend/app/core/startup.py b/backend/app/core/startup.py index b805ca5..2b2e756 100644 --- a/backend/app/core/startup.py +++ b/backend/app/core/startup.py @@ -1,4 +1,5 @@ import logging +from typing import Any from fastapi import HTTPException from sqlalchemy.orm import Session @@ -11,11 +12,16 @@ logger = logging.getLogger(__name__) -def setup_test_users(db: Session, users: list[dict[str, str]]): +def setup_test_users(db: Session, users: list[dict[str, Any]], default_password: str): """Create initial test users if they don't exist. Easily extendable.""" for user_info in users: - logger.info(f"Ensuring test user exists: {user_info['email']}") - create_user_if_not_exists(db, UserCreate(**user_info)) + # Use default password if not provided in user_info + data = user_info.copy() + if "password" not in data: + data["password"] = default_password + + logger.info(f"Ensuring test user exists: {data['email']}") + create_user_if_not_exists(db, UserCreate(**data)) def auto_seed_data(db: Session): @@ -35,7 +41,7 @@ def auto_seed_data(db: Session): def run_startup_tasks(db: Session, settings: Settings): """Run all necessary startup tasks for development environment.""" if settings.is_dev: - setup_test_users(db, settings.dev_users) + setup_test_users(db, settings.dev_users, settings.dev_users_password) auto_seed_data(db) elif settings.is_demo: create_user_if_not_exists( diff --git a/backend/app/settings.py b/backend/app/settings.py index 7df738f..1179b7c 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -57,10 +57,11 @@ def __init__(self, _env_file: Optional[str] = None, **kwargs: Any): default=None, alias="GOOGLE_CLIENT_SECRET" ) - dev_users: list[dict[str, str]] = Field( - default=[{"email": "user@example.com", "password": "12345678"}], + dev_users: list[dict[str, Any]] = Field( + default=[{"email": "user@example.com"}], alias="DEV_USERS", ) + dev_users_password: str = Field(default="12345678", alias="DEV_USERS_PASSWORD") demo_user_email: str = Field(default="demo@evsy.dev", alias="DEMO_USER_EMAIL") demo_user_password: str = Field(default="bestructured", alias="DEMO_USER_PASSWORD") diff --git a/backend/tests/test_startup.py b/backend/tests/test_startup.py index b446fdd..d5de3db 100644 --- a/backend/tests/test_startup.py +++ b/backend/tests/test_startup.py @@ -48,7 +48,7 @@ def test_setup_test_users(db, test_settings): db.delete(user) db.flush() - setup_test_users(db, test_settings.dev_users) + setup_test_users(db, test_settings.dev_users, test_settings.dev_users_password) user = db.query(User).filter(User.email == primary_dev_user["email"]).first() assert user is not None @@ -75,10 +75,11 @@ def test_run_startup_tasks_dev_calls_subtasks(db): mock_settings = MagicMock() mock_settings.is_dev = True mock_settings.is_demo = False - mock_settings.dev_users = [{"email": "user@example.com", "password": "password"}] + mock_settings.dev_users = [{"email": "user@example.com"}] + mock_settings.dev_users_password = "password" with patch("app.core.startup.setup_test_users") as mock_setup_users, \ patch("app.core.startup.auto_seed_data") as mock_auto_seed: run_startup_tasks(db, mock_settings) - mock_setup_users.assert_called_once_with(db, mock_settings.dev_users) + mock_setup_users.assert_called_once_with(db, mock_settings.dev_users, mock_settings.dev_users_password) mock_auto_seed.assert_called_once_with(db) From 6a9e50407d68b7b0c7f6af1f6e4f7ed705419e63 Mon Sep 17 00:00:00 2001 From: Ivan Skvortsov Date: Tue, 19 May 2026 14:03:15 +0200 Subject: [PATCH 7/7] format --- backend/tests/test_startup.py | 49 ++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/backend/tests/test_startup.py b/backend/tests/test_startup.py index d5de3db..e84fa1e 100644 --- a/backend/tests/test_startup.py +++ b/backend/tests/test_startup.py @@ -1,11 +1,13 @@ -import pytest -from unittest.mock import MagicMock, patch from datetime import UTC, datetime, timedelta +from unittest.mock import MagicMock, patch + +from fastapi import HTTPException from jose import jwt -from app.modules.auth.token import create_access_token -from app.core.startup import run_startup_tasks, setup_test_users, auto_seed_data + +from app.core.startup import auto_seed_data, run_startup_tasks, setup_test_users from app.modules.auth.models import User -from fastapi import HTTPException +from app.modules.auth.token import create_access_token + def test_create_access_token_dev_long_expiry(): """Test that tokens in dev mode have a very long expiry.""" @@ -13,15 +15,16 @@ def test_create_access_token_dev_long_expiry(): mock_settings.is_dev = True mock_settings.secret_key = "test_secret" mock_settings.jwt_algorithm = "HS256" - + with patch("app.modules.auth.token.get_settings", return_value=mock_settings): token = create_access_token({"sub": "user@example.com"}) payload = jwt.decode(token, "test_secret", algorithms=["HS256"]) - + exp = payload["exp"] expected_min_exp = (datetime.now(UTC) + timedelta(days=365 * 99)).timestamp() assert exp > expected_min_exp + def test_create_access_token_prod_normal_expiry(): """Test that tokens in prod mode have normal expiry.""" mock_settings = MagicMock() @@ -29,15 +32,16 @@ def test_create_access_token_prod_normal_expiry(): mock_settings.access_token_expire_minutes = 60 mock_settings.secret_key = "test_secret" mock_settings.jwt_algorithm = "HS256" - + with patch("app.modules.auth.token.get_settings", return_value=mock_settings): token = create_access_token({"sub": "user@example.com"}) payload = jwt.decode(token, "test_secret", algorithms=["HS256"]) - + exp = payload["exp"] # Should be roughly 60 minutes from now expected_exp = (datetime.now(UTC) + timedelta(minutes=60)).timestamp() - assert abs(exp - expected_exp) < 10 # Allow 10s difference + assert abs(exp - expected_exp) < 10 # Allow 10s difference + def test_setup_test_users(db, test_settings): """Test that test users are created if they don't exist.""" @@ -47,13 +51,14 @@ def test_setup_test_users(db, test_settings): if user: db.delete(user) db.flush() - + setup_test_users(db, test_settings.dev_users, test_settings.dev_users_password) - + user = db.query(User).filter(User.email == primary_dev_user["email"]).first() assert user is not None assert user.email == primary_dev_user["email"] + @patch("app.core.startup.seed_all") def test_auto_seed_data_empty_db(mock_seed_all, db): """Test that seeding is called when DB is empty.""" @@ -61,15 +66,19 @@ def test_auto_seed_data_empty_db(mock_seed_all, db): auto_seed_data(db) mock_seed_all.assert_called_once() + @patch("app.core.startup.seed_all") def test_auto_seed_data_already_seeded(mock_seed_all, db): """Test that seeding is skipped if DB already has data (simulated by HTTPException 405).""" - mock_seed_all.side_effect = HTTPException(status_code=405, detail="Action is only allowed on empty database") - + mock_seed_all.side_effect = HTTPException( + status_code=405, detail="Action is only allowed on empty database" + ) + # This should not raise an exception, just log and return auto_seed_data(db) mock_seed_all.assert_called_once() + def test_run_startup_tasks_dev_calls_subtasks(db): """Test that all dev startup tasks are triggered in dev mode.""" mock_settings = MagicMock() @@ -77,9 +86,13 @@ def test_run_startup_tasks_dev_calls_subtasks(db): mock_settings.is_demo = False mock_settings.dev_users = [{"email": "user@example.com"}] mock_settings.dev_users_password = "password" - - with patch("app.core.startup.setup_test_users") as mock_setup_users, \ - patch("app.core.startup.auto_seed_data") as mock_auto_seed: + + with ( + patch("app.core.startup.setup_test_users") as mock_setup_users, + patch("app.core.startup.auto_seed_data") as mock_auto_seed, + ): run_startup_tasks(db, mock_settings) - mock_setup_users.assert_called_once_with(db, mock_settings.dev_users, mock_settings.dev_users_password) + mock_setup_users.assert_called_once_with( + db, mock_settings.dev_users, mock_settings.dev_users_password + ) mock_auto_seed.assert_called_once_with(db)