Skip to content

Commit c7a0876

Browse files
committed
Add local API specific tests for error handling in OverkizClient
1 parent 8475b08 commit c7a0876

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed

tests/test_client.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,163 @@ async def test_refresh_device_states(self, client: OverkizClient):
988988
with patch.object(aiohttp.ClientSession, "post", return_value=resp):
989989
await client.refresh_device_states("rts://2025-8464-6867/16756006")
990990

991+
# --- Local API specific tests ---
992+
# The local gateway (KizOs) behaves differently from the cloud API
993+
# in several cases. These tests verify the client raises proper errors
994+
# instead of crashing when called via the local API.
995+
996+
@pytest.mark.asyncio
997+
async def test_local_get_current_execution_empty_list(
998+
self, local_client: OverkizClient
999+
):
1000+
"""Local gateway returns [] for non-existent exec_id (cloud returns {})."""
1001+
resp = MockResponse("[]")
1002+
1003+
with patch.object(aiohttp.ClientSession, "get", return_value=resp):
1004+
result = await local_client.get_current_execution(
1005+
"00000000-0000-0000-0000-000000000000"
1006+
)
1007+
assert result is None
1008+
1009+
@pytest.mark.asyncio
1010+
async def test_local_get_state_no_such_device(self, local_client: OverkizClient):
1011+
"""Local gateway raises NoSuchDeviceError for unknown device URLs."""
1012+
resp = MockResponse(
1013+
'{"error":"No such device : \\"io://0000-0000-0000/12345678\\"","errorCode":"NO_SUCH_DEVICE"}',
1014+
status=400,
1015+
)
1016+
1017+
with (
1018+
patch.object(aiohttp.ClientSession, "get", return_value=resp),
1019+
pytest.raises(exceptions.NoSuchDeviceError),
1020+
):
1021+
await local_client.get_state("io://0000-0000-0000/12345678")
1022+
1023+
@pytest.mark.asyncio
1024+
async def test_local_get_device_definition_no_such_device(
1025+
self, local_client: OverkizClient
1026+
):
1027+
"""Local gateway raises NoSuchDeviceError for unknown device definition lookups."""
1028+
resp = MockResponse(
1029+
'{"error":"No such device : \\"io://0000-0000-0000/12345678\\"","errorCode":"NO_SUCH_DEVICE"}',
1030+
status=400,
1031+
)
1032+
1033+
with (
1034+
patch.object(aiohttp.ClientSession, "get", return_value=resp),
1035+
pytest.raises(exceptions.NoSuchDeviceError),
1036+
):
1037+
await local_client.get_device_definition("io://0000-0000-0000/12345678")
1038+
1039+
@pytest.mark.asyncio
1040+
async def test_local_get_setup_option_unknown_object(
1041+
self, local_client: OverkizClient
1042+
):
1043+
"""Local gateway raises UnknownObjectError for non-existent options (cloud returns {})."""
1044+
resp = MockResponse(
1045+
'{"error":"Unknown object.","errorCode":"UNSPECIFIED_ERROR"}',
1046+
status=400,
1047+
)
1048+
1049+
with (
1050+
patch.object(aiohttp.ClientSession, "get", return_value=resp),
1051+
pytest.raises(exceptions.UnknownObjectError),
1052+
):
1053+
await local_client.get_setup_option("nonExistentOption")
1054+
1055+
@pytest.mark.asyncio
1056+
async def test_local_refresh_device_states_unknown_object(
1057+
self, local_client: OverkizClient
1058+
):
1059+
"""Local gateway raises UnknownObjectError for unknown device refresh."""
1060+
resp = MockResponse(
1061+
'{"error":"Unknown object.","errorCode":"UNSPECIFIED_ERROR"}',
1062+
status=400,
1063+
)
1064+
1065+
with (
1066+
patch.object(aiohttp.ClientSession, "post", return_value=resp),
1067+
pytest.raises(exceptions.UnknownObjectError),
1068+
):
1069+
await local_client.refresh_device_states("io://0000-0000-0000/12345678")
1070+
1071+
@pytest.mark.asyncio
1072+
async def test_local_get_reference_controllable_unknown_object(
1073+
self, local_client: OverkizClient
1074+
):
1075+
"""Local gateway raises UnknownObjectError for unknown controllable names."""
1076+
resp = MockResponse(
1077+
'{"error":"Unknown object.","errorCode":"UNSPECIFIED_ERROR"}',
1078+
status=400,
1079+
)
1080+
1081+
with (
1082+
patch.object(aiohttp.ClientSession, "get", return_value=resp),
1083+
pytest.raises(exceptions.UnknownObjectError),
1084+
):
1085+
await local_client.get_reference_controllable("io:NonExistentControllable")
1086+
1087+
@pytest.mark.asyncio
1088+
async def test_local_cancel_execution_succeeds_on_unknown_id(
1089+
self, local_client: OverkizClient
1090+
):
1091+
"""Local gateway returns 200 with [] for cancel on unknown exec_id (idempotent)."""
1092+
resp = MockResponse("[]", status=200)
1093+
1094+
with patch.object(aiohttp.ClientSession, "delete", return_value=resp):
1095+
await local_client.cancel_execution("00000000-0000-0000-0000-000000000000")
1096+
1097+
@pytest.mark.asyncio
1098+
async def test_local_execute_action_group_rts_close(
1099+
self, local_client: OverkizClient
1100+
):
1101+
"""Verify executing an RTS command via the local API."""
1102+
action = Action(
1103+
"rts://2025-8464-6867/16756006",
1104+
[Command(name="close")],
1105+
)
1106+
resp = MockResponse('{"execId": "45e52d27-3c08-4fd5-87f2-03d650b67f4b"}')
1107+
1108+
with patch.object(aiohttp.ClientSession, "post") as mock_post:
1109+
mock_post.return_value = resp
1110+
exec_id = await local_client.execute_action_group([action])
1111+
1112+
assert exec_id == "45e52d27-3c08-4fd5-87f2-03d650b67f4b"
1113+
1114+
@pytest.mark.asyncio
1115+
async def test_local_no_registered_event_listener(
1116+
self, local_client: OverkizClient
1117+
):
1118+
"""Local gateway raises NoRegisteredEventListenerError for unregistered fetch."""
1119+
resp = MockResponse(
1120+
'{"error":"\\"No registered event listener.\\"","errorCode":"UNSPECIFIED_ERROR"}',
1121+
status=400,
1122+
)
1123+
1124+
with (
1125+
patch.object(aiohttp.ClientSession, "post", return_value=resp),
1126+
pytest.raises(exceptions.NoRegisteredEventListenerError),
1127+
):
1128+
await check_response(resp)
1129+
1130+
@pytest.mark.asyncio
1131+
async def test_local_schedule_persisted_action_group_unknown_object(
1132+
self, local_client: OverkizClient
1133+
):
1134+
"""Local gateway raises UnknownObjectError when scheduling a non-existent action group."""
1135+
resp = MockResponse(
1136+
'{"error":"Unknown object.","errorCode":"UNSPECIFIED_ERROR"}',
1137+
status=400,
1138+
)
1139+
1140+
with (
1141+
patch.object(aiohttp.ClientSession, "post", return_value=resp),
1142+
pytest.raises(exceptions.UnknownObjectError),
1143+
):
1144+
await local_client.schedule_persisted_action_group(
1145+
"00000000-0000-0000-0000-000000000000", 9999999999
1146+
)
1147+
9911148

9921149
class MockResponse:
9931150
"""Simple stand-in for aiohttp responses used in tests."""

0 commit comments

Comments
 (0)