Power Topology: add test scripts (#32114)
* Initial XML for Power Topology cluster
* Regen
* Restyled really wants newlines at the end of every JSON file
* Rename LeafTopology to TreeTopology
* [Feature] Power Topology server & all-clusters-app stub
* Make endpointId a constructor arg for PowerTopologyDelegate
* Change PowerTopologyDelegate to not return std::vectors
* Remove unneeded entries in attributeAccessInterfaceAttributes for Power Topology cluster
* Typo in python/chip/clusters/__init__.py
* Format zcl.json
* Add DynamicPowerFlow feature to PowerTopology stub
* Add Power Topology to client
* Set CI PICS values
* Python test script for Power Topology
* Linted python script
* Add Power Topology python script test
* Add PWRTL_1_1 to ciTests.json
* Restyled
* Regen
* Format PICS.yaml
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 05d2670..f083cd7 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -502,6 +502,7 @@
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_IDM_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json --enable-key 000102030405060708090a0b0c0d0e0f" --script "src/python_testing/TC_IDM_1_4.py" --script-args "--hex-arg PIXIT.DGGEN.TEST_EVENT_TRIGGER_KEY:000102030405060708090a0b0c0d0e0f --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_IDM_4_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
+ scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_PWRTL_2_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RR_1_1.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCCLEANM_1_2.py" --script-args "--int-arg PIXIT_ENDPOINT:1 --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCRUNM_1_2.py" --script-args "--int-arg PIXIT_ENDPOINT:1 --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
diff --git a/src/app/tests/suites/certification/PICS.yaml b/src/app/tests/suites/certification/PICS.yaml
index 068db7f..49554c3 100644
--- a/src/app/tests/suites/certification/PICS.yaml
+++ b/src/app/tests/suites/certification/PICS.yaml
@@ -10160,3 +10160,36 @@
- label: "Can the mode change be manually controlled?"
id: EEVSEM.S.M.CAN_MANUALLY_CONTROLLED
+
+ #
+ # Power Topology Cluster
+ #
+ - label: "Does the device implement the Power Topology Cluster as a server?"
+ id: PWRTL.S
+
+ # Features
+
+ - label:
+ "Does the associated endpoint provide or consume power for the entire
+ node?"
+ id: PWRTL.S.F00
+
+ - label:
+ "Does the associated endpoint provide or consume power for itself and
+ its child endpoints?"
+ id: PWRTL.S.F01
+
+ - label:
+ "Does the associated endpoint provide or consume power for a provided
+ set of endpoints?"
+ id: PWRTL.S.F02
+
+ - label: "Can the provided set of endpoints change?"
+ id: PWRTL.S.F03
+
+ #Server attributes
+ - label: "Does the device implement the AvailableEndpoints attribute?"
+ id: PWRTL.S.A0000
+
+ - label: "Does the device implement the ActiveEndpoints attribute?"
+ id: PWRTL.S.A0001
diff --git a/src/app/tests/suites/certification/Test_TC_PWRTL_1_1.yaml b/src/app/tests/suites/certification/Test_TC_PWRTL_1_1.yaml
new file mode 100644
index 0000000..cfe6fd8
--- /dev/null
+++ b/src/app/tests/suites/certification/Test_TC_PWRTL_1_1.yaml
@@ -0,0 +1,119 @@
+# Copyright (c) 2021 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default
+
+name: 44.1.1. [TC-PWRTL-1.1] Global Attributes with DUT as Server
+
+PICS:
+ - PWRTL.S
+
+config:
+ nodeId: 0x12344321
+ cluster: "Power Topology"
+ endpoint: 1
+
+tests:
+ - label: "Step 1: Wait for the commissioned device to be retrieved"
+ cluster: "DelayCommands"
+ command: "WaitForCommissionee"
+ arguments:
+ values:
+ - name: "nodeId"
+ value: nodeId
+
+ - label: "Step 2: TH reads the ClusterRevision from DUT"
+ command: "readAttribute"
+ attribute: "ClusterRevision"
+ response:
+ value: 1
+ constraints:
+ type: int16u
+
+ - label:
+ "Step 3a: Given PWRTL.S.F00(Node) ensure featuremap has the correct
+ bit set"
+ PICS: PWRTL.S.F00
+ command: "readAttribute"
+ attribute: "FeatureMap"
+ response:
+ constraints:
+ type: bitmap32
+ hasMasksSet: [0x1]
+ hasMasksClear: [0x2, 0x4, 0x8]
+
+ - label:
+ "Step 3b: Given PWRTL.S.F01(Leaf) ensure featuremap has the correct
+ bit set"
+ PICS: PWRTL.S.F01
+ command: "readAttribute"
+ attribute: "FeatureMap"
+ response:
+ constraints:
+ type: bitmap32
+ hasMasksSet: [0x2]
+ hasMasksClear: [0x1, 0x4, 0x8]
+
+ - label:
+ "Step 3c: Given PWRTL.S.F02(Set) ensure featuremap has the correct bit
+ set"
+ PICS: PWRTL.S.F02
+ command: "readAttribute"
+ attribute: "FeatureMap"
+ response:
+ constraints:
+ type: bitmap32
+ hasMasksSet: [0x4]
+ hasMasksClear: [0x1, 0x2]
+
+ - label:
+ "Step 3d: Given PWRTL.S.F03(Dynamic Power Flow) ensure featuremap has
+ the correct bit set"
+ PICS: PWRTL.S.F03
+ command: "readAttribute"
+ attribute: "FeatureMap"
+ response:
+ constraints:
+ type: bitmap32
+ hasMasksSet: [0x4, 0x8]
+
+ - label: "Step 4a: TH reads AttributeList from DUT"
+ PICS: "!PICS_SF_SET && !PICS_SF_DYPF"
+ command: "readAttribute"
+ attribute: "AttributeList"
+ response:
+ constraints:
+ type: list
+ contains: []
+
+ - label:
+ "Step 4b: TH reads feature dependent attribute(AvailableEndpoints)
+ AttributeList from DUT"
+ PICS: "PICS_SF_SET && !PICS_SF_DYPF"
+ command: "readAttribute"
+ attribute: "AttributeList"
+ response:
+ constraints:
+ type: list
+ contains: [0]
+
+ - label:
+ "Step 4c: TH reads feature dependent attribute(ActiveEndpoints)
+ AttributeList from DUT"
+ PICS: "PICS_SF_SET && PICS_SF_DYPF"
+ command: "readAttribute"
+ attribute: "AttributeList"
+ response:
+ constraints:
+ type: list
+ contains: [0, 1]
diff --git a/src/app/tests/suites/certification/ci-pics-values b/src/app/tests/suites/certification/ci-pics-values
index c710f84..f200ad3 100644
--- a/src/app/tests/suites/certification/ci-pics-values
+++ b/src/app/tests/suites/certification/ci-pics-values
@@ -2939,3 +2939,15 @@
#Manual controllable
DEMM.S.M.CAN_TEST_MODE_FAILURE=1
DEMM.S.M.CAN_MANUALLY_CONTROLLED=1
+
+#Power Topology Cluster
+# Server
+PWRTL.S=1
+PWRTL.S.A0000=1
+PWRTL.S.A0001=1
+
+#Features
+PWRTL.S.F00=0
+PWRTL.S.F01=0
+PWRTL.S.F02=1
+PWRTL.S.F03=1
\ No newline at end of file
diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json
index ee6b543..26efd79 100644
--- a/src/app/tests/suites/ciTests.json
+++ b/src/app/tests/suites/ciTests.json
@@ -191,6 +191,7 @@
"Test_TC_OO_2_4"
],
"PowerSource": ["Test_TC_PS_1_1", "Test_TC_PS_2_1"],
+ "PowerTopology": ["Test_TC_PWRTL_1_1"],
"PressureMeasurement": [
"Test_TC_PRS_1_1",
"Test_TC_PRS_2_1",
diff --git a/src/app/tests/suites/manualTests.json b/src/app/tests/suites/manualTests.json
index 774b3d8..d199a68 100644
--- a/src/app/tests/suites/manualTests.json
+++ b/src/app/tests/suites/manualTests.json
@@ -311,6 +311,7 @@
"AccessControlEnforcement": [],
"OvenMode": ["Test_TC_OTCCM_1_1", "Test_TC_OTCCM_1_2"],
"EnergyEVSE": ["Test_TC_EEVSE_1_1", "Test_TC_EEVSE_2_1"],
+ "PowerTopology": ["Test_TC_PWRTL_1_1"],
"collection": [
"DeviceDiscovery",
"Groups",
@@ -338,6 +339,7 @@
"ModeSelect",
"OTASoftwareUpdate",
"PowerSourceConfiguration",
+ "PowerTopology",
"PressureMeasurement",
"SecureChannel",
"SoftwareDiagnostics",
diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json
index b399363..56adf0a 100644
--- a/src/app/zap_cluster_list.json
+++ b/src/app/zap_cluster_list.json
@@ -68,7 +68,6 @@
"MESSAGES_CLUSTER": [],
"MODE_SELECT_CLUSTER": [],
"NETWORK_COMMISSIONING_CLUSTER": [],
- "POWER_TOPOLOGY_CLUSTER": [],
"SAMPLE_MEI_CLUSTER": [],
"NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER": [],
"OCCUPANCY_SENSING_CLUSTER": ["occupancy-sensor-server"],
@@ -91,6 +90,7 @@
"POWER_PROFILE_CLUSTER": [],
"POWER_SOURCE_CLUSTER": [],
"POWER_SOURCE_CONFIGURATION_CLUSTER": [],
+ "POWER_TOPOLOGY_CLUSTER": [],
"PRESSURE_MEASUREMENT_CLUSTER": [],
"PROXY_CONFIGURATION_CLUSTER": [],
"PROXY_DISCOVERY_CLUSTER": [],
diff --git a/src/python_testing/TC_PWRTL_2_1.py b/src/python_testing/TC_PWRTL_2_1.py
new file mode 100644
index 0000000..bd839cd
--- /dev/null
+++ b/src/python_testing/TC_PWRTL_2_1.py
@@ -0,0 +1,69 @@
+#
+# Copyright (c) 2024 Project CHIP Authors
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import logging
+
+import chip.clusters as Clusters
+from chip.clusters.Types import NullValue
+from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main
+from mobly import asserts
+
+
+class TC_PWRTL_2_1(MatterBaseTest):
+
+ def pics_TC_PWRTL_2_1(self) -> list[str]:
+ return ["PWRTL.S"]
+
+ @async_test_body
+ async def test_TC_PWRTL_2_1(self):
+
+ attributes = Clusters.PowerTopology.Attributes
+
+ endpoint = self.user_params.get("endpoint", 1)
+
+ self.print_step(1, "Commissioning, already done")
+
+ if not self.check_pics("PWRTL.S.A0000"):
+ logging.info("Test skipped because PICS PWRTL.S.A0000 is not set")
+ return
+
+ self.print_step(2, "Read AvailableAttributes attribute")
+ available_endpoints = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=Clusters.Objects.PowerTopology, attribute=attributes.AvailableEndpoints)
+
+ if available_endpoints == NullValue:
+ logging.info("AvailableEndpoints is null")
+ else:
+ logging.info("AvailableEndpoints: %s" % (available_endpoints))
+
+ asserts.assert_less_equal(len(available_endpoints), 21,
+ "AvailableEndpoints length %d must be less than 21!" % len(available_endpoints))
+
+ if not self.check_pics("PWRTL.S.A0001"):
+ logging.info("Test skipped because PICS PWRTL.S.A0001 is not set")
+ return
+
+ self.print_step(3, "Read ActiveEndpoints attribute")
+ active_endpoints = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=Clusters.Objects.PowerTopology, attribute=attributes.ActiveEndpoints)
+ logging.info("ActiveEndpoints: %s" % (active_endpoints))
+
+ if available_endpoints == NullValue:
+ asserts.assert_true(active_endpoints == NullValue,
+ "ActiveEndpoints should be null when AvailableEndpoints is null: %s" % active_endpoints)
+
+
+if __name__ == "__main__":
+ default_matter_test_main()