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