From b678c783864cb58d9fd7a77d63c49d8bc2654e04 Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Tue, 26 Dec 2023 20:17:01 +0800 Subject: [PATCH 01/15] Add an option to set subscription capacity for linux examples --- BUILD.gn | 14 ++++++++++++++ examples/platform/linux/AppMain.cpp | 6 ++++++ examples/platform/linux/Options.cpp | 15 +++++++++++++++ examples/platform/linux/Options.h | 3 +++ scripts/build/gn_gen_cirque.sh | 2 +- 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/BUILD.gn b/BUILD.gn index 587d3df973c7a9..ed68689b0d3be8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -357,6 +357,10 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { enable_linux_lock_app_build = enable_default_builds && (host_os == "linux" || host_os == "mac") + # Build the Linux LIT ICD example. + enable_linux_lit_icd_app_build = + enable_default_builds && (host_os == "linux" || host_os == "mac") + # Build the cc13x2x7_26x2x7 lock app example. enable_cc13x2x7_26x2x7_lock_app_build = enable_ti_simplelink_builds @@ -610,6 +614,16 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { extra_build_deps += [ ":linux_lock_app" ] } + if (enable_linux_lit_icd_app_build) { + group("linux_lit_icd_app") { + deps = [ + "${chip_root}/examples/lit-icd-app/linux(${standalone_toolchain})", + ] + } + + extra_build_deps += [ ":linux_lit_icd_app" ] + } + if (enable_efr32_lock_app_build) { group("efr32_lock_app") { deps = [ "${chip_root}/examples/lock-app/efr32(${chip_root}/config/efr32/toolchain:efr32_lock_app)" ] diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 79e3e08edce718..dad244b19964b3 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -568,6 +568,12 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) // Init ZCL Data Model and CHIP App Server Server::GetInstance().Init(initParams); +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + // Set ReadHandler Capacity for Subscriptions + chip::app::InteractionModelEngine::GetInstance()->SetHandlerCapacityForSubscriptions(LinuxDeviceOptions::GetInstance().subscriptionCapacity); + chip::app::InteractionModelEngine::GetInstance()->SetForceHandlerQuota(true); +#endif + // Now that the server has started and we are done with our startup logging, // log our discovery/onboarding information again so it's not lost in the // noise. diff --git a/examples/platform/linux/Options.cpp b/examples/platform/linux/Options.cpp index c340f662df3269..f88f8967793e42 100644 --- a/examples/platform/linux/Options.cpp +++ b/examples/platform/linux/Options.cpp @@ -87,6 +87,9 @@ enum #if defined(PW_RPC_ENABLED) kOptionRpcServerPort = 0x1023, #endif +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + kDeviceOption_SubscriptionCapacity = 0x1024, +#endif }; constexpr unsigned kAppUsageLength = 64; @@ -143,6 +146,9 @@ OptionDef sDeviceOptionDefs[] = { { "simulate-no-internal-time", kNoArgument, kOptionSimulateNoInternalTime }, #if defined(PW_RPC_ENABLED) { "rpc-server-port", kArgumentRequired, kOptionRpcServerPort }, +#endif +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + { "subscription-capacity", kArgumentRequired, kDeviceOption_SubscriptionCapacity}, #endif {} }; @@ -263,6 +269,10 @@ const char * sDeviceOptionHelp = #if defined(PW_RPC_ENABLED) " --rpc-server-port\n" " Start RPC server on specified port\n" +#endif +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + " --subscription-capacity\n" + " Max subscriptions number for the device to manage\n" #endif "\n"; @@ -521,6 +531,11 @@ bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, case kOptionRpcServerPort: LinuxDeviceOptions::GetInstance().rpcServerPort = static_cast(atoi(aValue)); break; +#endif +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + case kDeviceOption_SubscriptionCapacity: + LinuxDeviceOptions::GetInstance().subscriptionCapacity = static_cast(atoi(aValue)); + break; #endif default: PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName); diff --git a/examples/platform/linux/Options.h b/examples/platform/linux/Options.h index 0aedffb57dc76e..e5267dd9634a17 100644 --- a/examples/platform/linux/Options.h +++ b/examples/platform/linux/Options.h @@ -70,6 +70,9 @@ struct LinuxDeviceOptions bool mSimulateNoInternalTime = false; #if defined(PW_RPC_ENABLED) uint16_t rpcServerPort = 33000; +#endif +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + size_t subscriptionCapacity = CHIP_IM_MAX_NUM_SUBSCRIPTIONS; #endif static LinuxDeviceOptions & GetInstance(); }; diff --git a/scripts/build/gn_gen_cirque.sh b/scripts/build/gn_gen_cirque.sh index 061f89932023ee..d6f6bd86905a0e 100755 --- a/scripts/build/gn_gen_cirque.sh +++ b/scripts/build/gn_gen_cirque.sh @@ -36,7 +36,7 @@ echo "Setup build environment" source "./scripts/activate.sh" echo "Build: GN configure" -gn --root="$CHIP_ROOT" gen --check --fail-on-unused-args out/debug --args='target_os="all"'"chip_build_tests=false chip_enable_wifi=false chip_im_force_fabric_quota_check=true enable_default_builds=false enable_host_gcc_build=true enable_standalone_chip_tool_build=true enable_linux_all_clusters_app_build=true enable_linux_lighting_app_build=true" +gn --root="$CHIP_ROOT" gen --check --fail-on-unused-args out/debug --args='target_os="all"'"chip_build_tests=false chip_enable_wifi=false chip_im_force_fabric_quota_check=true enable_default_builds=false enable_host_gcc_build=true enable_standalone_chip_tool_build=true enable_linux_all_clusters_app_build=true enable_linux_lighting_app_build=true enable_linux_lit_icd_app_build=true" echo "Build: Ninja build" time ninja -C out/debug all check From 27d76ac273a7c8ba2bbabd7aa5b95b0359b79882 Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Wed, 27 Dec 2023 14:50:38 +0800 Subject: [PATCH 02/15] Add basic subscription resumption cirque test and subscription resumption capacity cirque test --- .../chip-cirque-device-base/Dockerfile | 9 +- scripts/tests/cirque_tests.sh | 2 + src/controller/python/chip/ChipDeviceCtrl.py | 6 +- .../python/test/test_scripts/base.py | 272 ++++++++++++++++++ ...cription_resumption_capacity_test_ctrl1.py | 148 ++++++++++ ...cription_resumption_capacity_test_ctrl2.py | 162 +++++++++++ .../subscription_resumption_test.py | 151 ++++++++++ .../SubscriptionResumptionCapacityTest.py | 151 ++++++++++ .../SubscriptionResumptionTest.py | 124 ++++++++ 9 files changed, 1022 insertions(+), 3 deletions(-) create mode 100755 src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py create mode 100755 src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py create mode 100755 src/controller/python/test/test_scripts/subscription_resumption_test.py create mode 100755 src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py create mode 100755 src/test_driver/linux-cirque/SubscriptionResumptionTest.py diff --git a/integrations/docker/images/stage-2/chip-cirque-device-base/Dockerfile b/integrations/docker/images/stage-2/chip-cirque-device-base/Dockerfile index d7f7538e484e40..8d79b306c1a327 100644 --- a/integrations/docker/images/stage-2/chip-cirque-device-base/Dockerfile +++ b/integrations/docker/images/stage-2/chip-cirque-device-base/Dockerfile @@ -30,6 +30,7 @@ RUN apt-get update \ libgirepository1.0-dev \ libglib2.0-dev \ libjpeg-dev \ + openssh-server \ psmisc \ python3-dev \ python3-pip \ @@ -55,7 +56,12 @@ RUN apt-get update \ && echo "ctrl_interface=/run/wpa_supplicant" >> /etc/wpa_supplicant/wpa_supplicant.conf \ && echo "update_config=1" >> /etc/wpa_supplicant/wpa_supplicant.conf \ && rm -rf /var/lib/apt/lists/* \ - && pip3 install --no-cache-dir click==8.0.3 + && pip3 install --no-cache-dir click==8.0.3 paramiko \ + && mkdir /var/run/sshd \ + && echo 'root:admin' | chpasswd \ + && sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config \ + && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \ + && sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd COPY CHIPCirqueDaemon.py /bin/CHIPCirqueDaemon.py COPY entrypoint.sh /opt/entrypoint.sh @@ -65,3 +71,4 @@ WORKDIR / ENTRYPOINT ["/opt/entrypoint.sh"] EXPOSE 80 +EXPOSE 2222 diff --git a/scripts/tests/cirque_tests.sh b/scripts/tests/cirque_tests.sh index 2670a2e69eb0b3..0f9fe22e9cdde0 100755 --- a/scripts/tests/cirque_tests.sh +++ b/scripts/tests/cirque_tests.sh @@ -49,6 +49,8 @@ CIRQUE_TESTS=( "CommissioningFailureOnReportTest" "PythonCommissioningTest" "CommissioningWindowTest" + "SubscriptionResumptionTest" + "SubscriptionResumptionCapacityTest" ) BOLD_GREEN_TEXT="\033[1;32m" diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 72a1f7aaa681fd..78494b40691c73 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -1417,7 +1417,8 @@ def ZCLWriteAttribute(self, cluster: str, attribute: str, nodeid, endpoint, grou return asyncio.run(self.WriteAttribute(nodeid, [(endpoint, req, dataVersion)])) - def ZCLSubscribeAttribute(self, cluster, attribute, nodeid, endpoint, minInterval, maxInterval, blocking=True): + def ZCLSubscribeAttribute(self, cluster, attribute, nodeid, endpoint, minInterval, maxInterval, blocking=True, + keepSubscriptions=False, autoResubscribe=True): ''' Wrapper over ReadAttribute for a single attribute Returns a SubscriptionTransaction. See ReadAttribute for more information. ''' @@ -1428,7 +1429,8 @@ def ZCLSubscribeAttribute(self, cluster, attribute, nodeid, endpoint, minInterva req = eval(f"GeneratedObjects.{cluster}.Attributes.{attribute}") except BaseException: raise UnknownAttribute(cluster, attribute) - return asyncio.run(self.ReadAttribute(nodeid, [(endpoint, req)], None, False, reportInterval=(minInterval, maxInterval))) + return asyncio.run(self.ReadAttribute(nodeid, [(endpoint, req)], None, False, reportInterval=(minInterval, maxInterval), + keepSubscriptions=keepSubscriptions, autoResubscribe=autoResubscribe)) def ZCLCommandList(self): self.CheckIsActive() diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index 8ab30f8f6f5686..d04721478a5313 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -22,6 +22,7 @@ import inspect import logging import os +import paramiko import secrets import sys import threading @@ -41,6 +42,9 @@ from chip.crypto import p256keypair from chip.utils import CommissioningBuildingBlocks +CHIP_REPO = os.path.join(os.path.abspath( + os.path.dirname(__file__)), "..", "..", "..", "..", "..") + logger = logging.getLogger('PythonMatterControllerTEST') logger.setLevel(logging.INFO) @@ -1316,3 +1320,271 @@ def TestFabricScopedCommandDuringPase(self, nodeid: int): status = ex.status return status == IM.Status.UnsupportedAccess + + def TestSubscriptionResumption(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, remote_server_app: str): + desiredPath = None + receivedUpdate = False + updateLock = threading.Lock() + updateCv = threading.Condition(updateLock) + + def OnValueReport(path: Attribute.TypedAttributePath, transaction: Attribute.SubscriptionTransaction) -> None: + nonlocal desiredPath, updateCv, updateLock, receivedUpdate + if path.Path != desiredPath: + return + + data = transaction.GetAttribute(path) + logger.info( + f"Received report from server: path: {path.Path}, value: {data}") + with updateLock: + receivedUpdate = True + updateCv.notify_all() + + class _restartRemoteDevice(threading.Thread): + def __init__(self, remote_ip: str, ssh_port: int, remote_server_app: str): + super(_restartRemoteDevice, self).__init__() + self.remote_ip = remote_ip + self.ssh_port = ssh_port + self.remote_server_app = remote_server_app + + def run(self): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + client.connect(self.remote_ip, self.ssh_port, "root", "admin") + client.exec_command( + ("kill \"$(ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\')\"").format(self.remote_server_app)) + time.sleep(1) + stdin, stdout, stderr = client.exec_command( + ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\'").format(self.remote_server_app)) + if not stdout.read().decode().strip(): + logger.info(f"Succeed to kill remote process {self.remote_server_app}") + else: + logger.error(f"Failed to kill remote process {self.remote_server_app}") + + client.exec_command( + ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " + "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator 3840").format( + os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app))) + + finally: + client.close() + + try: + desiredPath = Clusters.Attribute.AttributePath( + EndpointId=1, ClusterId=6, AttributeId=0) + # OnOff Cluster, OnOff Attribute + subscription = self.devCtrl.ZCLSubscribeAttribute( + "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + subscription.SetAttributeUpdateCallback(OnValueReport) + + self.logger.info("Restart remote deivce") + restartRemoteThread = _restartRemoteDevice(remote_ip, ssh_port, remote_server_app) + restartRemoteThread.start() + # After device restarts, the attribute will be set dirty so the subscription can receive + # the update + with updateCv: + while receivedUpdate is False: + if not updateCv.wait(30.0): + self.logger.error( + "Failed to receive subscription resumption report") + break + + restartRemoteThread.join(30.0) + + # + # Clean-up by shutting down the sub. Otherwise, we're going to get callbacks through + # OnValueChange on what will soon become an invalid execution context above. + # + subscription.Shutdown() + + if restartRemoteThread.is_alive(): + # Thread join timed out + self.logger.error("Failed to join change thread") + return False + + return receivedUpdate + + except Exception as ex: + self.logger.exception(f"Failed to finish API test: {ex}") + return False + + return True + + def TestSubscriptionResumptionCapacity(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, + remote_server_app: str, subscription_capacity: int): + + class _restartRemoteDevice(threading.Thread): + def __init__(self, remote_ip: str, ssh_port: int, remote_server_app: str, subscription_capacity: int): + super(_restartRemoteDevice, self).__init__() + self.remote_ip = remote_ip + self.ssh_port = ssh_port + self.remote_server_app = remote_server_app + self.subscription_capacity = subscription_capacity + + def run(self): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + client.connect(self.remote_ip, self.ssh_port, "root", "admin") + client.exec_command( + ("kill \"$(ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\')\"").format(self.remote_server_app)) + time.sleep(1) + stdin, stdout, stderr = client.exec_command( + ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\'").format(self.remote_server_app)) + if not stdout.read().decode().strip(): + logger.info(f"Succeed to kill remote process {self.remote_server_app}") + else: + logger.error(f"Failed to kill remote process {self.remote_server_app}") + + client.exec_command("systemctl restart avahi-deamon.service") + client.exec_command( + ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " + "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator 3840 " + "--subscription-capacity {}").format( + os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app), + self.subscription_capacity)) + + finally: + client.close() + + try: + desiredPath = Clusters.Attribute.AttributePath( + EndpointId=1, ClusterId=6, AttributeId=0) + # OnOff Cluster, OnOff Attribute + for i in range(subscription_capacity): + self.devCtrl.ZCLSubscribeAttribute( + "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + + self.logger.info("Shutdown Controller 1") + self.devCtrl.Shutdown() + + self.logger.info("Restart remote deivce") + restartRemoteThread = _restartRemoteDevice(remote_ip, ssh_port, remote_server_app, subscription_capacity) + restartRemoteThread.start() + time.sleep(6) + + self.logger.info("Send a new subscription request from the second controller") + # Close previous session so that the controller 2 will res-establish the session to the remote device + self.devCtrl2.CloseSession(nodeid) + self.devCtrl2.ZCLSubscribeAttribute( + "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + restartRemoteThread.join(10.0) + + if restartRemoteThread.is_alive(): + # Thread join timed out + self.logger.error("Failed to join change thread") + return False + + return True + + except Exception as ex: + self.logger.exception(f"Failed to finish API test: {ex}") + return False + + return True + + def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, subscription_capacity: int): + + try: + # OnOff Cluster, OnOff Attribute + for i in range(subscription_capacity): + self.devCtrl.ZCLSubscribeAttribute( + "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + + logger.info("Send OpenBasicCommissioningWindow command on fist controller") + asyncio.run( + self.devCtrl.SendCommand( + nodeid, + 0, + Clusters.AdministratorCommissioning.Commands.OpenBasicCommissioningWindow(180), + timedRequestTimeoutMs=10000 + )) + return True + + except Exception as ex: + self.logger.exception(f"Failed to finish API test: {ex}") + return False + + return True + + def TestSubscriptionResumptionCapacityStep2(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, + remote_server_app: str, subscription_capacity: int): + remoteDeviceRestarted = False + updateLock = threading.Lock() + updateCv = threading.Condition(updateLock) + + class _restartRemoteDevice(threading.Thread): + def __init__(self, remote_ip: str, ssh_port: int, remote_server_app: str, subscription_capacity: int): + super(_restartRemoteDevice, self).__init__() + self.remote_ip = remote_ip + self.ssh_port = ssh_port + self.remote_server_app = remote_server_app + self.subscription_capacity = subscription_capacity + + def run(self): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + client.connect(self.remote_ip, self.ssh_port, "root", "admin") + client.exec_command( + ("kill \"$(ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\')\"").format(self.remote_server_app)) + time.sleep(1) + stdin, stdout, stderr = client.exec_command( + ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\'").format(self.remote_server_app)) + if not stdout.read().decode().strip(): + logger.info(f"Succeed to kill remote process {self.remote_server_app}") + else: + logger.error(f"Failed to kill remote process {self.remote_server_app}") + + client.exec_command("systemctl restart avahi-deamon.service") + client.exec_command( + ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " + "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator 3840 " + "--subscription-capacity {}").format( + os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app), + self.subscription_capacity)) + with updateLock: + remoteDeviceRestarted = True + updateCv.notifyAll() + + finally: + client.close() + + try: + self.logger.info("Restart remote deivce") + restartRemoteThread = _restartRemoteDevice(remote_ip, ssh_port, remote_server_app, subscription_capacity) + restartRemoteThread.start() + with updateCv: + while remoteDeviceRestarted is False: + if not updateCv.wait(8.0): + self.logger.error( + "Failed to restart the remote device") + break + # Wait for some time so that the device will be resolving the address of the first controller + time.sleep(3) + + self.logger.info("Send a new subscription request from the second controller") + # Close previous session so that the second controller will res-establish the session with the remote device + self.devCtrl.CloseSession(nodeid) + self.devCtrl.ZCLSubscribeAttribute( + "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + restartRemoteThread.join(10.0) + + if restartRemoteThread.is_alive(): + # Thread join timed out + self.logger.error("Failed to join change thread") + return False + + return True + + except Exception as ex: + self.logger.exception(f"Failed to finish API test: {ex}") + return False + + return True diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py new file mode 100755 index 00000000000000..3771d6e91fb214 --- /dev/null +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 + +# +# 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. +# + +# Commissioning test. + +import os +import sys +import time +from optparse import OptionParser + +from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger + +TEST_DISCRIMINATOR = 3840 +TEST_SETUPPIN = 20202021 + +TEST_ENDPOINT_ID = 1 + +def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): + logger.info("Testing discovery") + device = test.TestDiscovery(discriminator=discriminator) + FailIfNot(device, "Failed to discover any devices.") + + address = device.addresses[0] + + if address_override: + address = address_override + + logger.info("Testing commissioning") + FailIfNot(test.TestCommissioning(ip=address, + setuppin=setup_pin, + nodeid=device_nodeid), + "Failed to finish key exchange") + + +def main(): + optParser = OptionParser() + optParser.add_option( + "-t", + "--timeout", + action="store", + dest="testTimeout", + default=90, + type='int', + help="The program will return with timeout after specified seconds.", + metavar="", + ) + optParser.add_option( + "-a", + "--address", + action="store", + dest="deviceAddress", + default='', + type='str', + help="Address of the device", + metavar="", + ) + optParser.add_option( + "--nodeid", + action="store", + dest="nodeid", + default=1, + type=int, + help="The Node ID issued to the device", + metavar="" + ) + optParser.add_option( + "--discriminator", + action="store", + dest="discriminator", + default=TEST_DISCRIMINATOR, + type=int, + help="Discriminator of the device", + metavar="" + ) + optParser.add_option( + "--setuppin", + action="store", + dest="setuppin", + default=TEST_SETUPPIN, + type=int, + help="Setup PIN of the device", + metavar="" + ) + optParser.add_option( + "-p", + "--paa-trust-store-path", + action="store", + dest="paaTrustStorePath", + default='', + type='str', + help="Path that contains valid and trusted PAA Root Certificates.", + metavar="" + ) + optParser.add_option( + "--subscription-capacity", + action="store", + dest="subscriptionCapacity", + default=3, + type=int, + help="Subscription resumption capacity", + metavar="" + ) + + (options, remainingArgs) = optParser.parse_args(sys.argv[1:]) + + timeoutTicker = TestTimeout(options.testTimeout) + timeoutTicker.start() + + test = BaseTestHelper( + nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True) + + ethernet_commissioning(test, options.discriminator, options.setuppin, options.deviceAddress, options.nodeid) + + FailIfNot( + test.TestSubscriptionResumptionCapacityStep1(options.nodeid, TEST_ENDPOINT_ID, options.subscriptionCapacity), + "Failed on step 1 of testing subscription resumption capacity") + + timeoutTicker.stop() + + logger.info("Test finished") + + # TODO: Python device controller cannot be shutdown clean sometimes and will block on AsyncDNSResolverSockets shutdown. + # Call os._exit(0) to force close it. + os._exit(0) + + +if __name__ == "__main__": + try: + main() + except Exception as ex: + logger.exception(ex) + TestFail("Exception occurred when running tests.") diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py new file mode 100755 index 00000000000000..a5fd6b0a6cccaf --- /dev/null +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 + +# +# 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. +# + +# Commissioning test. + +import os +import sys +import time +from optparse import OptionParser + +from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger + +TEST_DISCRIMINATOR = 3840 +TEST_SETUPPIN = 20202021 + +TEST_ENDPOINT_ID = 1 + +TEST_SSH_PORT=2222 + + +def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): + logger.info("Testing discovery") + device = test.TestDiscovery(discriminator=discriminator) + FailIfNot(device, "Failed to discover any devices.") + + address = device.addresses[0] + + if address_override: + address = address_override + + logger.info("Testing commissioning") + FailIfNot(test.TestCommissioning(ip=address, + setuppin=setup_pin, + nodeid=device_nodeid), + "Failed to finish key exchange") + + +def main(): + optParser = OptionParser() + optParser.add_option( + "-t", + "--timeout", + action="store", + dest="testTimeout", + default=90, + type='int', + help="The program will return with timeout after specified seconds.", + metavar="", + ) + optParser.add_option( + "-a", + "--address", + action="store", + dest="deviceAddress", + default='', + type='str', + help="Address of the device", + metavar="", + ) + optParser.add_option( + "--nodeid", + action="store", + dest="nodeid", + default=1, + type=int, + help="The Node ID issued to the device", + metavar="" + ) + optParser.add_option( + "--discriminator", + action="store", + dest="discriminator", + default=TEST_DISCRIMINATOR, + type=int, + help="Discriminator of the device", + metavar="" + ) + optParser.add_option( + "--setuppin", + action="store", + dest="setuppin", + default=TEST_SETUPPIN, + type=int, + help="Setup PIN of the device", + metavar="" + ) + optParser.add_option( + "-p", + "--paa-trust-store-path", + action="store", + dest="paaTrustStorePath", + default='', + type='str', + help="Path that contains valid and trusted PAA Root Certificates.", + metavar="" + ) + optParser.add_option( + "--remote-server-app", + action="store", + dest="remoteServerApp", + default='', + type='str', + help="Remote Server App", + metavar="" + ) + optParser.add_option( + "--subscription-capacity", + action="store", + dest="subscriptionCapacity", + default=3, + type=int, + help="Subscription resumption capacity", + metavar="" + ) + + (options, remainingArgs) = optParser.parse_args(sys.argv[1:]) + + timeoutTicker = TestTimeout(options.testTimeout) + timeoutTicker.start() + + # Use a different node ID for the second controller + test = BaseTestHelper( + nodeid=112244, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True) + + ethernet_commissioning(test, options.discriminator, options.setuppin, options.deviceAddress, options.nodeid) + + FailIfNot( + test.TestSubscriptionResumptionCapacityStep2(options.nodeid, TEST_ENDPOINT_ID, options.deviceAddress, + TEST_SSH_PORT, options.remoteServerApp, options.subscriptionCapacity), + "Failed on testing subscription resumption capacity") + + timeoutTicker.stop() + + logger.info("Test finished") + + # TODO: Python device controller cannot be shutdown clean sometimes and will block on AsyncDNSResolverSockets shutdown. + # Call os._exit(0) to force close it. + os._exit(0) + + +if __name__ == "__main__": + try: + main() + except Exception as ex: + logger.exception(ex) + TestFail("Exception occurred when running tests.") diff --git a/src/controller/python/test/test_scripts/subscription_resumption_test.py b/src/controller/python/test/test_scripts/subscription_resumption_test.py new file mode 100755 index 00000000000000..a277d38e8d7315 --- /dev/null +++ b/src/controller/python/test/test_scripts/subscription_resumption_test.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 + +# +# 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. +# + +# Commissioning test. + +import os +import sys +import time +from optparse import OptionParser + +from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger + +TEST_DISCRIMINATOR = 3840 +TEST_SETUPPIN = 20202021 + +TEST_ENDPOINT_ID = 1 + +TEST_SSH_PORT=2222 + + +def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): + logger.info("Testing discovery") + device = test.TestDiscovery(discriminator=discriminator) + FailIfNot(device, "Failed to discover any devices.") + + address = device.addresses[0] + + if address_override: + address = address_override + + logger.info("Testing commissioning") + FailIfNot(test.TestCommissioning(ip=address, + setuppin=setup_pin, + nodeid=device_nodeid), + "Failed to finish key exchange") + + +def main(): + optParser = OptionParser() + optParser.add_option( + "-t", + "--timeout", + action="store", + dest="testTimeout", + default=90, + type='int', + help="The program will return with timeout after specified seconds.", + metavar="", + ) + optParser.add_option( + "-a", + "--address", + action="store", + dest="deviceAddress", + default='', + type='str', + help="Address of the device", + metavar="", + ) + optParser.add_option( + "--nodeid", + action="store", + dest="nodeid", + default=1, + type=int, + help="The Node ID issued to the device", + metavar="" + ) + optParser.add_option( + "--discriminator", + action="store", + dest="discriminator", + default=TEST_DISCRIMINATOR, + type=int, + help="Discriminator of the device", + metavar="" + ) + optParser.add_option( + "--setuppin", + action="store", + dest="setuppin", + default=TEST_SETUPPIN, + type=int, + help="Setup PIN of the device", + metavar="" + ) + optParser.add_option( + "-p", + "--paa-trust-store-path", + action="store", + dest="paaTrustStorePath", + default='', + type='str', + help="Path that contains valid and trusted PAA Root Certificates.", + metavar="" + ) + optParser.add_option( + "--remote-server-app", + action="store", + dest="remoteServerApp", + default='', + type='str', + help="Remote Server App", + metavar="" + ) + + (options, remainingArgs) = optParser.parse_args(sys.argv[1:]) + + timeoutTicker = TestTimeout(options.testTimeout) + timeoutTicker.start() + + test = BaseTestHelper( + nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True) + + ethernet_commissioning(test, options.discriminator, options.setuppin, options.deviceAddress, options.nodeid) + + FailIfNot( + test.TestSubscriptionResumption(options.nodeid, TEST_ENDPOINT_ID, options.deviceAddress, + TEST_SSH_PORT, options.remoteServerApp), "Failed to resume subscription") + + timeoutTicker.stop() + + logger.info("Test finished") + + # TODO: Python device controller cannot be shutdown clean sometimes and will block on AsyncDNSResolverSockets shutdown. + # Call os._exit(0) to force close it. + os._exit(0) + + +if __name__ == "__main__": + try: + main() + except Exception as ex: + logger.exception(ex) + TestFail("Exception occurred when running tests.") diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py new file mode 100755 index 00000000000000..717f99f448c8da --- /dev/null +++ b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +""" +Copyright (c) 2024 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. +""" + +import logging +import os +import sys + +from helper.CHIPTestBase import CHIPVirtualHome + +logger = logging.getLogger('SubscriptionResumptionTest') +logger.setLevel(logging.INFO) + +sh = logging.StreamHandler() +sh.setFormatter( + logging.Formatter( + '%(asctime)s [%(name)s] %(levelname)s %(message)s')) +logger.addHandler(sh) + +CHIP_PORT = 5540 + +CIRQUE_URL = "http://localhost:5000" +CHIP_REPO = os.path.join(os.path.abspath( + os.path.dirname(__file__)), "..", "..", "..") +TEST_EXTPANID = "fedcba9876543210" +TEST_DISCRIMINATOR = 3840 +MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs" +TEST_END_DEVICE_APP="chip-lighting-app" +TEST_SUBSCRIPTION_CAPACITY=3 + + +# TODO: If using one Mobile Device, the CHIPEndDevice can still resolve the address for first controller +# even if it was shutdown. +# Use two containers for two controller in two different fabrics. +DEVICE_CONFIG = { + 'device0': { + 'type': 'MobileDevice', + 'base_image': '@default', + 'capability': ['TrafficControl', 'Mount'], + 'rcp_mode': True, + 'docker_network': 'Ipv6', + 'traffic_control': {'latencyMs': 25}, + "mount_pairs": [[CHIP_REPO, CHIP_REPO]], + }, + 'device1': { + 'type': 'MobileDevice', + 'base_image': '@default', + 'capability': ['TrafficControl', 'Mount'], + 'rcp_mode': True, + 'docker_network': 'Ipv6', + 'traffic_control': {'latencyMs': 25}, + "mount_pairs": [[CHIP_REPO, CHIP_REPO]], + }, + 'device2': { + 'type': 'CHIPEndDevice', + 'base_image': '@default', + 'capability': ['Thread', 'TrafficControl', 'Mount'], + 'rcp_mode': True, + 'docker_network': 'Ipv6', + 'traffic_control': {'latencyMs': 25}, + "mount_pairs": [[CHIP_REPO, CHIP_REPO]], + } +} + + +class TestSubscriptionResumptionCapacity(CHIPVirtualHome): + def __init__(self, device_config): + super().__init__(CIRQUE_URL, device_config) + self.logger = logger + + def setup(self): + self.initialize_home() + + def test_routine(self): + self.run_subscription_resumption_capacity_test() + + def run_subscription_resumption_capacity_test(self): + ethernet_ip = [device['description']['ipv6_addr'] for device in self.non_ap_devices + if device['type'] == 'CHIPEndDevice'][0] + server_ids = [device['id'] for device in self.non_ap_devices + if device['type'] == 'CHIPEndDevice'] + req_ids = [device['id'] for device in self.non_ap_devices + if device['type'] == 'MobileDevice'] + + server_device_id = server_ids[0] + # Start SSH server + self.execute_device_cmd(server_device_id, "service ssh start") + self.execute_device_cmd( + server_device_id, + ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " + "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator {} " + "--subscription-capacity {}").format( + os.path.join(CHIP_REPO, "out/debug/standalone", TEST_END_DEVICE_APP), TEST_DISCRIMINATOR, + TEST_SUBSCRIPTION_CAPACITY)) + + self.reset_thread_devices(server_ids) + + for req_device_id in req_ids: + self.execute_device_cmd(req_device_id, "pip3 install {}".format(os.path.join( + CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_clusters-0.0-py3-none-any.whl"))) + self.execute_device_cmd(req_device_id, "pip3 install {}".format(os.path.join( + CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_core-0.0-cp37-abi3-linux_x86_64.whl"))) + self.execute_device_cmd(req_device_id, "pip3 install {}".format(os.path.join( + CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_repl-0.0-py3-none-any.whl"))) + + command1 = ("gdb -batch -return-child-result -q -ex run -ex \"thread apply all bt\" " + "--args python3 {} -t 300 -a {} --paa-trust-store-path {} --subscription-capacity {}").format( + os.path.join(CHIP_REPO, "src/controller/python/test/test_scripts", + "subscription_resumption_capacity_test_ctrl1.py"), + ethernet_ip, os.path.join(CHIP_REPO, MATTER_DEVELOPMENT_PAA_ROOT_CERTS), + TEST_SUBSCRIPTION_CAPACITY) + ret1 = self.execute_device_cmd(req_ids[0], command1) + + self.assertEqual(ret1['return_code'], '0', + "Test failed: non-zero return code") + + command2 = ("gdb -batch -return-child-result -q -ex run -ex \"thread apply all bt\" " + "--args python3 {} -t 300 -a {} --paa-trust-store-path {} --remote-server-app {} " + "--subscription-capacity {}").format( + os.path.join(CHIP_REPO, "src/controller/python/test/test_scripts", + "subscription_resumption_capacity_test_ctrl2.py"), + ethernet_ip, os.path.join(CHIP_REPO, MATTER_DEVELOPMENT_PAA_ROOT_CERTS), + TEST_END_DEVICE_APP, TEST_SUBSCRIPTION_CAPACITY) + ret2 = self.execute_device_cmd(req_ids[1], command2) + + self.assertEqual(ret2['return_code'], '0', + "Test failed: non-zero return code") + + # Check the device can evit existing subscriptions + self.logger.info("checking device log for {}".format( + self.get_device_pretty_id(server_device_id))) + self.assertFalse(self.sequenceMatch(self.get_device_log(server_device_id).decode('utf-8'), [ + "Failed to get required resources by evicting existing subscriptions"]), + "SubscriptionResumptionCapacity test failed: find abort log from device {}".format(server_device_id)) + + +if __name__ == "__main__": + sys.exit(TestSubscriptionResumptionCapacity(DEVICE_CONFIG).run_test()) diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py new file mode 100755 index 00000000000000..b74a38937edbc0 --- /dev/null +++ b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +""" +Copyright (c) 2024 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. +""" + +import logging +import os +import sys + +from helper.CHIPTestBase import CHIPVirtualHome + +logger = logging.getLogger('SubscriptionResumptionTest') +logger.setLevel(logging.INFO) + +sh = logging.StreamHandler() +sh.setFormatter( + logging.Formatter( + '%(asctime)s [%(name)s] %(levelname)s %(message)s')) +logger.addHandler(sh) + +CHIP_PORT = 5540 + +CIRQUE_URL = "http://localhost:5000" +CHIP_REPO = os.path.join(os.path.abspath( + os.path.dirname(__file__)), "..", "..", "..") +TEST_EXTPANID = "fedcba9876543210" +TEST_DISCRIMINATOR = 3840 +MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs" +TEST_END_DEVICE_APP="chip-lighting-app" + +DEVICE_CONFIG = { + 'device0': { + 'type': 'MobileDevice', + 'base_image': '@default', + 'capability': ['TrafficControl', 'Mount'], + 'rcp_mode': True, + 'docker_network': 'Ipv6', + 'traffic_control': {'latencyMs': 25}, + "mount_pairs": [[CHIP_REPO, CHIP_REPO]], + }, + 'device1': { + 'type': 'CHIPEndDevice', + 'base_image': '@default', + 'capability': ['Thread', 'TrafficControl', 'Mount'], + 'rcp_mode': True, + 'docker_network': 'Ipv6', + 'traffic_control': {'latencyMs': 25}, + "mount_pairs": [[CHIP_REPO, CHIP_REPO]], + } +} + + +class TestSubscriptionResumption(CHIPVirtualHome): + def __init__(self, device_config): + super().__init__(CIRQUE_URL, device_config) + self.logger = logger + + def setup(self): + self.initialize_home() + + def test_routine(self): + self.run_subscription_resumption_test() + + def run_subscription_resumption_test(self): + ethernet_ip = [device['description']['ipv6_addr'] for device in self.non_ap_devices + if device['type'] == 'CHIPEndDevice'][0] + server_ids = [device['id'] for device in self.non_ap_devices + if device['type'] == 'CHIPEndDevice'] + req_ids = [device['id'] for device in self.non_ap_devices + if device['type'] == 'MobileDevice'] + + server_device_id = server_ids[0] + # Start SSH server + self.execute_device_cmd(server_device_id, "service ssh start") + self.execute_device_cmd( + server_device_id, + ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " + "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator {}").format( + os.path.join(CHIP_REPO, "out/debug/standalone", TEST_END_DEVICE_APP), TEST_DISCRIMINATOR)) + + self.reset_thread_devices(server_ids) + + req_device_id = req_ids[0] + + self.execute_device_cmd(req_device_id, "pip3 install {}".format(os.path.join( + CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_clusters-0.0-py3-none-any.whl"))) + self.execute_device_cmd(req_device_id, "pip3 install {}".format(os.path.join( + CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_core-0.0-cp37-abi3-linux_x86_64.whl"))) + self.execute_device_cmd(req_device_id, "pip3 install {}".format(os.path.join( + CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_repl-0.0-py3-none-any.whl"))) + + command = ("gdb -batch -return-child-result -q -ex run -ex \"thread apply all bt\" " + "--args python3 {} -t 300 -a {} --paa-trust-store-path {} --remote-server-app {}").format( + os.path.join( + CHIP_REPO, "src/controller/python/test/test_scripts/subscription_resumption_test.py"), ethernet_ip, + os.path.join(CHIP_REPO, MATTER_DEVELOPMENT_PAA_ROOT_CERTS), TEST_END_DEVICE_APP) + ret = self.execute_device_cmd(req_device_id, command) + + self.assertEqual(ret['return_code'], '0', + "Test failed: non-zero return code") + + # Check the device can resume subscriptions + self.logger.info("checking device log for {}".format( + self.get_device_pretty_id(server_device_id))) + self.assertTrue(self.sequenceMatch(self.get_device_log(server_device_id).decode('utf-8'), [ + "Resuming 1 subscriptions in 1 seconds", + "Registered a ReadHandler that will schedule a report"]), + "SubscriptionResumption test failed: cannot find matching string from device {}".format(server_device_id)) + + +if __name__ == "__main__": + sys.exit(TestSubscriptionResumption(DEVICE_CONFIG).run_test()) From 0c8057b560ed0bb60c63ef62b09c09d5c8627d13 Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Tue, 9 Jan 2024 15:14:52 +0800 Subject: [PATCH 03/15] Change the test app for subscription resumption test to lit-icd-app --- .../lit-icd-common/lit-icd-server-app.matter | 1 + .../lit-icd-common/lit-icd-server-app.zap | 8 ++ .../python/test/test_scripts/base.py | 90 ++----------------- ...cription_resumption_capacity_test_ctrl1.py | 2 +- ...cription_resumption_capacity_test_ctrl2.py | 2 +- .../subscription_resumption_test.py | 2 +- .../SubscriptionResumptionCapacityTest.py | 4 +- .../SubscriptionResumptionTest.py | 2 +- 8 files changed, 22 insertions(+), 89 deletions(-) diff --git a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter index 1d09cf81bfbcd2..cf619a6ed89bbb 100644 --- a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter +++ b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter @@ -1670,6 +1670,7 @@ endpoint 0 { ram attribute clusterRevision default = 1; handle command OpenCommissioningWindow; + handle command OpenBasicCommissioningWindow; handle command RevokeCommissioning; } diff --git a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.zap b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.zap index 294429afe14e7f..24efe4f08d0434 100644 --- a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.zap +++ b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.zap @@ -2549,6 +2549,14 @@ "isIncoming": 1, "isEnabled": 1 }, + { + "name": "OpenBasicCommissioningWindow", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, { "name": "RevokeCommissioning", "code": 2, diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index d04721478a5313..a73bd8a566db0c 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -1373,10 +1373,10 @@ def run(self): try: desiredPath = Clusters.Attribute.AttributePath( - EndpointId=1, ClusterId=6, AttributeId=0) - # OnOff Cluster, OnOff Attribute + EndpointId=0, ClusterId=0x28, AttributeId=5) + # Basic Information Cluster, NodeLabel Attribute subscription = self.devCtrl.ZCLSubscribeAttribute( - "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + "BasicInformation", "NodeLabel", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) subscription.SetAttributeUpdateCallback(OnValueReport) self.logger.info("Restart remote deivce") @@ -1386,12 +1386,12 @@ def run(self): # the update with updateCv: while receivedUpdate is False: - if not updateCv.wait(30.0): + if not updateCv.wait(10.0): self.logger.error( "Failed to receive subscription resumption report") break - restartRemoteThread.join(30.0) + restartRemoteThread.join(10.0) # # Clean-up by shutting down the sub. Otherwise, we're going to get callbacks through @@ -1412,88 +1412,12 @@ def run(self): return True - def TestSubscriptionResumptionCapacity(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, - remote_server_app: str, subscription_capacity: int): - - class _restartRemoteDevice(threading.Thread): - def __init__(self, remote_ip: str, ssh_port: int, remote_server_app: str, subscription_capacity: int): - super(_restartRemoteDevice, self).__init__() - self.remote_ip = remote_ip - self.ssh_port = ssh_port - self.remote_server_app = remote_server_app - self.subscription_capacity = subscription_capacity - - def run(self): - client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - try: - client.connect(self.remote_ip, self.ssh_port, "root", "admin") - client.exec_command( - ("kill \"$(ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\')\"").format(self.remote_server_app)) - time.sleep(1) - stdin, stdout, stderr = client.exec_command( - ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\'").format(self.remote_server_app)) - if not stdout.read().decode().strip(): - logger.info(f"Succeed to kill remote process {self.remote_server_app}") - else: - logger.error(f"Failed to kill remote process {self.remote_server_app}") - - client.exec_command("systemctl restart avahi-deamon.service") - client.exec_command( - ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " - "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator 3840 " - "--subscription-capacity {}").format( - os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app), - self.subscription_capacity)) - - finally: - client.close() - - try: - desiredPath = Clusters.Attribute.AttributePath( - EndpointId=1, ClusterId=6, AttributeId=0) - # OnOff Cluster, OnOff Attribute - for i in range(subscription_capacity): - self.devCtrl.ZCLSubscribeAttribute( - "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) - - self.logger.info("Shutdown Controller 1") - self.devCtrl.Shutdown() - - self.logger.info("Restart remote deivce") - restartRemoteThread = _restartRemoteDevice(remote_ip, ssh_port, remote_server_app, subscription_capacity) - restartRemoteThread.start() - time.sleep(6) - - self.logger.info("Send a new subscription request from the second controller") - # Close previous session so that the controller 2 will res-establish the session to the remote device - self.devCtrl2.CloseSession(nodeid) - self.devCtrl2.ZCLSubscribeAttribute( - "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) - restartRemoteThread.join(10.0) - - if restartRemoteThread.is_alive(): - # Thread join timed out - self.logger.error("Failed to join change thread") - return False - - return True - - except Exception as ex: - self.logger.exception(f"Failed to finish API test: {ex}") - return False - - return True - def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, subscription_capacity: int): - try: # OnOff Cluster, OnOff Attribute for i in range(subscription_capacity): self.devCtrl.ZCLSubscribeAttribute( - "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + "BasicInformation", "NodeLabel", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) logger.info("Send OpenBasicCommissioningWindow command on fist controller") asyncio.run( @@ -1573,7 +1497,7 @@ def run(self): # Close previous session so that the second controller will res-establish the session with the remote device self.devCtrl.CloseSession(nodeid) self.devCtrl.ZCLSubscribeAttribute( - "OnOff", "OnOff", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) + "BasicInformation", "NodeLabel", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) restartRemoteThread.join(10.0) if restartRemoteThread.is_alive(): diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py index 3771d6e91fb214..c4199ba8799193 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py @@ -29,7 +29,7 @@ TEST_DISCRIMINATOR = 3840 TEST_SETUPPIN = 20202021 -TEST_ENDPOINT_ID = 1 +TEST_ENDPOINT_ID = 0 def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): logger.info("Testing discovery") diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py index a5fd6b0a6cccaf..84149cb55d1f2f 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py @@ -29,7 +29,7 @@ TEST_DISCRIMINATOR = 3840 TEST_SETUPPIN = 20202021 -TEST_ENDPOINT_ID = 1 +TEST_ENDPOINT_ID = 0 TEST_SSH_PORT=2222 diff --git a/src/controller/python/test/test_scripts/subscription_resumption_test.py b/src/controller/python/test/test_scripts/subscription_resumption_test.py index a277d38e8d7315..68a8dcd6530180 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_test.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_test.py @@ -29,7 +29,7 @@ TEST_DISCRIMINATOR = 3840 TEST_SETUPPIN = 20202021 -TEST_ENDPOINT_ID = 1 +TEST_ENDPOINT_ID = 0 TEST_SSH_PORT=2222 diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py index 717f99f448c8da..d18047bbb1d21a 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py @@ -21,7 +21,7 @@ from helper.CHIPTestBase import CHIPVirtualHome -logger = logging.getLogger('SubscriptionResumptionTest') +logger = logging.getLogger('SubscriptionResumptionCapacityTest') logger.setLevel(logging.INFO) sh = logging.StreamHandler() @@ -38,7 +38,7 @@ TEST_EXTPANID = "fedcba9876543210" TEST_DISCRIMINATOR = 3840 MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs" -TEST_END_DEVICE_APP="chip-lighting-app" +TEST_END_DEVICE_APP="lit-icd-app" TEST_SUBSCRIPTION_CAPACITY=3 diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py index b74a38937edbc0..9cc0544559579e 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py @@ -38,7 +38,7 @@ TEST_EXTPANID = "fedcba9876543210" TEST_DISCRIMINATOR = 3840 MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs" -TEST_END_DEVICE_APP="chip-lighting-app" +TEST_END_DEVICE_APP="lit-icd-app" DEVICE_CONFIG = { 'device0': { From e201764deb798d23fa59f5a4f5fb78d615b22525 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 9 Jan 2024 07:36:20 +0000 Subject: [PATCH 04/15] Restyled by clang-format --- examples/platform/linux/AppMain.cpp | 3 ++- examples/platform/linux/Options.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index dad244b19964b3..04ed5ad74fa8cc 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -570,7 +570,8 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl) #if CONFIG_BUILD_FOR_HOST_UNIT_TEST // Set ReadHandler Capacity for Subscriptions - chip::app::InteractionModelEngine::GetInstance()->SetHandlerCapacityForSubscriptions(LinuxDeviceOptions::GetInstance().subscriptionCapacity); + chip::app::InteractionModelEngine::GetInstance()->SetHandlerCapacityForSubscriptions( + LinuxDeviceOptions::GetInstance().subscriptionCapacity); chip::app::InteractionModelEngine::GetInstance()->SetForceHandlerQuota(true); #endif diff --git a/examples/platform/linux/Options.cpp b/examples/platform/linux/Options.cpp index f88f8967793e42..89d0cb7ff010ee 100644 --- a/examples/platform/linux/Options.cpp +++ b/examples/platform/linux/Options.cpp @@ -148,7 +148,7 @@ OptionDef sDeviceOptionDefs[] = { { "rpc-server-port", kArgumentRequired, kOptionRpcServerPort }, #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST - { "subscription-capacity", kArgumentRequired, kDeviceOption_SubscriptionCapacity}, + { "subscription-capacity", kArgumentRequired, kDeviceOption_SubscriptionCapacity }, #endif {} }; From ae03c5d5d281f30cba682e947610c1128328c0ea Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 9 Jan 2024 07:36:26 +0000 Subject: [PATCH 05/15] Restyled by gn --- BUILD.gn | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index ed68689b0d3be8..b51ab7238414e9 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -616,9 +616,8 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { if (enable_linux_lit_icd_app_build) { group("linux_lit_icd_app") { - deps = [ - "${chip_root}/examples/lit-icd-app/linux(${standalone_toolchain})", - ] + deps = + [ "${chip_root}/examples/lit-icd-app/linux(${standalone_toolchain})" ] } extra_build_deps += [ ":linux_lit_icd_app" ] From 58231b489504367ab846a2cb931af267e9f3e9f8 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 9 Jan 2024 07:36:49 +0000 Subject: [PATCH 06/15] Restyled by autopep8 --- src/controller/python/chip/ChipDeviceCtrl.py | 4 ++-- src/controller/python/test/test_scripts/base.py | 10 +++++----- .../subscription_resumption_capacity_test_ctrl1.py | 1 + .../subscription_resumption_capacity_test_ctrl2.py | 4 ++-- .../test/test_scripts/subscription_resumption_test.py | 4 ++-- .../linux-cirque/SubscriptionResumptionCapacityTest.py | 8 ++++---- .../linux-cirque/SubscriptionResumptionTest.py | 2 +- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 78494b40691c73..c21cc5388f81af 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -1418,7 +1418,7 @@ def ZCLWriteAttribute(self, cluster: str, attribute: str, nodeid, endpoint, grou return asyncio.run(self.WriteAttribute(nodeid, [(endpoint, req, dataVersion)])) def ZCLSubscribeAttribute(self, cluster, attribute, nodeid, endpoint, minInterval, maxInterval, blocking=True, - keepSubscriptions=False, autoResubscribe=True): + keepSubscriptions=False, autoResubscribe=True): ''' Wrapper over ReadAttribute for a single attribute Returns a SubscriptionTransaction. See ReadAttribute for more information. ''' @@ -1430,7 +1430,7 @@ def ZCLSubscribeAttribute(self, cluster, attribute, nodeid, endpoint, minInterva except BaseException: raise UnknownAttribute(cluster, attribute) return asyncio.run(self.ReadAttribute(nodeid, [(endpoint, req)], None, False, reportInterval=(minInterval, maxInterval), - keepSubscriptions=keepSubscriptions, autoResubscribe=autoResubscribe)) + keepSubscriptions=keepSubscriptions, autoResubscribe=autoResubscribe)) def ZCLCommandList(self): self.CheckIsActive() diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index a73bd8a566db0c..e5e458e26895e2 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -1356,8 +1356,8 @@ def run(self): "awk \'{{print $2}}\')\"").format(self.remote_server_app)) time.sleep(1) stdin, stdout, stderr = client.exec_command( - ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\'").format(self.remote_server_app)) + ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\'").format(self.remote_server_app)) if not stdout.read().decode().strip(): logger.info(f"Succeed to kill remote process {self.remote_server_app}") else: @@ -1436,7 +1436,7 @@ def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, su return True def TestSubscriptionResumptionCapacityStep2(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, - remote_server_app: str, subscription_capacity: int): + remote_server_app: str, subscription_capacity: int): remoteDeviceRestarted = False updateLock = threading.Lock() updateCv = threading.Condition(updateLock) @@ -1459,8 +1459,8 @@ def run(self): "awk \'{{print $2}}\')\"").format(self.remote_server_app)) time.sleep(1) stdin, stdout, stderr = client.exec_command( - ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\'").format(self.remote_server_app)) + ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\'").format(self.remote_server_app)) if not stdout.read().decode().strip(): logger.info(f"Succeed to kill remote process {self.remote_server_app}") else: diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py index c4199ba8799193..fcf9dcffe1d33e 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py @@ -31,6 +31,7 @@ TEST_ENDPOINT_ID = 0 + def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): logger.info("Testing discovery") device = test.TestDiscovery(discriminator=discriminator) diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py index 84149cb55d1f2f..f0eb69ca77656f 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py @@ -31,7 +31,7 @@ TEST_ENDPOINT_ID = 0 -TEST_SSH_PORT=2222 +TEST_SSH_PORT = 2222 def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): @@ -142,7 +142,7 @@ def main(): FailIfNot( test.TestSubscriptionResumptionCapacityStep2(options.nodeid, TEST_ENDPOINT_ID, options.deviceAddress, - TEST_SSH_PORT, options.remoteServerApp, options.subscriptionCapacity), + TEST_SSH_PORT, options.remoteServerApp, options.subscriptionCapacity), "Failed on testing subscription resumption capacity") timeoutTicker.stop() diff --git a/src/controller/python/test/test_scripts/subscription_resumption_test.py b/src/controller/python/test/test_scripts/subscription_resumption_test.py index 68a8dcd6530180..5a3922d5524d5f 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_test.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_test.py @@ -31,7 +31,7 @@ TEST_ENDPOINT_ID = 0 -TEST_SSH_PORT=2222 +TEST_SSH_PORT = 2222 def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): @@ -132,7 +132,7 @@ def main(): FailIfNot( test.TestSubscriptionResumption(options.nodeid, TEST_ENDPOINT_ID, options.deviceAddress, - TEST_SSH_PORT, options.remoteServerApp), "Failed to resume subscription") + TEST_SSH_PORT, options.remoteServerApp), "Failed to resume subscription") timeoutTicker.stop() diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py index d18047bbb1d21a..cd13cb058774b2 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py @@ -38,8 +38,8 @@ TEST_EXTPANID = "fedcba9876543210" TEST_DISCRIMINATOR = 3840 MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs" -TEST_END_DEVICE_APP="lit-icd-app" -TEST_SUBSCRIPTION_CAPACITY=3 +TEST_END_DEVICE_APP = "lit-icd-app" +TEST_SUBSCRIPTION_CAPACITY = 3 # TODO: If using one Mobile Device, the CHIPEndDevice can still resolve the address for first controller @@ -119,7 +119,7 @@ def run_subscription_resumption_capacity_test(self): command1 = ("gdb -batch -return-child-result -q -ex run -ex \"thread apply all bt\" " "--args python3 {} -t 300 -a {} --paa-trust-store-path {} --subscription-capacity {}").format( os.path.join(CHIP_REPO, "src/controller/python/test/test_scripts", - "subscription_resumption_capacity_test_ctrl1.py"), + "subscription_resumption_capacity_test_ctrl1.py"), ethernet_ip, os.path.join(CHIP_REPO, MATTER_DEVELOPMENT_PAA_ROOT_CERTS), TEST_SUBSCRIPTION_CAPACITY) ret1 = self.execute_device_cmd(req_ids[0], command1) @@ -131,7 +131,7 @@ def run_subscription_resumption_capacity_test(self): "--args python3 {} -t 300 -a {} --paa-trust-store-path {} --remote-server-app {} " "--subscription-capacity {}").format( os.path.join(CHIP_REPO, "src/controller/python/test/test_scripts", - "subscription_resumption_capacity_test_ctrl2.py"), + "subscription_resumption_capacity_test_ctrl2.py"), ethernet_ip, os.path.join(CHIP_REPO, MATTER_DEVELOPMENT_PAA_ROOT_CERTS), TEST_END_DEVICE_APP, TEST_SUBSCRIPTION_CAPACITY) ret2 = self.execute_device_cmd(req_ids[1], command2) diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py index 9cc0544559579e..42d2b4f525ed11 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py @@ -38,7 +38,7 @@ TEST_EXTPANID = "fedcba9876543210" TEST_DISCRIMINATOR = 3840 MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs" -TEST_END_DEVICE_APP="lit-icd-app" +TEST_END_DEVICE_APP = "lit-icd-app" DEVICE_CONFIG = { 'device0': { From 2e1ba118edf6433f4317f0341cecf7f9a695bd87 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 9 Jan 2024 07:36:54 +0000 Subject: [PATCH 07/15] Restyled by isort --- src/controller/python/test/test_scripts/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index e5e458e26895e2..8dce14e5e2a8c4 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -22,7 +22,6 @@ import inspect import logging import os -import paramiko import secrets import sys import threading @@ -37,6 +36,7 @@ import chip.FabricAdmin import chip.interaction_model as IM import chip.native +import paramiko from chip import ChipDeviceCtrl from chip.ChipStack import ChipStack from chip.crypto import p256keypair From f260377b458c58ef8fa19065347527f561b50cb5 Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Tue, 9 Jan 2024 16:25:54 +0800 Subject: [PATCH 08/15] Fix Subscriptions capacity option type cast --- examples/platform/linux/Options.cpp | 2 +- examples/platform/linux/Options.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/platform/linux/Options.cpp b/examples/platform/linux/Options.cpp index 89d0cb7ff010ee..12cc1b5f0f48e7 100644 --- a/examples/platform/linux/Options.cpp +++ b/examples/platform/linux/Options.cpp @@ -534,7 +534,7 @@ bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST case kDeviceOption_SubscriptionCapacity: - LinuxDeviceOptions::GetInstance().subscriptionCapacity = static_cast(atoi(aValue)); + LinuxDeviceOptions::GetInstance().subscriptionCapacity = static_cast(atoi(aValue)); break; #endif default: diff --git a/examples/platform/linux/Options.h b/examples/platform/linux/Options.h index e5267dd9634a17..784c8d11ef1231 100644 --- a/examples/platform/linux/Options.h +++ b/examples/platform/linux/Options.h @@ -72,7 +72,7 @@ struct LinuxDeviceOptions uint16_t rpcServerPort = 33000; #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST - size_t subscriptionCapacity = CHIP_IM_MAX_NUM_SUBSCRIPTIONS; + int32_t subscriptionCapacity = CHIP_IM_MAX_NUM_SUBSCRIPTIONS; #endif static LinuxDeviceOptions & GetInstance(); }; From 54445a196cd99908a8a491307fd0563f21c84565 Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Tue, 9 Jan 2024 16:40:49 +0800 Subject: [PATCH 09/15] lints changes --- src/controller/python/test/test_scripts/base.py | 11 ++++------- .../subscription_resumption_capacity_test_ctrl1.py | 1 - .../subscription_resumption_capacity_test_ctrl2.py | 1 - .../test/test_scripts/subscription_resumption_test.py | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index 8dce14e5e2a8c4..aa716922f5b415 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -1437,7 +1437,6 @@ def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, su def TestSubscriptionResumptionCapacityStep2(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, remote_server_app: str, subscription_capacity: int): - remoteDeviceRestarted = False updateLock = threading.Lock() updateCv = threading.Condition(updateLock) @@ -1474,7 +1473,6 @@ def run(self): os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app), self.subscription_capacity)) with updateLock: - remoteDeviceRestarted = True updateCv.notifyAll() finally: @@ -1485,11 +1483,10 @@ def run(self): restartRemoteThread = _restartRemoteDevice(remote_ip, ssh_port, remote_server_app, subscription_capacity) restartRemoteThread.start() with updateCv: - while remoteDeviceRestarted is False: - if not updateCv.wait(8.0): - self.logger.error( - "Failed to restart the remote device") - break + if not updateCv.wait(8.0): + self.logger.error( + "Failed to restart the remote device") + # Wait for some time so that the device will be resolving the address of the first controller time.sleep(3) diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py index fcf9dcffe1d33e..c5cecf4b8da2cb 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py @@ -21,7 +21,6 @@ import os import sys -import time from optparse import OptionParser from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py index f0eb69ca77656f..4e226e816abe52 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py @@ -21,7 +21,6 @@ import os import sys -import time from optparse import OptionParser from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger diff --git a/src/controller/python/test/test_scripts/subscription_resumption_test.py b/src/controller/python/test/test_scripts/subscription_resumption_test.py index 5a3922d5524d5f..0b0c0c985db77a 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_test.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_test.py @@ -21,7 +21,6 @@ import os import sys -import time from optparse import OptionParser from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger From a694b99d4fe613b054ce2302ac8b71baa3e51c0c Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Wed, 10 Jan 2024 14:12:21 +0800 Subject: [PATCH 10/15] review changes --- .../python/test/test_scripts/base.py | 145 +++++++----------- .../cirque_restart_remote_device.py | 78 ++++++++++ ...cription_resumption_capacity_test_ctrl1.py | 21 +-- ...cription_resumption_capacity_test_ctrl2.py | 21 +-- .../subscription_resumption_test.py | 21 +-- .../SubscriptionResumptionCapacityTest.py | 18 ++- .../SubscriptionResumptionTest.py | 9 +- 7 files changed, 168 insertions(+), 145 deletions(-) create mode 100644 src/controller/python/test/test_scripts/cirque_restart_remote_device.py diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index aa716922f5b415..5795a9a67bafff 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -36,14 +36,11 @@ import chip.FabricAdmin import chip.interaction_model as IM import chip.native -import paramiko from chip import ChipDeviceCtrl from chip.ChipStack import ChipStack from chip.crypto import p256keypair from chip.utils import CommissioningBuildingBlocks - -CHIP_REPO = os.path.join(os.path.abspath( - os.path.dirname(__file__)), "..", "..", "..", "..", "..") +from cirque_restart_remote_device import restartRemoteDevice logger = logging.getLogger('PythonMatterControllerTEST') logger.setLevel(logging.INFO) @@ -340,6 +337,21 @@ def TestCommissioningWithSetupPayload(self, setupPayload: str, nodeid: int): self.logger.info("Commissioning finished.") return True + def TestOnNetworkCommissioning(self, discriminator: int, setuppin: int, nodeid: int, ip_override: str = None): + self.logger.info("Testing discovery") + device = self.TestDiscovery(discriminator=discriminator) + if not device: + self.logger.info("Failed to discover any devices.") + return False + address = device.addresses[0] + if ip_override: + address = ip_override + self.logger.info("Testing commissioning") + if not self.TestCommissioning(address, setuppin, nodeid): + self.logger.info("Failed to finish commissioning") + return False + return True + def TestUsedTestCommissioner(self): return self.devCtrl.GetTestCommissionerUsed() @@ -1322,6 +1334,13 @@ def TestFabricScopedCommandDuringPase(self, nodeid: int): return status == IM.Status.UnsupportedAccess def TestSubscriptionResumption(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, remote_server_app: str): + ''' + This test validates that the device can resume the subscriptions after restarting. + It is executed in Linux Cirque tests and the steps of this test are: + 1. Subscription the NodeLable attribute on BasicInformation cluster with the controller + 2. Restart the remote server app + 3. Validate that the controller can receive a report from the remote server app + ''' desiredPath = None receivedUpdate = False updateLock = threading.Lock() @@ -1339,48 +1358,17 @@ def OnValueReport(path: Attribute.TypedAttributePath, transaction: Attribute.Sub receivedUpdate = True updateCv.notify_all() - class _restartRemoteDevice(threading.Thread): - def __init__(self, remote_ip: str, ssh_port: int, remote_server_app: str): - super(_restartRemoteDevice, self).__init__() - self.remote_ip = remote_ip - self.ssh_port = ssh_port - self.remote_server_app = remote_server_app - - def run(self): - client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - try: - client.connect(self.remote_ip, self.ssh_port, "root", "admin") - client.exec_command( - ("kill \"$(ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\')\"").format(self.remote_server_app)) - time.sleep(1) - stdin, stdout, stderr = client.exec_command( - ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\'").format(self.remote_server_app)) - if not stdout.read().decode().strip(): - logger.info(f"Succeed to kill remote process {self.remote_server_app}") - else: - logger.error(f"Failed to kill remote process {self.remote_server_app}") - - client.exec_command( - ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " - "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator 3840").format( - os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app))) - - finally: - client.close() - try: desiredPath = Clusters.Attribute.AttributePath( EndpointId=0, ClusterId=0x28, AttributeId=5) - # Basic Information Cluster, NodeLabel Attribute + # BasicInformation Cluster, NodeLabel Attribute subscription = self.devCtrl.ZCLSubscribeAttribute( "BasicInformation", "NodeLabel", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) subscription.SetAttributeUpdateCallback(OnValueReport) self.logger.info("Restart remote deivce") - restartRemoteThread = _restartRemoteDevice(remote_ip, ssh_port, remote_server_app) + restartRemoteThread = restartRemoteDevice( + remote_ip, ssh_port, "root", "admin", remote_server_app, "--thread --discriminator 3840") restartRemoteThread.start() # After device restarts, the attribute will be set dirty so the subscription can receive # the update @@ -1412,9 +1400,32 @@ def run(self): return True + ''' + The SubscriptionResumptionCapacity Cirque Test is to verify that the device can still handle new subscription + requests when resuming the maximum subscriptions. The steps for this test are: + 1. Commission the server app to the first fabric and send maximum subscription requests from the controller in + the first fabric to establish maximum subscriptions. + 2. Open the commissioning window to make the server app can be commissioned to the second fabric + 3. Shutdown the controller in the first fabric to extend the time of resuming subscriptions. The server app will + keep resolving the address of the first controller for a while after rebooting. + 4. Commission the server app to the second fabric. + 5. Restart the server app and the server app will start resuming subscriptions. Since the first controller is + shutdown, the server app will keep resolving the address of the first controller for a while and the subscription + resumption will not fail so quickly. + 6. When the server app is resuming subscriptions, send a new subscription request from the second controller. + Verify that the device can still handle this subscription. + + BaseTestHelper provides two controllers. However, if using the two controller (devCtrl and devCtrl2) in one + MobileDevice to execute this Cirque test, the CHIPEndDevice can still resolve the address for first controller + even if the first controller is shutdown by 'self.devCtrl.Shutdown()'. And the server will fail to estalish the + subscriptions immediately, which makes it hard to send the new subscription request from the second controller + at the time of server app resuming maximum subscriptions. + So we will use two controller containers for this test and divide the test to two steps. The Step1 is executed in + controller 1 in container 1 while the Step2 is executed in controller 2 in container 2 + ''' def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, subscription_capacity: int): try: - # OnOff Cluster, OnOff Attribute + # BasicInformation Cluster, NodeLabel Attribute for i in range(subscription_capacity): self.devCtrl.ZCLSubscribeAttribute( "BasicInformation", "NodeLabel", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) @@ -1436,66 +1447,22 @@ def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, su return True def TestSubscriptionResumptionCapacityStep2(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, - remote_server_app: str, subscription_capacity: int): - updateLock = threading.Lock() - updateCv = threading.Condition(updateLock) - - class _restartRemoteDevice(threading.Thread): - def __init__(self, remote_ip: str, ssh_port: int, remote_server_app: str, subscription_capacity: int): - super(_restartRemoteDevice, self).__init__() - self.remote_ip = remote_ip - self.ssh_port = ssh_port - self.remote_server_app = remote_server_app - self.subscription_capacity = subscription_capacity - - def run(self): - client = paramiko.SSHClient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - try: - client.connect(self.remote_ip, self.ssh_port, "root", "admin") - client.exec_command( - ("kill \"$(ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\')\"").format(self.remote_server_app)) - time.sleep(1) - stdin, stdout, stderr = client.exec_command( - ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " - "awk \'{{print $2}}\'").format(self.remote_server_app)) - if not stdout.read().decode().strip(): - logger.info(f"Succeed to kill remote process {self.remote_server_app}") - else: - logger.error(f"Failed to kill remote process {self.remote_server_app}") - - client.exec_command("systemctl restart avahi-deamon.service") - client.exec_command( - ("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " - "-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator 3840 " - "--subscription-capacity {}").format( - os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app), - self.subscription_capacity)) - with updateLock: - updateCv.notifyAll() - - finally: - client.close() - + remote_server_app: str, subscription_capacity: int): try: self.logger.info("Restart remote deivce") - restartRemoteThread = _restartRemoteDevice(remote_ip, ssh_port, remote_server_app, subscription_capacity) + extra_agrs = f"--thread --discriminator 3840 --subscription-capacity {subscription_capacity}" + restartRemoteThread = restartRemoteDevice(remote_ip, ssh_port, "root", "admin", remote_server_app, extra_agrs) restartRemoteThread.start() - with updateCv: - if not updateCv.wait(8.0): - self.logger.error( - "Failed to restart the remote device") - # Wait for some time so that the device will be resolving the address of the first controller - time.sleep(3) + # Wait for some time so that the device will be resolving the address of the first controller after restarting + time.sleep(8) + restartRemoteThread.join(10.0) self.logger.info("Send a new subscription request from the second controller") # Close previous session so that the second controller will res-establish the session with the remote device self.devCtrl.CloseSession(nodeid) self.devCtrl.ZCLSubscribeAttribute( "BasicInformation", "NodeLabel", nodeid, endpoint, 1, 50, keepSubscriptions=True, autoResubscribe=False) - restartRemoteThread.join(10.0) if restartRemoteThread.is_alive(): # Thread join timed out diff --git a/src/controller/python/test/test_scripts/cirque_restart_remote_device.py b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py new file mode 100644 index 00000000000000..5015854f167941 --- /dev/null +++ b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +# +# 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. +# + +# This is used to restart the remote device in cirque test + +import logging +import os +import paramiko +import sys +import threading +import time + +CHIP_REPO = os.path.join(os.path.abspath( + os.path.dirname(__file__)), "..", "..", "..", "..", "..") + +logger = logging.getLogger("CirqueRestartRemoteDevice") +logger.setLevel(logging.INFO) + +sh = logging.StreamHandler() +sh.setFormatter( + logging.Formatter( + '%(asctime)s [%(name)s] %(levelname)s %(message)s')) +sh.setStream(sys.stdout) +logger.addHandler(sh) + + +class restartRemoteDevice(threading.Thread): + def __init__(self, remote_ip: str, ssh_port: int, user: str, password: str, remote_server_app: str, + extra_args: str): + super(restartRemoteDevice, self).__init__() + self.remote_ip = remote_ip + self.ssh_port = ssh_port + self.user = user + self.password = password + self.remote_server_app = remote_server_app + self.extra_args = extra_args + + def run(self): + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + client.connect(self.remote_ip, self.ssh_port, self.user, self.password) + client.exec_command( + ("kill \"$(ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\')\"").format(self.remote_server_app)) + time.sleep(1) + stdin, stdout, stderr = client.exec_command( + ("ps aux | grep -E \'out/debug/standalone/{}\' | grep -v grep | grep -v gdb | " + "awk \'{{print $2}}\'").format(self.remote_server_app)) + if not stdout.read().decode().strip(): + logger.info(f"Succeed to kill remote process {self.remote_server_app}") + else: + logger.error(f"Failed to kill remote process {self.remote_server_app}") + + restart_remote_device_command = ( + "CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" " + "-ex run -ex \"thread apply all bt\" --args {} {}").format( + os.path.join(CHIP_REPO, "out/debug/standalone", self.remote_server_app), self.extra_args) + client.exec_command(restart_remote_device_command) + + finally: + client.close() diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py index c5cecf4b8da2cb..470ff5aea53da1 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl1.py @@ -31,23 +31,6 @@ TEST_ENDPOINT_ID = 0 -def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): - logger.info("Testing discovery") - device = test.TestDiscovery(discriminator=discriminator) - FailIfNot(device, "Failed to discover any devices.") - - address = device.addresses[0] - - if address_override: - address = address_override - - logger.info("Testing commissioning") - FailIfNot(test.TestCommissioning(ip=address, - setuppin=setup_pin, - nodeid=device_nodeid), - "Failed to finish key exchange") - - def main(): optParser = OptionParser() optParser.add_option( @@ -125,7 +108,9 @@ def main(): test = BaseTestHelper( nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True) - ethernet_commissioning(test, options.discriminator, options.setuppin, options.deviceAddress, options.nodeid) + FailIfNot( + test.TestOnNetworkCommissioning(options.discriminator, options.setuppin, options.nodeid, options.deviceAddress), + "Failed on on-network commissioing") FailIfNot( test.TestSubscriptionResumptionCapacityStep1(options.nodeid, TEST_ENDPOINT_ID, options.subscriptionCapacity), diff --git a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py index 4e226e816abe52..2f3058afcd3bca 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_capacity_test_ctrl2.py @@ -33,23 +33,6 @@ TEST_SSH_PORT = 2222 -def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): - logger.info("Testing discovery") - device = test.TestDiscovery(discriminator=discriminator) - FailIfNot(device, "Failed to discover any devices.") - - address = device.addresses[0] - - if address_override: - address = address_override - - logger.info("Testing commissioning") - FailIfNot(test.TestCommissioning(ip=address, - setuppin=setup_pin, - nodeid=device_nodeid), - "Failed to finish key exchange") - - def main(): optParser = OptionParser() optParser.add_option( @@ -137,7 +120,9 @@ def main(): test = BaseTestHelper( nodeid=112244, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True) - ethernet_commissioning(test, options.discriminator, options.setuppin, options.deviceAddress, options.nodeid) + FailIfNot( + test.TestOnNetworkCommissioning(options.discriminator, options.setuppin, options.nodeid, options.deviceAddress), + "Failed on on-network commissioing") FailIfNot( test.TestSubscriptionResumptionCapacityStep2(options.nodeid, TEST_ENDPOINT_ID, options.deviceAddress, diff --git a/src/controller/python/test/test_scripts/subscription_resumption_test.py b/src/controller/python/test/test_scripts/subscription_resumption_test.py index 0b0c0c985db77a..8b2000fb070cd7 100755 --- a/src/controller/python/test/test_scripts/subscription_resumption_test.py +++ b/src/controller/python/test/test_scripts/subscription_resumption_test.py @@ -33,23 +33,6 @@ TEST_SSH_PORT = 2222 -def ethernet_commissioning(test: BaseTestHelper, discriminator: int, setup_pin: int, address_override: str, device_nodeid: int): - logger.info("Testing discovery") - device = test.TestDiscovery(discriminator=discriminator) - FailIfNot(device, "Failed to discover any devices.") - - address = device.addresses[0] - - if address_override: - address = address_override - - logger.info("Testing commissioning") - FailIfNot(test.TestCommissioning(ip=address, - setuppin=setup_pin, - nodeid=device_nodeid), - "Failed to finish key exchange") - - def main(): optParser = OptionParser() optParser.add_option( @@ -127,7 +110,9 @@ def main(): test = BaseTestHelper( nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True) - ethernet_commissioning(test, options.discriminator, options.setuppin, options.deviceAddress, options.nodeid) + FailIfNot( + test.TestOnNetworkCommissioning(options.discriminator, options.setuppin, options.nodeid, options.deviceAddress), + "Failed on on-network commissioing") FailIfNot( test.TestSubscriptionResumption(options.nodeid, TEST_ENDPOINT_ID, options.deviceAddress, diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py index cd13cb058774b2..29af85d4f1d62e 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py @@ -15,6 +15,20 @@ limitations under the License. """ +''' +Test to verify that the device can still handle new subscription requests when resuming the maximum subscriptions. +Steps for this test: + 1. Commission the server app to the first fabric and send maximum subscription requests from the controller in + the first fabric to establish maximum subscriptions. + 2. Open the commissioning window to make the server app can be commissioned to the second fabric. + 3. Shutdown the controller in the first fabric to extend the time of resuming subscriptions. The server app will + keep resolving the address of the first controller for a while after rebooting. + 4. Commission the server app to the second fabric. + 5. Restart the server app and the server app will start resuming subscriptions. + 6. When the server app is resuming subscriptions, send a new subscription request from the second controller. + 7. Verify that the device can still handle this subscription request. +''' + import logging import os import sys @@ -43,7 +57,9 @@ # TODO: If using one Mobile Device, the CHIPEndDevice can still resolve the address for first controller -# even if it was shutdown. +# even if it is shutdown by 'devCtrl.Shutdown()'. And the server will fail to estalish the subscriptions +# immediately, which makes it hard to send the new subscription request from the second controller. + # Use two containers for two controller in two different fabrics. DEVICE_CONFIG = { 'device0': { diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py index 42d2b4f525ed11..c4ac38cd77be5a 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py @@ -15,6 +15,14 @@ limitations under the License. """ +''' +Basic Subscription Resumption Test to validate that the device can resume subscriptions after restarting. +Steps for this test: + 1. Subcription an attribute on the controller + 2. Restart the server app + 3. Verify that the server app with resume the subscription and send a report to the controller +''' + import logging import os import sys @@ -61,7 +69,6 @@ } } - class TestSubscriptionResumption(CHIPVirtualHome): def __init__(self, device_config): super().__init__(CIRQUE_URL, device_config) From eff0e6b894ddb47f094d019ee7fafe02b4b9a91a Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Wed, 10 Jan 2024 14:17:29 +0800 Subject: [PATCH 11/15] typo changes --- src/controller/python/test/test_scripts/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index 5795a9a67bafff..226bc13774a2eb 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -1405,7 +1405,7 @@ def OnValueReport(path: Attribute.TypedAttributePath, transaction: Attribute.Sub requests when resuming the maximum subscriptions. The steps for this test are: 1. Commission the server app to the first fabric and send maximum subscription requests from the controller in the first fabric to establish maximum subscriptions. - 2. Open the commissioning window to make the server app can be commissioned to the second fabric + 2. Open the commissioning window to make the server app can be commissioned to the second fabric. 3. Shutdown the controller in the first fabric to extend the time of resuming subscriptions. The server app will keep resolving the address of the first controller for a while after rebooting. 4. Commission the server app to the second fabric. @@ -1417,7 +1417,7 @@ def OnValueReport(path: Attribute.TypedAttributePath, transaction: Attribute.Sub BaseTestHelper provides two controllers. However, if using the two controller (devCtrl and devCtrl2) in one MobileDevice to execute this Cirque test, the CHIPEndDevice can still resolve the address for first controller - even if the first controller is shutdown by 'self.devCtrl.Shutdown()'. And the server will fail to estalish the + even if the first controller is shutdown by 'self.devCtrl.Shutdown()'. And the server will fail to establish the subscriptions immediately, which makes it hard to send the new subscription request from the second controller at the time of server app resuming maximum subscriptions. So we will use two controller containers for this test and divide the test to two steps. The Step1 is executed in From 7a75ef7f2c44c4b89c82a8636c272f4f5ce6941b Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 10 Jan 2024 06:18:20 +0000 Subject: [PATCH 12/15] Restyled by autopep8 --- src/controller/python/test/test_scripts/base.py | 5 +++-- .../python/test/test_scripts/cirque_restart_remote_device.py | 2 +- .../linux-cirque/SubscriptionResumptionCapacityTest.py | 3 +-- src/test_driver/linux-cirque/SubscriptionResumptionTest.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/controller/python/test/test_scripts/base.py b/src/controller/python/test/test_scripts/base.py index 226bc13774a2eb..8552e8f5062e2d 100644 --- a/src/controller/python/test/test_scripts/base.py +++ b/src/controller/python/test/test_scripts/base.py @@ -1368,7 +1368,7 @@ def OnValueReport(path: Attribute.TypedAttributePath, transaction: Attribute.Sub self.logger.info("Restart remote deivce") restartRemoteThread = restartRemoteDevice( - remote_ip, ssh_port, "root", "admin", remote_server_app, "--thread --discriminator 3840") + remote_ip, ssh_port, "root", "admin", remote_server_app, "--thread --discriminator 3840") restartRemoteThread.start() # After device restarts, the attribute will be set dirty so the subscription can receive # the update @@ -1423,6 +1423,7 @@ def OnValueReport(path: Attribute.TypedAttributePath, transaction: Attribute.Sub So we will use two controller containers for this test and divide the test to two steps. The Step1 is executed in controller 1 in container 1 while the Step2 is executed in controller 2 in container 2 ''' + def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, subscription_capacity: int): try: # BasicInformation Cluster, NodeLabel Attribute @@ -1447,7 +1448,7 @@ def TestSubscriptionResumptionCapacityStep1(self, nodeid: int, endpoint: int, su return True def TestSubscriptionResumptionCapacityStep2(self, nodeid: int, endpoint: int, remote_ip: str, ssh_port: int, - remote_server_app: str, subscription_capacity: int): + remote_server_app: str, subscription_capacity: int): try: self.logger.info("Restart remote deivce") extra_agrs = f"--thread --discriminator 3840 --subscription-capacity {subscription_capacity}" diff --git a/src/controller/python/test/test_scripts/cirque_restart_remote_device.py b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py index 5015854f167941..f2db9ea3130d01 100644 --- a/src/controller/python/test/test_scripts/cirque_restart_remote_device.py +++ b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py @@ -42,7 +42,7 @@ class restartRemoteDevice(threading.Thread): def __init__(self, remote_ip: str, ssh_port: int, user: str, password: str, remote_server_app: str, - extra_args: str): + extra_args: str): super(restartRemoteDevice, self).__init__() self.remote_ip = remote_ip self.ssh_port = ssh_port diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py index 29af85d4f1d62e..f4634d66993afc 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py @@ -29,12 +29,11 @@ 7. Verify that the device can still handle this subscription request. ''' + import logging import os import sys - from helper.CHIPTestBase import CHIPVirtualHome - logger = logging.getLogger('SubscriptionResumptionCapacityTest') logger.setLevel(logging.INFO) diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py index c4ac38cd77be5a..5e6d9bc9344c40 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py @@ -23,12 +23,11 @@ 3. Verify that the server app with resume the subscription and send a report to the controller ''' + import logging import os import sys - from helper.CHIPTestBase import CHIPVirtualHome - logger = logging.getLogger('SubscriptionResumptionTest') logger.setLevel(logging.INFO) @@ -69,6 +68,7 @@ } } + class TestSubscriptionResumption(CHIPVirtualHome): def __init__(self, device_config): super().__init__(CIRQUE_URL, device_config) From a33ad69365f95a043220b778cc1d4ed7d58592c4 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 10 Jan 2024 06:18:20 +0000 Subject: [PATCH 13/15] Restyled by isort --- .../python/test/test_scripts/cirque_restart_remote_device.py | 3 ++- .../linux-cirque/SubscriptionResumptionCapacityTest.py | 2 ++ src/test_driver/linux-cirque/SubscriptionResumptionTest.py | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/controller/python/test/test_scripts/cirque_restart_remote_device.py b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py index f2db9ea3130d01..7937834096de4f 100644 --- a/src/controller/python/test/test_scripts/cirque_restart_remote_device.py +++ b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py @@ -21,11 +21,12 @@ import logging import os -import paramiko import sys import threading import time +import paramiko + CHIP_REPO = os.path.join(os.path.abspath( os.path.dirname(__file__)), "..", "..", "..", "..", "..") diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py index f4634d66993afc..dd61953ac42f5f 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py @@ -33,7 +33,9 @@ import logging import os import sys + from helper.CHIPTestBase import CHIPVirtualHome + logger = logging.getLogger('SubscriptionResumptionCapacityTest') logger.setLevel(logging.INFO) diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py index 5e6d9bc9344c40..b5863dbf346350 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py @@ -27,7 +27,9 @@ import logging import os import sys + from helper.CHIPTestBase import CHIPVirtualHome + logger = logging.getLogger('SubscriptionResumptionTest') logger.setLevel(logging.INFO) From ab51c9df4d81736cd92a8ad979f79718b5b0fc5c Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Wed, 10 Jan 2024 16:21:28 +0800 Subject: [PATCH 14/15] ci fixes --- .../cirque_restart_remote_device.py | 5 ++++- .../SubscriptionResumptionCapacityTest.py | 17 ++++++++--------- .../linux-cirque/SubscriptionResumptionTest.py | 17 ++++++++--------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/controller/python/test/test_scripts/cirque_restart_remote_device.py b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py index 7937834096de4f..4cc773d52a1d35 100644 --- a/src/controller/python/test/test_scripts/cirque_restart_remote_device.py +++ b/src/controller/python/test/test_scripts/cirque_restart_remote_device.py @@ -25,7 +25,10 @@ import threading import time -import paramiko +try: + import paramiko +except ImportError: + pass CHIP_REPO = os.path.join(os.path.abspath( os.path.dirname(__file__)), "..", "..", "..", "..", "..") diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py index dd61953ac42f5f..d99d25e5d2b8b2 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionCapacityTest.py @@ -15,7 +15,13 @@ limitations under the License. """ -''' +import logging +import os +import sys + +from helper.CHIPTestBase import CHIPVirtualHome + +""" Test to verify that the device can still handle new subscription requests when resuming the maximum subscriptions. Steps for this test: 1. Commission the server app to the first fabric and send maximum subscription requests from the controller in @@ -27,14 +33,7 @@ 5. Restart the server app and the server app will start resuming subscriptions. 6. When the server app is resuming subscriptions, send a new subscription request from the second controller. 7. Verify that the device can still handle this subscription request. -''' - - -import logging -import os -import sys - -from helper.CHIPTestBase import CHIPVirtualHome +""" logger = logging.getLogger('SubscriptionResumptionCapacityTest') logger.setLevel(logging.INFO) diff --git a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py index b5863dbf346350..47de0f4f4a1d79 100755 --- a/src/test_driver/linux-cirque/SubscriptionResumptionTest.py +++ b/src/test_driver/linux-cirque/SubscriptionResumptionTest.py @@ -15,21 +15,20 @@ limitations under the License. """ -''' -Basic Subscription Resumption Test to validate that the device can resume subscriptions after restarting. -Steps for this test: - 1. Subcription an attribute on the controller - 2. Restart the server app - 3. Verify that the server app with resume the subscription and send a report to the controller -''' - - import logging import os import sys from helper.CHIPTestBase import CHIPVirtualHome +""" +Basic Subscription Resumption Test to validate that the device can resume subscriptions after restarting. +Steps for this test: + 1. Subcription an attribute on the controller + 2. Restart the server app + 3. Verify that the server app with resume the subscription and send a report to the controller +""" + logger = logging.getLogger('SubscriptionResumptionTest') logger.setLevel(logging.INFO) From 68d2a84f93f6bfea6ea9b5e8afe83acde3df7909 Mon Sep 17 00:00:00 2001 From: yunhanw-google Date: Wed, 10 Jan 2024 18:10:13 -0800 Subject: [PATCH 15/15] Update examples/platform/linux/Options.cpp Co-authored-by: Boris Zbarsky --- examples/platform/linux/Options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/platform/linux/Options.cpp b/examples/platform/linux/Options.cpp index 12cc1b5f0f48e7..4c6791a178e48e 100644 --- a/examples/platform/linux/Options.cpp +++ b/examples/platform/linux/Options.cpp @@ -272,7 +272,7 @@ const char * sDeviceOptionHelp = #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST " --subscription-capacity\n" - " Max subscriptions number for the device to manage\n" + " Max number of subscriptions the device will allow\n" #endif "\n";