From 0761b4547dc88cbbca19a8c8f9ddc70a301c9140 Mon Sep 17 00:00:00 2001 From: Rudolf Braun <48672663+BraunRudolf@users.noreply.github.com> Date: Tue, 8 Oct 2024 08:12:26 +0200 Subject: [PATCH 1/4] Add test + fixtures get_current_active_user --- backend-app/tests/unit/conftest.py | 86 ++++++++++++++++++++++++++++- backend-app/tests/unit/test_auth.py | 31 ++++++++++- 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/backend-app/tests/unit/conftest.py b/backend-app/tests/unit/conftest.py index edacacb0..a7a6d327 100644 --- a/backend-app/tests/unit/conftest.py +++ b/backend-app/tests/unit/conftest.py @@ -13,7 +13,7 @@ from app.models import user as api_m from app.models.database import User as db_user from app.models.file_db import create_file_table_class, update_schema -from app.models.user import UserCreate, UserInDB +from app.models.user import User, UserCreate, UserInDB from app.sql_db.crud import create_user, get_db, update_is_active, update_is_admin from app.sql_db.database import Base from app.sql_db.file_crud import create_update_table, insert_data @@ -197,6 +197,90 @@ def mock_user(): return user +@pytest.fixture +def mock_user_is_active(): + """Fixture for mocking a user.""" + user = User( + id=1, + email="user1@example.com", + password="test1", + hashed_password="test1fake_hash", + is_active=True, + ) + return user + + +@pytest.fixture +def mock_user_is_not_active(): + """Fixture for mocking a user.""" + user = User( + id=1, + email="user1@example.com", + password="test1", + hashed_password="test1fake_hash", + is_active=False, + ) + return user + + +@pytest.fixture +def mock_user_is_active_is_admin(): + """Fixture for mocking a user.""" + user = User( + id=1, + email="user1@example.com", + password="test1", + hashed_password="test1fake_hash", + is_active=True, + is_admin=True, + ) + return user + + +@pytest.fixture +def mock_user_is_not_active_is_admin(): + """Fixture for mocking a user.""" + user = User( + id=1, + email="user1@example.com", + password="test1", + hashed_password="test1fake_hash", + is_active=False, + is_admin=True, + ) + return user + + +@pytest.fixture +def mock_user_is_not_active_is_not_admin(): + """Fixture for mocking a user.""" + user = User( + id=1, + email="user1@example.com", + password="test1", + hashed_password="test1fake_hash", + is_active=False, + is_admin=False, + ) + return user + + +@pytest.fixture +def mock_get_current_user_active(mock_user_is_active): + """Fixture for mocking get_current_user to return the mock user.""" + mock_function = MagicMock() + mock_function.return_value = mock_user_is_active + return mock_function + + +@pytest.fixture +def mock_get_current_user_not_active(mock_user_is_not_active): + """Fixture for mocking get_current_user to return the mock user.""" + mock_function = MagicMock() + mock_function.return_value = mock_user_is_not_active + return mock_function + + @pytest.fixture def mock_get_user_by_email_success(mock_user): """Fixture for mocking get_user_by_email to return the mock user.""" diff --git a/backend-app/tests/unit/test_auth.py b/backend-app/tests/unit/test_auth.py index d3411cff..f80dc044 100644 --- a/backend-app/tests/unit/test_auth.py +++ b/backend-app/tests/unit/test_auth.py @@ -4,7 +4,12 @@ from fastapi.exceptions import HTTPException from jose import JWTError, jwt -from app.api.auth import authenticate_user, create_access_token, get_current_user +from app.api.auth import ( + authenticate_user, + create_access_token, + get_current_active_user, + get_current_user, +) def test_authenticate_user_success(mock_db, mock_get_user_by_email_success, mock_user, monkeypatch): @@ -195,3 +200,27 @@ async def test_get_current_user_user_not_found( assert exc_info.value.detail == "Could not validate credentials" mock_jwt_decode.assert_called_once_with(valid_token, TEST_SECRET_KEY, algorithms=["HS256"]) mock_get_user_by_email_none.assert_called_once_with(mock_db, email=valid_token_payload["sub"]) + + +@pytest.mark.asyncio +async def test_get_current_active_user_success( + mock_user_is_active, mock_get_current_user_active, monkeypatch +): + monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_active) + + user = await get_current_active_user(mock_user_is_active) + + assert user.id == mock_user_is_active.id + + +@pytest.mark.asyncio +async def test_get_current_active_user_not_active( + mock_user_is_not_active, mock_get_current_user_not_active, monkeypatch +): + monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_not_active) + + with pytest.raises(HTTPException) as exc_info: + await get_current_active_user(mock_user_is_not_active) + + assert exc_info.value.status_code == 400 + assert exc_info.value.detail == "Inactive user" From 90a31028f384c1c5a2436fbedfe7ed0870d80d68 Mon Sep 17 00:00:00 2001 From: Rudolf Braun <48672663+BraunRudolf@users.noreply.github.com> Date: Wed, 9 Oct 2024 08:18:31 +0200 Subject: [PATCH 2/4] Add/Edit Tests + Fixtures Add/Edit Fixutres for get_current_user Add Test get_current_active_admin --- backend-app/tests/unit/conftest.py | 38 +++++++++++---------- backend-app/tests/unit/test_auth.py | 51 +++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/backend-app/tests/unit/conftest.py b/backend-app/tests/unit/conftest.py index a7a6d327..0110bcf1 100644 --- a/backend-app/tests/unit/conftest.py +++ b/backend-app/tests/unit/conftest.py @@ -198,7 +198,7 @@ def mock_user(): @pytest.fixture -def mock_user_is_active(): +def mock_user_is_active_not_admin(): """Fixture for mocking a user.""" user = User( id=1, @@ -211,7 +211,7 @@ def mock_user_is_active(): @pytest.fixture -def mock_user_is_not_active(): +def mock_user_not_active_not_admin(): """Fixture for mocking a user.""" user = User( id=1, @@ -238,7 +238,7 @@ def mock_user_is_active_is_admin(): @pytest.fixture -def mock_user_is_not_active_is_admin(): +def mock_user_not_active_is_admin(): """Fixture for mocking a user.""" user = User( id=1, @@ -252,32 +252,34 @@ def mock_user_is_not_active_is_admin(): @pytest.fixture -def mock_user_is_not_active_is_not_admin(): - """Fixture for mocking a user.""" - user = User( - id=1, - email="user1@example.com", - password="test1", - hashed_password="test1fake_hash", - is_active=False, - is_admin=False, - ) - return user +def mock_get_current_user_is_active_not_admin(mock_user_is_active_not_admin): + """Fixture for mocking get_current_user to return the mock user.""" + mock_function = MagicMock() + mock_function.return_value = mock_user_is_active_not_admin + return mock_function + + +@pytest.fixture +def mock_get_current_user_not_active_not_admin(mock_user_not_active_not_admin): + """Fixture for mocking get_current_user to return the mock user.""" + mock_function = MagicMock() + mock_function.return_value = mock_user_not_active_not_admin + return mock_function @pytest.fixture -def mock_get_current_user_active(mock_user_is_active): +def mock_get_current_user_is_active_is_admin(mock_user_is_active_is_admin): """Fixture for mocking get_current_user to return the mock user.""" mock_function = MagicMock() - mock_function.return_value = mock_user_is_active + mock_function.return_value = mock_user_is_active_is_admin return mock_function @pytest.fixture -def mock_get_current_user_not_active(mock_user_is_not_active): +def mock_get_current_user_not_active_is_admin(mock_user_not_active_is_admin): """Fixture for mocking get_current_user to return the mock user.""" mock_function = MagicMock() - mock_function.return_value = mock_user_is_not_active + mock_function.return_value = mock_user_not_active_is_admin return mock_function diff --git a/backend-app/tests/unit/test_auth.py b/backend-app/tests/unit/test_auth.py index f80dc044..a7378dcb 100644 --- a/backend-app/tests/unit/test_auth.py +++ b/backend-app/tests/unit/test_auth.py @@ -204,23 +204,60 @@ async def test_get_current_user_user_not_found( @pytest.mark.asyncio async def test_get_current_active_user_success( - mock_user_is_active, mock_get_current_user_active, monkeypatch + mock_user_is_active_not_admin, mock_get_current_user_is_active_not_admin, monkeypatch ): - monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_active) + monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_is_active_not_admin) - user = await get_current_active_user(mock_user_is_active) + user = await get_current_active_user(mock_user_is_active_not_admin) - assert user.id == mock_user_is_active.id + assert user.id == mock_user_is_active_not_admin.id @pytest.mark.asyncio async def test_get_current_active_user_not_active( - mock_user_is_not_active, mock_get_current_user_not_active, monkeypatch + mock_user_not_active_not_admin, mock_get_current_user_not_active_not_admin, monkeypatch ): - monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_not_active) + monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_not_active_not_admin) with pytest.raises(HTTPException) as exc_info: - await get_current_active_user(mock_user_is_not_active) + await get_current_active_user(mock_user_not_active_not_admin) + + assert exc_info.value.status_code == 400 + assert exc_info.value.detail == "Inactive user" + + +@pytest.mark.asyncio +async def test_get_current_active_admin_success( + mock_user_is_active_is_admin, mock_get_current_user_is_active_is_admin, monkeypatch +): + monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_is_active_is_admin) + + user = await get_current_active_user(mock_user_is_active_is_admin) + + assert user.id == mock_user_is_active_is_admin.id + + +@pytest.mark.asyncio +async def test_get_current_active_admin_not_active_is_admin( + mock_user_not_active_is_admin, mock_get_current_user_not_active_is_admin, monkeypatch +): + monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_not_active_is_admin) + + with pytest.raises(HTTPException) as exc_info: + await get_current_active_user(mock_user_not_active_is_admin) + + assert exc_info.value.status_code == 400 + assert exc_info.value.detail == "Inactive user" + + +@pytest.mark.asyncio +async def test_get_current_admin_not_active_not_admin( + mock_user_not_active_not_admin, mock_get_current_user_not_active_not_admin, monkeypatch +): + monkeypatch.setattr("app.api.auth.get_current_user", mock_get_current_user_not_active_not_admin) + + with pytest.raises(HTTPException) as exc_info: + await get_current_active_user(mock_user_not_active_not_admin) assert exc_info.value.status_code == 400 assert exc_info.value.detail == "Inactive user" From 8cdb1a36fa84f3c362eff7945fb54d5e5091fdd2 Mon Sep 17 00:00:00 2001 From: Rudolf Braun <48672663+BraunRudolf@users.noreply.github.com> Date: Wed, 9 Oct 2024 08:27:32 +0200 Subject: [PATCH 3/4] Add test to route / --- backend-app/tests/unit/test_auth.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backend-app/tests/unit/test_auth.py b/backend-app/tests/unit/test_auth.py index a7378dcb..f8dd4d65 100644 --- a/backend-app/tests/unit/test_auth.py +++ b/backend-app/tests/unit/test_auth.py @@ -261,3 +261,22 @@ async def test_get_current_admin_not_active_not_admin( assert exc_info.value.status_code == 400 assert exc_info.value.detail == "Inactive user" + + +def test_api_helth_check(client): + # GET request + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"Status": "Something Different"} + + +def test_health_check_post(client): + # POST request to a GET-only route + response = client.post("/") + assert response.status_code == 405 # Method Not Allowed + + +def test_health_check_wrong_url(client): + # Wrong URL + response = client.get("/wrong-url") + assert response.status_code == 404 # Not Found From 764058f4eba6ec95978251dc484ac3816ff0fb89 Mon Sep 17 00:00:00 2001 From: Rudolf Braun <48672663+BraunRudolf@users.noreply.github.com> Date: Wed, 9 Oct 2024 08:56:18 +0200 Subject: [PATCH 4/4] Add Test + Fixtures test+fixtures successful login_for_access_token --- backend-app/tests/unit/conftest.py | 12 ++++++++++- backend-app/tests/unit/test_auth.py | 33 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/backend-app/tests/unit/conftest.py b/backend-app/tests/unit/conftest.py index 0110bcf1..0bba690a 100644 --- a/backend-app/tests/unit/conftest.py +++ b/backend-app/tests/unit/conftest.py @@ -1,5 +1,5 @@ from io import BytesIO -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock import pandas as pd import pytest @@ -319,3 +319,13 @@ def valid_token(valid_token_payload): def mock_jwt_decode(valid_token_payload): """Mock jwt.decode to return a valid payload.""" return MagicMock(return_value=valid_token_payload) + + +@pytest.fixture +def mock_authenticate_user(mock_get_user_by_email_success): + return MagicMock(return_value=mock_get_user_by_email_success) + + +@pytest.fixture +def mock_create_access_token_valid_token(valid_token): + return MagicMock(return_value=valid_token) diff --git a/backend-app/tests/unit/test_auth.py b/backend-app/tests/unit/test_auth.py index f8dd4d65..f523d2e3 100644 --- a/backend-app/tests/unit/test_auth.py +++ b/backend-app/tests/unit/test_auth.py @@ -280,3 +280,36 @@ def test_health_check_wrong_url(client): # Wrong URL response = client.get("/wrong-url") assert response.status_code == 404 # Not Found + + +def test_successful_login( + client, + mock_authenticate_user, + mock_create_access_token_valid_token, + valid_token, + db, + monkeypatch, +): + + monkeypatch.setattr("app.api.auth.authenticate_user", mock_authenticate_user) + monkeypatch.setattr("app.api.auth.create_access_token", mock_create_access_token_valid_token) + + # Prepare the data as if it is coming from OAuth2PasswordRequestForm + login_data = {"username": "user1@example.com", "password": "test1fake_hash"} + + # Send a POST request to the /token endpoint + response = client.post("/token", data=login_data) + + # Assert that the status code is 200 OK + assert response.status_code == 200 + + # Assert that the response JSON contains the correct token + expected_response = { + "access_token": valid_token, + "token_type": "bearer", + "message": "Welcome!", + } + assert response.json() == expected_response + + # # Ensure the authenticate_user was called with correct arguments + mock_authenticate_user.assert_called_once_with("user1@example.com", "test1fake_hash", db=db)