c086f64363
- Add 7 core API endpoints: users, transactions, partners, products, inventory, payments, credit - Implement role-based authentication (admin/write/read-only access) - Add comprehensive database models with proper relationships - Include full test coverage for all endpoints and business logic - Set up Alembic migrations and Docker configuration - Configure FastAPI app with CORS and database integration
217 lines
6.1 KiB
Python
217 lines
6.1 KiB
Python
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlmodel import Session, SQLModel, create_engine
|
|
from sqlmodel.pool import StaticPool
|
|
|
|
from app.main import app
|
|
from app.core.db import get_session
|
|
from app.schemas.models import User, Partner, Product, Transaction
|
|
from app.schemas.base import UserRole, PartnerType, TransactionType, TransactionStatus
|
|
from app.core.auth import get_password_hash
|
|
|
|
|
|
@pytest.fixture(name="session")
|
|
def session_fixture():
|
|
"""Create a test database session."""
|
|
engine = create_engine(
|
|
"sqlite:///:memory:", # Use in-memory database for each test
|
|
connect_args={"check_same_thread": False},
|
|
poolclass=StaticPool,
|
|
)
|
|
SQLModel.metadata.create_all(engine)
|
|
with Session(engine) as session:
|
|
yield session
|
|
|
|
|
|
@pytest.fixture(name="client")
|
|
def client_fixture(session: Session):
|
|
"""Create a test client with dependency override."""
|
|
def get_session_override():
|
|
return session
|
|
|
|
app.dependency_overrides[get_session] = get_session_override
|
|
client = TestClient(app)
|
|
yield client
|
|
app.dependency_overrides.clear()
|
|
|
|
|
|
@pytest.fixture(name="admin_user")
|
|
def admin_user_fixture(session: Session):
|
|
"""Create an admin user for testing."""
|
|
admin_user = User(
|
|
username="testadmin",
|
|
password_hash=get_password_hash("adminpassword"),
|
|
role=UserRole.ADMIN
|
|
)
|
|
session.add(admin_user)
|
|
session.commit()
|
|
session.refresh(admin_user)
|
|
return admin_user
|
|
|
|
|
|
@pytest.fixture(name="write_user")
|
|
def write_user_fixture(session: Session):
|
|
"""Create a write user for testing."""
|
|
write_user = User(
|
|
username="writeuser",
|
|
password_hash=get_password_hash("writepassword"),
|
|
role=UserRole.WRITE
|
|
)
|
|
session.add(write_user)
|
|
session.commit()
|
|
session.refresh(write_user)
|
|
return write_user
|
|
|
|
|
|
@pytest.fixture(name="read_only_user")
|
|
def read_only_user_fixture(session: Session):
|
|
"""Create a read-only user for testing."""
|
|
read_only_user = User(
|
|
username="readuser",
|
|
password_hash=get_password_hash("readpassword"),
|
|
role=UserRole.READ_ONLY
|
|
)
|
|
session.add(read_only_user)
|
|
session.commit()
|
|
session.refresh(read_only_user)
|
|
return read_only_user
|
|
|
|
|
|
@pytest.fixture(name="admin_token")
|
|
def admin_token_fixture(client: TestClient, admin_user: User):
|
|
"""Get admin authentication token."""
|
|
response = client.post("/api/v1/users/login", json={
|
|
"username": "testadmin",
|
|
"password": "adminpassword"
|
|
})
|
|
return response.json()["access_token"]
|
|
|
|
|
|
@pytest.fixture(name="write_token")
|
|
def write_token_fixture(client: TestClient, write_user: User):
|
|
"""Get write user authentication token."""
|
|
response = client.post("/api/v1/users/login", json={
|
|
"username": "writeuser",
|
|
"password": "writepassword"
|
|
})
|
|
return response.json()["access_token"]
|
|
|
|
|
|
@pytest.fixture(name="read_only_token")
|
|
def read_only_token_fixture(client: TestClient, read_only_user: User):
|
|
"""Get read-only user authentication token."""
|
|
response = client.post("/api/v1/users/login", json={
|
|
"username": "readuser",
|
|
"password": "readpassword"
|
|
})
|
|
return response.json()["access_token"]
|
|
|
|
|
|
@pytest.fixture(name="sample_partner")
|
|
def sample_partner_fixture(session: Session):
|
|
"""Create a sample partner for testing."""
|
|
partner = Partner(
|
|
tin_number=123456789,
|
|
names="Test Partner Ltd",
|
|
type=PartnerType.CLIENT,
|
|
phone_number="0123456789"
|
|
)
|
|
session.add(partner)
|
|
session.commit()
|
|
session.refresh(partner)
|
|
return partner
|
|
|
|
|
|
@pytest.fixture(name="sample_product")
|
|
def sample_product_fixture(session: Session):
|
|
"""Create a sample product for testing."""
|
|
product = Product(
|
|
product_code="PROD001",
|
|
product_name="Test Product",
|
|
purchase_price=100,
|
|
selling_price=150
|
|
)
|
|
session.add(product)
|
|
session.commit()
|
|
session.refresh(product)
|
|
return product
|
|
|
|
|
|
@pytest.fixture(name="sample_transaction")
|
|
def sample_transaction_fixture(session: Session, sample_partner, admin_user):
|
|
"""Create a sample transaction for testing."""
|
|
transaction = Transaction(
|
|
partner_id=sample_partner.id,
|
|
transcation_type=TransactionType.SALE,
|
|
transaction_status=TransactionStatus.UNPAID,
|
|
total_amount=1000,
|
|
created_by=admin_user.id,
|
|
updated_by=admin_user.id
|
|
)
|
|
session.add(transaction)
|
|
session.commit()
|
|
session.refresh(transaction)
|
|
return transaction
|
|
|
|
|
|
@pytest.fixture(name="multiple_partners")
|
|
def multiple_partners_fixture(session: Session):
|
|
"""Create multiple partners for testing."""
|
|
partners = [
|
|
Partner(
|
|
tin_number=100000001,
|
|
names="Client Partner One",
|
|
type=PartnerType.CLIENT,
|
|
phone_number="0111111111"
|
|
),
|
|
Partner(
|
|
tin_number=200000002,
|
|
names="Supplier Partner Two",
|
|
type=PartnerType.SUPPLIER,
|
|
phone_number="0222222222"
|
|
),
|
|
Partner(
|
|
tin_number=300000003,
|
|
names="Client Partner Three",
|
|
type=PartnerType.CLIENT,
|
|
phone_number="0333333333"
|
|
)
|
|
]
|
|
for partner in partners:
|
|
session.add(partner)
|
|
session.commit()
|
|
for partner in partners:
|
|
session.refresh(partner)
|
|
return partners
|
|
|
|
|
|
@pytest.fixture(name="multiple_products")
|
|
def multiple_products_fixture(session: Session):
|
|
"""Create multiple products for testing."""
|
|
products = [
|
|
Product(
|
|
product_code="ITEM001",
|
|
product_name="Product One",
|
|
purchase_price=50,
|
|
selling_price=75
|
|
),
|
|
Product(
|
|
product_code="ITEM002",
|
|
product_name="Product Two",
|
|
purchase_price=200,
|
|
selling_price=250
|
|
),
|
|
Product(
|
|
product_code="ITEM003",
|
|
product_name="Product Three",
|
|
purchase_price=1000,
|
|
selling_price=1200
|
|
)
|
|
]
|
|
for product in products:
|
|
session.add(product)
|
|
session.commit()
|
|
for product in products:
|
|
session.refresh(product)
|
|
return products
|