f0af44d840
- Update agent router/service/repository with new endpoints - Update auth routes with phone-based authentication - Update users service with new phone lookup - Update schedule_items with new schemas - Update message schemas with visibility support - Update settings with new automation scheduler config - Update CLI with new commands - Update tests to match new API contracts
363 lines
13 KiB
Python
363 lines
13 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
from typing import Callable
|
|
from uuid import UUID
|
|
|
|
from fastapi import HTTPException
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app import app
|
|
from core.auth.models import CurrentUser
|
|
from schemas.user.context import UserContext
|
|
from v1.friendships.dependencies import get_friendship_service
|
|
from v1.friendships.schemas import (
|
|
FriendRequestCreate,
|
|
FriendRequestResponse,
|
|
FriendResponse,
|
|
)
|
|
from v1.friendships.service import FriendshipService
|
|
from v1.users.dependencies import get_current_user
|
|
|
|
|
|
def _raise_unauthorized() -> CurrentUser:
|
|
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
|
|
|
|
class FakeFriendshipService(FriendshipService):
|
|
def __init__(self) -> None:
|
|
pass
|
|
|
|
async def send_request(self, request: FriendRequestCreate) -> FriendRequestResponse:
|
|
return FriendRequestResponse(
|
|
id=UUID("11111111-1111-1111-1111-111111111111"),
|
|
sender=UserContext(id="user-1", username="sender", avatar_url=None),
|
|
recipient=UserContext(id="user-2", username="recipient", avatar_url=None),
|
|
content={"text": request.content} if request.content else None,
|
|
status="pending",
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
async def accept_request(self, friendship_id: UUID) -> FriendRequestResponse:
|
|
return FriendRequestResponse(
|
|
id=friendship_id,
|
|
sender=UserContext(id="user-1", username="sender", avatar_url=None),
|
|
recipient=UserContext(id="user-2", username="recipient", avatar_url=None),
|
|
content={"text": "Hello!"},
|
|
status="accepted",
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
async def decline_request(self, friendship_id: UUID) -> FriendRequestResponse:
|
|
return FriendRequestResponse(
|
|
id=friendship_id,
|
|
sender=UserContext(id="user-1", username="sender", avatar_url=None),
|
|
recipient=UserContext(id="user-2", username="recipient", avatar_url=None),
|
|
content={"text": "Hello!"},
|
|
status="rejected",
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
async def cancel_request(self, friendship_id: UUID) -> FriendRequestResponse:
|
|
return FriendRequestResponse(
|
|
id=friendship_id,
|
|
sender=UserContext(id="user-1", username="sender", avatar_url=None),
|
|
recipient=UserContext(id="user-2", username="recipient", avatar_url=None),
|
|
content={"text": "Hello!"},
|
|
status="canceled",
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
async def get_inbox(self) -> list[FriendRequestResponse]:
|
|
return [
|
|
FriendRequestResponse(
|
|
id=UUID("11111111-1111-1111-1111-111111111111"),
|
|
sender=UserContext(id="user-1", username="sender", avatar_url=None),
|
|
recipient=UserContext(
|
|
id="user-2", username="recipient", avatar_url=None
|
|
),
|
|
content={"text": "Hello!"},
|
|
status="pending",
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
]
|
|
|
|
async def get_outgoing_requests(self) -> list[FriendRequestResponse]:
|
|
return [
|
|
FriendRequestResponse(
|
|
id=UUID("22222222-2222-2222-2222-222222222222"),
|
|
sender=UserContext(id="user-1", username="sender", avatar_url=None),
|
|
recipient=UserContext(id="user-3", username="target", avatar_url=None),
|
|
content=None,
|
|
status="pending",
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
]
|
|
|
|
async def get_friends_list(self) -> list[FriendResponse]:
|
|
return [
|
|
FriendResponse(
|
|
id=UUID("33333333-3333-3333-3333-333333333333"),
|
|
friend=UserContext(id="user-2", username="friend", avatar_url=None),
|
|
status="active",
|
|
created_at=datetime.now(timezone.utc),
|
|
accepted_at=datetime.now(timezone.utc),
|
|
)
|
|
]
|
|
|
|
async def remove_friend(self, friend_id: UUID) -> FriendResponse:
|
|
return FriendResponse(
|
|
id=UUID("33333333-3333-3333-3333-333333333333"),
|
|
friend=UserContext(id=str(friend_id), username="friend", avatar_url=None),
|
|
status="active",
|
|
created_at=datetime.now(timezone.utc),
|
|
accepted_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
|
|
def _override_friendship_service(
|
|
service: FriendshipService,
|
|
) -> Callable[[], FriendshipService]:
|
|
def _get_service() -> FriendshipService:
|
|
return service
|
|
|
|
return _get_service
|
|
|
|
|
|
def _get_fake_current_user() -> CurrentUser:
|
|
return CurrentUser(
|
|
id=UUID("00000000-0000-0000-0000-000000000001"),
|
|
phone="+8613812345678",
|
|
)
|
|
|
|
|
|
class TestSendFriendRequest:
|
|
def test_send_friend_request_returns_201(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.post(
|
|
"/api/v1/friends/requests",
|
|
json={
|
|
"target_user_id": "22222222-2222-2222-2222-222222222222",
|
|
"content": "Hello!",
|
|
},
|
|
)
|
|
assert response.status_code == 201
|
|
body = response.json()
|
|
assert body["status"] == "pending"
|
|
assert body["sender"]["username"] == "sender"
|
|
assert body["recipient"]["username"] == "recipient"
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
def test_send_friend_request_missing_target_returns_422(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.post("/api/v1/friends/requests", json={})
|
|
assert response.status_code == 422
|
|
assert response.headers["content-type"].startswith(
|
|
"application/problem+json"
|
|
)
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
def test_send_friend_request_invalid_uuid_returns_422(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.post(
|
|
"/api/v1/friends/requests",
|
|
json={"target_user_id": "invalid-uuid"},
|
|
)
|
|
assert response.status_code == 422
|
|
assert response.headers["content-type"].startswith(
|
|
"application/problem+json"
|
|
)
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestGetInbox:
|
|
def test_get_inbox_returns_200(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.get("/api/v1/friends/requests/inbox")
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert isinstance(body, list)
|
|
assert len(body) == 1
|
|
assert body[0]["status"] == "pending"
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestGetOutgoingRequests:
|
|
def test_get_outgoing_requests_returns_200(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.get("/api/v1/friends/requests/outgoing")
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert isinstance(body, list)
|
|
assert len(body) == 1
|
|
assert body[0]["status"] == "pending"
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestAcceptFriendRequest:
|
|
def test_accept_friend_request_returns_200(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.post(
|
|
"/api/v1/friends/requests/11111111-1111-1111-1111-111111111111/accept",
|
|
json={},
|
|
)
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["status"] == "accepted"
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestDeclineFriendRequest:
|
|
def test_decline_friend_request_returns_200(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.post(
|
|
"/api/v1/friends/requests/11111111-1111-1111-1111-111111111111/decline",
|
|
json={},
|
|
)
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert body["status"] == "rejected"
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestCancelFriendRequest:
|
|
def test_cancel_friend_request_returns_204(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.delete(
|
|
"/api/v1/friends/requests/11111111-1111-1111-1111-111111111111"
|
|
)
|
|
assert response.status_code == 204
|
|
assert response.content == b""
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestGetFriendsList:
|
|
def test_get_friends_list_returns_200(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.get("/api/v1/friends")
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert isinstance(body, list)
|
|
assert len(body) == 1
|
|
assert body[0]["status"] == "active"
|
|
assert body[0]["friend"]["username"] == "friend"
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestRemoveFriend:
|
|
def test_remove_friend_returns_204(self) -> None:
|
|
app.dependency_overrides[get_friendship_service] = _override_friendship_service(
|
|
FakeFriendshipService()
|
|
)
|
|
app.dependency_overrides[get_current_user] = _get_fake_current_user
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.delete(
|
|
"/api/v1/friends/33333333-3333-3333-3333-333333333333"
|
|
)
|
|
assert response.status_code == 204
|
|
assert response.content == b""
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
|
|
class TestFriendshipRequiresAuth:
|
|
def test_send_request_without_auth_returns_401(self) -> None:
|
|
app.dependency_overrides[get_current_user] = _raise_unauthorized
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.post(
|
|
"/api/v1/friends/requests",
|
|
json={
|
|
"target_user_id": "22222222-2222-2222-2222-222222222222",
|
|
},
|
|
)
|
|
assert response.status_code == 401
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
def test_get_inbox_without_auth_returns_401(self) -> None:
|
|
app.dependency_overrides[get_current_user] = _raise_unauthorized
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.get("/api/v1/friends/requests/inbox")
|
|
assert response.status_code == 401
|
|
finally:
|
|
app.dependency_overrides = {}
|
|
|
|
def test_get_friends_without_auth_returns_401(self) -> None:
|
|
app.dependency_overrides[get_current_user] = _raise_unauthorized
|
|
|
|
client = TestClient(app)
|
|
try:
|
|
response = client.get("/api/v1/friends")
|
|
assert response.status_code == 401
|
|
finally:
|
|
app.dependency_overrides = {}
|