Skip to content

Commit 8797e85

Browse files
committed
test: cover normalized user seeding
1 parent 38df3a8 commit 8797e85

1 file changed

Lines changed: 172 additions & 0 deletions

File tree

tests/test_user_seed.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import asyncio
2+
from uuid import uuid4
3+
4+
from src.core.seed.user import SeedUserConfig, seed_user
5+
from src.modules.authorization.domain.permissions import (
6+
ADMIN_ROLE,
7+
DEFAULT_USER_ROLE,
8+
MANAGER_ROLE,
9+
VIEWER_ROLE,
10+
)
11+
from src.modules.user.domain.entities.user import User, UserProfile
12+
13+
14+
class FakeUserRepository:
15+
def __init__(self, existing_users: tuple[User, ...] = ()) -> None:
16+
self.users = {user.email: user for user in existing_users}
17+
self.saved_users: list[User] = []
18+
self.saved_profiles: list[UserProfile] = []
19+
20+
async def get_by_email(self, email: str) -> User | None:
21+
return self.users.get(email)
22+
23+
async def save(self, user: User) -> User:
24+
self.users[user.email] = user
25+
self.saved_users.append(user)
26+
return user
27+
28+
async def save_profile(self, profile: UserProfile) -> UserProfile:
29+
self.saved_profiles.append(profile)
30+
return profile
31+
32+
33+
class FakeAuthorizationService:
34+
def __init__(self) -> None:
35+
self.assignments: list[tuple[str, str]] = []
36+
37+
async def assign_role(self, subject: str, role: str) -> None:
38+
self.assignments.append((subject, role))
39+
40+
41+
def test_seed_user_creates_admin_with_normalized_profile(monkeypatch):
42+
monkeypatch.setattr(
43+
"src.core.seed.user.PasswordSerrvice.hash",
44+
lambda password: f"hashed:{password}",
45+
)
46+
repository = FakeUserRepository()
47+
authorization = FakeAuthorizationService()
48+
49+
result = asyncio.run(
50+
seed_user(
51+
user_repository=repository,
52+
authorization_service=authorization,
53+
config=SeedUserConfig(
54+
app_env="production",
55+
admin_email="admin@example.com",
56+
admin_password="secret-password",
57+
admin_username="admin",
58+
admin_fullname="System Administrator",
59+
),
60+
)
61+
)
62+
63+
assert result.users_created == 1
64+
assert result.roles_assigned == 1
65+
assert len(repository.saved_users) == 1
66+
saved_user = repository.saved_users[0]
67+
assert saved_user.email == "admin@example.com"
68+
assert saved_user.username == "admin"
69+
assert saved_user.password_hash == "hashed:secret-password"
70+
assert repository.saved_profiles == [
71+
UserProfile(user_id=saved_user.id, display_name="System Administrator")
72+
]
73+
assert authorization.assignments == [(str(saved_user.id), ADMIN_ROLE)]
74+
75+
76+
def test_seed_user_creates_development_users_and_profiles(monkeypatch):
77+
monkeypatch.setattr(
78+
"src.core.seed.user.PasswordSerrvice.hash",
79+
lambda password: f"hashed:{password}",
80+
)
81+
repository = FakeUserRepository()
82+
authorization = FakeAuthorizationService()
83+
84+
result = asyncio.run(
85+
seed_user(
86+
user_repository=repository,
87+
authorization_service=authorization,
88+
config=SeedUserConfig(
89+
app_env="development",
90+
admin_email="",
91+
admin_password="",
92+
development_users_password="demo-password",
93+
),
94+
)
95+
)
96+
97+
assert result.users_created == 3
98+
assert result.roles_assigned == 3
99+
assert [user.email for user in repository.saved_users] == [
100+
"user@example.com",
101+
"manager@example.com",
102+
"viewer@example.com",
103+
]
104+
assert [profile.display_name for profile in repository.saved_profiles] == [
105+
"Default User",
106+
"Todo Manager",
107+
"Todo Viewer",
108+
]
109+
assert [role for _, role in authorization.assignments] == [
110+
DEFAULT_USER_ROLE,
111+
MANAGER_ROLE,
112+
VIEWER_ROLE,
113+
]
114+
115+
116+
def test_seed_user_does_not_modify_an_existing_user(monkeypatch):
117+
monkeypatch.setattr(
118+
"src.core.seed.user.PasswordSerrvice.hash",
119+
lambda password: f"hashed:{password}",
120+
)
121+
existing_user = User(
122+
id=uuid4(),
123+
email="admin@example.com",
124+
password_hash="existing-hash",
125+
username="existing-admin",
126+
)
127+
repository = FakeUserRepository((existing_user,))
128+
authorization = FakeAuthorizationService()
129+
130+
result = asyncio.run(
131+
seed_user(
132+
user_repository=repository,
133+
authorization_service=authorization,
134+
config=SeedUserConfig(
135+
app_env="production",
136+
admin_email="admin@example.com",
137+
admin_password="new-password",
138+
admin_username="admin",
139+
admin_fullname="System Administrator",
140+
),
141+
)
142+
)
143+
144+
assert result.users_created == 0
145+
assert result.roles_assigned == 0
146+
assert repository.saved_users == []
147+
assert repository.saved_profiles == []
148+
assert authorization.assignments == []
149+
assert repository.users[existing_user.email] == existing_user
150+
151+
152+
def test_seed_user_skips_users_without_credentials():
153+
repository = FakeUserRepository()
154+
authorization = FakeAuthorizationService()
155+
156+
result = asyncio.run(
157+
seed_user(
158+
user_repository=repository,
159+
authorization_service=authorization,
160+
config=SeedUserConfig(
161+
app_env="production",
162+
admin_email="",
163+
admin_password="",
164+
),
165+
)
166+
)
167+
168+
assert result.users_created == 0
169+
assert result.roles_assigned == 0
170+
assert repository.saved_users == []
171+
assert repository.saved_profiles == []
172+
assert authorization.assignments == []

0 commit comments

Comments
 (0)