-
Notifications
You must be signed in to change notification settings - Fork 182
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add API endpoints for order management and integrate with main applic…
…ation
- Loading branch information
Showing
5 changed files
with
220 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
""" | ||
API endpoints for order management. | ||
""" | ||
|
||
from fastapi import APIRouter, Depends, HTTPException, status | ||
from sqlalchemy.ext.asyncio import AsyncSession | ||
|
||
from app.crud.order import order_crud | ||
from app.models.order import Order | ||
from app.schemas.order import OrderCreate, OrderResponse | ||
|
||
router = APIRouter() | ||
|
||
|
||
@router.post( | ||
"/create_order", | ||
response_model=OrderResponse, | ||
status_code=status.HTTP_201_CREATED, | ||
summary="Create a new order", | ||
description="Creates a new order in the system", | ||
) | ||
async def create_order( | ||
order_data: OrderCreate, | ||
db: AsyncSession = Depends(order_crud.session), | ||
) -> Order: | ||
""" | ||
Create a new order with the provided order data. | ||
Args: | ||
order_data: The order data to create | ||
order_crud: The OrderCRUD instance for database operations | ||
Returns: | ||
The created order | ||
Raises: | ||
HTTPException: If there's an error creating the order | ||
""" | ||
try: | ||
order = await order_crud.add_new_order( | ||
user_id=order_data.user_id, | ||
price=order_data.price, | ||
token=order_data.token, | ||
position=order_data.position, | ||
) | ||
return order | ||
except Exception as e: | ||
raise HTTPException( | ||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | ||
detail=f"Failed to create order: {str(e)}", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
""" | ||
Pydantic schemas for order operations. | ||
""" | ||
|
||
import uuid | ||
|
||
from pydantic import BaseModel, Field | ||
|
||
|
||
class OrderCreate(BaseModel): | ||
"""Schema for creating a new order""" | ||
|
||
user_id: uuid.UUID = Field(..., description="ID of the user placing the order") | ||
price: float = Field(..., description="Price of the order") | ||
token: str = Field(..., description="Token symbol for the order") | ||
position: uuid.UUID = Field(..., description="Position ID related to the order") | ||
|
||
|
||
class OrderResponse(BaseModel): | ||
"""Schema for order response""" | ||
|
||
id: uuid.UUID | ||
user_id: uuid.UUID | ||
price: float | ||
token: str | ||
position: uuid.UUID | ||
|
||
class Config: | ||
"""Pydantic model configuration""" | ||
|
||
from_attributes = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
""" | ||
Unit tests for Order API endpoints using function-based approach without async/await. | ||
""" | ||
|
||
import uuid | ||
from unittest.mock import MagicMock, patch | ||
|
||
import pytest | ||
from fastapi import FastAPI, status | ||
from fastapi.testclient import TestClient | ||
|
||
from app.api.order import router | ||
from app.main import app | ||
from app.models.order import Order | ||
|
||
|
||
@pytest.fixture | ||
def app(): | ||
""" | ||
Create a FastAPI app for testing. | ||
""" | ||
test_app = FastAPI() | ||
test_app.include_router(router, prefix="/order") | ||
return test_app | ||
|
||
|
||
@pytest.fixture | ||
def client(app): | ||
""" | ||
Create a test client for the app. | ||
""" | ||
return TestClient(app) | ||
|
||
|
||
@pytest.fixture | ||
def mock_add_new_order(): | ||
""" | ||
Mock the add_new_order method of order_crud. | ||
""" | ||
with patch("app.api.order.order_crud.add_new_order") as mock: | ||
yield mock | ||
|
||
|
||
def create_mock_order(): | ||
"""Helper function to create a mock Order instance""" | ||
order_id = uuid.uuid4() | ||
user_id = uuid.uuid4() | ||
position_id = uuid.uuid4() | ||
|
||
mock_order = MagicMock(spec=Order) | ||
mock_order.id = order_id | ||
mock_order.user_id = user_id | ||
mock_order.price = 100.50 | ||
mock_order.token = "BTC" | ||
mock_order.position = position_id | ||
|
||
return mock_order | ||
|
||
|
||
def test_create_order_success(client, mock_add_new_order): | ||
"""Test successful order creation""" | ||
mock_order = create_mock_order() | ||
mock_add_new_order.return_value = mock_order | ||
|
||
response = client.post( | ||
"/order/create_order", | ||
json={ | ||
"user_id": str(mock_order.user_id), | ||
"price": mock_order.price, | ||
"token": mock_order.token, | ||
"position": str(mock_order.position), | ||
}, | ||
) | ||
|
||
assert response.status_code == status.HTTP_201_CREATED | ||
data = response.json() | ||
assert "id" in data | ||
assert data["price"] == mock_order.price | ||
assert data["token"] == mock_order.token | ||
assert data["user_id"] == str(mock_order.user_id) | ||
assert data["position"] == str(mock_order.position) | ||
|
||
mock_add_new_order.assert_called_once_with( | ||
user_id=mock_order.user_id, | ||
price=mock_order.price, | ||
token=mock_order.token, | ||
position=mock_order.position, | ||
) | ||
|
||
|
||
def test_create_order_invalid_data(client, mock_add_new_order): | ||
"""Test order creation with invalid data""" | ||
response = client.post( | ||
"/order/create_order", | ||
json={ | ||
"user_id": "not-a-uuid", | ||
"price": 100.50, | ||
"token": "BTC", | ||
"position": str(uuid.uuid4()), | ||
}, | ||
) | ||
|
||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY | ||
data = response.json() | ||
assert "detail" in data | ||
|
||
|
||
def test_create_order_database_error(client, mock_add_new_order): | ||
"""Test order creation with database error""" | ||
mock_add_new_order.side_effect = Exception("Database error") | ||
user_id = uuid.uuid4() | ||
position_id = uuid.uuid4() | ||
|
||
response = client.post( | ||
"/order/create_order", | ||
json={ | ||
"user_id": str(user_id), | ||
"price": 100.50, | ||
"token": "BTC", | ||
"position": str(position_id), | ||
}, | ||
) | ||
|
||
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR | ||
data = response.json() | ||
assert "detail" in data | ||
assert "Failed to create order" in data["detail"] |