| Server IP : 3.147.158.171 / Your IP : 216.73.216.88 Web Server : Apache/2.4.67 (Amazon Linux) OpenSSL/3.5.5 System : Linux ip-172-31-2-178.us-east-2.compute.internal 6.1.172-216.329.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 20 06:31:34 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.21 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /tsai/repo/api/tests/unit/ |
Upload File : |
"""
Unit tests for the /user/ endpoint.
Tests cover:
- POST /user/login/ - User authentication
- POST /user/logout/ - User logout
"""
import pytest
from unittest.mock import MagicMock, patch
from fastapi.testclient import TestClient
from app.main import app
from app.api.v1.endpoints.user import get_site_config_service
class FakeSite:
"""Mock site configuration for testing."""
wp_host = "https://fakewp.com"
cb_host = "chat.example.com"
api_host = "api.example.com"
wp_dir = "/sites/test"
drupal_host = "drupal.example.com"
drupal_api = "/api"
slug = "test"
drupal_uid = "test-user"
class FakeSiteConfigService:
"""Mock site config service that returns FakeSite."""
def get_site_by_cb_host(self, site):
return FakeSite()
class FakeSiteConfigServiceNotFound:
"""Mock site config service that returns None (site not found)."""
def get_site_by_cb_host(self, site):
return None
@pytest.fixture
def client():
"""Create test client."""
return TestClient(app)
@pytest.fixture
def client_with_mocks():
"""Create test client with dependency overrides for successful login."""
app.dependency_overrides[get_site_config_service] = lambda: FakeSiteConfigService()
client = TestClient(app)
yield client
# Clean up overrides after test
app.dependency_overrides.clear()
@pytest.fixture
def client_site_not_found():
"""Create test client where site is not found."""
app.dependency_overrides[get_site_config_service] = lambda: FakeSiteConfigServiceNotFound()
client = TestClient(app)
yield client
app.dependency_overrides.clear()
class TestUserLogin:
"""Tests for POST /api/v1/user/login/"""
def test_login_success(self, client_with_mocks):
"""Test successful user login."""
with patch('app.api.v1.endpoints.user.requests.post') as mock_post:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.text = '{"token": "wp_token_value"}'
mock_response.content = b'{"token": "wp_token_value"}'
mock_response.headers = {"Content-Type": "application/json"}
mock_response.json.return_value = {"token": "wp_token_value"}
mock_post.return_value = mock_response
payload = {"username": "testuser", "password": "testpass", "site": "mysite"}
response = client_with_mocks.post("/api/v1/user/login/", json=payload)
assert response.status_code == 200
data = response.json()
assert "wp_token" in data
assert "fapi_token" not in data
def test_login_invalid_site(self, client_site_not_found):
"""Test login fails with invalid site.
Note: The endpoint returns {"error": "..."} but the response_model
requires wp_token, causing a ResponseValidationError. This test
documents the actual behavior.
"""
import fastapi.exceptions
payload = {"username": "user", "password": "pass", "site": "invalid_site"}
with pytest.raises(fastapi.exceptions.ResponseValidationError):
client_site_not_found.post("/api/v1/user/login/", json=payload)
def test_login_wp_failure(self, client_with_mocks):
"""Test login handles WordPress API failure."""
with patch('app.api.v1.endpoints.user.requests.post') as mock_post:
mock_response = MagicMock()
mock_response.status_code = 403
mock_response.text = "Forbidden"
mock_response.content = b"Forbidden"
mock_response.headers = {"Content-Type": "text/plain"}
mock_post.return_value = mock_response
payload = {"username": "user", "password": "wrong", "site": "mysite"}
response = client_with_mocks.post("/api/v1/user/login/", json=payload)
assert response.status_code == 403
def test_login_missing_fields(self, client):
"""Test login fails with missing required fields."""
payload = {"username": "user", "site": "mysite"}
response = client.post("/api/v1/user/login/", json=payload)
assert response.status_code == 422
payload = {"password": "pass", "site": "mysite"}
response = client.post("/api/v1/user/login/", json=payload)
assert response.status_code == 422
payload = {"username": "user", "password": "pass"}
response = client.post("/api/v1/user/login/", json=payload)
assert response.status_code == 422
class TestUserLogout:
"""Tests for POST /api/v1/user/logout/"""
def test_logout_success(self, client):
"""Test successful logout."""
payload = {"token": "some_token"}
response = client.post("/api/v1/user/logout/", json=payload)
assert response.status_code == 200
data = response.json()
assert data["detail"] == "Logout successful"
def test_logout_missing_token(self, client):
"""Test logout fails with missing token."""
payload = {}
response = client.post("/api/v1/user/logout/", json=payload)
assert response.status_code == 422