Skip to content

Commit b07e06f

Browse files
PeterC1965restyled-commitsjamesharrowccruzagralopes
authored andcommitted
Add DEM test scripts (project-chip#34234)
* Add DEM test scripts * Restyled by autopep8 * Restyled by isort * Renamed DEMBaseTest.py to TC_DEMTestBase.py so that it's grouped with the TC_DEM scripts. Also split the expected result in the TestSteps() into 3rd 'expected' arg. Corrected some missing Verification steps. * Updated DEM_2.4 with corrections to match latest test plan. Also corrected PICS and description from DEM 2.3 * Restyled by isort * TC_DEM_2_5.py updated with TestSteps and corrections to match latest test plan * Reformatted TC_DEM_2_9.py * Changed PICS for DEM_2_5.py to have it as a single boolean - unsure on the correct format. * Updated DEM_2_6.py test steps in new format and corrected Test description and PICS * Fixed extra " in DEM_2_6 * Reformatted TC_DEM_2_7.py - corrected PICS and description * Corrected Feature 2 for DEM_2_6 * Corrected TC number for DEM_2_6 * Updated TC_DEM_2_8 test steps, description and pics * Restyled by isort * Apply review comments from James Harrow * Apply review comments from James Harrow * Restyled by autopep8 * Restyled by isort * Apply review comments from James Harrow * Fix python lint error * Apply review comments from James Harrow * Restyled by autopep8 * Added # === BEGIN CI TEST ARGUMENTS banners to TC_DEM python scripts * Specify --featureSet option on runner command line * Address review comments from Rob Bultman * Address review comments from Rob Bultman * Restyled by isort * Update src/python_testing/TC_DEM_2_5.py Co-authored-by: Carolina Lopes <116589288+ccruzagralopes@users.noreply.github.com> * Update TC_DEM_2_6.py - changed PICS conformance to comma separated list * Update TC_DEM_2_7.py - changed PICS conformance to comma separated list * Update TC_DEM_2_9.py - changed PICS conformance to comma separated list * Update TC_DEM_2_8.py - changed PICS conformance to comma separated list * Enabled DEM Test scripts as part of CI --------- Co-authored-by: Restyled.io <commits@restyled.io> Co-authored-by: James Harrow <james.harrow@gmail.com> Co-authored-by: jamesharrow <93921463+jamesharrow@users.noreply.github.com> Co-authored-by: Carolina Lopes <116589288+ccruzagralopes@users.noreply.github.com>
1 parent 9f6897b commit b07e06f

10 files changed

+2290
-7
lines changed

.github/workflows/tests.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,14 @@ jobs:
513513
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DRLK_2_3.py'
514514
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DeviceBasicComposition.py'
515515
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DeviceConformance.py'
516+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_2.py'
517+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_3.py'
518+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_4.py'
519+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_5.py'
520+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_6.py'
521+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_7.py'
522+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_8.py'
523+
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_9.py'
516524
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_1.py'
517525
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_2.py'
518526
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_3.py'

src/python_testing/TC_DEMTestBase.py

+242
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
#
2+
# Copyright (c) 2023 Project CHIP Authors
3+
# All rights reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
import logging
19+
20+
import chip.clusters as Clusters
21+
from chip.interaction_model import InteractionModelError, Status
22+
from matter_testing_support import utc_time_in_matter_epoch
23+
from mobly import asserts
24+
25+
logger = logging.getLogger(__name__)
26+
27+
28+
class DEMTestBase:
29+
30+
async def read_dem_attribute_expect_success(self, endpoint: int = None, attribute: str = ""):
31+
cluster = Clusters.Objects.DeviceEnergyManagement
32+
full_attr = getattr(cluster.Attributes, attribute)
33+
logging.info(f"endpoint {endpoint} full_attr {full_attr}")
34+
return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=full_attr)
35+
36+
async def check_dem_attribute(self, attribute, expected_value, endpoint: int = None):
37+
value = await self.read_dem_attribute_expect_success(endpoint=endpoint, attribute=attribute)
38+
asserts.assert_equal(value, expected_value,
39+
f"Unexpected '{attribute}' value - expected {expected_value}, was {value}")
40+
41+
async def send_power_adjustment_command(self, power: int, duration: int,
42+
cause: Clusters.Objects.DeviceEnergyManagement.Enums.CauseEnum,
43+
endpoint: int = None, timedRequestTimeoutMs: int = 3000,
44+
expected_status: Status = Status.Success):
45+
try:
46+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.PowerAdjustRequest(
47+
power=power,
48+
duration=duration,
49+
cause=cause),
50+
endpoint=endpoint,
51+
timedRequestTimeoutMs=timedRequestTimeoutMs)
52+
53+
asserts.assert_equal(expected_status, Status.Success)
54+
55+
except InteractionModelError as e:
56+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
57+
58+
async def send_cancel_power_adjustment_command(self, endpoint: int = None, timedRequestTimeoutMs: int = 3000,
59+
expected_status: Status = Status.Success):
60+
try:
61+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.CancelPowerAdjustRequest(),
62+
endpoint=endpoint,
63+
timedRequestTimeoutMs=timedRequestTimeoutMs)
64+
65+
asserts.assert_equal(expected_status, Status.Success)
66+
67+
except InteractionModelError as e:
68+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
69+
70+
async def send_start_time_adjust_request_command(self, requestedStartTime: int,
71+
cause: Clusters.Objects.DeviceEnergyManagement.Enums.CauseEnum,
72+
endpoint: int = None, timedRequestTimeoutMs: int = 3000,
73+
expected_status: Status = Status.Success):
74+
try:
75+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.StartTimeAdjustRequest(
76+
requestedStartTime=requestedStartTime,
77+
cause=cause),
78+
endpoint=endpoint,
79+
timedRequestTimeoutMs=timedRequestTimeoutMs)
80+
81+
asserts.assert_equal(expected_status, Status.Success)
82+
83+
except InteractionModelError as e:
84+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
85+
86+
async def send_start_time_adjust_clear_command(self,
87+
endpoint: int = None, timedRequestTimeoutMs: int = 3000,
88+
expected_status: Status = Status.Success):
89+
try:
90+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.StartTimeAdjustClear(), # StartTimeAdjustmentClear(),
91+
endpoint=endpoint,
92+
timedRequestTimeoutMs=timedRequestTimeoutMs)
93+
94+
asserts.assert_equal(expected_status, Status.Success)
95+
96+
except InteractionModelError as e:
97+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
98+
99+
async def send_cancel_request_command(self,
100+
endpoint: int = None, timedRequestTimeoutMs: int = 3000,
101+
expected_status: Status = Status.Success):
102+
try:
103+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.CancelRequest(),
104+
endpoint=endpoint,
105+
timedRequestTimeoutMs=timedRequestTimeoutMs)
106+
107+
asserts.assert_equal(expected_status, Status.Success)
108+
109+
except InteractionModelError as e:
110+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
111+
112+
async def send_pause_request_command(self, duration: int, cause:
113+
Clusters.Objects.DeviceEnergyManagement.Enums.AdjustmentCauseEnum,
114+
endpoint: int = None, timedRequestTimeoutMs: int = 3000,
115+
expected_status: Status = Status.Success):
116+
try:
117+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.PauseRequest(
118+
duration=duration,
119+
cause=cause),
120+
endpoint=endpoint,
121+
timedRequestTimeoutMs=timedRequestTimeoutMs)
122+
123+
asserts.assert_equal(expected_status, Status.Success)
124+
125+
except InteractionModelError as e:
126+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
127+
128+
async def send_resume_request_command(self, endpoint: int = None, timedRequestTimeoutMs: int = 3000,
129+
expected_status: Status = Status.Success):
130+
try:
131+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.ResumeRequest(),
132+
endpoint=endpoint,
133+
timedRequestTimeoutMs=timedRequestTimeoutMs)
134+
135+
asserts.assert_equal(expected_status, Status.Success)
136+
137+
except InteractionModelError as e:
138+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
139+
140+
async def send_modify_forecast_request_command(self, forecastID: int,
141+
slotAdjustments: list[Clusters.DeviceEnergyManagement.Structs.SlotAdjustmentStruct],
142+
cause: Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum,
143+
endpoint: int = None, timedRequestTimeoutMs: int = 3000,
144+
expected_status: Status = Status.Success):
145+
try:
146+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.ModifyForecastRequest(forecastID=forecastID,
147+
slotAdjustments=slotAdjustments,
148+
cause=cause),
149+
endpoint=endpoint,
150+
timedRequestTimeoutMs=timedRequestTimeoutMs)
151+
152+
asserts.assert_equal(expected_status, Status.Success)
153+
154+
except InteractionModelError as e:
155+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
156+
157+
async def send_request_constraint_based_forecast(self, constraintList: list[Clusters.DeviceEnergyManagement.Structs.ConstraintsStruct],
158+
cause: Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum,
159+
endpoint: int = None, timedRequestTimeoutMs: int = 3000,
160+
expected_status: Status = Status.Success):
161+
try:
162+
await self.send_single_cmd(cmd=Clusters.DeviceEnergyManagement.Commands.RequestConstraintBasedForecast(constraints=constraintList,
163+
cause=cause),
164+
endpoint=endpoint,
165+
timedRequestTimeoutMs=timedRequestTimeoutMs)
166+
167+
asserts.assert_equal(expected_status, Status.Success)
168+
169+
except InteractionModelError as e:
170+
asserts.assert_equal(e.status, expected_status, "Unexpected error returned")
171+
172+
def print_forecast(self, forecast):
173+
for index, slot in enumerate(forecast.slots):
174+
logging.info(
175+
f" [{index}] MinDuration: {slot.minDuration} MaxDuration: {slot.maxDuration} DefaultDuration: {slot.defaultDuration}")
176+
logging.info(f" ElapseSlotTime: {slot.elapsedSlotTime} RemainingSlotTime: {slot.remainingSlotTime}")
177+
logging.info(
178+
f" SlotIsPausable: {slot.slotIsPausable} MinPauseDuration: {slot.minPauseDuration} MaxPauseDuration: {slot.maxPauseDuration}")
179+
logging.info(f" ManufacturerESAState: {slot.manufacturerESAState}")
180+
logging.info(f" NominalPower: {slot.nominalPower} MinPower: {slot.minPower} MaxPower: {slot.maxPower}")
181+
logging.info(f" MinPowerAdjustment: {slot.minPowerAdjustment} MaxPowerAdjustment: {slot.maxPowerAdjustment}")
182+
logging.info(
183+
f" MinDurationAdjustment: {slot.minDurationAdjustment} MaxDurationAdjustment: {slot.maxDurationAdjustment}")
184+
if slot.costs is not None:
185+
for cost_index, cost in enumerate(slot):
186+
logging.info(
187+
f" Cost: [{cost_index}] CostType:{cost.costType} Value: {cost.value} DecimalPoints: {cost.decimalPoints} Currency: {cost.currency}")
188+
189+
def get_current_utc_time_in_seconds(self):
190+
microseconds_in_second = 1000000
191+
return int(utc_time_in_matter_epoch()/microseconds_in_second)
192+
193+
async def send_test_event_trigger_power_adjustment(self):
194+
await self.send_test_event_triggers(eventTrigger=0x0098000000000000)
195+
196+
async def send_test_event_trigger_power_adjustment_clear(self):
197+
await self.send_test_event_triggers(eventTrigger=0x0098000000000001)
198+
199+
async def send_test_event_trigger_user_opt_out_local(self):
200+
await self.send_test_event_triggers(eventTrigger=0x0098000000000002)
201+
202+
async def send_test_event_trigger_user_opt_out_grid(self):
203+
await self.send_test_event_triggers(eventTrigger=0x0098000000000003)
204+
205+
async def send_test_event_trigger_user_opt_out_clear_all(self):
206+
await self.send_test_event_triggers(eventTrigger=0x0098000000000004)
207+
208+
async def send_test_event_trigger_start_time_adjustment(self):
209+
await self.send_test_event_triggers(eventTrigger=0x0098000000000005)
210+
211+
async def send_test_event_trigger_start_time_adjustment_clear(self):
212+
await self.send_test_event_triggers(eventTrigger=0x0098000000000006)
213+
214+
async def send_test_event_trigger_pausable(self):
215+
await self.send_test_event_triggers(eventTrigger=0x0098000000000007)
216+
217+
async def send_test_event_trigger_pausable_next_slot(self):
218+
await self.send_test_event_triggers(eventTrigger=0x0098000000000008)
219+
220+
async def send_test_event_trigger_pausable_clear(self):
221+
await self.send_test_event_triggers(eventTrigger=0x0098000000000009)
222+
223+
async def send_test_event_trigger_forecast_adjustment(self):
224+
await self.send_test_event_triggers(eventTrigger=0x009800000000000A)
225+
226+
async def send_test_event_trigger_forecast_adjustment_next_slot(self):
227+
await self.send_test_event_triggers(eventTrigger=0x009800000000000B)
228+
229+
async def send_test_event_trigger_forecast_adjustment_clear(self):
230+
await self.send_test_event_triggers(eventTrigger=0x009800000000000C)
231+
232+
async def send_test_event_trigger_constraint_based_adjustment(self):
233+
await self.send_test_event_triggers(eventTrigger=0x009800000000000D)
234+
235+
async def send_test_event_trigger_constraint_based_adjustment_clear(self):
236+
await self.send_test_event_triggers(eventTrigger=0x009800000000000E)
237+
238+
async def send_test_event_trigger_forecast(self):
239+
await self.send_test_event_triggers(eventTrigger=0x009800000000000F)
240+
241+
async def send_test_event_trigger_forecast_clear(self):
242+
await self.send_test_event_triggers(eventTrigger=0x0098000000000010)

