From dfe1ebe1a835f8653f747b0a9078465b5abd2a0e Mon Sep 17 00:00:00 2001 From: Andrey Khodyrev Date: Thu, 27 Feb 2025 17:10:09 -0600 Subject: [PATCH 1/7] add test TC_CNET_4_1.py --- src/python_testing/TC_CNET_4_1.py | 138 ++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 src/python_testing/TC_CNET_4_1.py diff --git a/src/python_testing/TC_CNET_4_1.py b/src/python_testing/TC_CNET_4_1.py new file mode 100644 index 00000000000000..7b053999fd4d6f --- /dev/null +++ b/src/python_testing/TC_CNET_4_1.py @@ -0,0 +1,138 @@ +# +# Copyright (c) 2025 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. +# + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${ALL_CLUSTERS_APP} +# app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# script-args: > +# --endpoint 0 +# --storage-path admin_storage.json +# --commissioning-method on-network +# --discriminator 1234 +# --passcode 20202021 +# --trace-to json:${TRACE_TEST_JSON}.json +# --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# factory-reset: true +# quiet: true +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +import test_plan_support +from chip.clusters.Types import NullValue +from chip.testing import matter_asserts +from chip.testing.matter_testing import MatterBaseTest, TestStep, default_matter_test_main, has_feature, run_if_endpoint_matches +from mobly import asserts + + +class TC_CNET_4_1(MatterBaseTest): + + def desc_TC_CNET_4_1(self) -> str: + return "[TC-CNET-4.1] [Wi-Fi] Verification for attributes check [DUT-Server]" + + def steps_TC_CNET_4_1(self) -> list[TestStep]: + steps = [ + TestStep(1, test_plan_support.commission_if_required(), "", is_commissioning=True), + TestStep(2, "TH reads Descriptor Cluster from the DUT with EP0 TH reads ServerList from the DUT", + "Verify for the presence of an element with value 49 (0x0031) in the ServerList"), + TestStep(3, "TH reads the MaxNetworks attribute from the DUT", + "Verify that MaxNetworks attribute value is within a range of 1 to 255"), + TestStep(4, "TH reads the Networks attribute list from the DUT", + "Verify that each element in the Networks attribute list has the following fields: 'NetworkID', 'connected'.\n\ + NetworkID field is of type octstr with a length range 1 to 32 \n\ + The connected field is of type bool \n\ + Verify that only one entry has connected status as TRUE \n\ + Verify that the number of entries in the Networks attribute is less than or equal to 'MaxNetworksValue'"), + TestStep(5, "TH reads InterfaceEnabled attribute from the DUT", "Verify that InterfaceEnabled attribute value is true"), + TestStep(6, "TH reads LastNetworkingStatus attribute from the DUT", + "LastNetworkingStatus attribute value will be within any one of the following values \ + Success, NetworkNotFound, OutOfRange, RegulatoryError, UnknownError, null"), + TestStep(7, "TH reads the LastNetworkID attribute from the DUT", + "Verify that LastNetworkID attribute matches the NetworkID value of one of the entries in the Networks attribute list"), + TestStep(8, "TH reads the LastConnectErrorValue attribute from the DUT", + "Verify that LastConnectErrorValue attribute value is null") + ] + return steps + + @run_if_endpoint_matches(has_feature(Clusters.NetworkCommissioning, + Clusters.NetworkCommissioning.Bitmaps.Feature.kWiFiNetworkInterface)) + async def test_TC_CNET_4_1(self): + # Commissioning already done + self.step(1) + + self.step(2) + server_list = await self.read_single_attribute_check_success( + cluster=Clusters.Descriptor, + attribute=Clusters.Descriptor.Attributes.ServerList) + asserts.assert_true(49 in server_list, + msg="Verify for the presence of an element with value 49 (0x0031) in the ServerList") + + self.step(3) + max_networks_count = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.MaxNetworks) + matter_asserts.assert_int_in_range(max_networks_count, min_value=1, max_value=255, description="MaxNetworks") + + self.step(4) + networks = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.Networks) + asserts.assert_true(networks, "NetworkInfoStruct list should not be empty") + matter_asserts.assert_list_element_type(networks, Clusters.NetworkCommissioning.Structs.NetworkInfoStruct, + "All elements in list are of type NetworkInfoStruct") + matter_asserts.assert_all(networks, lambda x: isinstance(x.networkID, bytes) and 1 <= len(x.networkID) <= 32, + "NetworkID field is an octet string within a length range 1 to 32") + connected_networks_count = sum(map(lambda x: x.connected, networks)) + asserts.assert_equal(connected_networks_count, 1, "Verify that only one entry has connected status as TRUE") + asserts.assert_less_equal(len(networks), max_networks_count, + "Number of entries in the Networks attribute is less than or equal to 'MaxNetworksValue'") + + self.step(5) + interface_enabled = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.InterfaceEnabled) + asserts.assert_true(interface_enabled, "Verify that InterfaceEnabled attribute value is true") + + self.step(6) + last_networking_status = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.LastNetworkingStatus) + expected_status = Clusters.NetworkCommissioning.Enums.NetworkCommissioningStatusEnum.kSuccess + asserts.assert_is(last_networking_status, expected_status, "Verify that LastNetworkingStatus attribute value is success") + + self.step(7) + last_network_id = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.LastNetworkID) + matching_networks_count = sum(map(lambda x: x.networkID == last_network_id, networks)) + asserts.assert_equal(matching_networks_count, 1, + "Verify that LastNetworkID attribute matches the NetworkID value of one of the entries") + asserts.assert_true(isinstance(last_network_id, bytes) and 1 <= len(last_network_id) <= 32) + + self.step(8) + last_connect_error_value = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.LastConnectErrorValue) + asserts.assert_is(last_connect_error_value, NullValue, "Verify that LastConnectErrorValue attribute value is null") + + +if __name__ == "__main__": + default_matter_test_main() From d0c663df56efce94010f5bfde5bf7dea1ba3b3fa Mon Sep 17 00:00:00 2001 From: Andrey Khodyrev Date: Thu, 27 Feb 2025 17:57:23 -0600 Subject: [PATCH 2/7] fix step 7 --- src/python_testing/TC_CNET_4_1.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python_testing/TC_CNET_4_1.py b/src/python_testing/TC_CNET_4_1.py index 7b053999fd4d6f..4a7f3a09c15713 100644 --- a/src/python_testing/TC_CNET_4_1.py +++ b/src/python_testing/TC_CNET_4_1.py @@ -125,7 +125,8 @@ async def test_TC_CNET_4_1(self): matching_networks_count = sum(map(lambda x: x.networkID == last_network_id, networks)) asserts.assert_equal(matching_networks_count, 1, "Verify that LastNetworkID attribute matches the NetworkID value of one of the entries") - asserts.assert_true(isinstance(last_network_id, bytes) and 1 <= len(last_network_id) <= 32) + asserts.assert_true(isinstance(last_network_id, bytes) and 1 <= len(last_network_id) <= 32, + "Verify LastNetworkID attribute value will be of type octstr with a length range of 1 to 32") self.step(8) last_connect_error_value = await self.read_single_attribute_check_success( From fc6025b927b0fe1f7cefcd6d2e5bea98542902e6 Mon Sep 17 00:00:00 2001 From: Andrey Khodyrev Date: Fri, 28 Feb 2025 16:40:34 -0600 Subject: [PATCH 3/7] define all test steps --- src/python_testing/TC_CNET_4_1.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/python_testing/TC_CNET_4_1.py b/src/python_testing/TC_CNET_4_1.py index 4a7f3a09c15713..45eac77cc8a703 100644 --- a/src/python_testing/TC_CNET_4_1.py +++ b/src/python_testing/TC_CNET_4_1.py @@ -61,14 +61,20 @@ def steps_TC_CNET_4_1(self) -> list[TestStep]: The connected field is of type bool \n\ Verify that only one entry has connected status as TRUE \n\ Verify that the number of entries in the Networks attribute is less than or equal to 'MaxNetworksValue'"), - TestStep(5, "TH reads InterfaceEnabled attribute from the DUT", "Verify that InterfaceEnabled attribute value is true"), - TestStep(6, "TH reads LastNetworkingStatus attribute from the DUT", + TestStep(5, "TH reads ScanMaxTimeSeconds attribute from the DUT", + "Verify that ScanMaxTimeSeconds attribute value is within the range of 1 to 255 seconds"), + TestStep(6, "TH reads ConnectMaxTimeSeconds Attribute from the DUT", + "Verify that ConnectMaxTimeSeconds attribute value is within the range of 1 to 255 seconds"), + TestStep(7, "TH reads InterfaceEnabled attribute from the DUT", "Verify that InterfaceEnabled attribute value is true"), + TestStep(8, "TH reads LastNetworkingStatus attribute from the DUT", "LastNetworkingStatus attribute value will be within any one of the following values \ Success, NetworkNotFound, OutOfRange, RegulatoryError, UnknownError, null"), - TestStep(7, "TH reads the LastNetworkID attribute from the DUT", + TestStep(9, "TH reads the LastNetworkID attribute from the DUT", "Verify that LastNetworkID attribute matches the NetworkID value of one of the entries in the Networks attribute list"), - TestStep(8, "TH reads the LastConnectErrorValue attribute from the DUT", - "Verify that LastConnectErrorValue attribute value is null") + TestStep(10, "TH reads the LastConnectErrorValue attribute from the DUT", + "Verify that LastConnectErrorValue attribute value is null"), + TestStep(11, "TH reads the SupportedWiFiBands attribute from the DUT", + "Verify that SupportedWiFiBands attribute value has 1 or more entries, all of which are in the range of WiFiBandEnum.") ] return steps From 675094087233019896af25020c3e2b85b9e53514 Mon Sep 17 00:00:00 2001 From: Andrey Khodyrev Date: Fri, 28 Feb 2025 17:04:01 -0600 Subject: [PATCH 4/7] step implementations --- src/python_testing/TC_CNET_4_1.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/python_testing/TC_CNET_4_1.py b/src/python_testing/TC_CNET_4_1.py index 45eac77cc8a703..110efc5bec6183 100644 --- a/src/python_testing/TC_CNET_4_1.py +++ b/src/python_testing/TC_CNET_4_1.py @@ -112,19 +112,31 @@ async def test_TC_CNET_4_1(self): "Number of entries in the Networks attribute is less than or equal to 'MaxNetworksValue'") self.step(5) + scan_max_time_seconds = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.ScanMaxTimeSeconds) + matter_asserts.assert_int_in_range(max_networks_count, min_value=1, max_value=255, description="ScanMaxTimeSeconds") + + self.step(6) + scan_max_time_seconds = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.ConnectMaxTimeSeconds) + matter_asserts.assert_int_in_range(max_networks_count, min_value=1, max_value=255, description="ConnectMaxTimeSeconds") + + self.step(7) interface_enabled = await self.read_single_attribute_check_success( cluster=Clusters.NetworkCommissioning, attribute=Clusters.NetworkCommissioning.Attributes.InterfaceEnabled) asserts.assert_true(interface_enabled, "Verify that InterfaceEnabled attribute value is true") - self.step(6) + self.step(8) last_networking_status = await self.read_single_attribute_check_success( cluster=Clusters.NetworkCommissioning, attribute=Clusters.NetworkCommissioning.Attributes.LastNetworkingStatus) expected_status = Clusters.NetworkCommissioning.Enums.NetworkCommissioningStatusEnum.kSuccess asserts.assert_is(last_networking_status, expected_status, "Verify that LastNetworkingStatus attribute value is success") - self.step(7) + self.step(9) last_network_id = await self.read_single_attribute_check_success( cluster=Clusters.NetworkCommissioning, attribute=Clusters.NetworkCommissioning.Attributes.LastNetworkID) @@ -134,12 +146,17 @@ async def test_TC_CNET_4_1(self): asserts.assert_true(isinstance(last_network_id, bytes) and 1 <= len(last_network_id) <= 32, "Verify LastNetworkID attribute value will be of type octstr with a length range of 1 to 32") - self.step(8) + self.step(10) last_connect_error_value = await self.read_single_attribute_check_success( cluster=Clusters.NetworkCommissioning, attribute=Clusters.NetworkCommissioning.Attributes.LastConnectErrorValue) asserts.assert_is(last_connect_error_value, NullValue, "Verify that LastConnectErrorValue attribute value is null") + self.step(11) + supported_wifi_bands = await self.read_single_attribute_check_success( + cluster=Clusters.NetworkCommissioning, + attribute=Clusters.NetworkCommissioning.Attributes.SupportedWiFiBands) + if __name__ == "__main__": default_matter_test_main() From 8d8b36fbe812fc4210b6fa4927f22f048c539b3c Mon Sep 17 00:00:00 2001 From: Andrey Khodyrev Date: Fri, 28 Feb 2025 17:10:48 -0600 Subject: [PATCH 5/7] add assert step 11 --- src/python_testing/TC_CNET_4_1.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/python_testing/TC_CNET_4_1.py b/src/python_testing/TC_CNET_4_1.py index 110efc5bec6183..91757678ad93c4 100644 --- a/src/python_testing/TC_CNET_4_1.py +++ b/src/python_testing/TC_CNET_4_1.py @@ -156,6 +156,8 @@ async def test_TC_CNET_4_1(self): supported_wifi_bands = await self.read_single_attribute_check_success( cluster=Clusters.NetworkCommissioning, attribute=Clusters.NetworkCommissioning.Attributes.SupportedWiFiBands) + matter_asserts.assert_list_element_type(supported_wifi_bands, Clusters.NetworkCommissioning.Enums.WiFiBandEnum, + "Verify that SupportedWiFiBands attribute value has 1 or more entries, all of which are in the range of WiFiBandEnum.") if __name__ == "__main__": From cd8f6e49c14a1092e36cc874ac00fa7ce46fb364 Mon Sep 17 00:00:00 2001 From: Andrey Khodyrev Date: Fri, 28 Feb 2025 17:18:40 -0600 Subject: [PATCH 6/7] change commissioning method --- src/python_testing/TC_CNET_4_1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_testing/TC_CNET_4_1.py b/src/python_testing/TC_CNET_4_1.py index 91757678ad93c4..0c778038a3f85b 100644 --- a/src/python_testing/TC_CNET_4_1.py +++ b/src/python_testing/TC_CNET_4_1.py @@ -26,7 +26,7 @@ # script-args: > # --endpoint 0 # --storage-path admin_storage.json -# --commissioning-method on-network +# --commissioning-method ble-wifi # --discriminator 1234 # --passcode 20202021 # --trace-to json:${TRACE_TEST_JSON}.json From 323b62c33c4d0aa18dfb2d359dca0e7fb0d35188 Mon Sep 17 00:00:00 2001 From: Andrey Khodyrev Date: Fri, 28 Feb 2025 17:59:35 -0600 Subject: [PATCH 7/7] fix steps 5 6 --- src/python_testing/TC_CNET_4_1.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/python_testing/TC_CNET_4_1.py b/src/python_testing/TC_CNET_4_1.py index 0c778038a3f85b..f55dfc8e4694ea 100644 --- a/src/python_testing/TC_CNET_4_1.py +++ b/src/python_testing/TC_CNET_4_1.py @@ -115,13 +115,14 @@ async def test_TC_CNET_4_1(self): scan_max_time_seconds = await self.read_single_attribute_check_success( cluster=Clusters.NetworkCommissioning, attribute=Clusters.NetworkCommissioning.Attributes.ScanMaxTimeSeconds) - matter_asserts.assert_int_in_range(max_networks_count, min_value=1, max_value=255, description="ScanMaxTimeSeconds") + matter_asserts.assert_int_in_range(scan_max_time_seconds, min_value=1, max_value=255, description="ScanMaxTimeSeconds") self.step(6) - scan_max_time_seconds = await self.read_single_attribute_check_success( + connect_max_time_seconds = await self.read_single_attribute_check_success( cluster=Clusters.NetworkCommissioning, attribute=Clusters.NetworkCommissioning.Attributes.ConnectMaxTimeSeconds) - matter_asserts.assert_int_in_range(max_networks_count, min_value=1, max_value=255, description="ConnectMaxTimeSeconds") + matter_asserts.assert_int_in_range(connect_max_time_seconds, min_value=1, + max_value=255, description="ConnectMaxTimeSeconds") self.step(7) interface_enabled = await self.read_single_attribute_check_success(