- Add hash_password/verify_password to app/auth.py using bcrypt - Fix /login to reject bootstrap creds (403) when admin users exist - Add normal password-based login path for existing admin users - Eagerly load User.roles to avoid lazy-load outside async session - Fix test_user_models.py VARCHAR assertion (SQLAlchemy 2.0 uses 'string') - Use shared-cache SQLite in conftest for endpoint-level tests - Add 23 tests covering all 3 required scenarios plus edge cases: 1. Bootstrap login with hardcoded creds when no admins → PASS (200) 2. Bootstrap login with hardcoded creds when admins exist → FAIL (403) 3. Password login for existing admin with hashed password → PASS (200) - All 130 tests pass (107 existing + 23 new)
88 lines
2.7 KiB
Python
88 lines
2.7 KiB
Python
"""Tests for app.user_models — User, Role, and UserRole relationships."""
|
|
|
|
import pytest
|
|
|
|
from app.user_models import User, Role, user_roles
|
|
|
|
|
|
class TestRoleModel:
|
|
"""Verify Role model definition."""
|
|
|
|
def test_role_table_name(self):
|
|
assert Role.__tablename__ == "roles"
|
|
|
|
def test_role_has_name_column(self):
|
|
col = Role.__table__.columns["name"]
|
|
assert col.type.__visit_name__ in ("VARCHAR", "string")
|
|
|
|
def test_role_name_is_unique(self):
|
|
col = Role.__table__.columns["name"]
|
|
assert col.unique is True
|
|
|
|
def test_role_name_not_nullable(self):
|
|
col = Role.__table__.columns["name"]
|
|
assert col.nullable is False
|
|
|
|
|
|
class TestUserModel:
|
|
"""Verify User model still works with new role fields."""
|
|
|
|
def test_user_table_name(self):
|
|
assert User.__tablename__ == "users"
|
|
|
|
def test_user_has_is_admin_column(self):
|
|
col = User.__table__.columns["is_admin"]
|
|
assert col.default.arg is False
|
|
|
|
def test_user_has_password_hash_column(self):
|
|
col = User.__table__.columns["password_hash"]
|
|
assert col.nullable is True
|
|
|
|
def test_user_roles_relationship(self):
|
|
assert hasattr(User, "roles")
|
|
|
|
|
|
class TestUserRoleAssociation:
|
|
"""Verify the user_roles association table."""
|
|
|
|
def test_user_roles_table_name(self):
|
|
assert user_roles.name == "user_roles"
|
|
|
|
def test_user_roles_has_user_id(self):
|
|
assert "user_id" in user_roles.columns
|
|
|
|
def test_user_roles_has_role_id(self):
|
|
assert "role_id" in user_roles.columns
|
|
|
|
def test_user_roles_composite_primary_key(self):
|
|
pk = [col for col in user_roles.columns if col.primary_key]
|
|
assert len(pk) == 2
|
|
|
|
|
|
class TestIsAdminEffective:
|
|
"""Test the is_admin_effective property."""
|
|
|
|
def test_legacy_is_admin_true(self):
|
|
user = User(email="a@test.com", display_name="A", is_admin=True)
|
|
assert user.is_admin_effective is True
|
|
|
|
def test_legacy_is_admin_false_no_roles(self):
|
|
user = User(email="b@test.com", display_name="B", is_admin=False)
|
|
assert user.is_admin_effective is False
|
|
|
|
def test_role_based_admin(self):
|
|
user = User(email="c@test.com", display_name="C", is_admin=False)
|
|
role = Role(name="admin")
|
|
user.roles.append(role)
|
|
assert user.is_admin_effective is True
|
|
|
|
def test_non_admin_role_does_not_grant_admin(self):
|
|
user = User(email="d@test.com", display_name="D", is_admin=False)
|
|
role = Role(name="editor")
|
|
user.roles.append(role)
|
|
assert user.is_admin_effective is False
|
|
|
|
def test_legacy_is_admin_true_overrides_empty_roles(self):
|
|
user = User(email="e@test.com", display_name="E", is_admin=True)
|
|
assert user.is_admin_effective is True
|