src/python_testing/TC_DEM_2_2.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ async def test_TC_DEM_2_2(self):
196196
await self.check_dem_attribute("OptOutState", Clusters.DeviceEnergyManagement.Enums.OptOutStateEnum.kNoOptOut)
197197

198198
self.step("4")
199-
await self.send_power_adjustment_command(power=max_power,
199+
await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower,
200200
duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].minDuration,
201201
cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization)
202202

@@ -218,7 +218,6 @@ async def test_TC_DEM_2_2(self):
218218

219219
self.step("5a")
220220
powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability")
221-
asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1)
222221
asserts.assert_equal(powerAdjustCapabilityStruct.cause,
223222
Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kNoAdjustment)
224223

@@ -254,21 +253,20 @@ async def test_TC_DEM_2_2(self):
254253

255254
self.step("11")
256255
start = datetime.datetime.now()
257-
await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower,
256+
await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].minPower,
258257
duration=min_duration,
259258
cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization)
260259

261260
event_data = events_callback.wait_for_event_report(Clusters.DeviceEnergyManagement.Events.PowerAdjustStart)
262261

263262
self.step("11a")
264263
powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability")
265-
asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1)
266264
asserts.assert_equal(powerAdjustCapabilityStruct.cause,
267265
Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kLocalOptimizationAdjustment)
268266

269267
self.step("12")
270268
await self.send_power_adjustment_command(power=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxPower,
271-
duration=min_duration,
269+
duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].minDuration,
272270
cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kGridOptimization)
273271

274272
# Wait 5 seconds for an event not to be reported
@@ -279,7 +277,6 @@ async def test_TC_DEM_2_2(self):
279277

280278
self.step("12b")
281279
powerAdjustCapabilityStruct = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability")
282-
asserts.assert_greater_equal(len(powerAdjustCapabilityStruct.powerAdjustCapability), 1)
283280
asserts.assert_equal(powerAdjustCapabilityStruct.cause,
284281
Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum.kGridOptimizationAdjustment)
285282

@@ -294,7 +291,7 @@ async def test_TC_DEM_2_2(self):
294291

295292
self.step("14")
296293
await self.send_power_adjustment_command(power=max_power,
297-
duration=max_duration,
294+
duration=powerAdjustCapabilityStruct.powerAdjustCapability[0].maxDuration,
298295
cause=Clusters.DeviceEnergyManagement.Enums.AdjustmentCauseEnum.kLocalOptimization,
299296
expected_status=Status.ConstraintError)
300297

0 commit comments

Comments
 (0)