Skip to content

Commit 6c747f7

Browse files
Tests of update_role and delete_role routes
1 parent 2e46c19 commit 6c747f7

File tree

2 files changed

+341
-10
lines changed

2 files changed

+341
-10
lines changed

routers/role.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,6 @@ class RoleUpdate(BaseModel):
8585
organization_id: int
8686
permissions: List[ValidPermissions]
8787

88-
@field_validator("id")
89-
@classmethod
90-
def validate_role_exists(cls, id: int, info):
91-
session = info.context.get("session")
92-
if session:
93-
role = session.get(Role, id)
94-
if not role or not role.id:
95-
raise RoleNotFoundError()
96-
return id
97-
9888
@classmethod
9989
async def as_form(
10090
cls,

tests/test_role.py

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,344 @@ def test_create_role_unauthenticated(unauth_client, test_organization):
109109
)
110110

111111
assert response.status_code == 303
112+
113+
114+
@pytest.fixture
115+
def editor_user(session: Session, test_user: User, test_organization):
116+
"""
117+
Creates a user who has EDIT_ROLE permission assigned via a role in the
118+
specified organization.
119+
"""
120+
editor_role = Role(
121+
name="Editor Role",
122+
organization_id=test_organization.id
123+
)
124+
edit_permission = session.exec(
125+
select(Permission).where(Permission.name == ValidPermissions.EDIT_ROLE)
126+
).first()
127+
if not edit_permission:
128+
raise ValueError("EDIT_ROLE permission not found in the Permission table. Check seeds/setup.")
129+
130+
editor_role.permissions.append(edit_permission)
131+
session.add(editor_role)
132+
133+
# Assign the newly created 'Editor Role' to our test user
134+
test_user.roles.append(editor_role)
135+
session.commit()
136+
return test_user
137+
138+
139+
def test_update_role_success(auth_client, editor_user, test_organization, session: Session):
140+
"""
141+
Test successfully updating a role's name and permissions.
142+
Ensures a user with EDIT_ROLE permission can update the role.
143+
"""
144+
# Create a role we will update
145+
existing_role = Role(
146+
name="Old Role Name",
147+
organization_id=test_organization.id
148+
)
149+
session.add(existing_role)
150+
session.commit()
151+
session.refresh(existing_role)
152+
153+
# Add an existing permission to the role so we can test it being removed
154+
perm_create = session.exec(
155+
select(Permission).where(Permission.name == ValidPermissions.CREATE_ROLE)
156+
).first()
157+
existing_role.permissions.append(perm_create)
158+
session.commit()
159+
160+
# Verify setup
161+
assert existing_role.id is not None
162+
original_id = existing_role.id
163+
164+
# Update the role using the /roles/update endpoint
165+
response = auth_client.post(
166+
"/roles/update",
167+
data={
168+
"id": existing_role.id,
169+
"name": "New Role Name",
170+
"organization_id": test_organization.id,
171+
"permissions": [ValidPermissions.EDIT_ROLE.value] # remove CREATE_ROLE, add EDIT_ROLE
172+
},
173+
follow_redirects=False
174+
)
175+
176+
assert response.status_code == 303
177+
178+
# Check that the role was updated in the database
179+
updated_role = session.exec(
180+
select(Role).where(Role.id == original_id)
181+
).first()
182+
assert updated_role is not None
183+
assert updated_role.name == "New Role Name"
184+
perm_names = [p.name for p in updated_role.permissions]
185+
assert ValidPermissions.CREATE_ROLE not in perm_names
186+
assert ValidPermissions.EDIT_ROLE in perm_names
187+
188+
189+
def test_update_role_unauthorized(auth_client, test_user, test_organization, session: Session):
190+
"""
191+
Test that a user without EDIT_ROLE permission cannot update a role.
192+
A 403 (InsufficientPermissionsError) is expected.
193+
"""
194+
# Create a role in the same organization that we try to update
195+
some_role = Role(
196+
name="Role Without Permission",
197+
organization_id=test_organization.id
198+
)
199+
session.add(some_role)
200+
session.commit()
201+
session.refresh(some_role)
202+
203+
response = auth_client.post(
204+
"/roles/update",
205+
data={
206+
"id": some_role.id,
207+
"name": "Attempted Update",
208+
"organization_id": test_organization.id,
209+
"permissions": [ValidPermissions.EDIT_ROLE.value]
210+
},
211+
follow_redirects=True
212+
)
213+
# Because the user has no EDIT_ROLE permission, the endpoint should raise 403
214+
assert response.status_code == 403
215+
216+
217+
def test_update_role_nonexistent(auth_client, editor_user, test_organization):
218+
"""
219+
Test attempting to update a role that does not exist.
220+
A 404 (RoleNotFoundError) is expected.
221+
"""
222+
response = auth_client.post(
223+
"/roles/update",
224+
data={
225+
"id": 9999999, # A role ID that doesn't exist
226+
"name": "Nonexistent Role",
227+
"organization_id": test_organization.id,
228+
"permissions": [ValidPermissions.EDIT_ROLE.value]
229+
},
230+
follow_redirects=True
231+
)
232+
assert response.status_code == 404
233+
234+
235+
def test_update_role_duplicate_name(auth_client, editor_user, test_organization, session: Session):
236+
"""
237+
Test that updating a role to a name that already exists in the same organization
238+
fails with 400 (RoleAlreadyExistsError).
239+
"""
240+
# Create two roles in the same organization
241+
role1 = Role(name="Original Role", organization_id=test_organization.id)
242+
role2 = Role(name="Conflict Role", organization_id=test_organization.id)
243+
session.add(role1)
244+
session.add(role2)
245+
session.commit()
246+
247+
# Try to update 'role1' to have the same name as 'role2'
248+
response = auth_client.post(
249+
"/roles/update",
250+
data={
251+
"id": role1.id,
252+
"name": "Conflict Role",
253+
"organization_id": test_organization.id,
254+
"permissions": [ValidPermissions.EDIT_ROLE.value]
255+
},
256+
follow_redirects=True
257+
)
258+
259+
assert response.status_code == 400
260+
261+
262+
def test_update_role_invalid_permission(auth_client, editor_user, test_organization, session: Session):
263+
"""
264+
Test attempting to update a role with an invalid permission
265+
that is not in the ValidPermissions enum. Expects a 400 status.
266+
"""
267+
role_to_update = Role(
268+
name="Role With Bad Permission",
269+
organization_id=test_organization.id
270+
)
271+
session.add(role_to_update)
272+
session.commit()
273+
session.refresh(role_to_update)
274+
275+
# Provide an invalid permission string
276+
response = auth_client.post(
277+
"/roles/update",
278+
data={
279+
"id": role_to_update.id,
280+
"name": "Invalid Permission Test",
281+
"organization_id": test_organization.id,
282+
"permissions": ["NOT_A_VALID_PERMISSION"]
283+
},
284+
follow_redirects=True
285+
)
286+
287+
assert response.status_code == 422
288+
289+
290+
def test_update_role_unauthenticated(unauth_client, test_organization, session: Session):
291+
"""
292+
Test that an unauthenticated user (no valid tokens) will not have access
293+
to update a role. By default, the router requires login, so it should
294+
redirect.
295+
"""
296+
# Create a role
297+
some_role = Role(
298+
name="Role For Unauth Test",
299+
organization_id=test_organization.id
300+
)
301+
session.add(some_role)
302+
session.commit()
303+
session.refresh(some_role)
304+
305+
response = unauth_client.post(
306+
"/roles/update",
307+
data={
308+
"id": some_role.id,
309+
"name": "Should Not Succeed",
310+
"organization_id": test_organization.id,
311+
"permissions": [ValidPermissions.EDIT_ROLE.value]
312+
},
313+
follow_redirects=False
314+
)
315+
assert response.status_code == 303
316+
317+
318+
@pytest.fixture
319+
def delete_role_user(session: Session, test_user: User, test_organization):
320+
"""Create a user with DELETE_ROLE permission"""
321+
delete_role = Role(
322+
name="Delete Role Permission",
323+
organization_id=test_organization.id
324+
)
325+
326+
delete_permission: Permission | None = session.exec(
327+
select(Permission).where(Permission.name == ValidPermissions.DELETE_ROLE)
328+
).first()
329+
330+
if delete_permission is None:
331+
raise ValueError("Error during test setup: DELETE_ROLE permission not found")
332+
333+
delete_role.permissions.append(delete_permission)
334+
session.add(delete_role)
335+
336+
test_user.roles.append(delete_role)
337+
session.commit()
338+
339+
return test_user
340+
341+
342+
def test_delete_role_success(auth_client, delete_role_user, test_organization, session: Session):
343+
"""Test successful role deletion"""
344+
# Create a role to delete
345+
role_to_delete = Role(
346+
name="Role To Delete",
347+
organization_id=test_organization.id
348+
)
349+
session.add(role_to_delete)
350+
session.commit()
351+
session.refresh(role_to_delete)
352+
353+
response = auth_client.post(
354+
"/roles/delete",
355+
data={
356+
"id": role_to_delete.id,
357+
"organization_id": test_organization.id
358+
},
359+
follow_redirects=False
360+
)
361+
362+
assert response.status_code == 303
363+
364+
# Verify role was deleted from database
365+
deleted_role = session.exec(
366+
select(Role).where(Role.id == role_to_delete.id)
367+
).first()
368+
assert deleted_role is None
369+
370+
371+
def test_delete_role_unauthorized(auth_client, test_user, test_organization, session: Session):
372+
"""Test role deletion without proper permissions"""
373+
# Create a role to attempt to delete
374+
role = Role(
375+
name="Unauthorized Delete",
376+
organization_id=test_organization.id
377+
)
378+
session.add(role)
379+
session.commit()
380+
381+
response = auth_client.post(
382+
"/roles/delete",
383+
data={
384+
"id": role.id,
385+
"organization_id": test_organization.id
386+
},
387+
follow_redirects=False
388+
)
389+
390+
assert response.status_code == 403
391+
392+
393+
def test_delete_nonexistent_role(auth_client, delete_role_user, test_organization):
394+
"""Test attempting to delete a role that doesn't exist"""
395+
response = auth_client.post(
396+
"/roles/delete",
397+
data={
398+
"id": 99999, # Non-existent role ID
399+
"organization_id": test_organization.id
400+
},
401+
follow_redirects=False
402+
)
403+
404+
assert response.status_code == 404
405+
406+
407+
def test_delete_role_with_users(auth_client, delete_role_user, test_organization, session: Session):
408+
"""Test attempting to delete a role that has users assigned"""
409+
# Create a role and assign it to a user
410+
role_with_users = Role(
411+
name="Role With Users",
412+
organization_id=test_organization.id
413+
)
414+
session.add(role_with_users)
415+
session.commit()
416+
417+
# Assign the role to our test user
418+
delete_role_user.roles.append(role_with_users)
419+
session.commit()
420+
421+
response = auth_client.post(
422+
"/roles/delete",
423+
data={
424+
"id": role_with_users.id,
425+
"organization_id": test_organization.id
426+
},
427+
follow_redirects=False
428+
)
429+
430+
assert response.status_code == 400
431+
432+
433+
def test_delete_role_unauthenticated(unauth_client, test_organization, session: Session):
434+
"""Test role deletion without authentication"""
435+
# Create a role to attempt to delete
436+
role = Role(
437+
name="Unauthenticated Delete",
438+
organization_id=test_organization.id
439+
)
440+
session.add(role)
441+
session.commit()
442+
443+
response = unauth_client.post(
444+
"/roles/delete",
445+
data={
446+
"id": role.id,
447+
"organization_id": test_organization.id
448+
},
449+
follow_redirects=False
450+
)
451+
452+
assert response.status_code == 303 # Redirects to login page

0 commit comments

Comments
 (0)