Files
Internal-apps/roles/trade_hub/files/trade-hub/backend/tests/test_api.py
2026-11-13 12:47:35 -07:00

194 lines
6.1 KiB
Python

"""API tests for the Star Citizen inventory backend (fixture dataset)."""
from fastapi.testclient import TestClient
from app.api import app
client = TestClient(app)
def test_healthz():
resp = client.get("/healthz")
assert resp.status_code == 200
body = resp.json()
assert body["status"] == "ok"
assert body["counts"] == {
"ships": 2,
"ship-items": 2,
"fps-items": 1,
"commodities": 4,
}
def test_stats():
resp = client.get("/api/v1/stats")
assert resp.status_code == 200
body = resp.json()
assert body["categories"] == {
"ships": 2,
"ship-items": 2,
"fps-items": 1,
"commodities": 4,
}
assert body["manufacturers"] == 4
def test_manufacturers_sorted_by_name():
resp = client.get("/api/v1/manufacturers")
assert resp.status_code == 200
names = [m["name"] for m in resp.json()]
assert names == ["Anvil Aerospace", "Behring", "PHLD", "Unknown Manufacturer"]
def test_items_default_pagination():
resp = client.get("/api/v1/items")
assert resp.status_code == 200
body = resp.json()
assert body["total"] == 9
assert body["page"] == 1
assert body["page_size"] == 25
assert body["total_pages"] == 1
assert len(body["items"]) == 9
def test_items_page_size_capped():
resp = client.get("/api/v1/items", params={"page_size": 500})
assert resp.status_code == 200
assert resp.json()["page_size"] == 100
def test_items_page_size_minimum_enforced():
resp = client.get("/api/v1/items", params={"page_size": 0})
assert resp.status_code == 422 # pydantic ge=1 validation
def test_items_category_filter():
resp = client.get("/api/v1/items", params={"category": "ships"})
assert resp.status_code == 200
body = resp.json()
assert body["total"] == 2
assert all(i["category"] == "ships" for i in body["items"])
def test_items_invalid_category_rejected():
resp = client.get("/api/v1/items", params={"category": "bogus"})
assert resp.status_code == 422
def test_items_search_matches_name_case_insensitive():
resp = client.get("/api/v1/items", params={"search": "carrack"})
body = resp.json()
assert body["total"] == 1
assert body["items"][0]["name"] == "Anvil Carrack"
def test_items_search_matches_class_name():
resp = client.get("/api/v1/items", params={"search": "test_ph"})
body = resp.json()
assert body["total"] == 1
assert body["items"][0]["class_name"] == "TEST_Ph_Item"
def test_items_manufacturer_filter_case_insensitive():
resp = client.get("/api/v1/items", params={"manufacturer": "behr"})
body = resp.json()
assert body["total"] == 2 # Behring shield + Behring rifle
assert all(i["manufacturer"]["code"] == "BEHR" for i in body["items"])
def test_items_type_filter_case_insensitive():
resp = client.get("/api/v1/items", params={"type": "weaponpersonal"})
body = resp.json()
assert body["total"] == 1
assert body["items"][0]["class_name"] == "BEHR_Rifle_Ballistic_01"
def test_items_size_filter():
resp = client.get("/api/v1/items", params={"size": 2})
body = resp.json()
assert body["total"] == 2 # TEST_Ph_Item (size 2) + rifle (size 2)
assert {i["class_name"] for i in body["items"]} == {
"TEST_Ph_Item",
"BEHR_Rifle_Ballistic_01",
}
def test_item_detail_ship():
resp = client.get("/api/v1/items/ANVL_Carrack")
assert resp.status_code == 200
body = resp.json()
assert body["name"] == "Anvil Carrack"
assert body["category"] == "ships"
assert body["details"]["crew"] == 4
assert body["details"]["is_spaceship"] is True
assert body["details"]["length"] == 35.0
def test_item_detail_item_ports():
resp = client.get("/api/v1/items/BEHR_Rifle_Ballistic_01")
assert resp.status_code == 200
body = resp.json()
assert body["details"]["ports"][0]["PortName"] == "magazine_attach"
assert body["details"]["mass"] == 4
def test_item_detail_404():
resp = client.get("/api/v1/items/NOPE_Does_Not_Exist")
assert resp.status_code == 404
assert resp.json()["detail"] == "Item 'NOPE_Does_Not_Exist' not found"
def test_placeholder_name_falls_back_to_class_name():
# Ship with Name == "<= PLACEHOLDER =>"
resp = client.get("/api/v1/items/TEST_Placeholder_Ship")
assert resp.status_code == 200
assert resp.json()["name"] == "TEST Placeholder Ship"
# Item with stdItem.Name == "<= PLACEHOLDER =>"
resp = client.get("/api/v1/items/TEST_Ph_Item")
assert resp.status_code == 200
assert resp.json()["name"] == "TEST Ph Item"
def test_manufacturer_placeholder_name_falls_back_to_code():
# manufacturers.json entry with Name == "<= PLACEHOLDER =>"
resp = client.get("/api/v1/manufacturers")
phld = [m for m in resp.json() if m["code"] == "PHLD"]
assert len(phld) == 1
assert phld[0]["name"] == "PHLD"
# Item whose embedded manufacturer Name is a placeholder
resp = client.get("/api/v1/items/TEST_Ph_Item")
assert resp.json()["manufacturer"]["name"] == "UNKN"
def test_deterministic_sort_order():
body = client.get("/api/v1/items", params={"page_size": 100}).json()
keys = [(i["category"], i["name"].lower()) for i in body["items"]]
assert keys == sorted(keys)
def test_items_category_filter_commodities():
resp = client.get("/api/v1/items", params={"category": "commodities"})
assert resp.status_code == 200
body = resp.json()
assert body["total"] == 4
assert all(i["category"] == "commodities" for i in body["items"])
def test_items_search_matches_refined_and_ore_iron():
resp = client.get("/api/v1/items", params={"search": "iron"})
body = resp.json()
assert body["total"] == 2
assert {i["name"] for i in body["items"]} == {"Iron", "Iron (Ore)"}
def test_item_detail_commodity():
resp = client.get("/api/v1/items/Carryable_TBO_FL_1SCU_Commodity_Metal_Ore_Iron")
assert resp.status_code == 200
body = resp.json()
assert body["name"] == "Iron (Ore)"
assert body["category"] == "commodities"
assert body["type"] == "Cargo"
assert body["size"] is None
assert isinstance(body["details"], dict)