This commit is contained in:
Mateusz Gruszczyński
2026-09-04 11:00:15 +02:00
parent 8152e63d63
commit 236540e0f0
27 changed files with 557 additions and 102 deletions
+20 -4
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Developer smoke/integration tests for GREE Controller API 0.12.1.
"""Developer smoke/integration tests for GREE Controller API 0.13.0.
Default mode is read-only and safe to run against a real controller.
Use --settings-write to additionally round-trip all split settings resources and
@@ -26,7 +26,7 @@ from typing import Any, Callable, Iterable, Optional
DEFAULT_BASE_URL = os.environ.get("GREE_API_URL", "http://127.0.0.1:8787")
DEFAULT_TOKEN = os.environ.get("GREE_API_TOKEN", "")
DEFAULT_EXPECTED_VERSION = "0.12.1"
DEFAULT_EXPECTED_VERSION = "0.13.0"
SETTINGS_PATHS: dict[str, set[str]] = {
"/api/settings/application": {"simulator_enabled"},
@@ -113,6 +113,7 @@ HA_SAFE_GET_PATHS = [
"/api/integrations/home-assistant/devices",
"/api/integrations/home-assistant/control-plan",
"/api/integrations/home-assistant/groups",
"/api/integrations/home-assistant/snapshot",
]
DETAIL_COLLECTIONS = [
@@ -127,6 +128,7 @@ DETAIL_COLLECTIONS = [
EXPECTED_OPENAPI_PATHS = set(SETTINGS_PATHS) | {
"/api/configuration/export",
"/api/configuration/import",
"/api/integrations/home-assistant/snapshot",
}
@@ -381,6 +383,20 @@ def test_ha_safe_get(client: ApiClient, path: str) -> str:
return "restricted HA auth enforced (no token supplied)"
assert_status(resp, 200)
data = resp.json()
if path == "/api/integrations/home-assistant/snapshot":
if not isinstance(data, dict):
raise TestFailure(f"snapshot is not an object: {type(data).__name__}")
required = {"devices", "control_plan", "control_plan_revision", "groups"}
missing = sorted(required - set(data))
if missing:
raise TestFailure(f"snapshot missing keys: {missing}")
if not isinstance(data["devices"], list) or not isinstance(data["groups"], list):
raise TestFailure("snapshot devices/groups must be arrays")
if not isinstance(data["control_plan"], dict):
raise TestFailure("snapshot control_plan must be an object")
if not isinstance(data["control_plan_revision"], int):
raise TestFailure("snapshot control_plan_revision must be an integer")
return f"devices={len(data['devices'])}, groups={len(data['groups'])}, revision={data['control_plan_revision']}"
if not isinstance(data, (list, dict)):
raise TestFailure(f"unexpected JSON type {type(data).__name__}")
if isinstance(data, list):
@@ -503,7 +519,7 @@ def run_suite(args: argparse.Namespace) -> int:
print(f"Settings write tests: {'ENABLED' if args.settings_write else 'disabled'}\n")
runner.run("public health", lambda: test_health(client, args.expected_version))
runner.run("OpenAPI 0.12.1 contract", lambda: test_openapi(client, args.expected_version))
runner.run("OpenAPI 0.13.0 contract", lambda: test_openapi(client, args.expected_version))
runner.run("protected API requires auth", lambda: test_protected_auth(client))
for path in SAFE_GET_PATHS:
@@ -571,7 +587,7 @@ def run_suite(args: argparse.Namespace) -> int:
def parse_args(argv: Optional[Iterable[str]] = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Developer smoke/integration tests for GREE Controller API 0.12.1.",
description="Developer smoke/integration tests for GREE Controller API 0.13.0.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""Examples:
python3 scripts/api_dev_test.py