diff --git a/backend-app/tests/unit/conftest.py b/backend-app/tests/unit/conftest.py index edacacb0..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 @@ -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,92 @@ def mock_user(): return user +@pytest.fixture +def mock_user_is_active_not_admin(): + """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_not_active_not_admin(): + """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_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_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_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_is_admin + return mock_function + + +@pytest.fixture +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_not_active_is_admin + 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.""" @@ -233,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 d3411cff..f523d2e3 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,116 @@ 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_not_admin, mock_get_current_user_is_active_not_admin, monkeypatch +): + 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_not_admin) + + assert user.id == mock_user_is_active_not_admin.id + + +@pytest.mark.asyncio +async def test_get_current_active_user_not_active( + 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" + + +@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" + + +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 + + +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)