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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user