Skip to content

Commit

Permalink
[icd] Add WaitForActive testing in Cirque (#34200)
Browse files Browse the repository at this point in the history
* [icd] Add WaitForActive testing in Cirque

* Update

* Update

* Fix test

* fix test

* fix

* Fix

* Restyled by autopep8

---------

Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
erjiaqing and restyled-commits authored Jul 23, 2024
1 parent 66847c6 commit 63959ca
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 6 deletions.
10 changes: 10 additions & 0 deletions examples/lit-icd-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,26 @@
#include "AppMain.h"
#include <app-common/zap-generated/ids/Clusters.h>

#include "system/SystemClock.h"

using namespace chip;
using namespace chip::app;
using namespace chip::System::Clock::Literals;

void ApplicationInit() {}

void ApplicationShutdown() {}

void notifyIcdActive(System::Layer * layer, void *)
{
ICDNotifier::GetInstance().NotifyNetworkActivityNotification();
DeviceLayer::SystemLayer().StartTimer(10000_ms32, notifyIcdActive, nullptr);
}

int main(int argc, char * argv[])
{
VerifyOrDie(ChipLinuxAppInit(argc, argv) == 0);
DeviceLayer::SystemLayer().StartTimer(10000_ms32, notifyIcdActive, nullptr);
ChipLinuxAppMainLoop();
return 0;
}
Expand Down
1 change: 1 addition & 0 deletions scripts/tests/cirque_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ CIRQUE_TESTS=(
"MobileDeviceTest"
"CommissioningTest"
"InteractionModelTest"
"IcdWaitForActiveTest"
"SplitCommissioningTest"
"CommissioningFailureTest"
"CommissioningFailureOnReportTest"
Expand Down
2 changes: 2 additions & 0 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ struct IcdRegistrationParameters
uint64_t checkInNodeId;
uint64_t monitoredSubject;
uint32_t stayActiveMsec;
uint8_t clientType;
};

PyChipError pychip_DeviceController_SetIcdRegistrationParameters(bool enabled, const IcdRegistrationParameters * params)
Expand Down Expand Up @@ -622,6 +623,7 @@ PyChipError pychip_DeviceController_SetIcdRegistrationParameters(bool enabled, c
sCommissioningParameters.SetICDCheckInNodeId(params->checkInNodeId);
sCommissioningParameters.SetICDMonitoredSubject(params->monitoredSubject);
sCommissioningParameters.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete);
sCommissioningParameters.SetICDClientType(static_cast<app::Clusters::IcdManagement::ClientTypeEnum>(params->clientType));

return ToPyChipError(CHIP_NO_ERROR);
}
Expand Down
11 changes: 6 additions & 5 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,14 @@ class ICDRegistrationParameters:
checkInNodeId: typing.Optional[int]
monitoredSubject: typing.Optional[int]
stayActiveMs: typing.Optional[int]
clientType: typing.Optional[Clusters.IcdManagement.Enums.ClientTypeEnum]

class CStruct(Structure):
_fields_ = [('symmetricKey', c_char_p), ('symmetricKeyLength', c_size_t), ('checkInNodeId',
c_uint64), ('monitoredSubject', c_uint64), ('stayActiveMsec', c_uint32)]
c_uint64), ('monitoredSubject', c_uint64), ('stayActiveMsec', c_uint32), ('clientType', c_uint8)]

def to_c(self):
return ICDRegistrationParameters.CStruct(self.symmetricKey, len(self.symmetricKey), self.checkInNodeId, self.monitoredSubject, self.stayActiveMs)
return ICDRegistrationParameters.CStruct(self.symmetricKey, len(self.symmetricKey), self.checkInNodeId, self.monitoredSubject, self.stayActiveMs, self.clientType.value)


@_DeviceAvailableCallbackFunct
Expand Down Expand Up @@ -207,8 +208,7 @@ def OnCheckInCallback(nodeid):
RegisterOnActiveCallback(scopedNodeId, OnCheckInCallback)

try:
async with asyncio.timeout(timeoutSeconds):
await future
asyncio.wait_for(future, timeout=timeoutSeconds)
finally:
UnregisterOnActiveCallback(scopedNodeId, OnCheckInCallback)

Expand Down Expand Up @@ -2018,7 +2018,8 @@ def GenerateICDRegistrationParameters(self):
secrets.token_bytes(16),
self._nodeId,
self._nodeId,
30)
30,
Clusters.IcdManagement.Enums.ClientTypeEnum.kPermanent)

