import pytest from asyncpg.pool import Pool from fastapi import FastAPI from httpx import AsyncClient from starlette import status from app.db.repositories.users import UsersRepository from app.models.domain.users import UserInDB from app.models.schemas.users import UserInResponse pytestmark = pytest.mark.asyncio @pytest.fixture(params=("", "value", "Token value", "JWT value", "Bearer value")) def wrong_authorization_header(request) -> str: return request.param @pytest.mark.parametrize( "api_method, route_name", (("GET", "users:get-current-user"), ("PUT", "users:update-current-user")), ) async def test_user_can_not_access_own_profile_if_not_logged_in( app: FastAPI, client: AsyncClient, test_user: UserInDB, api_method: str, route_name: str, ) -> None: response = await client.request(api_method, app.url_path_for(route_name)) assert response.status_code == status.HTTP_403_FORBIDDEN @pytest.mark.parametrize( "api_method, route_name", (("GET", "users:get-current-user"), ("PUT", "users:update-current-user")), ) async def test_user_can_not_retrieve_own_profile_if_wrong_token( app: FastAPI, client: AsyncClient, test_user: UserInDB, api_method: str, route_name: str, wrong_authorization_header: str, ) -> None: response = await client.request( api_method, app.url_path_for(route_name), headers={"Authorization": wrong_authorization_header}, ) assert response.status_code == status.HTTP_403_FORBIDDEN async def test_user_can_retrieve_own_profile( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, token: str ) -> None: response = await authorized_client.get(app.url_path_for("users:get-current-user")) assert response.status_code == status.HTTP_200_OK user_profile = UserInResponse(**response.json()) assert user_profile.user.email == test_user.email @pytest.mark.parametrize( "update_field, update_value", ( ("username", "new_username"), ("email", "new_email@email.com"), ("bio", "new bio"), ("image", "http://testhost.com/imageurl"), ), ) async def test_user_can_update_own_profile( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, token: str, update_value: str, update_field: str, ) -> None: response = await authorized_client.put( app.url_path_for("users:update-current-user"), json={"user": {update_field: update_value}}, ) assert response.status_code == status.HTTP_200_OK user_profile = UserInResponse(**response.json()).dict() assert user_profile["user"][update_field] == update_value async def test_user_can_change_password( app: FastAPI, authorized_client: AsyncClient, test_user: UserInDB, token: str, pool: Pool, ) -> None: response = await authorized_client.put( app.url_path_for("users:update-current-user"), json={"user": {"password": "new_password"}}, ) assert response.status_code == status.HTTP_200_OK user_profile = UserInResponse(**response.json()) async with pool.acquire() as connection: users_repo = UsersRepository(connection) user = await users_repo.get_user_by_username( username=user_profile.user.username ) assert user.check_password("new_password") @pytest.mark.parametrize( "credentials_part, credentials_value", (("username", "taken_username"), ("email", "taken@email.com")), ) async def test_user_can_not_take_already_used_credentials( app: FastAPI, authorized_client: AsyncClient, pool: Pool, token: str, credentials_part: str, credentials_value: str, ) -> None: user_dict = { "username": "not_taken_username", "password": "password", "email": "free_email@email.com", } user_dict.update({credentials_part: credentials_value}) async with pool.acquire() as conn: users_repo = UsersRepository(conn) await users_repo.create_user(**user_dict) response = await authorized_client.put( app.url_path_for("users:update-current-user"), json={"user": {credentials_part: credentials_value}}, ) assert response.status_code == status.HTTP_400_BAD_REQUEST