mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-09-21 05:15:00 -04:00
FE+BE: performance improvements
This commit is contained in:
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
|
||||
|
||||
@@ -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"""
|
||||
|
||||
Reference in new issue
Block a user