diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9024b0e3a207ee..9e87e73b7a4dbf 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -502,6 +502,7 @@ jobs: --target linux-x64-fabric-bridge-rpc-ipv6only-no-ble-no-wifi-clang \ --target linux-x64-fabric-sync-ipv6only-no-ble-no-wifi-clang \ --target linux-x64-light-data-model-no-unique-id-ipv6only-no-ble-no-wifi-clang \ + --target linux-x64-terms-and-conditions \ --target linux-x64-python-bindings \ build \ --copy-artifacts-to objdir-clone \ @@ -520,6 +521,7 @@ jobs: echo "FABRIC_BRIDGE_APP: out/linux-x64-fabric-bridge-rpc-ipv6only-no-ble-no-wifi-clang/fabric-bridge-app" >> /tmp/test_env.yaml echo "FABRIC_SYNC_APP: out/linux-x64-fabric-sync-ipv6only-no-ble-no-wifi-clang/fabric-sync" >> /tmp/test_env.yaml echo "LIGHTING_APP_NO_UNIQUE_ID: out/linux-x64-light-data-model-no-unique-id-ipv6only-no-ble-no-wifi-clang/chip-lighting-app" >> /tmp/test_env.yaml + echo "TERMS_AND_CONDITIONS_APP: out/linux-x64-terms-and-conditions/chip-terms-and-conditions-app" >> /tmp/test_env.yaml echo "TRACE_APP: out/trace_data/app-{SCRIPT_BASE_NAME}" >> /tmp/test_env.yaml echo "TRACE_TEST_JSON: out/trace_data/test-{SCRIPT_BASE_NAME}" >> /tmp/test_env.yaml echo "TRACE_TEST_PERFETTO: out/trace_data/test-{SCRIPT_BASE_NAME}" >> /tmp/test_env.yaml diff --git a/integrations/docker/images/chip-cert-bins/Dockerfile b/integrations/docker/images/chip-cert-bins/Dockerfile index ef823f7eeb674d..633f4e849cb100 100644 --- a/integrations/docker/images/chip-cert-bins/Dockerfile +++ b/integrations/docker/images/chip-cert-bins/Dockerfile @@ -168,6 +168,7 @@ RUN case ${TARGETPLATFORM} in \ --target linux-x64-fabric-admin-rpc-ipv6only \ --target linux-x64-light-data-model-no-unique-id-ipv6only \ --target linux-x64-network-manager-ipv6only \ + --target linux-x64-terms-and-conditions \ build \ && mv out/linux-x64-chip-tool-ipv6only-platform-mdns/chip-tool out/chip-tool \ && mv out/linux-x64-shell-ipv6only-platform-mdns/chip-shell out/chip-shell \ @@ -192,6 +193,7 @@ RUN case ${TARGETPLATFORM} in \ && mv out/linux-x64-fabric-admin-rpc-ipv6only/fabric-admin out/fabric-admin \ && mv out/linux-x64-light-data-model-no-unique-id-ipv6only/chip-lighting-app out/chip-lighting-data-model-no-unique-id-app \ && mv out/linux-x64-network-manager-ipv6only/matter-network-manager-app out/matter-network-manager-app \ + && mv out/linux-x64-terms-and-conditions/chip-terms-and-conditions-app out/chip-terms-and-conditions-app \ ;; \ "linux/arm64")\ set -x \ @@ -220,6 +222,7 @@ RUN case ${TARGETPLATFORM} in \ --target linux-arm64-fabric-admin-rpc-ipv6only \ --target linux-arm64-light-data-model-no-unique-id-ipv6only \ --target linux-arm64-network-manager-ipv6only \ + --target linux-arm64-terms-and-conditions \ build \ && mv out/linux-arm64-chip-tool-ipv6only-platform-mdns/chip-tool out/chip-tool \ && mv out/linux-arm64-shell-ipv6only-platform-mdns/chip-shell out/chip-shell \ @@ -244,6 +247,7 @@ RUN case ${TARGETPLATFORM} in \ && mv out/linux-arm64-fabric-admin-rpc-ipv6only/fabric-admin out/fabric-admin \ && mv out/linux-arm64-light-data-model-no-unique-id-ipv6only/chip-lighting-app out/chip-lighting-data-model-no-unique-id-app \ && mv out/linux-arm64-network-manager-ipv6only/matter-network-manager-app out/matter-network-manager-app \ + && mv out/linux-arm64-terms-and-conditions/chip-terms-and-conditions-app out/chip-terms-and-conditions-app \ ;; \ *) ;; \ esac @@ -283,6 +287,7 @@ COPY --from=chip-build-cert-bins /root/connectedhomeip/out/fabric-bridge-app app COPY --from=chip-build-cert-bins /root/connectedhomeip/out/fabric-admin apps/fabric-admin COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-lighting-data-model-no-unique-id-app apps/chip-lighting-data-model-no-unique-id-app COPY --from=chip-build-cert-bins /root/connectedhomeip/out/matter-network-manager-app apps/matter-network-manager-app +COPY --from=chip-build-cert-bins /root/connectedhomeip/out/chip-terms-and-conditions-app apps/chip-terms-and-conditions-app # Create symbolic links for now since this allows users to use existing configurations # for running just `app-name` instead of `apps/app-name` diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py index 4df8719def5596..0d6d99a5f00e71 100644 --- a/scripts/build/builders/host.py +++ b/scripts/build/builders/host.py @@ -282,8 +282,8 @@ def OutputNames(self): yield 'water-leak-detector-app' yield 'water-leak-detector-app.map' elif self == HostApp.TERMS_AND_CONDITIONS: - yield 'terms-and-conditions-app' - yield 'terms-and-conditions-app.map' + yield 'chip-terms-and-conditions-app' + yield 'chip-terms-and-conditions-app.map' else: raise Exception('Unknown app type: %r' % self) diff --git a/scripts/tests/local.py b/scripts/tests/local.py index 7321c1b1bead4c..eb9cbce8c0af68 100755 --- a/scripts/tests/local.py +++ b/scripts/tests/local.py @@ -387,6 +387,7 @@ def as_runner(path): FABRIC_SYNC_APP: { as_runner(f'out/{target_prefix}-fabric-sync-no-ble-no-wifi-ipv6only-clang-boringssl/fabric-sync')} LIGHTING_APP_NO_UNIQUE_ID: {as_runner(f'out/{target_prefix}-light-data-model-no-unique-id-ipv6only-no-ble-no-wifi-clang/chip-lighting-app')} + TERMS_AND_CONDITIONS_APP: {as_runner(f'out/{target_prefix}-terms-and-conditions/chip-terms-and-conditions-app')} TRACE_APP: out/trace_data/app-{{SCRIPT_BASE_NAME}} TRACE_TEST_JSON: out/trace_data/test-{{SCRIPT_BASE_NAME}} TRACE_TEST_PERFETTO: out/trace_data/test-{{SCRIPT_BASE_NAME}} diff --git a/src/app/tests/suites/certification/PICS.yaml b/src/app/tests/suites/certification/PICS.yaml index 9faf23bd10bf79..9aec1522c923ae 100644 --- a/src/app/tests/suites/certification/PICS.yaml +++ b/src/app/tests/suites/certification/PICS.yaml @@ -3632,6 +3632,23 @@ PICS: CommissioningCompleteResponse command?" id: CGEN.S.C05.Tx + # + # server / features + # + - label: + "Does the device implement the General Commissioning cluster's terms + and conditions feature?" + id: CGEN.S.F00 + + - label: "The device's failsafe expiration limit." + id: PIXIT.CGEN.FailsafeExpiryLengthSeconds + + - label: "The device's required terms and conditions acknowledgements." + id: PIXIT.CGEN.RequiredTCAcknowledgements + + - label: "The device's required minimum terms and conditions revision." + id: PIXIT.CGEN.TCRevision + # General Diagnostics Cluster Test Plan - label: "Does the device implement the General Diagnostics cluster as a diff --git a/src/app/tests/suites/certification/ci-pics-values b/src/app/tests/suites/certification/ci-pics-values index a2d2df1e173e0d..c33afb15a7bead 100644 --- a/src/app/tests/suites/certification/ci-pics-values +++ b/src/app/tests/suites/certification/ci-pics-values @@ -729,6 +729,7 @@ SWTCH.C.AO-READ=0 SWTCH.C.AO-WRITE=0 # General Commissioning Cluster +CGEN.C=1 CGEN.S=1 CGEN.S.A0000=1 CGEN.S.A0001=1 @@ -742,7 +743,13 @@ CGEN.S.C03.Tx=1 CGEN.S.C04.Rsp=1 CGEN.S.C05.Tx=1 -CGEN.C=1 +#Feature +CGEN.S.F00=1 + +#PIXIT +PIXIT.CGEN.FailsafeExpiryLengthSeconds=0 +PIXIT.CGEN.RequiredTCAcknowledgements=1 +PIXIT.CGEN.TCRevision=1 # LAUNDRY WASHER MODE CLUSTER LWM.S=1 diff --git a/src/python_testing/TC_CGEN_2_10.py b/src/python_testing/TC_CGEN_2_10.py new file mode 100644 index 00000000000000..4e094148e3d0d1 --- /dev/null +++ b/src/python_testing/TC_CGEN_2_10.py @@ -0,0 +1,154 @@ +# +# 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${TERMS_AND_CONDITIONS_APP} +# app-args: > +# --tc-min-required-version 1 +# --tc-required-acknowledgements 1 +# --custom-flow 2 +# --capabilities 6 +# script-args: +# --PICS src/app/tests/suites/certification/ci-pics-values +# --in-test-commissioning-method on-network +# --tc-version-to-simulate 1 +# --tc-user-response-to-simulate 1 +# --qr-code MT:-24J0AFN00KA0648G00 +# --trace-to json:log +# factoryreset: True +# quiet: True +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +from chip import ChipDeviceCtrl +from chip.commissioning import ROOT_ENDPOINT_ID +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_10(MatterBaseTest): + def desc_TC_CGEN_2_10(self) -> str: + return "[TC-CGEN-2.10] Verification that required terms can't be unset from TCAcknowledgements with SetTCAcknowledgements [DUT as Server]" + + def pics_TC_CGEN_2_10(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["CGEN.S", "CGEN.S.F00"] + + def steps_TC_CGEN_2_10(self) -> list[TestStep]: + return [ + TestStep(0, description="", expectation="", is_commissioning=False), + TestStep(1, "TH reads from the DUT the attribute TCAcceptedVersion. Store the value as acceptedVersion."), + TestStep(2, "TH reads from the DUT the attribute TCAcknowledgements. Store the value as userAcknowledgements."), + TestStep(3, "TH Sends the SetTCAcknowledgements command to the DUT with the fields set as follows:\n* TCVersion: 0\n* TCUserResponse: 65535"), + TestStep(4, "TH reads from the DUT the attribute TCAcceptedVersion."), + TestStep(5, "TH reads from the DUT the attribute TCAcknowledgements."), + TestStep(6, "TH Sends the SetTCAcknowledgements command to the DUT with the fields set as follows:\n* TCVersion: acceptedVersion + 1\n* TCUserResponse: 0"), + TestStep(7, "TH reads from the DUT the attribute TCAcceptedVersion."), + TestStep(8, "TH reads from the DUT the attribute TCAcknowledgements."), + ] + + @async_test_body + async def test_TC_CGEN_2_10(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + + self.step(0) + if not self.check_pics("CGEN.S.F00"): + asserts.skip('Root endpoint does not support the [commissioning] feature under test') + return + + # Step 1: Begin commissioning with PASE and failsafe + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.commissioning_method = self.matter_test_config.in_test_commissioning_method + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + # Step 1: Read TCAcceptedVersion + self.step(1) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion)]) + accepted_version = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion] + + # Step 2: Read TCAcknowledgements + self.step(2) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgements)]) + user_acknowledgements = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgements] + + # Step 3: Send SetTCAcknowledgements with invalid version + self.step(3) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements(TCVersion=0, TCUserResponse=65535), + ) + + # Verify TCMinVersionNotMet error + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kTCMinVersionNotMet, + "Expected TCMinVersionNotMet error", + ) + + # Step 4: Verify TCAcceptedVersion unchanged + self.step(4) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion)]) + current_version = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion] + asserts.assert_equal(current_version, accepted_version, "TCAcceptedVersion changed unexpectedly") + + # Step 5: Verify TCAcknowledgements unchanged + self.step(5) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgements)]) + current_acknowledgements = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgements] + asserts.assert_equal(current_acknowledgements, user_acknowledgements, "TCAcknowledgements changed unexpectedly") + + # Step 6: Send SetTCAcknowledgements with invalid response + self.step(6) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=accepted_version + 1, TCUserResponse=0 + ), + ) + + # Verify RequiredTCNotAccepted error + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kRequiredTCNotAccepted, + "Expected RequiredTCNotAccepted error", + ) + + # Step 7: Verify TCAcceptedVersion still unchanged + self.step(7) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion)]) + current_version = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion] + asserts.assert_equal(current_version, accepted_version, "TCAcceptedVersion changed unexpectedly after second attempt") + + # Step 8: Verify TCAcknowledgements still unchanged + self.step(8) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgements)]) + current_acknowledgements = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgements] + asserts.assert_equal( + current_acknowledgements, + user_acknowledgements, + "TCAcknowledgements changed unexpectedly after second attempt", + ) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_CGEN_2_11.py b/src/python_testing/TC_CGEN_2_11.py new file mode 100644 index 00000000000000..dc600135fad1ef --- /dev/null +++ b/src/python_testing/TC_CGEN_2_11.py @@ -0,0 +1,179 @@ +# +# 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${TERMS_AND_CONDITIONS_APP} +# app-args: > +# --tc-min-required-version 1 +# --tc-required-acknowledgements 1 +# --custom-flow 2 +# --capabilities 6 +# script-args: +# --PICS src/app/tests/suites/certification/ci-pics-values +# --in-test-commissioning-method on-network +# --int-arg PIXIT.CGEN.FailsafeExpiryLengthSeconds:900 +# --int-arg PIXIT.CGEN.RequiredTCAcknowledgements:1 +# --int-arg PIXIT.CGEN.TCRevision:1 +# --qr-code MT:-24J0AFN00KA0648G00 +# --trace-to json:log +# factoryreset: True +# quiet: True +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +from chip import ChipDeviceCtrl +from chip.commissioning import ROOT_ENDPOINT_ID +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_11(MatterBaseTest): + def desc_TC_CGEN_2_11(self) -> str: + return "[TC-CGEN-2.11] Verification that TCAcknowledgements and TCAcceptedVersion can be updated after being commissioned [DUT as Server]" + + def pics_TC_CGEN_2_11(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["CGEN.S", "CGEN.S.F00"] + + def steps_TC_CGEN_2_11(self) -> list[TestStep]: + return [ + TestStep(0, description="", expectation="", is_commissioning=False), + TestStep(1, "TH begins commissioning the DUT and performs the following steps in order:\n* Security setup using PASE\n* Setup fail-safe timer, with ExpiryLengthSeconds field set to PIXIT.CGEN.FailsafeExpiryLengthSeconds and the Breadcrumb value as 1\n* Configure information- UTC time, regulatory, etc."), + TestStep(2, "TH sends SetTCAcknowledgements to DUT with the following values:\n* TCVersion: PIXIT.CGEN.TCRevision\n* TCUserResponse: PIXIT.CGEN.RequiredTCAcknowledgements"), + TestStep(3, "TH sends CommissioningComplete to DUT."), + TestStep(4, "TH Sends the SetTCAcknowledgements command to the DUT with the fields set as follows:\n* TCVersion: PIXIT.CGEN.TCRevision + 1\n* TCUserResponse: PIXIT.CGEN.RequiredTCAcknowledgements"), + TestStep(5, "TH reads from the DUT the attribute TCAcceptedVersion."), + TestStep(6, "TH Sends the SetTCAcknowledgements command to the DUT with the fields set as follows:\n* TCVersion: PIXIT.CGEN.TCRevision + 1\n* TCUserResponse: 65535"), + TestStep(7, "TH reads from the DUT the attribute TCAcknowledgements."), + ] + + @async_test_body + async def test_TC_CGEN_2_11(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + failsafe_expiry_length_seconds = self.matter_test_config.global_test_params['PIXIT.CGEN.FailsafeExpiryLengthSeconds'] + tc_version_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.TCRevision'] + tc_user_response_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.RequiredTCAcknowledgements'] + + self.step(0) + if not self.check_pics("CGEN.S.F00"): + asserts.skip('Root endpoint does not support the [commissioning] feature under test') + return + + # Step 1: Begin commissioning with PASE and failsafe + self.step(1) + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.commissioning_method = self.matter_test_config.in_test_commissioning_method + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.ArmFailSafe( + expiryLengthSeconds=failsafe_expiry_length_seconds, breadcrumb=1), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "ArmFailSafeResponse error code is not OK.", + ) + + # Step 2: Send initial SetTCAcknowledgements + self.step(2) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=tc_version_to_simulate, TCUserResponse=tc_user_response_to_simulate + ), + ) + + # Verify initial SetTCAcknowledgements response + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "Initial SetTCAcknowledgements failed", + ) + + # Step 3: Send CommissioningComplete + self.step(3) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + + # Verify CommissioningComplete response + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "CommissioningComplete failed", + ) + + # Step 4: Send SetTCAcknowledgements with updated version + self.step(4) + updated_tc_version = tc_version_to_simulate + 1 + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=updated_tc_version, TCUserResponse=tc_user_response_to_simulate + ), + ) + + # Verify SetTCAcknowledgements response with updated version + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "SetTCAcknowledgements with updated version failed", + ) + + # Step 5: Verify TCAcceptedVersion is updated + self.step(5) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion)]) + current_version = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion] + asserts.assert_equal(current_version, updated_tc_version, "TCAcceptedVersion not updated correctly") + + # Step 6: Send SetTCAcknowledgements with maximum acknowledgements + self.step(6) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=updated_tc_version, TCUserResponse=65535 + ), + ) + + # Verify SetTCAcknowledgements response with maximum acknowledgements + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "SetTCAcknowledgements with maximum acknowledgements failed", + ) + + # Step 7: Verify TCAcknowledgements is updated + self.step(7) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgements)]) + current_acknowledgements = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgements] + asserts.assert_equal(current_acknowledgements, 65535, "TCAcknowledgements not updated to maximum value") + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_CGEN_2_5.py b/src/python_testing/TC_CGEN_2_5.py new file mode 100644 index 00000000000000..f6d6043958b005 --- /dev/null +++ b/src/python_testing/TC_CGEN_2_5.py @@ -0,0 +1,199 @@ +# +# 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${TERMS_AND_CONDITIONS_APP} +# app-args: > +# --tc-min-required-version 1 +# --tc-required-acknowledgements 1 +# --custom-flow 2 +# --capabilities 6 +# script-args: +# --PICS src/app/tests/suites/certification/ci-pics-values +# --in-test-commissioning-method on-network +# --int-arg PIXIT.CGEN.FailsafeExpiryLengthSeconds:900 +# --int-arg PIXIT.CGEN.RequiredTCAcknowledgements:1 +# --int-arg PIXIT.CGEN.TCRevision:1 +# --qr-code MT:-24J0AFN00KA0648G00 +# --trace-to json:log +# factoryreset: True +# quiet: True +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +from chip import ChipDeviceCtrl +from chip.clusters.Types import Nullable +from chip.commissioning import ROOT_ENDPOINT_ID +from chip.testing import matter_asserts +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_5(MatterBaseTest): + def desc_TC_CGEN_2_5(self) -> str: + return "[TC-CGEN-2.5] Verification for SetTCAcknowledgements [DUT as Server]" + + def pics_TC_CGEN_2_5(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["CGEN.S", "CGEN.S.F00"] + + def steps_TC_CGEN_2_5(self) -> list[TestStep]: + return [ + TestStep(0, description="", expectation="", is_commissioning=False), + TestStep(1, "TH begins commissioning the DUT and performs the following steps in order:\n* Security setup using PASE\n* Setup fail-safe timer, with ExpiryLengthSeconds field set to PIXIT.CGEN.FailsafeExpiryLengthSeconds and the Breadcrumb value as 1\n* Configure information- UTC time, regulatory, etc."), + TestStep(2, "TH reads TCAcknowledgementsRequired attribute from the DUT"), + TestStep(3, "TH reads TCUpdateDeadline attribute from the DUT"), + TestStep(4, "TH reads the FeatureMap from the General Commissioning Cluster."), + TestStep(5, "TH sends SetTCAcknowledgements to DUT with the following values:\n* TCVersion: PIXIT.CGEN.TCRevision\n* TCUserResponse: PIXIT.CGEN.RequiredTCAcknowledgements"), + TestStep(6, "TH reads TCAcknowledgementsRequired attribute from the DUT"), + TestStep(7, "TH continues commissioning with the DUT and performs the steps from 'Operation CSR exchange' through 'Security setup using CASE'"), + TestStep(8, "TH sends CommissioningComplete to DUT."), + TestStep(9, "TH reads from the DUT the attribute TCAcceptedVersion."), + TestStep(10, "TH reads from the DUT the attribute TCAcknowledgements."), + TestStep(11, "TH reads from the DUT the attribute TCMinRequiredVersion."), + TestStep(12, "TH reads from the DUT the attribute TCAcknowledgementsRequired."), + ] + + @async_test_body + async def test_TC_CGEN_2_5(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + + failsafe_expiry_length_seconds = self.matter_test_config.global_test_params['PIXIT.CGEN.FailsafeExpiryLengthSeconds'] + tc_version_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.TCRevision'] + tc_user_response_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.RequiredTCAcknowledgements'] + + self.step(0) + if not self.check_pics("CGEN.S.F00"): + asserts.skip('Root endpoint does not support the [commissioning] feature under test') + return + + # Step 1: Begin commissioning with PASE and failsafe + self.step(1) + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.commissioning_method = self.matter_test_config.in_test_commissioning_method + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.ArmFailSafe( + expiryLengthSeconds=failsafe_expiry_length_seconds, breadcrumb=1), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "ArmFailSafeResponse error code is not OK.", + ) + + # Step 2: Read TCAcknowledgementsRequired + self.step(2) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgementsRequired)]) + tc_acknowledgements_required = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgementsRequired] + asserts.assert_equal(tc_acknowledgements_required, True, "TCAcknowledgementsRequired should be True.") + + # Step 3: Read TCUpdateDeadline + self.step(3) + response = await commissioner.ReadAttribute( + nodeid=self.dut_node_id, + attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCUpdateDeadline)], + ) + tc_update_deadline = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCUpdateDeadline] + + # Validate the value is of type Optional[uint32], e.g. either Nullable or within the 32-bit range. + if not isinstance(tc_update_deadline, Nullable): + matter_asserts.assert_valid_uint32(tc_update_deadline, "TCUpdateDeadline exceeds uint32 range") + + # Step 4: Verify TC feature flag in FeatureMap + self.step(4) + response = await commissioner.ReadAttribute( + nodeid=self.dut_node_id, + attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.FeatureMap)], + ) + feature_map = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.FeatureMap] + asserts.assert_equal(feature_map & Clusters.GeneralCommissioning.Bitmaps.Feature.kTermsAndConditions, + Clusters.GeneralCommissioning.Bitmaps.Feature.kTermsAndConditions, "TC feature flag is not set.") + + # Step 5: Send SetTCAcknowledgements + self.step(5) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=tc_version_to_simulate, TCUserResponse=tc_user_response_to_simulate + ), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "SetTCAcknowledgementsResponse error code is not OK.", + ) + + # Step 6: Verify TCAcknowledgementsRequired is False + self.step(6) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgementsRequired)]) + tc_acknowledgements_required = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgementsRequired] + asserts.assert_equal(tc_acknowledgements_required, False, "TCAcknowledgementsRequired should be False.") + + # Step 7: Continue with CSR and CASE setup + self.step(7) + + # Step 8: Send CommissioningComplete + self.step(8) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "CommissioningCompleteResponse error code is not OK.", + ) + + # Step 9: Verify TCAcceptedVersion + self.step(9) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion)]) + accepted_version = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcceptedVersion] + asserts.assert_equal(accepted_version, tc_version_to_simulate, "TCAcceptedVersion does not match expected value.") + matter_asserts.assert_valid_uint16(accepted_version, "TCAcceptedVersion is not a uint16 type.") + + # Step 10: Verify TCAcknowledgements + self.step(10) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgements)]) + acknowledgements = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgements] + asserts.assert_equal(acknowledgements, tc_user_response_to_simulate, "TCAcknowledgements does not match expected value.") + matter_asserts.assert_valid_uint16(accepted_version, "TCAcknowledgements is not a map16 type.") + + # Step 11: Verify TCMinRequiredVersion + self.step(11) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCMinRequiredVersion)]) + min_required_version = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCMinRequiredVersion] + matter_asserts.assert_valid_uint16(min_required_version, "TCMinRequiredVersion is not a uint16 type.") + + # Step 12: Verify TCAcknowledgementsRequired is False again + self.step(12) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCAcknowledgementsRequired)]) + tc_acknowledgements_required = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCAcknowledgementsRequired] + asserts.assert_equal(tc_acknowledgements_required, False, "TCAcknowledgementsRequired should be False.") + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_CGEN_2_6.py b/src/python_testing/TC_CGEN_2_6.py new file mode 100644 index 00000000000000..07017842d59df1 --- /dev/null +++ b/src/python_testing/TC_CGEN_2_6.py @@ -0,0 +1,93 @@ +# +# 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${TERMS_AND_CONDITIONS_APP} +# app-args: > +# --tc-min-required-version 1 +# --tc-required-acknowledgements 1 +# --custom-flow 2 +# --capabilities 6 +# script-args: +# --PICS src/app/tests/suites/certification/ci-pics-values +# --in-test-commissioning-method on-network +# --qr-code MT:-24J0AFN00KA0648G00 +# --trace-to json:log +# factoryreset: True +# quiet: True +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +from chip import ChipDeviceCtrl +from chip.commissioning import ROOT_ENDPOINT_ID +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_6(MatterBaseTest): + def desc_TC_CGEN_2_6(self) -> str: + return "[TC-CGEN-2.6] Verification for CommissioningComplete no terms accepted when required [DUT as Server]" + + def pics_TC_CGEN_2_6(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["CGEN.S", "CGEN.S.F00"] + + def steps_TC_CGEN_2_6(self) -> list[TestStep]: + return [ + TestStep(0, description="", expectation="", is_commissioning=False), + TestStep(1, "TH starts commissioning the DUT. It performs all commissioning steps from 'Device discovery and establish commissioning channel' to 'Security setup using CASE', except for TC configuration with SetTCAcknowledgements."), + TestStep(2, "TH sends CommissioningComplete to DUT."), + ] + + @async_test_body + async def test_TC_CGEN_2_6(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + + self.step(0) + if not self.check_pics("CGEN.S.F00"): + asserts.skip('Root endpoint does not support the [commissioning] feature under test') + return + + # Step 1: Commission device without setting TC acknowledgements + self.step(1) + # Don't set TCs for the next commissioning and skip CommissioningComplete so we can manually call CommissioningComplete to check the response error code + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.commissioning_method = self.matter_test_config.in_test_commissioning_method + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + # Step 2: Send CommissioningComplete and verify error response + self.step(2) + response: Clusters.GeneralCommissioning.Commands.CommissioningCompleteResponse = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + + # Verify that DUT sends CommissioningCompleteResponse Command to TH with ErrorCode as 'TCAcknowledgementsNotReceived'(6) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kTCAcknowledgementsNotReceived, + "Expected TCAcknowledgementsNotReceived error code", + ) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_CGEN_2_7.py b/src/python_testing/TC_CGEN_2_7.py new file mode 100644 index 00000000000000..95a15b8cbd8229 --- /dev/null +++ b/src/python_testing/TC_CGEN_2_7.py @@ -0,0 +1,173 @@ +# +# 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${TERMS_AND_CONDITIONS_APP} +# app-args: > +# --tc-min-required-version 1 +# --tc-required-acknowledgements 1 +# --custom-flow 2 +# --capabilities 6 +# script-args: +# --PICS src/app/tests/suites/certification/ci-pics-values +# --in-test-commissioning-method on-network +# --int-arg PIXIT.CGEN.FailsafeExpiryLengthSeconds:900 +# --int-arg PIXIT.CGEN.RequiredTCAcknowledgements:1 +# --int-arg PIXIT.CGEN.TCRevision:1 +# --qr-code MT:-24J0AFN00KA0648G00 +# --trace-to json:log +# factoryreset: True +# quiet: True +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +from chip import ChipDeviceCtrl +from chip.commissioning import ROOT_ENDPOINT_ID +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_7(MatterBaseTest): + def desc_TC_CGEN_2_7(self) -> str: + return "[TC-CGEN-2.7] Verification for CommissioningComplete when SetTCAcknowledgements provides invalid terms [DUT as Server]" + + def pics_TC_CGEN_2_7(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["CGEN.S", "CGEN.S.F00"] + + def steps_TC_CGEN_2_7(self) -> list[TestStep]: + return [ + TestStep(0, description="", expectation="", is_commissioning=False), + TestStep(1, "TH begins commissioning the DUT and performs the following steps in order:\n* Security setup using PASE\n* Setup fail-safe timer, with ExpiryLengthSeconds field set to PIXIT.CGEN.FailsafeExpiryLengthSeconds and the Breadcrumb value as 1\n* Configure information- UTC time, regulatory, etc."), + TestStep(2, "TH reads from the DUT the attribute TCMinRequiredVersion. Store the value as minVersion."), + TestStep(3, "TH sends SetTCAcknowledgements to DUT with the following values:\n* TCVersion: minVersion\n* TCUserResponse: 0"), + TestStep(4, "TH continues commissioning with the DUT and performs the steps from 'Operation CSR exchange' through 'Security setup using CASE'"), + TestStep(5, "TH sends CommissioningComplete to DUT."), + TestStep(6, "TH sends SetTCAcknowledgements to DUT with the following values:\n* TCVersion: PIXIT.CGEN.TCRevision\n* TCUserResponse: PIXIT.CGEN.RequiredTCAcknowledgements"), + TestStep(7, "TH sends CommissioningComplete to DUT."), + ] + + @async_test_body + async def test_TC_CGEN_2_7(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + failsafe_expiry_length_seconds = self.matter_test_config.global_test_params['PIXIT.CGEN.FailsafeExpiryLengthSeconds'] + tc_version_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.TCRevision'] + tc_user_response_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.RequiredTCAcknowledgements'] + + self.step(0) + if not self.check_pics("CGEN.S.F00"): + asserts.skip('Root endpoint does not support the [commissioning] feature under test') + return + + # Step 1: Begin commissioning with PASE and failsafe + self.step(1) + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.commissioning_method = self.matter_test_config.in_test_commissioning_method + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.ArmFailSafe( + expiryLengthSeconds=failsafe_expiry_length_seconds, breadcrumb=1), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "ArmFailSafeResponse error code is not OK.", + ) + + # Step 2: Read TCMinRequiredVersion + self.step(2) + response = await commissioner.ReadAttribute(nodeid=self.dut_node_id, attributes=[(ROOT_ENDPOINT_ID, Clusters.GeneralCommissioning.Attributes.TCMinRequiredVersion)]) + min_version = response[ROOT_ENDPOINT_ID][Clusters.GeneralCommissioning][Clusters.GeneralCommissioning.Attributes.TCMinRequiredVersion] + + # Step 3: Send SetTCAcknowledgements with invalid response + self.step(3) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=min_version, TCUserResponse=0 + ), + ) + + # Verify error code is RequiredTCNotAccepted + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kRequiredTCNotAccepted, + "Expected RequiredTCNotAccepted error code", + ) + + # Step 4: Continue with CSR and CASE setup + self.step(4) + # Note: CSR and CASE setup is handled by the commissioning process + + # Step 5: Send CommissioningComplete and verify it fails + self.step(5) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + + # Verify error code is TCAcknowledgementsNotReceived + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kTCAcknowledgementsNotReceived, + "Expected TCAcknowledgementsNotReceived error code", + ) + + # Step 6: Send SetTCAcknowledgements with valid values + self.step(6) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=tc_version_to_simulate, TCUserResponse=tc_user_response_to_simulate + ), + ) + + # Verify error code is OK + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "Expected OK response for valid TC acknowledgements", + ) + + # Step 7: Send CommissioningComplete and verify success + self.step(7) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + + # Verify error code is OK + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "Expected OK response for CommissioningComplete", + ) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_CGEN_2_8.py b/src/python_testing/TC_CGEN_2_8.py new file mode 100644 index 00000000000000..1b885452d21d8d --- /dev/null +++ b/src/python_testing/TC_CGEN_2_8.py @@ -0,0 +1,165 @@ +# +# 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${TERMS_AND_CONDITIONS_APP} +# app-args: > +# --tc-min-required-version 1 +# --tc-required-acknowledgements 1 +# --custom-flow 2 +# --capabilities 6 +# script-args: +# --PICS src/app/tests/suites/certification/ci-pics-values +# --in-test-commissioning-method on-network +# --int-arg PIXIT.CGEN.FailsafeExpiryLengthSeconds:900 +# --int-arg PIXIT.CGEN.RequiredTCAcknowledgements:1 +# --int-arg PIXIT.CGEN.TCRevision:1 +# --qr-code MT:-24J0AFN00KA0648G00 +# --trace-to json:log +# factoryreset: True +# quiet: True +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +from chip import ChipDeviceCtrl +from chip.commissioning import ROOT_ENDPOINT_ID +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_8(MatterBaseTest): + def desc_TC_CGEN_2_8(self) -> str: + return "[TC-CGEN-2.8] Verification that TCAcknowledgements is reset after Factory Reset [DUT as Server]" + + def pics_TC_CGEN_2_8(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["CGEN.S", "CGEN.S.F00"] + + def steps_TC_CGEN_2_8(self) -> list[TestStep]: + return [ + TestStep(0, description="", expectation="", is_commissioning=False), + TestStep(1, "TH begins commissioning the DUT and performs the following steps in order:\n* Security setup using PASE\n* Setup fail-safe timer, with ExpiryLengthSeconds field set to PIXIT.CGEN.FailsafeExpiryLengthSeconds and the Breadcrumb value as 1\n* Configure information- UTC time, regulatory, etc."), + TestStep(2, "TH sends SetTCAcknowledgements to DUT with the following values:\n* TCVersion: PIXIT.CGEN.TCRevision\n* TCUserResponse: PIXIT.CGEN.RequiredTCAcknowledgements"), + TestStep(3, "TH continues commissioning steps with the DUT and performs steps 'Operation CSR exchange' through 'Security setup using CASE'"), + TestStep(4, "TH sends CommissioningComplete to DUT."), + TestStep(5, "DUT is factory reset."), + TestStep(6, "Perform the necessary actions to put the DUT into a commissionable state."), + TestStep(7, "TH begins commissioning the DUT and performs the steps 'Device discovery and establish commissioning channel' through 'Security setup using CASE', skipping 'Configure information- TC Acknowledgements'"), + TestStep(8, "TH sends CommissioningComplete to DUT."), + ] + + @async_test_body + async def test_TC_CGEN_2_8(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + failsafe_expiry_length_seconds = self.matter_test_config.global_test_params['PIXIT.CGEN.FailsafeExpiryLengthSeconds'] + tc_version_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.TCRevision'] + tc_user_response_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.RequiredTCAcknowledgements'] + + self.step(0) + if not self.check_pics("CGEN.S.F00"): + asserts.skip('Root endpoint does not support the [commissioning] feature under test') + return + + # Step 1: Begin commissioning with PASE and failsafe + self.step(1) + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.commissioning_method = self.matter_test_config.in_test_commissioning_method + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.ArmFailSafe( + expiryLengthSeconds=failsafe_expiry_length_seconds, breadcrumb=1), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "ArmFailSafeResponse error code is not OK.", + ) + + # Step 2: Send SetTCAcknowledgements + self.step(2) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=tc_version_to_simulate, TCUserResponse=tc_user_response_to_simulate + ), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "SetTCAcknowledgements failed", + ) + + # Step 3: Continue with CSR and CASE setup + self.step(3) + # Note: CSR and CASE setup is handled by the commissioning process + + # Step 4: Send CommissioningComplete + self.step(4) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "First CommissioningComplete failed", + ) + + # Step 5: Factory reset is handled by test operator + self.step(5) + if not self.check_pics('PICS_USER_PROMPT'): + self.skip_all_remaining_steps(6) + return + + self.wait_for_user_input(prompt_msg="Manually trigger factory reset on the DUT, then continue") + + # Step 6: Put device in commissioning mode (requiring user input, so skip in CI) + self.step(6) + self.wait_for_user_input(prompt_msg="Manually set the DUT into commissioning mode, then continue") + + # Step 7: Commission without TC acknowledgements + self.step(7) + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + # Step 8: Verify CommissioningComplete fails + self.step(8) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kTCAcknowledgementsNotReceived, + "Expected TCAcknowledgementsNotReceived error after factory reset", + ) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_CGEN_2_9.py b/src/python_testing/TC_CGEN_2_9.py new file mode 100644 index 00000000000000..03521e5dd89b38 --- /dev/null +++ b/src/python_testing/TC_CGEN_2_9.py @@ -0,0 +1,194 @@ +# +# 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${TERMS_AND_CONDITIONS_APP} +# app-args: > +# --tc-min-required-version 1 +# --tc-required-acknowledgements 1 +# --custom-flow 2 +# --capabilities 6 +# script-args: +# --PICS src/app/tests/suites/certification/ci-pics-values +# --in-test-commissioning-method on-network +# --int-arg PIXIT.CGEN.FailsafeExpiryLengthSeconds:900 +# --int-arg PIXIT.CGEN.RequiredTCAcknowledgements:1 +# --int-arg PIXIT.CGEN.TCRevision:1 +# --qr-code MT:-24J0AFN00KA0648G00 +# --trace-to json:log +# factoryreset: True +# quiet: True +# === END CI TEST ARGUMENTS === + +import chip.clusters as Clusters +from chip import ChipDeviceCtrl +from chip.commissioning import ROOT_ENDPOINT_ID +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_CGEN_2_9(MatterBaseTest): + + async def remove_commissioner_fabric(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + + fabrics: list[Clusters.OperationalCredentials.Structs.FabricDescriptorStruct] = await self.read_single_attribute( + dev_ctrl=commissioner, + node_id=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + attribute=Clusters.OperationalCredentials.Attributes.Fabrics) + + # Re-order the list of fabrics so that the test harness admin fabric is removed last + commissioner_fabric = next((fabric for fabric in fabrics if fabric.fabricIndex == commissioner.fabricId), None) + fabrics.remove(commissioner_fabric) + fabrics.append(commissioner_fabric) + + for fabric in fabrics: + response: Clusters.OperationalCredentials.Commands.NOCResponse = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.OperationalCredentials.Commands.RemoveFabric(fabric.fabricIndex), + ) + asserts.assert_equal(response.statusCode, Clusters.OperationalCredentials.Enums.NodeOperationalCertStatusEnum.kOk) + + def desc_TC_CGEN_2_9(self) -> str: + return "[TC-CGEN-2.9] Verification that TCAcknowledgements is reset after all fabrics removed [DUT as Server]" + + def pics_TC_CGEN_2_9(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + return ["CGEN.S", "CGEN.S.F00"] + + def steps_TC_CGEN_2_9(self) -> list[TestStep]: + return [ + TestStep(0, description="", expectation="", is_commissioning=False), + TestStep(1, "TH begins commissioning the DUT and performs the following steps in order:\n* Security setup using PASE\n* Setup fail-safe timer, with ExpiryLengthSeconds field set to PIXIT.CGEN.FailsafeExpiryLengthSeconds and the Breadcrumb value as 1\n* Configure information- UTC time, regulatory, etc."), + TestStep(2, "TH sends SetTCAcknowledgements to DUT with the following values:\n* TCVersion: PIXIT.CGEN.TCRevision\n* TCUserResponse: PIXIT.CGEN.RequiredTCAcknowledgements"), + TestStep(3, "TH continues commissioning with the DUT and performs the steps from 'Operation CSR exchange' through 'Security setup using CASE'"), + TestStep(4, "TH sends CommissioningComplete to DUT."), + TestStep(5, "TH removes all fabrics from DUT with RemoveFabric."), + TestStep(6, "Perform the necessary actions to put the DUT into a commissionable state."), + TestStep(7, "TH begins commissioning the DUT and performs all steps from 'Device discovery and establish commissioning channel' through 'Security setup using CASE', skipping the 'Configure TC acknowledgements' step"), + TestStep(8, "TH sends CommissioningComplete to DUT."), + ] + + @async_test_body + async def test_TC_CGEN_2_9(self): + commissioner: ChipDeviceCtrl.ChipDeviceController = self.default_controller + failsafe_expiry_length_seconds = self.matter_test_config.global_test_params['PIXIT.CGEN.FailsafeExpiryLengthSeconds'] + tc_version_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.TCRevision'] + tc_user_response_to_simulate = self.matter_test_config.global_test_params['PIXIT.CGEN.RequiredTCAcknowledgements'] + + self.step(0) + if not self.check_pics("CGEN.S.F00"): + asserts.skip('Root endpoint does not support the [commissioning] feature under test') + return + + # Step 1: Begin commissioning with PASE and failsafe + self.step(1) + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.commissioning_method = self.matter_test_config.in_test_commissioning_method + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.ArmFailSafe( + expiryLengthSeconds=failsafe_expiry_length_seconds, breadcrumb=1), + ) + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "ArmFailSafeResponse error code is not OK.", + ) + + # Step 2: Send SetTCAcknowledgements + self.step(2) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.SetTCAcknowledgements( + TCVersion=tc_version_to_simulate, TCUserResponse=tc_user_response_to_simulate + ), + ) + + # Verify SetTCAcknowledgements response + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "SetTCAcknowledgements failed", + ) + + # Step 3: Continue with CSR and CASE setup + self.step(3) + # Note: CSR and CASE setup is handled by the commissioning process + + # Step 4: Send CommissioningComplete + self.step(4) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + + # Verify CommissioningComplete response + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kOk, + "First CommissioningComplete failed", + ) + + # Step 5: Remove all fabrics + self.step(5) + await self.remove_commissioner_fabric() + + # Step 6: Put device in commissioning mode (requiring user input, so skip in CI) + self.step(6) + if not self.check_pics('PICS_USER_PROMPT'): + self.skip_all_remaining_steps(7) + return + + self.wait_for_user_input(prompt_msg="Set the DUT into commissioning mode") + + # Step 7: Commission without TC acknowledgements + self.step(7) + commissioner.SetSkipCommissioningComplete(True) + self.matter_test_config.tc_version_to_simulate = None + self.matter_test_config.tc_user_response_to_simulate = None + await self.commission_devices() + + # Step 8: Verify CommissioningComplete fails + self.step(8) + response = await commissioner.SendCommand( + nodeid=self.dut_node_id, + endpoint=ROOT_ENDPOINT_ID, + payload=Clusters.GeneralCommissioning.Commands.CommissioningComplete(), + ) + + # Verify CommissioningComplete fails with correct error + asserts.assert_equal( + response.errorCode, + Clusters.GeneralCommissioning.Enums.CommissioningErrorEnum.kTCAcknowledgementsNotReceived, + "Expected TCAcknowledgementsNotReceived error after fabric removal", + ) + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py index bac18a7d408414..5a6481d3d315a1 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2022 Project CHIP Authors +# Copyright (c) 2022-2025 Project CHIP Authors # All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -221,6 +221,100 @@ def get_wait_seconds_from_set_time(set_time_matter_us: int, wait_seconds: int): return wait_seconds - seconds_passed +@dataclass +class SetupPayloadInfo: + filter_type: discovery.FilterType = discovery.FilterType.LONG_DISCRIMINATOR + filter_value: int = 0 + passcode: int = 0 + + +@dataclass +class CommissioningInfo: + commissionee_ip_address_just_for_testing: Optional[str] = None + commissioning_method: Optional[str] = None + thread_operational_dataset: Optional[str] = None + wifi_passphrase: Optional[str] = None + wifi_ssid: Optional[str] = None + # Accepted Terms and Conditions if used + tc_version_to_simulate: int = None + tc_user_response_to_simulate: int = None + + +async def commission_device( + dev_ctrl: ChipDeviceCtrl.ChipDeviceController, node_id: int, info: SetupPayloadInfo, commissioning_info: CommissioningInfo +) -> bool: + if commissioning_info.tc_version_to_simulate is not None and commissioning_info.tc_user_response_to_simulate is not None: + logging.debug( + f"Setting TC Acknowledgements to version {commissioning_info.tc_version_to_simulate} with user response {commissioning_info.tc_user_response_to_simulate}." + ) + dev_ctrl.SetTCAcknowledgements(commissioning_info.tc_version_to_simulate, commissioning_info.tc_user_response_to_simulate) + + if commissioning_info.commissioning_method == "on-network": + try: + await dev_ctrl.CommissionOnNetwork( + nodeId=node_id, setupPinCode=info.passcode, filterType=info.filter_type, filter=info.filter_value + ) + return True + except ChipStackError as e: + logging.error("Commissioning failed: %s" % e) + return False + elif commissioning_info.commissioning_method == "ble-wifi": + try: + await dev_ctrl.CommissionWiFi( + info.filter_value, + info.passcode, + node_id, + commissioning_info.wifi_ssid, + commissioning_info.wifi_passphrase, + isShortDiscriminator=(info.filter_type == DiscoveryFilterType.SHORT_DISCRIMINATOR), + ) + return True + except ChipStackError as e: + logging.error("Commissioning failed: %s" % e) + return False + elif commissioning_info.commissioning_method == "ble-thread": + try: + await dev_ctrl.CommissionThread( + info.filter_value, + info.passcode, + node_id, + commissioning_info.thread_operational_dataset, + isShortDiscriminator=(info.filter_type == DiscoveryFilterType.SHORT_DISCRIMINATOR), + ) + return True + except ChipStackError as e: + logging.error("Commissioning failed: %s" % e) + return False + elif commissioning_info.commissioning_method == "on-network-ip": + try: + logging.warning("==== USING A DIRECT IP COMMISSIONING METHOD NOT SUPPORTED IN THE LONG TERM ====") + await dev_ctrl.CommissionIP( + ipaddr=commissioning_info.commissionee_ip_address_just_for_testing, + setupPinCode=info.passcode, + nodeid=node_id, + ) + return True + except ChipStackError as e: + logging.error("Commissioning failed: %s" % e) + return False + else: + raise ValueError("Invalid commissioning method %s!" % commissioning_info.commissioning_method) + + +async def commission_devices( + dev_ctrl: ChipDeviceCtrl.ChipDeviceController, + dut_node_ids: List[int], + setup_payloads: List[SetupPayloadInfo], + commissioning_info: CommissioningInfo, +) -> bool: + commissioned = [] + for node_id, setup_payload in zip(dut_node_ids, setup_payloads): + logging.info(f"Commissioning method: {commissioning_info.commissioning_method}") + commissioned.append(await commission_device(dev_ctrl, node_id, setup_payload, commissioning_info)) + + return all(commissioned) + + class SimpleEventCallback: def __init__(self, name: str, expected_cluster_id: int, expected_event_id: int, output_queue: queue.SimpleQueue): self._name = name @@ -858,13 +952,6 @@ def manual_code(self): self.custom_flow, self.capabilities, self.version) -@dataclass -class SetupPayloadInfo: - filter_type: discovery.FilterType = discovery.FilterType.LONG_DISCRIMINATOR - filter_value: int = 0 - passcode: int = 0 - - class MatterStackState: def __init__(self, config: MatterTestConfig): self._logger = logger @@ -1180,6 +1267,22 @@ def check_pics(self, pics_key: str) -> bool: def is_pics_sdk_ci_only(self) -> bool: return self.check_pics('PICS_SDK_CI_ONLY') + async def commission_devices(self) -> bool: + dev_ctrl: ChipDeviceCtrl.ChipDeviceController = self.default_controller + dut_node_ids: List[int] = self.matter_test_config.dut_node_ids + setup_payloads: List[SetupPayloadInfo] = self.get_setup_payload_info() + commissioning_info: CommissioningInfo = CommissioningInfo( + commissionee_ip_address_just_for_testing=self.matter_test_config.commissionee_ip_address_just_for_testing, + commissioning_method=self.matter_test_config.commissioning_method, + thread_operational_dataset=self.matter_test_config.thread_operational_dataset, + wifi_passphrase=self.matter_test_config.wifi_passphrase, + wifi_ssid=self.matter_test_config.wifi_ssid, + tc_version_to_simulate=self.matter_test_config.tc_version_to_simulate, + tc_user_response_to_simulate=self.matter_test_config.tc_user_response_to_simulate, + ) + + return await commission_devices(dev_ctrl, dut_node_ids, setup_payloads, commissioning_info) + async def open_commissioning_window(self, dev_ctrl: Optional[ChipDeviceCtrl.ChipDeviceController] = None, node_id: Optional[int] = None, timeout: int = 900) -> CustomCommissioningParameters: rnd_discriminator = random.randint(0, 4095) if dev_ctrl is None: @@ -2364,82 +2467,6 @@ def test_run_commissioning(self): if not self.event_loop.run_until_complete(self.commission_devices()): raise signals.TestAbortAll("Failed to commission node(s)") - async def commission_devices(self) -> bool: - conf = self.matter_test_config - - commissioned = [] - setup_payloads = self.get_setup_payload_info() - for node_id, setup_payload in zip(conf.dut_node_ids, setup_payloads): - logging.info(f"Starting commissioning for root index {conf.root_of_trust_index}, " - f"fabric ID 0x{conf.fabric_id:016X}, node ID 0x{node_id:016X}") - logging.info(f"Commissioning method: {conf.commissioning_method}") - commissioned.append(await self.commission_device(node_id, setup_payload)) - - return all(commissioned) - - async def commission_device(self, node_id: int, info: SetupPayloadInfo) -> bool: - dev_ctrl = self.default_controller - conf = self.matter_test_config - - if conf.tc_version_to_simulate is not None and conf.tc_user_response_to_simulate is not None: - logging.debug( - f"Setting TC Acknowledgements to version {conf.tc_version_to_simulate} with user response {conf.tc_user_response_to_simulate}.") - dev_ctrl.SetTCAcknowledgements(conf.tc_version_to_simulate, conf.tc_user_response_to_simulate) - - if conf.commissioning_method == "on-network": - try: - await dev_ctrl.CommissionOnNetwork( - nodeId=node_id, - setupPinCode=info.passcode, - filterType=info.filter_type, - filter=info.filter_value - ) - return True - except ChipStackError as e: - logging.error("Commissioning failed: %s" % e) - return False - elif conf.commissioning_method == "ble-wifi": - try: - await dev_ctrl.CommissionWiFi( - info.filter_value, - info.passcode, - node_id, - conf.wifi_ssid, - conf.wifi_passphrase, - isShortDiscriminator=(info.filter_type == DiscoveryFilterType.SHORT_DISCRIMINATOR) - ) - return True - except ChipStackError as e: - logging.error("Commissioning failed: %s" % e) - return False - elif conf.commissioning_method == "ble-thread": - try: - await dev_ctrl.CommissionThread( - info.filter_value, - info.passcode, - node_id, - conf.thread_operational_dataset, - isShortDiscriminator=(info.filter_type == DiscoveryFilterType.SHORT_DISCRIMINATOR) - ) - return True - except ChipStackError as e: - logging.error("Commissioning failed: %s" % e) - return False - elif conf.commissioning_method == "on-network-ip": - try: - logging.warning("==== USING A DIRECT IP COMMISSIONING METHOD NOT SUPPORTED IN THE LONG TERM ====") - await dev_ctrl.CommissionIP( - ipaddr=conf.commissionee_ip_address_just_for_testing, - setupPinCode=info.passcode, - nodeid=node_id, - ) - return True - except ChipStackError as e: - logging.error("Commissioning failed: %s" % e) - return False - else: - raise ValueError("Invalid commissioning method %s!" % conf.commissioning_method) - def default_matter_test_main(): """Execute the test class in a test module.