Add versioned HTTP API routes
This commit is contained in:
@@ -22,14 +22,41 @@ def assert_keys(payload, keys):
|
||||
|
||||
|
||||
def registered_routes():
|
||||
pattern = re.compile(r'server\.on\("([^"]+)"(?:,\s*(HTTP_[A-Z]+))?')
|
||||
return {(match.group(1), match.group(2) or "ANY") for match in pattern.finditer(firmware_source())}
|
||||
source = firmware_source()
|
||||
literal_pattern = re.compile(r'server\.on\("([^"]+)"(?:,\s*(HTTP_[A-Z]+))?')
|
||||
macro_pattern = re.compile(r'server\.on\(API_V1\("([^"]+)"\)(?:,\s*(HTTP_[A-Z]+))?')
|
||||
|
||||
routes = {(match.group(1), match.group(2) or "ANY") for match in literal_pattern.finditer(source)}
|
||||
routes.update({
|
||||
(f"/api/v1{match.group(1)}", match.group(2) or "ANY")
|
||||
for match in macro_pattern.finditer(source)
|
||||
})
|
||||
return routes
|
||||
|
||||
|
||||
def test_firmware_registers_current_http_contract_routes():
|
||||
routes = registered_routes()
|
||||
|
||||
expected_routes = {
|
||||
("/api/v1/status", "ANY"),
|
||||
("/api/v1/config", "HTTP_GET"),
|
||||
("/api/v1/relay/set", "HTTP_POST"),
|
||||
("/api/v1/config/wifi", "HTTP_GET"),
|
||||
("/api/v1/config/wifi", "HTTP_POST"),
|
||||
("/api/v1/wifi/connect", "HTTP_POST"),
|
||||
("/api/v1/wifi/clear", "HTTP_POST"),
|
||||
("/api/v1/temps/scan", "HTTP_POST"),
|
||||
("/api/v1/temps/assign", "HTTP_POST"),
|
||||
("/api/v1/temps/clear", "HTTP_POST"),
|
||||
}
|
||||
|
||||
assert expected_routes <= routes
|
||||
|
||||
|
||||
def test_firmware_keeps_root_compatibility_aliases():
|
||||
routes = registered_routes()
|
||||
|
||||
compatibility_routes = {
|
||||
("/status", "ANY"),
|
||||
("/config", "HTTP_GET"),
|
||||
("/relay/set", "HTTP_POST"),
|
||||
@@ -42,7 +69,21 @@ def test_firmware_registers_current_http_contract_routes():
|
||||
("/temps/clear", "HTTP_POST"),
|
||||
}
|
||||
|
||||
assert expected_routes <= routes
|
||||
assert compatibility_routes <= routes
|
||||
|
||||
|
||||
def test_embedded_webui_uses_versioned_api_routes():
|
||||
source = firmware_source()
|
||||
|
||||
assert 'const API_BASE="/api/v1";' in source
|
||||
assert 'fetch(api("' in source
|
||||
assert 'fetch("/status"' not in source
|
||||
assert 'fetch("/config' not in source
|
||||
assert 'fetch("/relay' not in source
|
||||
assert 'fetch("/temps' not in source
|
||||
assert 'fetch("/wifi' not in source
|
||||
assert "/bms/reconnect" not in source
|
||||
assert "/system/restart" not in source
|
||||
|
||||
|
||||
def test_status_fixture_matches_dashboard_contract_shape():
|
||||
|
||||
+33
-11
@@ -241,6 +241,7 @@ class FakeResponse:
|
||||
class FakeRequests:
|
||||
def __init__(self):
|
||||
self.urls = []
|
||||
self.posts = []
|
||||
self.responses = []
|
||||
|
||||
def get(self, url):
|
||||
@@ -251,6 +252,15 @@ class FakeRequests:
|
||||
|
||||
return FakeResponse({"ok": True})
|
||||
|
||||
def post(self, url, json=None):
|
||||
self.urls.append(url)
|
||||
self.posts.append({"url": url, "json": json})
|
||||
|
||||
if self.responses:
|
||||
return FakeResponse(self.responses.pop(0))
|
||||
|
||||
return FakeResponse({"ok": True})
|
||||
|
||||
|
||||
def test_http_client_get_status():
|
||||
from comms.http_client import HttpClient
|
||||
@@ -264,7 +274,7 @@ def test_http_client_get_status():
|
||||
|
||||
payload = client.get_status()
|
||||
|
||||
assert fake_requests.urls == ["http://192.168.4.1/status"]
|
||||
assert fake_requests.urls == ["http://192.168.4.1/api/v1/status"]
|
||||
assert payload["type"] == "status_response"
|
||||
assert payload["battery"]["soc"] == 82
|
||||
|
||||
@@ -275,9 +285,13 @@ def test_http_client_set_relay_on():
|
||||
fake_requests = FakeRequests()
|
||||
client = HttpClient(fake_requests)
|
||||
|
||||
payload = client.set_relay("starlink", True)
|
||||
payload = client.set_relay("relay_1", True)
|
||||
|
||||
assert fake_requests.urls == ["http://192.168.4.1/relay/starlink/on"]
|
||||
assert fake_requests.urls == ["http://192.168.4.1/api/v1/relay/set"]
|
||||
assert fake_requests.posts == [{
|
||||
"url": "http://192.168.4.1/api/v1/relay/set",
|
||||
"json": {"id": "relay_1", "state": True},
|
||||
}]
|
||||
assert payload == {"ok": True}
|
||||
|
||||
|
||||
@@ -287,9 +301,13 @@ def test_http_client_set_relay_off():
|
||||
fake_requests = FakeRequests()
|
||||
client = HttpClient(fake_requests)
|
||||
|
||||
payload = client.set_relay("fridge", False)
|
||||
payload = client.set_relay("relay_2", False)
|
||||
|
||||
assert fake_requests.urls == ["http://192.168.4.1/relay/fridge/off"]
|
||||
assert fake_requests.urls == ["http://192.168.4.1/api/v1/relay/set"]
|
||||
assert fake_requests.posts == [{
|
||||
"url": "http://192.168.4.1/api/v1/relay/set",
|
||||
"json": {"id": "relay_2", "state": False},
|
||||
}]
|
||||
assert payload == {"ok": True}
|
||||
|
||||
|
||||
@@ -317,7 +335,7 @@ def test_communication_service_http_fallback_status():
|
||||
assert response["type"] == "status_response"
|
||||
assert state.battery["soc"] == 66
|
||||
assert fake_uart.writes == []
|
||||
assert fake_requests.urls == ["http://192.168.4.1/status"]
|
||||
assert fake_requests.urls == ["http://192.168.4.1/api/v1/status"]
|
||||
|
||||
|
||||
def test_communication_service_http_fallback_relay():
|
||||
@@ -330,8 +348,8 @@ def test_communication_service_http_fallback_relay():
|
||||
fake_requests.responses = [
|
||||
{
|
||||
"type": "relay_response",
|
||||
"relay": "fridge",
|
||||
"enabled": True,
|
||||
"id": "relay_1",
|
||||
"state": True,
|
||||
"ok": True,
|
||||
}
|
||||
]
|
||||
@@ -344,12 +362,16 @@ def test_communication_service_http_fallback_relay():
|
||||
)
|
||||
|
||||
service.enable_http_fallback()
|
||||
response = service.set_relay("fridge", True)
|
||||
response = service.set_relay("relay_1", True)
|
||||
|
||||
assert response["type"] == "relay_response"
|
||||
assert state.relays["fridge"] is True
|
||||
assert state.relays["relay_1"] is True
|
||||
assert fake_uart.writes == []
|
||||
assert fake_requests.urls == ["http://192.168.4.1/relay/fridge/on"]
|
||||
assert fake_requests.urls == ["http://192.168.4.1/api/v1/relay/set"]
|
||||
assert fake_requests.posts == [{
|
||||
"url": "http://192.168.4.1/api/v1/relay/set",
|
||||
"json": {"id": "relay_1", "state": True},
|
||||
}]
|
||||
|
||||
|
||||
def test_communication_service_marks_uart_connected_on_status():
|
||||
|
||||
Reference in New Issue
Block a user