test(backend): add comprehensive tests for OAuth and agent endpoints

- Added tests for OAuth provider admin and consent endpoints covering edge cases.
- Extended agent-related tests to handle incorrect project associations and lifecycle state transitions.
- Introduced tests for sprint status transitions and validation checks.
- Improved multiline formatting consistency across all test functions.
This commit is contained in:
2026-01-03 01:44:11 +01:00
parent acd18ff694
commit 664415111a
28 changed files with 1530 additions and 216 deletions

View File

@@ -437,3 +437,197 @@ class TestOAuthProviderEndpoints:
)
# Missing client_id returns 401 (invalid_client)
assert response.status_code == 401
class TestOAuthProviderAdminEndpoints:
"""Tests for OAuth provider admin endpoints."""
@pytest.mark.asyncio
async def test_list_clients_admin_only(self, client, user_token):
"""Test that listing clients requires superuser."""
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.get(
"/api/v1/oauth/provider/clients",
headers={"Authorization": f"Bearer {user_token}"},
)
# Regular user should be forbidden
assert response.status_code == 403
@pytest.mark.asyncio
async def test_list_clients_success(self, client, superuser_token):
"""Test listing OAuth clients as superuser."""
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.get(
"/api/v1/oauth/provider/clients",
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert response.status_code == 200
assert isinstance(response.json(), list)
@pytest.mark.asyncio
async def test_delete_client_not_found(self, client, superuser_token):
"""Test deleting non-existent OAuth client."""
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.delete(
"/api/v1/oauth/provider/clients/non_existent_client_id",
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert response.status_code == 404
@pytest.mark.asyncio
async def test_delete_client_success(self, client, superuser_token, async_test_db):
"""Test successfully deleting an OAuth client."""
_test_engine, AsyncTestingSessionLocal = async_test_db
from app.crud.oauth import oauth_client
from app.schemas.oauth import OAuthClientCreate
# Create a test client to delete
async with AsyncTestingSessionLocal() as session:
client_data = OAuthClientCreate(
client_name="Delete Test Client",
redirect_uris=["http://localhost:3000/callback"],
allowed_scopes=["read:users"],
)
test_client, _ = await oauth_client.create_client(
session, obj_in=client_data
)
test_client_id = test_client.client_id
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.delete(
f"/api/v1/oauth/provider/clients/{test_client_id}",
headers={"Authorization": f"Bearer {superuser_token}"},
)
assert response.status_code == 204
class TestOAuthProviderConsentEndpoints:
"""Tests for OAuth provider consent management endpoints."""
@pytest.mark.asyncio
async def test_list_consents_unauthenticated(self, client):
"""Test listing consents without authentication."""
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.get("/api/v1/oauth/provider/consents")
assert response.status_code == 401
@pytest.mark.asyncio
async def test_list_consents_empty(self, client, user_token):
"""Test listing consents when user has none."""
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.get(
"/api/v1/oauth/provider/consents",
headers={"Authorization": f"Bearer {user_token}"},
)
assert response.status_code == 200
assert response.json() == []
@pytest.mark.asyncio
async def test_list_consents_with_data(
self, client, user_token, async_test_user, async_test_db
):
"""Test listing consents when user has granted some."""
_test_engine, AsyncTestingSessionLocal = async_test_db
from app.crud.oauth import oauth_client
from app.models.oauth_provider_token import OAuthConsent
from app.schemas.oauth import OAuthClientCreate
# Create a test client and grant consent
async with AsyncTestingSessionLocal() as session:
client_data = OAuthClientCreate(
client_name="Consented App",
redirect_uris=["http://localhost:3000/callback"],
allowed_scopes=["read:users", "write:users"],
)
test_client, _ = await oauth_client.create_client(
session, obj_in=client_data
)
# Create consent record
consent = OAuthConsent(
user_id=async_test_user.id,
client_id=test_client.client_id,
granted_scopes="read:users write:users",
)
session.add(consent)
await session.commit()
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.get(
"/api/v1/oauth/provider/consents",
headers={"Authorization": f"Bearer {user_token}"},
)
assert response.status_code == 200
data = response.json()
assert len(data) == 1
assert data[0]["client_name"] == "Consented App"
assert "read:users" in data[0]["granted_scopes"]
@pytest.mark.asyncio
async def test_revoke_consent_not_found(self, client, user_token):
"""Test revoking consent that doesn't exist."""
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.delete(
"/api/v1/oauth/provider/consents/non_existent_client",
headers={"Authorization": f"Bearer {user_token}"},
)
assert response.status_code == 404
@pytest.mark.asyncio
async def test_revoke_consent_success(
self, client, user_token, async_test_user, async_test_db
):
"""Test successfully revoking consent."""
_test_engine, AsyncTestingSessionLocal = async_test_db
from app.crud.oauth import oauth_client
from app.models.oauth_provider_token import OAuthConsent
from app.schemas.oauth import OAuthClientCreate
# Create a test client and grant consent
async with AsyncTestingSessionLocal() as session:
client_data = OAuthClientCreate(
client_name="Revoke Test App",
redirect_uris=["http://localhost:3000/callback"],
allowed_scopes=["read:users"],
)
test_client, _ = await oauth_client.create_client(
session, obj_in=client_data
)
test_client_id = test_client.client_id
# Create consent record
consent = OAuthConsent(
user_id=async_test_user.id,
client_id=test_client.client_id,
granted_scopes="read:users",
)
session.add(consent)
await session.commit()
with patch("app.api.routes.oauth_provider.settings") as mock_settings:
mock_settings.OAUTH_PROVIDER_ENABLED = True
response = await client.delete(
f"/api/v1/oauth/provider/consents/{test_client_id}",
headers={"Authorization": f"Bearer {user_token}"},
)
assert response.status_code == 204