Skip to content

Commit 6a53ed4

Browse files
authored
Added TC_DEM_2_1.py (project-chip#34969)
* Added TC_DEM_2_1.py - see project-chip#4483 in chip-test-plans * Added wait_for_user_input() for questions to the user to check the correct values are stored in the appliance. * Updated test steps to read the FeatureMap and try to align to the code below more closely. Improved / corrected power adjustment checking. * Fixed TC_DEM_2.1 power adjustment verification steps. * Align test steps to proposed changed words in test plan * Added --PICS to include the CI flag
1 parent e4502c3 commit 6a53ed4

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed

src/python_testing/TC_DEM_2_1.py

+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#
2+
# Copyright (c) 2024 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+
# pylint: disable=invalid-name
17+
18+
# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments
19+
# for details about the block below.
20+
#
21+
# === BEGIN CI TEST ARGUMENTS ===
22+
# test-runner-runs: run1
23+
# test-runner-run/run1/app: ${ENERGY_MANAGEMENT_APP}
24+
# test-runner-run/run1/factoryreset: True
25+
# test-runner-run/run1/quiet: True
26+
# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json --enable-key 000102030405060708090a0b0c0d0e0f --featureSet 0x7e
27+
# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values --hex-arg enableKey:000102030405060708090a0b0c0d0e0f --endpoint 1 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto
28+
# === END CI TEST ARGUMENTS ===
29+
30+
"""Define Matter test case TC_DEM_2_1."""
31+
32+
33+
import logging
34+
35+
import chip.clusters as Clusters
36+
from chip.clusters.Types import NullValue
37+
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main
38+
from mobly import asserts
39+
from TC_DEMTestBase import DEMTestBase
40+
41+
logger = logging.getLogger(__name__)
42+
43+
44+
class TC_DEM_2_1(MatterBaseTest, DEMTestBase):
45+
"""Implementation of test case TC_DEM_2_1."""
46+
47+
def desc_TC_DEM_2_1(self) -> str:
48+
"""Return a description of this test."""
49+
return "4.1.2. [TC-DEM-2.1] Attributes with DUT as Server"
50+
51+
def pics_TC_DEM_2_1(self):
52+
"""Return the PICS definitions associated with this test."""
53+
pics = [
54+
"DEM.S",
55+
]
56+
return pics
57+
58+
def steps_TC_DEM_2_1(self) -> list[TestStep]:
59+
"""Execute the test steps."""
60+
steps = [
61+
TestStep("1", "Commissioning, already done",
62+
is_commissioning=True),
63+
TestStep("2", "TH reads from the DUT FeatureMap attribute.",
64+
"Store the value as FeatureMap."),
65+
TestStep("3", "TH reads from the DUT ESAType attribute.",
66+
"Verify that the DUT response contains an a ESATypeEnum (enum8) value to match the DUT type."),
67+
TestStep("4", "TH reads from the DUT the ESACanGenerate attribute.",
68+
"Verify that the DUT response contains a boolean value to match the DUT capability."),
69+
TestStep("5", "TH reads from the DUT ESAState attribute.",
70+
"Verify that the DUT response contains an a ESAStateEnum (enum8) value to match the DUT state (Online or Offline)."),
71+
TestStep("6", "TH reads from the DUT the AbsMinPower attribute.",
72+
"Verify that the DUT response contains a power-mW value to match the DUT capability, and is negative if and only if the ESACanGenerate read in step 4 is TRUE."),
73+
TestStep("7", "TH reads from the DUT the AbsMaxPower attribute.",
74+
"Verify that the DUT response contains a power-mW value to match the DUT capability, and greater than or equal to the AbsMinPower read in step 6."),
75+
TestStep("8", "TH reads from the DUT the PowerAdjustmentCapability attribute.",
76+
"Verify that the DUT response contains either a null value or a PowerAdjustCapabilityStruct value which contains a list of PowerAdjustStruct values and a valid Cause PowerAdjustReasonEnum (enum8) value."),
77+
TestStep("9", "If PFR or SFR feature is supported on the cluster, TH reads from the DUT the Forecast attribute.",
78+
"Verify that the DUT response contains either a null value or a valid ForecastStruct value."),
79+
TestStep("10", "If PA, STA, PAU, FA or CON feature is supported on the cluster, TH reads from the DUT the OptOutState attribute.",
80+
"Verify that the DUT response contains an OptOutStateEnum (enum8) value."),
81+
]
82+
83+
return steps
84+
85+
@async_test_body
86+
async def test_TC_DEM_2_1(self):
87+
# pylint: disable=too-many-locals, too-many-statements
88+
"""Run the test steps."""
89+
90+
# Allow some user input steps to be skipped if running under CI
91+
self.is_ci = self.check_pics("PICS_SDK_CI_ONLY")
92+
93+
self.step("1")
94+
# Commission DUT - already done
95+
96+
# Get the feature map for later
97+
self.step("2")
98+
feature_map = await self.read_dem_attribute_expect_success(attribute="FeatureMap")
99+
logger.info(f"FeatureMap: {feature_map}")
100+
101+
self.step("3")
102+
esa_type = await self.read_dem_attribute_expect_success(attribute="ESAType")
103+
asserts.assert_is_instance(esa_type, Clusters.DeviceEnergyManagement.Enums.ESATypeEnum, "Invalid type for ESAType")
104+
105+
if not self.is_ci:
106+
user_response = self.wait_for_user_input(prompt_msg=f"Detected ESAType is {esa_type.name}:{esa_type} - is this correct? Enter 'y' or 'n'",
107+
prompt_msg_placeholder="y",
108+
default_value="y")
109+
asserts.assert_equal(user_response.lower(), "y")
110+
111+
self.step("4")
112+
esa_can_generate = await self.read_dem_attribute_expect_success(attribute="ESACanGenerate")
113+
asserts.assert_is_instance(esa_can_generate, bool)
114+
115+
if not self.is_ci:
116+
user_response = self.wait_for_user_input(prompt_msg=f"Detected ESACanGenerate is: {esa_can_generate} - is this correct? Enter 'y' or 'n'",
117+
prompt_msg_placeholder="y",
118+
default_value="y")
119+
asserts.assert_equal(user_response.lower(), "y")
120+
121+
self.step("5")
122+
esa_state = await self.read_dem_attribute_expect_success(attribute="ESAState")
123+
logger.info(f"ESAState is {esa_state}")
124+
asserts.assert_is_instance(esa_state, Clusters.DeviceEnergyManagement.Enums.ESAStateEnum)
125+
126+
self.step("6")
127+
abs_min_power = await self.read_dem_attribute_expect_success(attribute="AbsMinPower")
128+
asserts.assert_is_instance(abs_min_power, int)
129+
130+
if not self.is_ci:
131+
user_response = self.wait_for_user_input(prompt_msg=f"AbsMinPower is {abs_min_power/1000000.0} W - is this correct? Enter 'y' or 'n'",
132+
prompt_msg_placeholder="y",
133+
default_value="y")
134+
asserts.assert_equal(user_response.lower(), "y")
135+
136+
if not esa_can_generate:
137+
# ESA's that can't generate must have positive values
138+
asserts.assert_greater_equal(abs_min_power, 0)
139+
140+
self.step("7")
141+
abs_max_power = await self.read_dem_attribute_expect_success(attribute="AbsMaxPower")
142+
asserts.assert_is_instance(abs_max_power, int)
143+
asserts.assert_greater_equal(abs_max_power, abs_min_power)
144+
145+
if not self.is_ci:
146+
user_response = self.wait_for_user_input(prompt_msg=f"AbsMaxPower is {abs_max_power/1000000.0} W - is this correct? Enter 'y' or 'n'",
147+
prompt_msg_placeholder="y",
148+
default_value="y")
149+
asserts.assert_equal(user_response.lower(), "y")
150+
151+
self.step("8")
152+
if Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerAdjustment & feature_map:
153+
power_adjustment_capability = await self.read_dem_attribute_expect_success(attribute="PowerAdjustmentCapability")
154+
logger.info(f"PowerAdjustmentCapability is {power_adjustment_capability}")
155+
156+
if power_adjustment_capability is not NullValue:
157+
asserts.assert_is_instance(power_adjustment_capability,
158+
Clusters.DeviceEnergyManagement.Structs.PowerAdjustCapabilityStruct)
159+
160+
power_adjustment_list = power_adjustment_capability.powerAdjustCapability
161+
if power_adjustment_list is not NullValue:
162+
asserts.assert_is_instance(power_adjustment_list, list)
163+
for entry in power_adjustment_list:
164+
asserts.assert_is_instance(entry, Clusters.DeviceEnergyManagement.Structs.PowerAdjustStruct)
165+
166+
power_adjustment_cause = power_adjustment_capability.cause
167+
asserts.assert_is_instance(power_adjustment_cause, Clusters.DeviceEnergyManagement.Enums.PowerAdjustReasonEnum)
168+
169+
self.step("9")
170+
if Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerForecastReporting & feature_map or \
171+
Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStateForecastReporting & feature_map:
172+
forecast = await self.read_dem_attribute_expect_success(attribute="Forecast")
173+
logger.info(f"Forecast is {forecast}")
174+
175+
if forecast is not NullValue:
176+
asserts.assert_is_instance(forecast,
177+
Clusters.DeviceEnergyManagement.Structs.ForecastStruct)
178+
179+
self.step("10")
180+
if Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPowerAdjustment & feature_map or \
181+
Clusters.DeviceEnergyManagement.Bitmaps.Feature.kStartTimeAdjustment & feature_map or \
182+
Clusters.DeviceEnergyManagement.Bitmaps.Feature.kPausable & feature_map or \
183+
Clusters.DeviceEnergyManagement.Bitmaps.Feature.kForecastAdjustment & feature_map or \
184+
Clusters.DeviceEnergyManagement.Bitmaps.Feature.kConstraintBasedAdjustment & feature_map:
185+
opt_out_state = await self.read_dem_attribute_expect_success(attribute="OptOutState")
186+
logger.info(f"OptOutState is {opt_out_state.name}:{opt_out_state}")
187+
188+
189+
if __name__ == "__main__":
190+
default_matter_test_main()

0 commit comments

Comments
 (0)