test: add stock operations and offline sync tests
This commit is contained in:
189
backend/tests/test_operations.py
Normal file
189
backend/tests/test_operations.py
Normal file
@@ -0,0 +1,189 @@
|
||||
import pytest
|
||||
from fastapi import status
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class TestStockOperations:
|
||||
"""Test check-in and check-out operations."""
|
||||
|
||||
def test_check_in_item(self, test_client, test_db):
|
||||
"""Test checking in inventory (increasing quantity)."""
|
||||
from backend.models import Item
|
||||
|
||||
item = Item(
|
||||
name="Test Item",
|
||||
category="Electronics",
|
||||
item_type="Component",
|
||||
quantity=10,
|
||||
barcode="123456789",
|
||||
part_number="PN-12345"
|
||||
)
|
||||
test_db.add(item)
|
||||
test_db.commit()
|
||||
|
||||
response = test_client.post(
|
||||
"/api/operations/check-in",
|
||||
json={"item_id": item.id, "quantity": 5}
|
||||
)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert data["new_quantity"] == 15
|
||||
|
||||
def test_check_out_item(self, test_client, test_db):
|
||||
"""Test checking out inventory (decreasing quantity)."""
|
||||
from backend.models import Item
|
||||
|
||||
item = Item(
|
||||
name="Test Item",
|
||||
category="Electronics",
|
||||
item_type="Component",
|
||||
quantity=10,
|
||||
barcode="123456789",
|
||||
part_number="PN-12345"
|
||||
)
|
||||
test_db.add(item)
|
||||
test_db.commit()
|
||||
|
||||
response = test_client.post(
|
||||
"/api/operations/check-out",
|
||||
json={"item_id": item.id, "quantity": 3}
|
||||
)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert data["new_quantity"] == 7
|
||||
|
||||
def test_check_out_insufficient_quantity(self, test_client, test_db):
|
||||
"""Test that check-out fails if quantity insufficient."""
|
||||
from backend.models import Item
|
||||
|
||||
item = Item(
|
||||
name="Test Item",
|
||||
category="Electronics",
|
||||
item_type="Component",
|
||||
quantity=5,
|
||||
barcode="123456789",
|
||||
part_number="PN-12345"
|
||||
)
|
||||
test_db.add(item)
|
||||
test_db.commit()
|
||||
|
||||
response = test_client.post(
|
||||
"/api/operations/check-out",
|
||||
json={"item_id": item.id, "quantity": 10}
|
||||
)
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
def test_audit_log_created(self, test_client, test_db):
|
||||
"""Test that audit log entry created for each operation."""
|
||||
from backend.models import Item
|
||||
|
||||
item = Item(
|
||||
name="Test Item",
|
||||
category="Electronics",
|
||||
item_type="Component",
|
||||
quantity=10,
|
||||
barcode="123456789",
|
||||
part_number="PN-12345"
|
||||
)
|
||||
test_db.add(item)
|
||||
test_db.commit()
|
||||
|
||||
# Perform operation
|
||||
response = test_client.post(
|
||||
"/api/operations/check-in",
|
||||
json={"item_id": item.id, "quantity": 5}
|
||||
)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
# Verify audit log
|
||||
response = test_client.get(f"/api/audit-logs?item_id={item.id}")
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
logs = response.json()
|
||||
assert len(logs) > 0
|
||||
assert logs[-1]["operation"] == "CHECK_IN"
|
||||
assert logs[-1]["quantity_change"] == 5
|
||||
|
||||
|
||||
class TestBulkSync:
|
||||
"""Test offline sync with UUID idempotency."""
|
||||
|
||||
def test_bulk_sync_offline_operations(self, test_client, test_db):
|
||||
"""Test syncing multiple offline-generated operations."""
|
||||
from backend.models import Item
|
||||
|
||||
item = Item(
|
||||
name="Test Item",
|
||||
category="Electronics",
|
||||
item_type="Component",
|
||||
quantity=10,
|
||||
barcode="123456789",
|
||||
part_number="PN-12345"
|
||||
)
|
||||
test_db.add(item)
|
||||
test_db.commit()
|
||||
|
||||
# Simulate offline operations with UUIDs
|
||||
response = test_client.post(
|
||||
"/api/bulk-sync",
|
||||
json={
|
||||
"operations": [
|
||||
{
|
||||
"id": "uuid-1",
|
||||
"type": "CHECK_IN",
|
||||
"item_id": item.id,
|
||||
"quantity": 5
|
||||
},
|
||||
{
|
||||
"id": "uuid-2",
|
||||
"type": "CHECK_IN",
|
||||
"item_id": item.id,
|
||||
"quantity": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert data["synced"] == 2
|
||||
assert data["final_quantity"] == 18
|
||||
|
||||
def test_bulk_sync_idempotent(self, test_client, test_db):
|
||||
"""Test that syncing same UUID twice doesn't duplicate."""
|
||||
from backend.models import Item
|
||||
|
||||
item = Item(
|
||||
name="Test Item",
|
||||
category="Electronics",
|
||||
item_type="Component",
|
||||
quantity=10,
|
||||
barcode="123456789",
|
||||
part_number="PN-12345"
|
||||
)
|
||||
test_db.add(item)
|
||||
test_db.commit()
|
||||
|
||||
operation = {
|
||||
"id": "uuid-1",
|
||||
"type": "CHECK_IN",
|
||||
"item_id": item.id,
|
||||
"quantity": 5
|
||||
}
|
||||
|
||||
# Sync once
|
||||
response1 = test_client.post(
|
||||
"/api/bulk-sync",
|
||||
json={"operations": [operation]}
|
||||
)
|
||||
assert response1.status_code == status.HTTP_200_OK
|
||||
q1 = response1.json()["final_quantity"]
|
||||
|
||||
# Sync again (same UUID)
|
||||
response2 = test_client.post(
|
||||
"/api/bulk-sync",
|
||||
json={"operations": [operation]}
|
||||
)
|
||||
assert response2.status_code == status.HTTP_200_OK
|
||||
q2 = response2.json()["final_quantity"]
|
||||
|
||||
# Quantity should not increase twice
|
||||
assert q1 == q2 == 15
|
||||
Reference in New Issue
Block a user