FE+BE: performance improvements

This commit is contained in:
jokob-sk committed 2026-09-14 08:29:02 +10:00
1 parent cff3ddfc38
commit f52de6cbdc
23 files changed
+428 -31

No files matched your search

@@ -208,6 +208,53 @@ def test_devices_by_status(client, api_token, test_mac):
delete_dummy(client, api_token, test_mac)
def test_devices_by_status_pagination(client, api_token):
"""limit/offset must page through the same set ORDER BY devMac gives
unpaginated, with no gaps or duplicates, and must reject invalid values.
Doesn't assume an otherwise-empty DB: reconstructs the full 'my' list from
pages and compares it to the unpaginated response instead of asserting
exact positions for the 3 dummies.
"""
macs = [f"aa:bb:cc:dd:ee:0{i}" for i in (1, 2, 3)]
for mac in macs:
create_dummy(client, api_token, mac)
try:
full_resp = client.get("/devices/by-status?status=my", headers=auth_headers(api_token))
assert full_resp.status_code == 200
full_macs = [d["id"] for d in full_resp.json]
assert set(macs).issubset(set(full_macs))
# Page through the full set in halves and confirm the reassembled
# list matches the unpaginated one exactly (no gaps/duplicates).
total = len(full_macs)
half = (total + 1) // 2
page1 = client.get(
f"/devices/by-status?status=my&limit={half}&offset=0",
headers=auth_headers(api_token),
).json
page2 = client.get(
f"/devices/by-status?status=my&limit={total - half}&offset={half}",
headers=auth_headers(api_token),
).json
paged_macs = [d["id"] for d in page1] + [d["id"] for d in page2]
assert paged_macs == full_macs
# Invalid limit/offset are rejected, not silently clamped.
resp_bad_limit = client.get(
"/devices/by-status?status=my&limit=0", headers=auth_headers(api_token)
)
assert resp_bad_limit.status_code == 422
resp_bad_offset = client.get(
"/devices/by-status?status=my&offset=-1", headers=auth_headers(api_token)
)
assert resp_bad_offset.status_code == 422
finally:
for mac in macs:
delete_dummy(client, api_token, mac)
def test_delete_test_devices(client, api_token):
# Delete by MAC
+42 -1
View File
@@ -5,7 +5,7 @@ import pytest
INSTALL_PATH = "/app"
sys.path.extend([f"{INSTALL_PATH}/server/plugins", f"{INSTALL_PATH}/server"])
from helper import get_setting_value # noqa: E402 [flake8 lint suppression]
from helper import get_setting_value, count_children_by_parent_mac # noqa: E402 [flake8 lint suppression]
from api_server.api_server_start import app # noqa: E402 [flake8 lint suppression]
@@ -79,6 +79,47 @@ def test_graphql_post_devices(client, api_token):
assert isinstance(data["devices"]["count"], int)
def test_graphql_devices_parent_children_count_matches_recount(client, api_token):
"""devParentChildrenCount for every returned device must match an independent
recount of the same response (regression guard for the O(n^2)->O(n) rewrite of
resolve_devices()/count_children_by_parent_mac() in graphql_endpoint.py/helper.py).
Not seeded against a freshly-created fixture pair: table_devices.json (what
resolve_devices() reads) is only refreshed by the periodic update_api() loop,
not synchronously on a POST /device/<mac> create - a create-then-query test
would be flaky against snapshot staleness. Recomputing from the response
itself avoids that while still exercising the real resolver wiring.
"""
query = {
"query": """
{
devices {
devices {
devMac
devParentMAC
devParentChildrenCount
}
count
}
}
"""
}
resp = client.post("/graphql", json=query, headers=auth_headers(api_token))
assert resp.status_code == 200
devices = resp.get_json()["data"]["devices"]["devices"]
expected_counts = count_children_by_parent_mac(
[{"devParentMAC": d["devParentMAC"]} for d in devices]
)
for device in devices:
expected = expected_counts.get((device["devMac"] or "").strip(), 0)
assert device["devParentChildrenCount"] == expected, (
f"devMac={device['devMac']}: expected {expected}, "
f"got {device['devParentChildrenCount']}"
)
# --- SETTINGS TESTS ---
def test_graphql_post_settings(client, api_token):
"""POST /graphql should return settings data"""