Merge remote-tracking branch 'origin/feature/friendship' into dev
This commit is contained in:
@@ -0,0 +1,364 @@
|
||||
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 v1.friendships.dependencies import get_friendship_service
|
||||
from v1.friendships.schemas import (
|
||||
FriendRequestCreate,
|
||||
FriendRequestResponse,
|
||||
FriendResponse,
|
||||
UserBasicInfo,
|
||||
)
|
||||
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=UserBasicInfo(id="user-1", username="sender", avatar_url=None),
|
||||
recipient=UserBasicInfo(id="user-2", username="recipient", avatar_url=None),
|
||||
content=request.content,
|
||||
status="pending",
|
||||
created_at=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
async def accept_request(self, friendship_id: UUID) -> FriendRequestResponse:
|
||||
return FriendRequestResponse(
|
||||
id=friendship_id,
|
||||
sender=UserBasicInfo(id="user-1", username="sender", avatar_url=None),
|
||||
recipient=UserBasicInfo(id="user-2", username="recipient", avatar_url=None),
|
||||
content="Hello!",
|
||||
status="accepted",
|
||||
created_at=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
async def decline_request(self, friendship_id: UUID) -> FriendRequestResponse:
|
||||
return FriendRequestResponse(
|
||||
id=friendship_id,
|
||||
sender=UserBasicInfo(id="user-1", username="sender", avatar_url=None),
|
||||
recipient=UserBasicInfo(id="user-2", username="recipient", avatar_url=None),
|
||||
content="Hello!",
|
||||
status="rejected",
|
||||
created_at=datetime.now(timezone.utc),
|
||||
)
|
||||
|
||||
async def cancel_request(self, friendship_id: UUID) -> FriendRequestResponse:
|
||||
return FriendRequestResponse(
|
||||
id=friendship_id,
|
||||
sender=UserBasicInfo(id="user-1", username="sender", avatar_url=None),
|
||||
recipient=UserBasicInfo(id="user-2", username="recipient", avatar_url=None),
|
||||
content="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=UserBasicInfo(id="user-1", username="sender", avatar_url=None),
|
||||
recipient=UserBasicInfo(
|
||||
id="user-2", username="recipient", avatar_url=None
|
||||
),
|
||||
content="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=UserBasicInfo(id="user-1", username="sender", avatar_url=None),
|
||||
recipient=UserBasicInfo(
|
||||
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=UserBasicInfo(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=UserBasicInfo(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"),
|
||||
email="test@example.com",
|
||||
)
|
||||
|
||||
|
||||
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 = {}
|
||||
Reference in New Issue
Block a user