Files
resolutionflow/backend/tests/test_oauth_only_user_paths.py

84 lines
2.9 KiB
Python

import uuid
import pytest
from sqlalchemy import select
from app.models.user import User
from app.models.account import Account
from app.models.oauth_identity import OAuthIdentity
async def _make_oauth_only_user(test_db, email, *, with_identity=True):
"""Create an OAuth-only user (password_hash=None) directly in the test DB."""
import secrets
account = Account(
name=f"{email}-acct",
display_code=secrets.token_hex(4).upper(),
)
test_db.add(account)
await test_db.flush()
user = User(
email=email,
name="OAuth User",
password_hash=None,
account_id=account.id,
account_role="owner",
)
test_db.add(user)
await test_db.flush()
if with_identity:
test_db.add(OAuthIdentity(
user_id=user.id, provider="google",
provider_subject=f"google_{email}",
provider_email_at_link=email,
))
await test_db.commit()
return user
@pytest.mark.asyncio
async def test_login_form_rejects_oauth_only_user_with_helpful_error(client, test_db):
await _make_oauth_only_user(test_db, "oauth-only@example.com")
response = await client.post(
"/api/v1/auth/login",
data={"username": "oauth-only@example.com", "password": "wontwork"},
)
assert response.status_code == 400
body = response.json()
assert body["detail"]["error"] == "use_oauth_provider"
assert "google" in body["detail"]["providers"]
@pytest.mark.asyncio
async def test_login_json_rejects_oauth_only_user(client, test_db):
await _make_oauth_only_user(test_db, "oauth-only2@example.com")
response = await client.post(
"/api/v1/auth/login/json",
json={"email": "oauth-only2@example.com", "password": "wontwork"},
)
assert response.status_code == 400
assert response.json()["detail"]["error"] == "use_oauth_provider"
@pytest.mark.asyncio
async def test_password_forgot_silent_for_oauth_only_user(client, test_db):
"""OAuth-only users get the generic message; no email is sent."""
await _make_oauth_only_user(test_db, "oauth-forgot@example.com", with_identity=False)
from unittest.mock import AsyncMock, patch
with patch("app.core.email.EmailService.send_password_reset_email", new_callable=AsyncMock) as mock_send:
response = await client.post(
"/api/v1/auth/password/forgot",
json={"email": "oauth-forgot@example.com"},
)
assert response.status_code == 200
mock_send.assert_not_called()
@pytest.mark.asyncio
async def test_login_for_password_user_still_works(client, test_user):
"""Regression: existing password-based login must still succeed."""
response = await client.post(
"/api/v1/auth/login/json",
json={"email": test_user["email"], "password": test_user["password"]},
)
assert response.status_code == 200
assert response.json()["access_token"]