334 lines
14 KiB
Python
Raw Normal View History

2025-11-08 22:05:07 +01:00
import pytest
2025-11-08 22:36:29 +01:00
from unittest.mock import call
2025-11-08 22:05:07 +01:00
@pytest.fixture
async def admin_client(client):
"""Fixture to provide an aiohttp client with mocked services."""
return client
@pytest.fixture
async def logged_in_admin_client(admin_client):
# Get the mocked user_service from the app
mock_user_service = admin_client.app["user_service"]
resp = await admin_client.post(
"/login", data={"email": "admin@example.com", "password": "password"}, allow_redirects=False
)
if resp.status != 302:
print(f"Login failed with status {resp.status}. Response text: {await resp.text()}")
assert resp.status == 302 # Expecting a redirect after successful login
# Assert that authenticate_user was called on the mock
mock_user_service.authenticate_user.assert_called_once_with("admin@example.com", "password")
# The client will not follow the redirect, so the session cookie will be set on the client
return admin_client, mock_user_service # Return both client and mock_user_service
async def test_get_users_unauthorized(admin_client):
resp = await admin_client.get("/api/users")
assert resp.status == 401
data = await resp.json()
assert data["error"] == "Unauthorized"
async def test_get_users_authorized(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.get("/api/users")
assert resp.status == 200
data = await resp.json()
assert "users" in data
assert len(data["users"]) == 2
assert data["users"][0]["email"] == "admin@example.com"
assert data["users"][1]["email"] == "child1@example.com"
mock_user_service.get_all_users.assert_called_once()
async def test_add_user_unauthorized(admin_client):
resp = await admin_client.post("/api/users", json={
"full_name": "New User",
"email": "new@example.com",
"password": "password123"
})
assert resp.status == 401
data = await resp.json()
assert data["error"] == "Unauthorized"
async def test_add_user_authorized(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.post("/api/users", json={
"full_name": "New User",
"email": "new@example.com",
"password": "password123"
})
assert resp.status == 201
data = await resp.json()
assert data["message"] == "User added successfully"
assert data["user"]["email"] == "new@example.com"
mock_user_service.create_user.assert_called_once_with(
full_name="New User",
email="new@example.com",
password="password123",
parent_email="admin@example.com"
)
async def test_add_user_invalid_data(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.post("/api/users", json={
"full_name": "Nu", # Too short
"email": "invalid-email",
"password": "123" # Too short
})
assert resp.status == 400
data = await resp.json()
assert "3 validation errors for RegistrationModel" in data["error"]
async def test_add_user_email_exists(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.create_user.side_effect = ValueError("User with this email already exists")
resp = await client.post("/api/users", json={
"full_name": "Existing User",
"email": "admin@example.com",
"password": "password123"
})
assert resp.status == 400
data = await resp.json()
assert data["error"] == "User with this email already exists"
async def test_update_user_quota_unauthorized(admin_client):
resp = await admin_client.put("/api/users/child1@example.com/quota", json={
"new_quota_gb": 200
})
assert resp.status == 401
data = await resp.json()
assert data["error"] == "Unauthorized"
async def test_update_user_quota_authorized(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.put("/api/users/child1@example.com/quota", json={
"new_quota_gb": 200
})
assert resp.status == 200
data = await resp.json()
assert data["message"] == "Quota for child1@example.com updated successfully"
mock_user_service.update_user_quota.assert_called_once_with("child1@example.com", 200)
async def test_update_user_quota_self(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.put("/api/users/admin@example.com/quota", json={
"new_quota_gb": 200
})
assert resp.status == 200
data = await resp.json()
assert data["message"] == "Quota for admin@example.com updated successfully"
mock_user_service.update_user_quota.assert_called_once_with("admin@example.com", 200)
async def test_update_user_quota_forbidden(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.side_effect = [
{ # For current_user_email check
"full_name": "Admin User",
"email": "admin@example.com",
"password": "hashed_password",
"storage_quota_gb": 100,
"storage_used_gb": 10,
"parent_email": None
},
{ # For target_user_email check, not a child and not self
"full_name": "Other User",
"email": "other@example.com",
"password": "hashed_password",
"storage_quota_gb": 50,
"storage_used_gb": 5,
"parent_email": "another@example.com"
}
]
resp = await client.put("/api/users/other@example.com/quota", json={
"new_quota_gb": 200
})
assert resp.status == 403
data = await resp.json()
assert data["error"] == "Forbidden: You do not have permission to update this user's quota"
async def test_update_user_quota_user_not_found(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.side_effect = [
{ # For current_user_email check
"full_name": "Admin User",
"email": "admin@example.com",
"password": "hashed_password",
"storage_quota_gb": 100,
"storage_used_gb": 10,
"parent_email": None
},
None # For target_user_email check
]
resp = await client.put("/api/users/nonexistent@example.com/quota", json={
"new_quota_gb": 200
})
assert resp.status == 403 # Forbidden because user not found
data = await resp.json()
assert data["error"] == "Forbidden: You do not have permission to update this user's quota"
async def test_delete_user_unauthorized(admin_client):
resp = await admin_client.delete("/api/users/child1@example.com")
assert resp.status == 401
data = await resp.json()
assert data["error"] == "Unauthorized"
async def test_delete_user_authorized(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.delete("/api/users/child1@example.com")
assert resp.status == 200
data = await resp.json()
assert data["message"] == "User child1@example.com deleted successfully"
mock_user_service.delete_user.assert_called_once_with("child1@example.com")
async def test_delete_user_self_forbidden(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.delete("/api/users/admin@example.com")
assert resp.status == 403
data = await resp.json()
assert data["error"] == "Forbidden: You cannot delete your own account from this interface"
async def test_delete_user_forbidden(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.side_effect = [
{ # For current_user_email check
"full_name": "Admin User",
"email": "admin@example.com",
"password": "hashed_password",
"storage_quota_gb": 100,
"storage_used_gb": 10,
"parent_email": None
},
{ # For target_user_email check, not a child
"full_name": "Other User",
"email": "other@example.com",
"password": "hashed_password",
"storage_quota_gb": 50,
"storage_used_gb": 5,
"parent_email": "another@example.com"
}
]
resp = await client.delete("/api/users/other@example.com")
assert resp.status == 403
data = await resp.json()
assert data["error"] == "Forbidden: You do not have permission to delete this user"
async def test_delete_user_not_found(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.side_effect = [
{ # For current_user_email check
"full_name": "Admin User",
"email": "admin@example.com",
"password": "hashed_password",
"storage_quota_gb": 100,
"storage_used_gb": 10,
"parent_email": None
},
None # For target_user_email check
]
mock_user_service.delete_user.return_value = False
resp = await client.delete("/api/users/nonexistent@example.com")
assert resp.status == 403 # Forbidden because user not found
data = await resp.json()
assert data["error"] == "Forbidden: You do not have permission to delete this user"
async def test_get_user_details_unauthorized(admin_client):
resp = await admin_client.get("/api/users/child1@example.com")
assert resp.status == 401
data = await resp.json()
assert data["error"] == "Unauthorized"
async def test_get_user_details_authorized(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.reset_mock() # Reset mock call count
resp = await client.get("/api/users/child1@example.com")
assert resp.status == 200
data = await resp.json()
assert "user" in data
assert data["user"]["email"] == "child1@example.com"
assert "password" not in data["user"] # Ensure sensitive data is not returned
mock_user_service.get_user_by_email.assert_has_calls([call("admin@example.com"), call("child1@example.com")])
async def test_get_user_details_self(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.reset_mock() # Reset mock call count
resp = await client.get("/api/users/admin@example.com")
assert resp.status == 200
data = await resp.json()
assert "user" in data
assert data["user"]["email"] == "admin@example.com"
mock_user_service.get_user_by_email.assert_has_calls([call("admin@example.com"), call("admin@example.com")])
async def test_get_user_details_forbidden(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.side_effect = [
{ # For current_user_email check
"full_name": "Admin User",
"email": "admin@example.com",
"password": "hashed_password",
"storage_quota_gb": 100,
"storage_used_gb": 10,
"parent_email": None
},
{ # For target_user_email check, not a child and not self
"full_name": "Other User",
"email": "other@example.com",
"password": "hashed_password",
"storage_quota_gb": 50,
"storage_used_gb": 5,
"parent_email": "another@example.com"
}
]
resp = await client.get("/api/users/other@example.com")
assert resp.status == 403
data = await resp.json()
assert data["error"] == "Forbidden: You do not have permission to view this user's details"
async def test_get_user_details_not_found(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.get_user_by_email.side_effect = [
{ # For current_user_email check
"full_name": "Admin User",
"email": "admin@example.com",
"password": "hashed_password",
"storage_quota_gb": 100,
"storage_used_gb": 10,
"parent_email": None
},
None # For target_user_email check
]
resp = await client.get("/api/users/nonexistent@example.com")
assert resp.status == 403 # Forbidden because user not found
data = await resp.json()
assert data["error"] == "Forbidden: You do not have permission to view this user's details"
async def test_delete_team_unauthorized(admin_client):
resp = await admin_client.delete("/api/teams/admin@example.com")
assert resp.status == 401
data = await resp.json()
assert data["error"] == "Unauthorized"
async def test_delete_team_authorized(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.delete("/api/teams/admin@example.com")
assert resp.status == 200
data = await resp.json()
assert data["message"] == "Successfully deleted 1 users from the team managed by admin@example.com"
mock_user_service.delete_users_by_parent_email.assert_called_once_with("admin@example.com")
async def test_delete_team_forbidden(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
resp = await client.delete("/api/teams/other@example.com")
assert resp.status == 403
data = await resp.json()
assert data["error"] == "Forbidden: You do not have permission to delete this team"
async def test_delete_team_no_users_found(logged_in_admin_client):
client, mock_user_service = logged_in_admin_client
mock_user_service.delete_users_by_parent_email.side_effect = lambda parent_email: 0
resp = await client.delete("/api/teams/admin@example.com")
assert resp.status == 404
data = await resp.json()
assert data["message"] == "No users found for team managed by admin@example.com or could not be deleted"