mirror of
https://github.com/fastapi-users/fastapi-users.git
synced 2025-08-14 18:58:10 +08:00
506 lines
19 KiB
Python
506 lines
19 KiB
Python
from typing import AsyncGenerator, Optional
|
|
|
|
import httpx
|
|
import pytest
|
|
from fastapi import Depends, FastAPI, status
|
|
|
|
from fastapi_users import FastAPIUsers, schemas
|
|
from tests.conftest import IDType, User, UserCreate, UserModel, UserUpdate
|
|
|
|
|
|
@pytest.fixture
|
|
@pytest.mark.asyncio
|
|
async def test_app_client(
|
|
secret,
|
|
get_user_manager,
|
|
mock_authentication,
|
|
oauth_client,
|
|
get_test_client,
|
|
) -> AsyncGenerator[httpx.AsyncClient, None]:
|
|
fastapi_users = FastAPIUsers[UserModel, IDType](
|
|
get_user_manager, [mock_authentication]
|
|
)
|
|
|
|
app = FastAPI()
|
|
app.include_router(fastapi_users.get_register_router(User, UserCreate))
|
|
app.include_router(fastapi_users.get_reset_password_router())
|
|
app.include_router(fastapi_users.get_auth_router(mock_authentication))
|
|
app.include_router(
|
|
fastapi_users.get_oauth_router(oauth_client, mock_authentication, secret)
|
|
)
|
|
app.include_router(
|
|
fastapi_users.get_oauth_associate_router(oauth_client, User, secret)
|
|
)
|
|
|
|
@app.delete("/users/me")
|
|
def custom_users_route():
|
|
return None
|
|
|
|
app.include_router(
|
|
fastapi_users.get_users_router(User, UserUpdate), prefix="/users"
|
|
)
|
|
app.include_router(fastapi_users.get_verify_router(User))
|
|
|
|
@app.get("/current-user", response_model=User)
|
|
def current_user(user: UserModel = Depends(fastapi_users.current_user())):
|
|
return user
|
|
|
|
@app.get("/current-active-user", response_model=User)
|
|
def current_active_user(
|
|
user: UserModel = Depends(fastapi_users.current_user(active=True)),
|
|
):
|
|
return user
|
|
|
|
@app.get("/current-verified-user", response_model=User)
|
|
def current_verified_user(
|
|
user: UserModel = Depends(fastapi_users.current_user(verified=True)),
|
|
):
|
|
return user
|
|
|
|
@app.get("/current-superuser", response_model=User)
|
|
def current_superuser(
|
|
user: UserModel = Depends(
|
|
fastapi_users.current_user(active=True, superuser=True)
|
|
),
|
|
):
|
|
return user
|
|
|
|
@app.get("/current-verified-superuser", response_model=User)
|
|
def current_verified_superuser(
|
|
user: UserModel = Depends(
|
|
fastapi_users.current_user(active=True, verified=True, superuser=True)
|
|
),
|
|
):
|
|
return user
|
|
|
|
@app.get("/optional-current-user")
|
|
def optional_current_user(
|
|
user: Optional[UserModel] = Depends(fastapi_users.current_user(optional=True)),
|
|
):
|
|
return schemas.model_validate(User, user) if user else None
|
|
|
|
@app.get("/optional-current-active-user")
|
|
def optional_current_active_user(
|
|
user: Optional[UserModel] = Depends(
|
|
fastapi_users.current_user(optional=True, active=True)
|
|
),
|
|
):
|
|
return schemas.model_validate(User, user) if user else None
|
|
|
|
@app.get("/optional-current-verified-user")
|
|
def optional_current_verified_user(
|
|
user: Optional[UserModel] = Depends(
|
|
fastapi_users.current_user(optional=True, verified=True)
|
|
),
|
|
):
|
|
return schemas.model_validate(User, user) if user else None
|
|
|
|
@app.get("/optional-current-superuser")
|
|
def optional_current_superuser(
|
|
user: Optional[UserModel] = Depends(
|
|
fastapi_users.current_user(optional=True, active=True, superuser=True)
|
|
),
|
|
):
|
|
return schemas.model_validate(User, user) if user else None
|
|
|
|
@app.get("/optional-current-verified-superuser")
|
|
def optional_current_verified_superuser(
|
|
user: Optional[UserModel] = Depends(
|
|
fastapi_users.current_user(
|
|
optional=True, active=True, verified=True, superuser=True
|
|
)
|
|
),
|
|
):
|
|
return schemas.model_validate(User, user) if user else None
|
|
|
|
async for client in get_test_client(app):
|
|
yield client
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize(
|
|
"path,method",
|
|
[
|
|
("/register", "POST"),
|
|
("/request-verify-token", "POST"),
|
|
("/verify", "POST"),
|
|
("/forgot-password", "POST"),
|
|
("/reset-password", "POST"),
|
|
("/login", "POST"),
|
|
("/logout", "POST"),
|
|
("/register", "POST"),
|
|
("/users/d35d213e-f3d8-4f08-954a-7e0d1bea286f", "GET"),
|
|
("/users/d35d213e-f3d8-4f08-954a-7e0d1bea286f", "PATCH"),
|
|
("/users/d35d213e-f3d8-4f08-954a-7e0d1bea286f", "DELETE"),
|
|
],
|
|
)
|
|
async def test_route_exists(test_app_client: httpx.AsyncClient, path: str, method: str):
|
|
response = await test_app_client.request(method, path)
|
|
assert response.status_code not in (
|
|
status.HTTP_404_NOT_FOUND,
|
|
status.HTTP_405_METHOD_NOT_ALLOWED,
|
|
)
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
async def test_custom_users_route_not_catched(test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.request("DELETE", "/users/me")
|
|
assert response.status_code == status.HTTP_200_OK
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestGetCurrentUser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/current-user")
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/current-user", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_valid_token(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-user", headers={"Authorization": f"Bearer {user.id}"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestGetCurrentActiveUser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/current-active-user")
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/current-active-user", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_valid_token_inactive_user(
|
|
self, test_app_client: httpx.AsyncClient, inactive_user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-active-user",
|
|
headers={"Authorization": f"Bearer {inactive_user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_valid_token(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-active-user", headers={"Authorization": f"Bearer {user.id}"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestGetCurrentVerifiedUser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/current-verified-user")
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/current-verified-user", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_valid_token_unverified_user(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-verified-user",
|
|
headers={"Authorization": f"Bearer {user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
|
|
async def test_valid_token_verified_user(
|
|
self, test_app_client: httpx.AsyncClient, verified_user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-verified-user",
|
|
headers={"Authorization": f"Bearer {verified_user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestGetCurrentSuperuser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/current-superuser")
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/current-superuser", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_valid_token_regular_user(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-superuser", headers={"Authorization": f"Bearer {user.id}"}
|
|
)
|
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
|
|
async def test_valid_token_superuser(
|
|
self, test_app_client: httpx.AsyncClient, superuser: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-superuser", headers={"Authorization": f"Bearer {superuser.id}"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestGetCurrentVerifiedSuperuser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/current-verified-superuser")
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/current-verified-superuser", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
|
|
async def test_valid_token_regular_user(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
|
|
async def test_valid_token_verified_user(
|
|
self, test_app_client: httpx.AsyncClient, verified_user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {verified_user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
|
|
async def test_valid_token_superuser(
|
|
self, test_app_client: httpx.AsyncClient, superuser: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
|
|
async def test_valid_token_verified_superuser(
|
|
self, test_app_client: httpx.AsyncClient, verified_superuser: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {verified_superuser.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestOptionalGetCurrentUser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/optional-current-user")
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/optional-current-user", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-user", headers={"Authorization": f"Bearer {user.id}"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is not None
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestOptionalGetCurrentVerifiedUser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/optional-current-verified-user")
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-user", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_unverified_user(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-user",
|
|
headers={"Authorization": f"Bearer {user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_verified_user(
|
|
self, test_app_client: httpx.AsyncClient, verified_user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-user",
|
|
headers={"Authorization": f"Bearer {verified_user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is not None
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestOptionalGetCurrentActiveUser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/optional-current-active-user")
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/optional-current-active-user", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_inactive_user(
|
|
self, test_app_client: httpx.AsyncClient, inactive_user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-active-user",
|
|
headers={"Authorization": f"Bearer {inactive_user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-active-user",
|
|
headers={"Authorization": f"Bearer {user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is not None
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestOptionalGetCurrentSuperuser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/optional-current-superuser")
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/optional-current-superuser", headers={"Authorization": "Bearer foo"}
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_regular_user(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-superuser",
|
|
headers={"Authorization": f"Bearer {user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_superuser(
|
|
self, test_app_client: httpx.AsyncClient, superuser: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-superuser",
|
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is not None
|
|
|
|
|
|
@pytest.mark.fastapi_users
|
|
@pytest.mark.asyncio
|
|
class TestOptionalGetCurrentVerifiedSuperuser:
|
|
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get("/optional-current-verified-superuser")
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_invalid_token(self, test_app_client: httpx.AsyncClient):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-superuser",
|
|
headers={"Authorization": "Bearer foo"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_regular_user(
|
|
self, test_app_client: httpx.AsyncClient, user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_verified_user(
|
|
self, test_app_client: httpx.AsyncClient, verified_user: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {verified_user.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_superuser(
|
|
self, test_app_client: httpx.AsyncClient, superuser: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is None
|
|
|
|
async def test_valid_token_verified_superuser(
|
|
self, test_app_client: httpx.AsyncClient, verified_superuser: UserModel
|
|
):
|
|
response = await test_app_client.get(
|
|
"/optional-current-verified-superuser",
|
|
headers={"Authorization": f"Bearer {verified_superuser.id}"},
|
|
)
|
|
assert response.status_code == status.HTTP_200_OK
|
|
assert response.json() is not None
|