def EnableICDRegistration(self, parameters: ICDRegistrationParameters):
''' Enables ICD registration for the following commissioning session.
Expand Down
20 changes: 19 additions & 1 deletion src/controller/python/test/test_scripts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def __init__(self, nodeid: int, paaTrustStorePath: str, testCommissioner: bool =
keypair: p256keypair.P256Keypair = None):
chip.native.Init()

self.chipStack = ChipStack('/tmp/repl_storage.json')
self.chipStack = ChipStack('/tmp/repl_storage.json', enableServerInteractions=True)
self.certificateAuthorityManager = chip.CertificateAuthority.CertificateAuthorityManager(chipStack=self.chipStack)
self.certificateAuthority = self.certificateAuthorityManager.NewCertificateAuthority()
self.fabricAdmin = self.certificateAuthority.NewFabricAdmin(vendorId=0xFFF1, fabricId=1)
Expand Down Expand Up @@ -1158,6 +1158,24 @@ def TestResolve(self, nodeid):
self.logger.exception("Failed to resolve. {}".format(ex))
return False

async def TestTriggerTestEventHandler(self, nodeid, enable_key, event_trigger):
self.logger.info("Test trigger test event handler for device = %08x", nodeid)
try:
await self.devCtrl.SendCommand(nodeid, 0, Clusters.GeneralDiagnostics.Commands.TestEventTrigger(enableKey=enable_key, eventTrigger=event_trigger))
return True
except Exception as ex:
self.logger.exception("Failed to trigger test event handler {}".format(ex))
return False

async def TestWaitForActive(self, nodeid):
self.logger.info("Test wait for device = %08x", nodeid)
try:
await self.devCtrl.WaitForActive(nodeid)
return True
except Exception as ex:
self.logger.exception("Failed to wait for active. {}".format(ex))
return False

async def TestReadBasicAttributes(self, nodeid: int, endpoint: int):
attrs = Clusters.BasicInformation.Attributes
basic_cluster_attrs = {
Expand Down
148 changes: 148 additions & 0 deletions src/controller/python/test/test_scripts/icd_wait_for_device_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/usr/bin/env python3

#
# Copyright (c) 2021 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 asyncio
import os
import sys
from optparse import OptionParser

from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger

TEST_DISCRIMINATOR = 3840
TEST_DISCOVERY_TYPE = 2

ENDPOINT_ID = 0
LIGHTING_ENDPOINT_ID = 1
GROUP_ID = 0


async def waitForActiveAndTriggerCheckIn(test, nodeid):
coro = test.TestWaitForActive(nodeid=nodeid)
await test.TestTriggerTestEventHandler(nodeid, bytes.fromhex("00112233445566778899aabbccddeeff"), 0x0046 << 48)
return await coro


async def main():
optParser = OptionParser()
optParser.add_option(
"-t",
"--timeout",
action="store",
dest="testTimeout",
default=75,
type='int',
help="The program will return with timeout after specified seconds.",
metavar="<timeout-second>",
)
optParser.add_option(
"-a",
"--address",
action="store",
dest="deviceAddress",
default='',
type='str',
help="Address of the device",
metavar="<device-addr>",
)
optParser.add_option(
"--setup-payload",
action="store",
dest="setupPayload",
default='',
type='str',
help="Setup Payload (manual pairing code or QR code content)",
metavar="<setup-payload>"
)
optParser.add_option(
"--nodeid",
action="store",
dest="nodeid",
default=1,
type=int,
help="The Node ID issued to the device",
metavar="<nodeid>"
)
optParser.add_option(
"--discriminator",
action="store",
dest="discriminator",
default=TEST_DISCRIMINATOR,
type=int,
help="Discriminator of the device",
metavar="<nodeid>"
)
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="<paa-trust-store-path>"
)
optParser.add_option(
"--discovery-type",
action="store",
dest="discoveryType",
default=TEST_DISCOVERY_TYPE,
type=int,
help="Discovery type of commissioning. (0: networkOnly 1: networkOnlyWithoutPASEAutoRetry 2: All<Ble & Network>)",
metavar="<discovery-type>"
)

(options, remainingArgs) = optParser.parse_args(sys.argv[1:])

timeoutTicker = TestTimeout(options.testTimeout)
timeoutTicker.start()

test = BaseTestHelper(
nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True)

devCtrl = test.devCtrl
devCtrl.EnableICDRegistration(devCtrl.GenerateICDRegistrationParameters())
logger.info("Testing commissioning")
FailIfNot(await test.TestCommissioning(ip=options.deviceAddress,
setuppin=20202021,
nodeid=options.nodeid),
"Failed to finish key exchange")
logger.info("Commissioning completed")
logger.info("Testing wait for active")
FailIfNot(await waitForActiveAndTriggerCheckIn(test, nodeid=options.nodeid), "Failed to test wait for active")
logger.info('Successfully handled wait-for-active')

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:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
except Exception as ex:
logger.exception(ex)
TestFail("Exception occurred when running tests.")
117 changes: 117 additions & 0 deletions src/test_driver/linux-cirque/IcdWaitForActiveTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
"""
Copyright (c) 2021 Project CHIP Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

import logging
import os
import sys

from helper.CHIPTestBase import CHIPVirtualHome

logger = logging.getLogger('MobileDeviceTest')
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
TEST_DISCRIMINATOR2 = 3584
TEST_DISCRIMINATOR3 = 1203
TEST_DISCRIMINATOR4 = 2145
TEST_DISCOVERY_TYPE = [0, 1, 2]
MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs"

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 TestCommissioner(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_controller_test()

def run_controller_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']

for server in server_ids:
self.execute_device_cmd(
server,
("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/lit_icd/lit-icd-app"), TEST_DISCRIMINATOR))

self.reset_thread_devices(server_ids)

req_device_id = req_ids[0]

self.execute_device_cmd(req_device_id, "pip3 install --break-system-packages {}".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 --break-system-packages {}".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 --break-system-packages {}".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 {}").format(
os.path.join(
CHIP_REPO, "src/controller/python/test/test_scripts/icd_wait_for_device_test.py"), ethernet_ip,
os.path.join(CHIP_REPO, MATTER_DEVELOPMENT_PAA_ROOT_CERTS))
ret = self.execute_device_cmd(req_device_id, command)

self.assertEqual(ret['return_code'], '0',
"Test failed: non-zero return code")


if __name__ == "__main__":
sys.exit(TestCommissioner(DEVICE_CONFIG).run_test())

0 comments on commit 63959ca

Please sign in to comment.