Fred808 commited on
Commit
4c5298a
·
verified ·
1 Parent(s): 66bc8fc

Upload 7 files

Browse files
tests/api/test_auth.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from httpx import AsyncClient
3
+ from sqlalchemy.ext.asyncio import AsyncSession
4
+ from app.core.security import create_access_token
5
+
6
+ pytestmark = pytest.mark.asyncio
7
+
8
+ async def test_login(client: AsyncClient, db_session: AsyncSession):
9
+ # First register a test user
10
+ register_response = await client.post(
11
+ "/api/v1/auth/register",
12
+ data={
13
+ "username": "testuser@example.com",
14
+ "password": "testpass123"
15
+ }
16
+ )
17
+ assert register_response.status_code == 200
18
+
19
+ # Test login with correct credentials
20
+ response = await client.post(
21
+ "/api/v1/auth/login",
22
+ data={
23
+ "username": "testuser@example.com",
24
+ "password": "testpass123"
25
+ }
26
+ )
27
+ assert response.status_code == 200
28
+ assert "access_token" in response.json()
29
+ assert response.json()["token_type"] == "bearer"
30
+
31
+ # Test login with incorrect password
32
+ response = await client.post(
33
+ "/api/v1/auth/login",
34
+ data={
35
+ "username": "testuser@example.com",
36
+ "password": "wrongpass"
37
+ }
38
+ )
39
+ assert response.status_code == 401
40
+
41
+ # Test login with non-existent user
42
+ response = await client.post(
43
+ "/api/v1/auth/login",
44
+ data={
45
+ "username": "nonexistent@example.com",
46
+ "password": "testpass123"
47
+ }
48
+ )
49
+ assert response.status_code == 401
50
+
51
+ async def test_register(client: AsyncClient, db_session: AsyncSession):
52
+ # Test successful registration
53
+ response = await client.post(
54
+ "/api/v1/auth/register",
55
+ data={
56
+ "username": "newuser@example.com",
57
+ "password": "newpass123"
58
+ }
59
+ )
60
+ assert response.status_code == 200
61
+ user_data = response.json()
62
+ assert user_data["email"] == "newuser@example.com"
63
+ assert "hashed_password" not in user_data
64
+
65
+ # Test registration with existing email
66
+ response = await client.post(
67
+ "/api/v1/auth/register",
68
+ data={
69
+ "username": "newuser@example.com",
70
+ "password": "anotherpass"
71
+ }
72
+ )
73
+ assert response.status_code == 400
74
+ assert "Email already registered" in response.json()["detail"]
tests/api/test_branches.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from httpx import AsyncClient
3
+ from sqlalchemy.ext.asyncio import AsyncSession
4
+ from ..utils import create_user_and_login, create_branch
5
+
6
+ pytestmark = pytest.mark.asyncio
7
+
8
+ @pytest.fixture
9
+ async def admin_token(client: AsyncClient) -> str:
10
+ """Create an admin user and return their token"""
11
+ user_data = await create_user_and_login(
12
+ client,
13
+ email="admin@example.com",
14
+ password="adminpass123",
15
+ full_name="Admin User",
16
+ is_superuser=True
17
+ )
18
+ return user_data["token"]
19
+
20
+ @pytest.fixture
21
+ async def regular_token(client: AsyncClient) -> str:
22
+ """Create a regular user and return their token"""
23
+ user_data = await create_user_and_login(
24
+ client,
25
+ email="user@example.com",
26
+ password="userpass123",
27
+ full_name="Regular User",
28
+ is_superuser=False
29
+ )
30
+ return user_data["token"]
31
+
32
+ async def test_create_branch(client: AsyncClient, admin_token: str):
33
+ # Test creating a branch as admin
34
+ response = await client.post(
35
+ "/api/v1/branches/",
36
+ json={
37
+ "name": "Test Branch",
38
+ "location": "Test Location",
39
+ "contact_email": "branch@example.com",
40
+ "phone": "1234567890"
41
+ },
42
+ headers={"Authorization": f"Bearer {admin_token}"}
43
+ )
44
+ assert response.status_code == 200
45
+ data = response.json()
46
+ assert data["name"] == "Test Branch"
47
+ assert data["location"] == "Test Location"
48
+ return data["id"]
49
+
50
+ async def test_create_branch_unauthorized(client: AsyncClient, regular_token: str):
51
+ # Test creating a branch as regular user (should fail)
52
+ response = await client.post(
53
+ "/api/v1/branches/",
54
+ json={
55
+ "name": "Test Branch",
56
+ "location": "Test Location"
57
+ },
58
+ headers={"Authorization": f"Bearer {regular_token}"}
59
+ )
60
+ assert response.status_code == 403
61
+
62
+ async def test_get_branch(client: AsyncClient, admin_token: str):
63
+ # First create a branch
64
+ branch_id = await test_create_branch(client, admin_token)
65
+
66
+ # Test getting the branch
67
+ response = await client.get(
68
+ f"/api/v1/branches/{branch_id}",
69
+ headers={"Authorization": f"Bearer {admin_token}"}
70
+ )
71
+ assert response.status_code == 200
72
+ data = response.json()
73
+ assert data["id"] == branch_id
74
+ assert data["name"] == "Test Branch"
75
+
76
+ async def test_list_branches(client: AsyncClient, admin_token: str):
77
+ # Create multiple branches
78
+ await test_create_branch(client, admin_token)
79
+ await client.post(
80
+ "/api/v1/branches/",
81
+ json={
82
+ "name": "Another Branch",
83
+ "location": "Another Location",
84
+ "contact_email": "another@example.com",
85
+ "phone": "0987654321"
86
+ },
87
+ headers={"Authorization": f"Bearer {admin_token}"}
88
+ )
89
+
90
+ # Test listing branches
91
+ response = await client.get(
92
+ "/api/v1/branches/",
93
+ headers={"Authorization": f"Bearer {admin_token}"}
94
+ )
95
+ assert response.status_code == 200
96
+ data = response.json()
97
+ assert len(data) >= 2
98
+ assert any(b["name"] == "Test Branch" for b in data)
99
+ assert any(b["name"] == "Another Branch" for b in data)
100
+
101
+ async def test_update_branch(client: AsyncClient, admin_token: str):
102
+ # First create a branch
103
+ branch_id = await test_create_branch(client, admin_token)
104
+
105
+ # Test updating the branch
106
+ response = await client.put(
107
+ f"/api/v1/branches/{branch_id}",
108
+ json={
109
+ "name": "Updated Branch",
110
+ "location": "Updated Location",
111
+ "contact_email": "updated@example.com",
112
+ "phone": "1112223333"
113
+ },
114
+ headers={"Authorization": f"Bearer {admin_token}"}
115
+ )
116
+ assert response.status_code == 200
117
+ data = response.json()
118
+ assert data["name"] == "Updated Branch"
119
+ assert data["location"] == "Updated Location"
120
+ assert data["contact_email"] == "updated@example.com"
121
+
122
+ async def test_delete_branch(client: AsyncClient, admin_token: str):
123
+ # First create a branch
124
+ branch_id = await test_create_branch(client, admin_token)
125
+
126
+ # Test deleting the branch
127
+ response = await client.delete(
128
+ f"/api/v1/branches/{branch_id}",
129
+ headers={"Authorization": f"Bearer {admin_token}"}
130
+ )
131
+ assert response.status_code == 200
132
+
133
+ # Verify branch is deleted
134
+ response = await client.get(
135
+ f"/api/v1/branches/{branch_id}",
136
+ headers={"Authorization": f"Bearer {admin_token}"}
137
+ )
138
+ assert response.status_code == 404
139
+
140
+ async def test_branch_statistics(client: AsyncClient, admin_token: str):
141
+ # First create a branch
142
+ branch_id = await test_create_branch(client, admin_token)
143
+
144
+ # Test getting branch statistics
145
+ response = await client.get(
146
+ f"/api/v1/branches/{branch_id}/statistics",
147
+ headers={"Authorization": f"Bearer {admin_token}"}
148
+ )
149
+ assert response.status_code == 200
150
+ data = response.json()
151
+ assert "total_products" in data
152
+ assert "total_orders" in data
153
+ assert "total_revenue" in data
154
+ assert "average_order_value" in data
tests/api/test_orders.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from httpx import AsyncClient
3
+ from sqlalchemy.ext.asyncio import AsyncSession
4
+
5
+ pytestmark = pytest.mark.asyncio
6
+
7
+ @pytest.fixture
8
+ async def user_token(client: AsyncClient) -> str:
9
+ """Create a test user and return their token"""
10
+ # Register user
11
+ await client.post(
12
+ "/api/v1/auth/register",
13
+ data={
14
+ "username": "testuser@example.com",
15
+ "password": "testpass123",
16
+ "full_name": "Test User"
17
+ }
18
+ )
19
+
20
+ # Login to get token
21
+ response = await client.post(
22
+ "/api/v1/auth/login",
23
+ data={
24
+ "username": "testuser@example.com",
25
+ "password": "testpass123"
26
+ }
27
+ )
28
+ return response.json()["access_token"]
29
+
30
+ @pytest.fixture
31
+ async def test_product(client: AsyncClient, user_token: str) -> dict:
32
+ """Create a test product and return its data"""
33
+ response = await client.post(
34
+ "/api/v1/products/",
35
+ json={
36
+ "name": "Test Product",
37
+ "description": "A test product",
38
+ "price": 99.99,
39
+ "category": "test",
40
+ "inventory_count": 10
41
+ },
42
+ headers={"Authorization": f"Bearer {user_token}"}
43
+ )
44
+ return response.json()
45
+
46
+ async def test_create_order(client: AsyncClient, user_token: str, test_product: dict):
47
+ # Test creating an order
48
+ response = await client.post(
49
+ "/api/v1/orders/",
50
+ json={
51
+ "items": [
52
+ {
53
+ "product_id": test_product["id"],
54
+ "quantity": 2
55
+ }
56
+ ]
57
+ },
58
+ headers={"Authorization": f"Bearer {user_token}"}
59
+ )
60
+ assert response.status_code == 200
61
+ data = response.json()
62
+ assert len(data["items"]) == 1
63
+ assert data["items"][0]["product_id"] == test_product["id"]
64
+ assert data["total_amount"] == test_product["price"] * 2
65
+ return data["id"]
66
+
67
+ async def test_get_order(client: AsyncClient, user_token: str, test_product: dict):
68
+ # First create an order
69
+ order_id = await test_create_order(client, user_token, test_product)
70
+
71
+ # Test getting the order
72
+ response = await client.get(
73
+ f"/api/v1/orders/{order_id}",
74
+ headers={"Authorization": f"Bearer {user_token}"}
75
+ )
76
+ assert response.status_code == 200
77
+ data = response.json()
78
+ assert data["id"] == order_id
79
+ assert len(data["items"]) == 1
80
+
81
+ async def test_list_orders(client: AsyncClient, user_token: str, test_product: dict):
82
+ # Create multiple orders
83
+ await test_create_order(client, user_token, test_product)
84
+ await test_create_order(client, user_token, test_product)
85
+
86
+ # Test listing orders
87
+ response = await client.get(
88
+ "/api/v1/orders/",
89
+ headers={"Authorization": f"Bearer {user_token}"}
90
+ )
91
+ assert response.status_code == 200
92
+ data = response.json()
93
+ assert len(data) >= 2
94
+
95
+ async def test_update_order_status(client: AsyncClient, user_token: str, test_product: dict):
96
+ # First create an order
97
+ order_id = await test_create_order(client, user_token, test_product)
98
+
99
+ # Test updating the order status
100
+ response = await client.put(
101
+ f"/api/v1/orders/{order_id}/status",
102
+ json={"status": "processing"},
103
+ headers={"Authorization": f"Bearer {user_token}"}
104
+ )
105
+ assert response.status_code == 200
106
+ data = response.json()
107
+ assert data["status"] == "processing"
108
+
109
+ # Test invalid status
110
+ response = await client.put(
111
+ f"/api/v1/orders/{order_id}/status",
112
+ json={"status": "invalid_status"},
113
+ headers={"Authorization": f"Bearer {user_token}"}
114
+ )
115
+ assert response.status_code == 400
116
+
117
+ async def test_cancel_order(client: AsyncClient, user_token: str, test_product: dict):
118
+ # First create an order
119
+ order_id = await test_create_order(client, user_token, test_product)
120
+
121
+ # Get initial product inventory
122
+ product_response = await client.get(
123
+ f"/api/v1/products/{test_product['id']}",
124
+ headers={"Authorization": f"Bearer {user_token}"}
125
+ )
126
+ initial_inventory = product_response.json()["inventory_count"]
127
+
128
+ # Cancel the order
129
+ response = await client.put(
130
+ f"/api/v1/orders/{order_id}/status",
131
+ json={"status": "cancelled"},
132
+ headers={"Authorization": f"Bearer {user_token}"}
133
+ )
134
+ assert response.status_code == 200
135
+ assert response.json()["status"] == "cancelled"
136
+
137
+ # Verify inventory was restored
138
+ product_response = await client.get(
139
+ f"/api/v1/products/{test_product['id']}",
140
+ headers={"Authorization": f"Bearer {user_token}"}
141
+ )
142
+ final_inventory = product_response.json()["inventory_count"]
143
+ assert final_inventory == initial_inventory + 2 # We ordered 2 items
tests/api/test_products.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytest
2
+ from httpx import AsyncClient
3
+ from sqlalchemy.ext.asyncio import AsyncSession
4
+ from app.core.security import create_access_token
5
+
6
+ pytestmark = pytest.mark.asyncio
7
+
8
+ @pytest.fixture
9
+ async def user_token(client: AsyncClient) -> str:
10
+ """Create a test user and return their token"""
11
+ # Register user
12
+ await client.post(
13
+ "/api/v1/auth/register",
14
+ data={
15
+ "username": "testuser@example.com",
16
+ "password": "testpass123",
17
+ "full_name": "Test User"
18
+ }
19
+ )
20
+
21
+ # Login to get token
22
+ response = await client.post(
23
+ "/api/v1/auth/login",
24
+ data={
25
+ "username": "testuser@example.com",
26
+ "password": "testpass123"
27
+ }
28
+ )
29
+ return response.json()["access_token"]
30
+
31
+ async def test_create_product(client: AsyncClient, user_token: str):
32
+ # Test creating a product
33
+ response = await client.post(
34
+ "/api/v1/products/",
35
+ json={
36
+ "name": "Test Product",
37
+ "description": "A test product",
38
+ "price": 99.99,
39
+ "category": "test",
40
+ "inventory_count": 10
41
+ },
42
+ headers={"Authorization": f"Bearer {user_token}"}
43
+ )
44
+ assert response.status_code == 200
45
+ data = response.json()
46
+ assert data["name"] == "Test Product"
47
+ assert data["price"] == 99.99
48
+ return data["id"]
49
+
50
+ async def test_get_product(client: AsyncClient, user_token: str):
51
+ # First create a product
52
+ product_id = await test_create_product(client, user_token)
53
+
54
+ # Test getting the product
55
+ response = await client.get(
56
+ f"/api/v1/products/{product_id}",
57
+ headers={"Authorization": f"Bearer {user_token}"}
58
+ )
59
+ assert response.status_code == 200
60
+ data = response.json()
61
+ assert data["id"] == product_id
62
+ assert data["name"] == "Test Product"
63
+
64
+ async def test_list_products(client: AsyncClient, user_token: str):
65
+ # Create multiple products
66
+ await test_create_product(client, user_token)
67
+ await client.post(
68
+ "/api/v1/products/",
69
+ json={
70
+ "name": "Another Product",
71
+ "description": "Another test product",
72
+ "price": 49.99,
73
+ "category": "test",
74
+ "inventory_count": 5
75
+ },
76
+ headers={"Authorization": f"Bearer {user_token}"}
77
+ )
78
+
79
+ # Test listing products
80
+ response = await client.get(
81
+ "/api/v1/products/",
82
+ headers={"Authorization": f"Bearer {user_token}"}
83
+ )
84
+ assert response.status_code == 200
85
+ data = response.json()
86
+ assert len(data) >= 2
87
+ assert any(p["name"] == "Test Product" for p in data)
88
+ assert any(p["name"] == "Another Product" for p in data)
89
+
90
+ async def test_update_product(client: AsyncClient, user_token: str):
91
+ # First create a product
92
+ product_id = await test_create_product(client, user_token)
93
+
94
+ # Test updating the product
95
+ response = await client.put(
96
+ f"/api/v1/products/{product_id}",
97
+ json={
98
+ "name": "Updated Product",
99
+ "description": "Updated description",
100
+ "price": 149.99,
101
+ "category": "test",
102
+ "inventory_count": 20
103
+ },
104
+ headers={"Authorization": f"Bearer {user_token}"}
105
+ )
106
+ assert response.status_code == 200
107
+ data = response.json()
108
+ assert data["name"] == "Updated Product"
109
+ assert data["price"] == 149.99
110
+ assert data["inventory_count"] == 20
111
+
112
+ async def test_delete_product(client: AsyncClient, user_token: str):
113
+ # First create a product
114
+ product_id = await test_create_product(client, user_token)
115
+
116
+ # Test deleting the product
117
+ response = await client.delete(
118
+ f"/api/v1/products/{product_id}",
119
+ headers={"Authorization": f"Bearer {user_token}"}
120
+ )
121
+ assert response.status_code == 200
122
+
123
+ # Verify product is deleted
124
+ response = await client.get(
125
+ f"/api/v1/products/{product_id}",
126
+ headers={"Authorization": f"Bearer {user_token}"}
127
+ )
128
+ assert response.status_code == 404
tests/conftest.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pytest
3
+ import asyncio
4
+ from typing import AsyncGenerator, Generator
5
+ from fastapi.testclient import TestClient
6
+ from httpx import AsyncClient
7
+ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
8
+ from sqlalchemy.orm import sessionmaker
9
+ from sqlalchemy.pool import StaticPool
10
+ from dotenv import load_dotenv
11
+ from pathlib import Path
12
+
13
+ # Load test environment variables
14
+ test_env_path = Path(__file__).parent / "test.env"
15
+ load_dotenv(test_env_path)
16
+
17
+ from app.db.database import Base, get_db
18
+ from app.main import app
19
+ from app.core.config import settings
20
+
21
+ # Use SQLite for testing
22
+ SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///:memory:"
23
+
24
+ engine = create_async_engine(
25
+ SQLALCHEMY_DATABASE_URL,
26
+ connect_args={"check_same_thread": False},
27
+ poolclass=StaticPool,
28
+ )
29
+
30
+ TestingSessionLocal = sessionmaker(
31
+ engine,
32
+ class_=AsyncSession,
33
+ expire_on_commit=False,
34
+ )
35
+
36
+ @pytest.fixture(scope="session")
37
+ def event_loop() -> Generator:
38
+ """Create an instance of the default event loop for each test case."""
39
+ try:
40
+ loop = asyncio.get_event_loop()
41
+ except RuntimeError:
42
+ loop = asyncio.new_event_loop()
43
+ yield loop
44
+ loop.close()
45
+
46
+ @pytest.fixture(scope="session")
47
+ async def test_app():
48
+ """Create tables for testing and clean up afterward."""
49
+ # Create test upload directories
50
+ os.makedirs("./test_uploads/documents", exist_ok=True)
51
+ os.makedirs("./test_uploads/images", exist_ok=True)
52
+
53
+ # Create tables
54
+ async with engine.begin() as conn:
55
+ await conn.run_sync(Base.metadata.drop_all) # Ensure clean state
56
+ await conn.run_sync(Base.metadata.create_all)
57
+
58
+ yield app
59
+
60
+ # Cleanup
61
+ async with engine.begin() as conn:
62
+ await conn.run_sync(Base.metadata.drop_all)
63
+
64
+ @pytest.fixture
65
+ async def db_session() -> AsyncGenerator[AsyncSession, None]:
66
+ """Get a test database session."""
67
+ async with TestingSessionLocal() as session:
68
+ yield session
69
+ # Rollback any changes made in the test
70
+ await session.rollback()
71
+
72
+ @pytest.fixture
73
+ async def client(test_app) -> AsyncGenerator[AsyncClient, None]:
74
+ """Get a test client with database session override."""
75
+ async def override_get_db():
76
+ async with TestingSessionLocal() as session:
77
+ yield session
78
+
79
+ app.dependency_overrides[get_db] = override_get_db
80
+
81
+ async with AsyncClient(app=app, base_url="http://test") as client:
82
+ yield client
83
+
84
+ app.dependency_overrides.clear()
tests/test.env ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ PROJECT_NAME=Admin Dashboard Test
2
+ VERSION=1.0.0
3
+ API_V1_STR=/api/v1
4
+ SECRET_KEY=testingsecretkey123notforproduction
5
+ ALGORITHM=HS256
6
+ ACCESS_TOKEN_EXPIRE_MINUTES=30
7
+
8
+ # Database settings
9
+ DATABASE_URL=sqlite+aiosqlite:///:memory:
10
+
11
+ # Redis settings (using dummy values for testing)
12
+ REDIS_HOST=localhost
13
+ REDIS_PORT=6379
14
+
15
+ # Email settings (using dummy values for testing)
16
+ SMTP_HOST=localhost
17
+ SMTP_PORT=587
18
+ SMTP_USER=test@example.com
19
+ SMTP_PASSWORD=dummypassword
20
+ EMAILS_FROM_EMAIL=test@example.com
21
+ EMAILS_FROM_NAME=Test System
22
+
23
+ # Storage settings
24
+ MAX_UPLOAD_DIR_SIZE_MB=1024
25
+ UPLOAD_DIR=./test_uploads
26
+ MAX_DB_CONNECTIONS=100
tests/utils.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, Any
2
+ from httpx import AsyncClient
3
+ import json
4
+
5
+ async def create_user_and_login(
6
+ client: AsyncClient,
7
+ email: str = "testuser@example.com",
8
+ password: str = "testpass123",
9
+ full_name: str = "Test User",
10
+ is_superuser: bool = False
11
+ ) -> Dict[str, Any]:
12
+ """Create a test user and return their token and data"""
13
+ # Register user
14
+ register_response = await client.post(
15
+ "/api/v1/auth/register",
16
+ json={
17
+ "email": email,
18
+ "password": password,
19
+ "full_name": full_name,
20
+ "is_superuser": is_superuser
21
+ }
22
+ )
23
+ user_data = register_response.json()
24
+
25
+ # Login to get token
26
+ login_response = await client.post(
27
+ "/api/v1/auth/login",
28
+ data={
29
+ "username": email,
30
+ "password": password
31
+ }
32
+ )
33
+ token_data = login_response.json()
34
+
35
+ return {
36
+ "token": token_data["access_token"],
37
+ "user": user_data
38
+ }
39
+
40
+ async def create_branch(
41
+ client: AsyncClient,
42
+ token: str,
43
+ name: str = "Test Branch",
44
+ location: str = "Test Location"
45
+ ) -> Dict[str, Any]:
46
+ """Create a test branch and return its data"""
47
+ response = await client.post(
48
+ "/api/v1/branches/",
49
+ json={
50
+ "name": name,
51
+ "location": location
52
+ },
53
+ headers={"Authorization": f"Bearer {token}"}
54
+ )
55
+ return response.json()
56
+
57
+ async def create_product(
58
+ client: AsyncClient,
59
+ token: str,
60
+ branch_id: int,
61
+ name: str = "Test Product",
62
+ price: float = 99.99,
63
+ inventory: int = 10
64
+ ) -> Dict[str, Any]:
65
+ """Create a test product and return its data"""
66
+ response = await client.post(
67
+ "/api/v1/products/",
68
+ json={
69
+ "name": name,
70
+ "description": f"Description for {name}",
71
+ "price": price,
72
+ "category": "test",
73
+ "inventory_count": inventory,
74
+ "branch_id": branch_id
75
+ },
76
+ headers={"Authorization": f"Bearer {token}"}
77
+ )
78
+ return response.json()
79
+
80
+ async def create_order(
81
+ client: AsyncClient,
82
+ token: str,
83
+ items: list,
84
+ branch_id: int
85
+ ) -> Dict[str, Any]:
86
+ """Create a test order and return its data"""
87
+ response = await client.post(
88
+ "/api/v1/orders/",
89
+ json={
90
+ "items": items,
91
+ "branch_id": branch_id
92
+ },
93
+ headers={"Authorization": f"Bearer {token}"}
94
+ )
95
+ return response.json()
96
+
97
+ def assert_response_matches_schema(response_data: Dict[str, Any], schema: Dict[str, Any]):
98
+ """Assert that an API response matches its expected schema"""
99
+ assert all(key in response_data for key in schema.keys()), \
100
+ f"Missing required fields. Expected {schema.keys()}, got {response_data.keys()}"
101
+
102
+ for key, value_type in schema.items():
103
+ assert isinstance(response_data[key], value_type), \
104
+ f"Field {key} should be of type {value_type}, got {type(response_data[key])}"