aiohomematic-test-support 2025.12.26__tar.gz → 2025.12.54__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aiohomematic_test_support-2025.12.26/aiohomematic_test_support.egg-info → aiohomematic_test_support-2025.12.54}/PKG-INFO +2 -2
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/__init__.py +32 -1
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54/aiohomematic_test_support.egg-info}/PKG-INFO +2 -2
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/aiohomematic_test_support.egg-info/SOURCES.txt +6 -0
- aiohomematic_test_support-2025.12.54/const.py +264 -0
- aiohomematic_test_support-2025.12.54/data/device_translation.json +364 -0
- aiohomematic_test_support-2025.12.54/event_capture.py +256 -0
- aiohomematic_test_support-2025.12.54/event_mock.py +300 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/factory.py +25 -10
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/helper.py +5 -3
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/mock.py +48 -13
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/pyproject.toml +1 -0
- aiohomematic_test_support-2025.12.26/const.py +0 -603
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/MANIFEST.in +0 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/README.md +0 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/aiohomematic_test_support.egg-info/dependency_links.txt +0 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/aiohomematic_test_support.egg-info/top_level.txt +0 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/data/full_session_randomized_ccu.zip +0 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/data/full_session_randomized_pydevccu.zip +0 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/py.typed +0 -0
- {aiohomematic_test_support-2025.12.26 → aiohomematic_test_support-2025.12.54}/setup.cfg +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiohomematic-test-support
|
|
3
|
-
Version: 2025.12.
|
|
3
|
+
Version: 2025.12.54
|
|
4
4
|
Summary: Support-only package for AioHomematic (tests/dev). Not part of production builds.
|
|
5
|
-
Author-email: SukramJ <sukramj@icloud.com>
|
|
5
|
+
Author-email: SukramJ <sukramj@icloud.com>, Daniel Perna <danielperna84@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/SukramJ/aiohomematic
|
|
7
7
|
Classifier: Development Status :: 3 - Alpha
|
|
8
8
|
Classifier: Intended Audience :: Developers
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2021-2025
|
|
1
3
|
"""
|
|
2
4
|
Test support infrastructure for aiohomematic.
|
|
3
5
|
|
|
@@ -16,6 +18,8 @@ Key Components
|
|
|
16
18
|
playback support for deterministic testing.
|
|
17
19
|
- **helper**: Test helper utilities for common testing operations.
|
|
18
20
|
- **const**: Test-specific constants and configuration values.
|
|
21
|
+
- **event_capture**: Event capture and assertion utilities for behavior testing.
|
|
22
|
+
- **event_mock**: Event-driven mock server for test triggers.
|
|
19
23
|
|
|
20
24
|
Usage Example
|
|
21
25
|
-------------
|
|
@@ -33,6 +37,33 @@ Using the factory to create a test central with session playback:
|
|
|
33
37
|
device = central.device_coordinator.get_device_by_address("VCU0000001")
|
|
34
38
|
await central.stop()
|
|
35
39
|
|
|
40
|
+
Using EventCapture for behavior-focused testing:
|
|
41
|
+
|
|
42
|
+
from aiohomematic_test_support.event_capture import EventCapture
|
|
43
|
+
from aiohomematic.central.event_bus import CircuitBreakerTrippedEvent
|
|
44
|
+
|
|
45
|
+
capture = EventCapture()
|
|
46
|
+
capture.subscribe_to(central.event_bus, CircuitBreakerTrippedEvent)
|
|
47
|
+
|
|
48
|
+
# ... trigger failures ...
|
|
49
|
+
|
|
50
|
+
capture.assert_event_emitted(CircuitBreakerTrippedEvent, failure_count=5)
|
|
51
|
+
capture.cleanup()
|
|
52
|
+
|
|
53
|
+
Using EventDrivenMockServer for event-triggered test behavior:
|
|
54
|
+
|
|
55
|
+
from aiohomematic_test_support.event_mock import EventDrivenMockServer
|
|
56
|
+
from aiohomematic.central.event_bus import DataRefreshTriggeredEvent
|
|
57
|
+
|
|
58
|
+
mock_server = EventDrivenMockServer(event_bus=central.event_bus)
|
|
59
|
+
mock_server.when(DataRefreshTriggeredEvent).then_call(
|
|
60
|
+
lambda event: inject_mock_data()
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# ... trigger refresh ...
|
|
64
|
+
|
|
65
|
+
mock_server.cleanup()
|
|
66
|
+
|
|
36
67
|
The session player replays pre-recorded backend responses, enabling fast and
|
|
37
68
|
reproducible tests without backend dependencies.
|
|
38
69
|
|
|
@@ -45,4 +76,4 @@ test dependencies to access test support functionality.
|
|
|
45
76
|
|
|
46
77
|
from __future__ import annotations
|
|
47
78
|
|
|
48
|
-
__version__ = "2025.12.
|
|
79
|
+
__version__ = "2025.12.54"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aiohomematic-test-support
|
|
3
|
-
Version: 2025.12.
|
|
3
|
+
Version: 2025.12.54
|
|
4
4
|
Summary: Support-only package for AioHomematic (tests/dev). Not part of production builds.
|
|
5
|
-
Author-email: SukramJ <sukramj@icloud.com>
|
|
5
|
+
Author-email: SukramJ <sukramj@icloud.com>, Daniel Perna <danielperna84@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/SukramJ/aiohomematic
|
|
7
7
|
Classifier: Development Status :: 3 - Alpha
|
|
8
8
|
Classifier: Intended Audience :: Developers
|
|
@@ -2,6 +2,8 @@ MANIFEST.in
|
|
|
2
2
|
README.md
|
|
3
3
|
__init__.py
|
|
4
4
|
const.py
|
|
5
|
+
event_capture.py
|
|
6
|
+
event_mock.py
|
|
5
7
|
factory.py
|
|
6
8
|
helper.py
|
|
7
9
|
mock.py
|
|
@@ -9,15 +11,19 @@ py.typed
|
|
|
9
11
|
pyproject.toml
|
|
10
12
|
./__init__.py
|
|
11
13
|
./const.py
|
|
14
|
+
./event_capture.py
|
|
15
|
+
./event_mock.py
|
|
12
16
|
./factory.py
|
|
13
17
|
./helper.py
|
|
14
18
|
./mock.py
|
|
15
19
|
./py.typed
|
|
20
|
+
./data/device_translation.json
|
|
16
21
|
./data/full_session_randomized_ccu.zip
|
|
17
22
|
./data/full_session_randomized_pydevccu.zip
|
|
18
23
|
aiohomematic_test_support.egg-info/PKG-INFO
|
|
19
24
|
aiohomematic_test_support.egg-info/SOURCES.txt
|
|
20
25
|
aiohomematic_test_support.egg-info/dependency_links.txt
|
|
21
26
|
aiohomematic_test_support.egg-info/top_level.txt
|
|
27
|
+
data/device_translation.json
|
|
22
28
|
data/full_session_randomized_ccu.zip
|
|
23
29
|
data/full_session_randomized_pydevccu.zip
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2021-2025
|
|
3
|
+
"""Constants for tests."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import functools
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from typing import cast
|
|
11
|
+
|
|
12
|
+
from aiohomematic.client.json_rpc import _JsonKey
|
|
13
|
+
from aiohomematic.const import LOCAL_HOST, UTF_8, HubValueType, Interface, ProgramData, SystemVariableData
|
|
14
|
+
|
|
15
|
+
CENTRAL_NAME = "CentralTest"
|
|
16
|
+
CCU_HOST = LOCAL_HOST
|
|
17
|
+
CCU_USERNAME = "user"
|
|
18
|
+
CCU_PASSWORD = "pass"
|
|
19
|
+
CCU_PORT = 2002
|
|
20
|
+
CCU_MINI_PORT = 2003
|
|
21
|
+
INTERFACE_ID = f"{CENTRAL_NAME}-{Interface.BIDCOS_RF}"
|
|
22
|
+
|
|
23
|
+
# Backend info response for get_backend_info.fn script
|
|
24
|
+
BACKEND_INFO_JSON = {
|
|
25
|
+
"version": "3.75.6.20240316",
|
|
26
|
+
"product": "CCU3",
|
|
27
|
+
"hostname": "ccu-test",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
FULL_SESSION_RANDOMIZED_PYDEVCCU = "full_session_randomized_pydevccu.zip"
|
|
31
|
+
FULL_SESSION_RANDOMIZED_CCU = "full_session_randomized_ccu.zip"
|
|
32
|
+
|
|
33
|
+
ALL_SESSION_FILES = [
|
|
34
|
+
FULL_SESSION_RANDOMIZED_PYDEVCCU,
|
|
35
|
+
FULL_SESSION_RANDOMIZED_CCU,
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
SYSVAR_DATA: list[SystemVariableData] = [
|
|
40
|
+
SystemVariableData(
|
|
41
|
+
vid="1",
|
|
42
|
+
legacy_name="alarm",
|
|
43
|
+
description="",
|
|
44
|
+
data_type=HubValueType.ALARM,
|
|
45
|
+
unit=None,
|
|
46
|
+
value=False,
|
|
47
|
+
values=None,
|
|
48
|
+
max_value=None,
|
|
49
|
+
min_value=None,
|
|
50
|
+
extended_sysvar=False,
|
|
51
|
+
),
|
|
52
|
+
SystemVariableData(
|
|
53
|
+
vid="2",
|
|
54
|
+
legacy_name="alarm_ext",
|
|
55
|
+
description="HAHM",
|
|
56
|
+
data_type=HubValueType.ALARM,
|
|
57
|
+
unit=None,
|
|
58
|
+
value=False,
|
|
59
|
+
values=None,
|
|
60
|
+
max_value=None,
|
|
61
|
+
min_value=None,
|
|
62
|
+
extended_sysvar=True,
|
|
63
|
+
),
|
|
64
|
+
SystemVariableData(
|
|
65
|
+
vid="3",
|
|
66
|
+
legacy_name="logic",
|
|
67
|
+
description="",
|
|
68
|
+
data_type=HubValueType.LOGIC,
|
|
69
|
+
unit=None,
|
|
70
|
+
value=False,
|
|
71
|
+
values=None,
|
|
72
|
+
max_value=None,
|
|
73
|
+
min_value=None,
|
|
74
|
+
extended_sysvar=False,
|
|
75
|
+
),
|
|
76
|
+
SystemVariableData(
|
|
77
|
+
vid="4",
|
|
78
|
+
legacy_name="logic_ext",
|
|
79
|
+
description="HAHM",
|
|
80
|
+
data_type=HubValueType.LOGIC,
|
|
81
|
+
unit=None,
|
|
82
|
+
value=False,
|
|
83
|
+
values=None,
|
|
84
|
+
max_value=None,
|
|
85
|
+
min_value=None,
|
|
86
|
+
extended_sysvar=True,
|
|
87
|
+
),
|
|
88
|
+
SystemVariableData(
|
|
89
|
+
vid="5",
|
|
90
|
+
legacy_name="list",
|
|
91
|
+
description="",
|
|
92
|
+
data_type=HubValueType.LIST,
|
|
93
|
+
unit=None,
|
|
94
|
+
value=0,
|
|
95
|
+
values=("v1", "v2", "v3"),
|
|
96
|
+
max_value=None,
|
|
97
|
+
min_value=None,
|
|
98
|
+
extended_sysvar=False,
|
|
99
|
+
),
|
|
100
|
+
SystemVariableData(
|
|
101
|
+
vid="6",
|
|
102
|
+
legacy_name="list_ext",
|
|
103
|
+
description="HAHM",
|
|
104
|
+
data_type=HubValueType.LIST,
|
|
105
|
+
unit=None,
|
|
106
|
+
value=0,
|
|
107
|
+
values=("v1", "v2", "v3"),
|
|
108
|
+
max_value=None,
|
|
109
|
+
min_value=None,
|
|
110
|
+
extended_sysvar=True,
|
|
111
|
+
),
|
|
112
|
+
SystemVariableData(
|
|
113
|
+
vid="7",
|
|
114
|
+
legacy_name="string",
|
|
115
|
+
description="",
|
|
116
|
+
data_type=HubValueType.STRING,
|
|
117
|
+
unit=None,
|
|
118
|
+
value="test1",
|
|
119
|
+
values=None,
|
|
120
|
+
max_value=None,
|
|
121
|
+
min_value=None,
|
|
122
|
+
extended_sysvar=False,
|
|
123
|
+
),
|
|
124
|
+
SystemVariableData(
|
|
125
|
+
vid="8",
|
|
126
|
+
legacy_name="string_ext",
|
|
127
|
+
description="HAHM",
|
|
128
|
+
data_type=HubValueType.STRING,
|
|
129
|
+
unit=None,
|
|
130
|
+
value="test1",
|
|
131
|
+
values=None,
|
|
132
|
+
max_value=None,
|
|
133
|
+
min_value=None,
|
|
134
|
+
extended_sysvar=True,
|
|
135
|
+
),
|
|
136
|
+
SystemVariableData(
|
|
137
|
+
vid="9",
|
|
138
|
+
legacy_name="float",
|
|
139
|
+
description="",
|
|
140
|
+
data_type=HubValueType.FLOAT,
|
|
141
|
+
unit=None,
|
|
142
|
+
value=23.2,
|
|
143
|
+
values=None,
|
|
144
|
+
max_value=30.0,
|
|
145
|
+
min_value=5.0,
|
|
146
|
+
extended_sysvar=False,
|
|
147
|
+
),
|
|
148
|
+
SystemVariableData(
|
|
149
|
+
vid="10",
|
|
150
|
+
legacy_name="float_ext",
|
|
151
|
+
description="HAHM",
|
|
152
|
+
data_type=HubValueType.FLOAT,
|
|
153
|
+
unit="°C",
|
|
154
|
+
value=23.2,
|
|
155
|
+
values=None,
|
|
156
|
+
max_value=30.0,
|
|
157
|
+
min_value=5.0,
|
|
158
|
+
extended_sysvar=True,
|
|
159
|
+
),
|
|
160
|
+
SystemVariableData(
|
|
161
|
+
vid="11",
|
|
162
|
+
legacy_name="integer",
|
|
163
|
+
description="",
|
|
164
|
+
data_type=HubValueType.INTEGER,
|
|
165
|
+
unit=None,
|
|
166
|
+
value=17,
|
|
167
|
+
values=None,
|
|
168
|
+
max_value=30,
|
|
169
|
+
min_value=5,
|
|
170
|
+
extended_sysvar=False,
|
|
171
|
+
),
|
|
172
|
+
SystemVariableData(
|
|
173
|
+
vid="12",
|
|
174
|
+
legacy_name="integer_ext",
|
|
175
|
+
description="HAHM",
|
|
176
|
+
data_type=HubValueType.INTEGER,
|
|
177
|
+
unit=None,
|
|
178
|
+
value=17,
|
|
179
|
+
values=None,
|
|
180
|
+
max_value=30,
|
|
181
|
+
min_value=5,
|
|
182
|
+
extended_sysvar=True,
|
|
183
|
+
),
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
SYSVAR_DATA_JSON = [
|
|
188
|
+
{
|
|
189
|
+
_JsonKey.ID: sv.vid,
|
|
190
|
+
_JsonKey.IS_INTERNAL: False,
|
|
191
|
+
_JsonKey.MAX_VALUE: sv.max_value,
|
|
192
|
+
_JsonKey.MIN_VALUE: sv.min_value,
|
|
193
|
+
_JsonKey.NAME: sv.legacy_name,
|
|
194
|
+
_JsonKey.TYPE: sv.data_type,
|
|
195
|
+
_JsonKey.UNIT: sv.unit,
|
|
196
|
+
_JsonKey.VALUE: sv.value,
|
|
197
|
+
_JsonKey.VALUE_LIST: ";".join(sv.values) if sv.values else None,
|
|
198
|
+
}
|
|
199
|
+
for sv in SYSVAR_DATA
|
|
200
|
+
]
|
|
201
|
+
SYSVAR_DATA_JSON_DESCRIPTION = [
|
|
202
|
+
{
|
|
203
|
+
_JsonKey.ID: sv.vid,
|
|
204
|
+
_JsonKey.DESCRIPTION: sv.description,
|
|
205
|
+
}
|
|
206
|
+
for sv in SYSVAR_DATA
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
SYSVAR_DATA_XML = {sv.legacy_name: sv.value for sv in SYSVAR_DATA}
|
|
210
|
+
|
|
211
|
+
PROGRAM_DATA: list[ProgramData] = [
|
|
212
|
+
ProgramData(
|
|
213
|
+
legacy_name="p1",
|
|
214
|
+
pid="pid1",
|
|
215
|
+
description="1",
|
|
216
|
+
is_active=True,
|
|
217
|
+
is_internal=False,
|
|
218
|
+
last_execute_time="",
|
|
219
|
+
),
|
|
220
|
+
ProgramData(
|
|
221
|
+
legacy_name="p_2",
|
|
222
|
+
pid="pid2",
|
|
223
|
+
description="2",
|
|
224
|
+
is_active=False,
|
|
225
|
+
is_internal=False,
|
|
226
|
+
last_execute_time="",
|
|
227
|
+
),
|
|
228
|
+
]
|
|
229
|
+
PROGRAM_DATA_JSON = [
|
|
230
|
+
{
|
|
231
|
+
_JsonKey.ID: p.pid,
|
|
232
|
+
_JsonKey.IS_ACTIVE: p.is_active,
|
|
233
|
+
_JsonKey.IS_INTERNAL: p.is_internal,
|
|
234
|
+
_JsonKey.LAST_EXECUTE_TIME: p.last_execute_time,
|
|
235
|
+
_JsonKey.NAME: p.legacy_name,
|
|
236
|
+
}
|
|
237
|
+
for p in PROGRAM_DATA
|
|
238
|
+
]
|
|
239
|
+
PROGRAM_DATA_JSON_DESCRIPTION = [
|
|
240
|
+
{
|
|
241
|
+
_JsonKey.ID: p.pid,
|
|
242
|
+
_JsonKey.DESCRIPTION: p.description,
|
|
243
|
+
}
|
|
244
|
+
for p in PROGRAM_DATA
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
@functools.cache
|
|
249
|
+
def _load_device_translation() -> dict[str, str]:
|
|
250
|
+
"""Load device translation mapping from JSON file."""
|
|
251
|
+
file_path = os.path.join(os.path.dirname(__file__), "data", "device_translation.json")
|
|
252
|
+
if os.path.exists(file_path):
|
|
253
|
+
with open(file_path, encoding=UTF_8) as f:
|
|
254
|
+
return cast(dict[str, str], json.load(f))
|
|
255
|
+
return {}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def get_address_device_translation() -> dict[str, str]:
|
|
259
|
+
"""Return the address to device translation mapping."""
|
|
260
|
+
return _load_device_translation()
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
# Public accessor - use this instead of direct dict access
|
|
264
|
+
ADDRESS_DEVICE_TRANSLATION = get_address_device_translation()
|