Skip to content

Commit 63959ca

Browse files
[icd] Add WaitForActive testing in Cirque (#34200)
* [icd] Add WaitForActive testing in Cirque * Update * Update * Fix test * fix test * fix * Fix * Restyled by autopep8 --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 66847c6 commit 63959ca

File tree

7 files changed

+303
-6
lines changed

7 files changed

+303
-6
lines changed

examples/lit-icd-app/linux/main.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,26 @@
1919
#include "AppMain.h"
2020
#include <app-common/zap-generated/ids/Clusters.h>
2121

22+
#include "system/SystemClock.h"
23+
2224
using namespace chip;
2325
using namespace chip::app;
26+
using namespace chip::System::Clock::Literals;
2427

2528
void ApplicationInit() {}
2629

2730
void ApplicationShutdown() {}
2831

32+
void notifyIcdActive(System::Layer * layer, void *)
33+
{
34+
ICDNotifier::GetInstance().NotifyNetworkActivityNotification();
35+
DeviceLayer::SystemLayer().StartTimer(10000_ms32, notifyIcdActive, nullptr);
36+
}
37+
2938
int main(int argc, char * argv[])
3039
{
3140
VerifyOrDie(ChipLinuxAppInit(argc, argv) == 0);
41+
DeviceLayer::SystemLayer().StartTimer(10000_ms32, notifyIcdActive, nullptr);
3242
ChipLinuxAppMainLoop();
3343
return 0;
3444
}

scripts/tests/cirque_tests.sh

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ CIRQUE_TESTS=(
4444
"MobileDeviceTest"
4545
"CommissioningTest"
4646
"InteractionModelTest"
47+
"IcdWaitForActiveTest"
4748
"SplitCommissioningTest"
4849
"CommissioningFailureTest"
4950
"CommissioningFailureOnReportTest"

src/controller/python/ChipDeviceController-ScriptBinding.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ struct IcdRegistrationParameters
584584
uint64_t checkInNodeId;
585585
uint64_t monitoredSubject;
586586
uint32_t stayActiveMsec;
587+
uint8_t clientType;
587588
};
588589

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

626628
return ToPyChipError(CHIP_NO_ERROR);
627629
}

src/controller/python/chip/ChipDeviceCtrl.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,14 @@ class ICDRegistrationParameters:
107107
checkInNodeId: typing.Optional[int]
108108
monitoredSubject: typing.Optional[int]
109109
stayActiveMs: typing.Optional[int]
110+
clientType: typing.Optional[Clusters.IcdManagement.Enums.ClientTypeEnum]
110111

111112
class CStruct(Structure):
112113
_fields_ = [('symmetricKey', c_char_p), ('symmetricKeyLength', c_size_t), ('checkInNodeId',
113-
c_uint64), ('monitoredSubject', c_uint64), ('stayActiveMsec', c_uint32)]
114+
c_uint64), ('monitoredSubject', c_uint64), ('stayActiveMsec', c_uint32), ('clientType', c_uint8)]
114115

115116
def to_c(self):
116-
return ICDRegistrationParameters.CStruct(self.symmetricKey, len(self.symmetricKey), self.checkInNodeId, self.monitoredSubject, self.stayActiveMs)
117+
return ICDRegistrationParameters.CStruct(self.symmetricKey, len(self.symmetricKey), self.checkInNodeId, self.monitoredSubject, self.stayActiveMs, self.clientType.value)
117118

118119

119120
@_DeviceAvailableCallbackFunct
@@ -207,8 +208,7 @@ def OnCheckInCallback(nodeid):
207208
RegisterOnActiveCallback(scopedNodeId, OnCheckInCallback)
208209

209210
try:
210-
async with asyncio.timeout(timeoutSeconds):
211-
await future
211+
asyncio.wait_for(future, timeout=timeoutSeconds)
212212
finally:
213213
UnregisterOnActiveCallback(scopedNodeId, OnCheckInCallback)
214214

@@ -2018,7 +2018,8 @@ def GenerateICDRegistrationParameters(self):
20182018
secrets.token_bytes(16),
20192019
self._nodeId,
20202020
self._nodeId,
2021-
30)
2021+
30,
2022+
Clusters.IcdManagement.Enums.ClientTypeEnum.kPermanent)
20222023

20232024
def EnableICDRegistration(self, parameters: ICDRegistrationParameters):
20242025
''' Enables ICD registration for the following commissioning session.

src/controller/python/test/test_scripts/base.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ def __init__(self, nodeid: int, paaTrustStorePath: str, testCommissioner: bool =
184184
keypair: p256keypair.P256Keypair = None):
185185
chip.native.Init()
186186

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

1161+
async def TestTriggerTestEventHandler(self, nodeid, enable_key, event_trigger):
1162+
self.logger.info("Test trigger test event handler for device = %08x", nodeid)
1163+
try:
1164+
await self.devCtrl.SendCommand(nodeid, 0, Clusters.GeneralDiagnostics.Commands.TestEventTrigger(enableKey=enable_key, eventTrigger=event_trigger))
1165+
return True
1166+
except Exception as ex:
1167+
self.logger.exception("Failed to trigger test event handler {}".format(ex))
1168+
return False
1169+
1170+
async def TestWaitForActive(self, nodeid):
1171+
self.logger.info("Test wait for device = %08x", nodeid)
1172+
try:
1173+
await self.devCtrl.WaitForActive(nodeid)
1174+
return True
1175+
except Exception as ex:
1176+
self.logger.exception("Failed to wait for active. {}".format(ex))
1177+
return False
1178+
11611179
async def TestReadBasicAttributes(self, nodeid: int, endpoint: int):
11621180
attrs = Clusters.BasicInformation.Attributes
11631181
basic_cluster_attrs = {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env python3
2+
3+
#
4+
# Copyright (c) 2021 Project CHIP Authors
5+
# All rights reserved.
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
#
19+
20+
# Commissioning test.
21+
22+
import asyncio
23+
import os
24+
import sys
25+
from optparse import OptionParser
26+
27+
from base import BaseTestHelper, FailIfNot, TestFail, TestTimeout, logger
28+
29+
TEST_DISCRIMINATOR = 3840
30+
TEST_DISCOVERY_TYPE = 2
31+
32+
ENDPOINT_ID = 0
33+
LIGHTING_ENDPOINT_ID = 1
34+
GROUP_ID = 0
35+
36+
37+
async def waitForActiveAndTriggerCheckIn(test, nodeid):
38+
coro = test.TestWaitForActive(nodeid=nodeid)
39+
await test.TestTriggerTestEventHandler(nodeid, bytes.fromhex("00112233445566778899aabbccddeeff"), 0x0046 << 48)
40+
return await coro
41+
42+
43+
async def main():
44+
optParser = OptionParser()
45+
optParser.add_option(
46+
"-t",
47+
"--timeout",
48+
action="store",
49+
dest="testTimeout",
50+
default=75,
51+
type='int',
52+
help="The program will return with timeout after specified seconds.",
53+
metavar="<timeout-second>",
54+
)
55+
optParser.add_option(
56+
"-a",
57+
"--address",
58+
action="store",
59+
dest="deviceAddress",
60+
default='',
61+
type='str',
62+
help="Address of the device",
63+
metavar="<device-addr>",
64+
)
65+
optParser.add_option(
66+
"--setup-payload",
67+
action="store",
68+
dest="setupPayload",
69+
default='',
70+
type='str',
71+
help="Setup Payload (manual pairing code or QR code content)",
72+
metavar="<setup-payload>"
73+
)
74+
optParser.add_option(
75+
"--nodeid",
76+
action="store",
77+
dest="nodeid",
78+
default=1,
79+
type=int,
80+
help="The Node ID issued to the device",
81+
metavar="<nodeid>"
82+
)
83+
optParser.add_option(
84+
"--discriminator",
85+
action="store",
86+
dest="discriminator",
87+
default=TEST_DISCRIMINATOR,
88+
type=int,
89+
help="Discriminator of the device",
90+
metavar="<nodeid>"
91+
)
92+
optParser.add_option(
93+
"-p",
94+
"--paa-trust-store-path",
95+
action="store",
96+
dest="paaTrustStorePath",
97+
default='',
98+
type='str',
99+
help="Path that contains valid and trusted PAA Root Certificates.",
100+
metavar="<paa-trust-store-path>"
101+
)
102+
optParser.add_option(
103+
"--discovery-type",
104+
action="store",
105+
dest="discoveryType",
106+
default=TEST_DISCOVERY_TYPE,
107+
type=int,
108+
help="Discovery type of commissioning. (0: networkOnly 1: networkOnlyWithoutPASEAutoRetry 2: All<Ble & Network>)",
109+
metavar="<discovery-type>"
110+
)
111+
112+
(options, remainingArgs) = optParser.parse_args(sys.argv[1:])
113+
114+
timeoutTicker = TestTimeout(options.testTimeout)
115+
timeoutTicker.start()
116+
117+
test = BaseTestHelper(
118+
nodeid=112233, paaTrustStorePath=options.paaTrustStorePath, testCommissioner=True)
119+
120+
devCtrl = test.devCtrl
121+
devCtrl.EnableICDRegistration(devCtrl.GenerateICDRegistrationParameters())
122+
logger.info("Testing commissioning")
123+
FailIfNot(await test.TestCommissioning(ip=options.deviceAddress,
124+
setuppin=20202021,
125+
nodeid=options.nodeid),
126+
"Failed to finish key exchange")
127+
logger.info("Commissioning completed")
128+
logger.info("Testing wait for active")
129+
FailIfNot(await waitForActiveAndTriggerCheckIn(test, nodeid=options.nodeid), "Failed to test wait for active")
130+
logger.info('Successfully handled wait-for-active')
131+
132+
timeoutTicker.stop()
133+
134+
logger.info("Test finished")
135+
136+
# TODO: Python device controller cannot be shutdown clean sometimes and will block on AsyncDNSResolverSockets shutdown.
137+
# Call os._exit(0) to force close it.
138+
os._exit(0)
139+
140+
141+
if __name__ == "__main__":
142+
try:
143+
loop = asyncio.get_event_loop()
144+
loop.run_until_complete(main())
145+
loop.close()
146+
except Exception as ex:
147+
logger.exception(ex)
148+
TestFail("Exception occurred when running tests.")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Copyright (c) 2021 Project CHIP Authors
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
"""
17+
18+
import logging
19+
import os
20+
import sys
21+
22+
from helper.CHIPTestBase import CHIPVirtualHome
23+
24+
logger = logging.getLogger('MobileDeviceTest')
25+
logger.setLevel(logging.INFO)
26+
27+
sh = logging.StreamHandler()
28+
sh.setFormatter(
29+
logging.Formatter(
30+
'%(asctime)s [%(name)s] %(levelname)s %(message)s'))
31+
logger.addHandler(sh)
32+
33+
CHIP_PORT = 5540
34+
35+
CIRQUE_URL = "http://localhost:5000"
36+
CHIP_REPO = os.path.join(os.path.abspath(
37+
os.path.dirname(__file__)), "..", "..", "..")
38+
TEST_EXTPANID = "fedcba9876543210"
39+
TEST_DISCRIMINATOR = 3840
40+
TEST_DISCRIMINATOR2 = 3584
41+
TEST_DISCRIMINATOR3 = 1203
42+
TEST_DISCRIMINATOR4 = 2145
43+
TEST_DISCOVERY_TYPE = [0, 1, 2]
44+
MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "credentials/development/paa-root-certs"
45+
46+
DEVICE_CONFIG = {
47+
'device0': {
48+
'type': 'MobileDevice',
49+
'base_image': '@default',
50+
'capability': ['TrafficControl', 'Mount'],
51+
'rcp_mode': True,
52+
'docker_network': 'Ipv6',
53+
'traffic_control': {'latencyMs': 25},
54+
"mount_pairs": [[CHIP_REPO, CHIP_REPO]],
55+
},
56+
'device1': {
57+
'type': 'CHIPEndDevice',
58+
'base_image': '@default',
59+
'capability': ['Thread', 'TrafficControl', 'Mount'],
60+
'rcp_mode': True,
61+
'docker_network': 'Ipv6',
62+
'traffic_control': {'latencyMs': 25},
63+
"mount_pairs": [[CHIP_REPO, CHIP_REPO]],
64+
}
65+
}
66+
67+
68+
class TestCommissioner(CHIPVirtualHome):
69+
def __init__(self, device_config):
70+
super().__init__(CIRQUE_URL, device_config)
71+
self.logger = logger
72+
73+
def setup(self):
74+
self.initialize_home()
75+
76+
def test_routine(self):
77+
self.run_controller_test()
78+
79+
def run_controller_test(self):
80+
ethernet_ip = [device['description']['ipv6_addr'] for device in self.non_ap_devices
81+
if device['type'] == 'CHIPEndDevice'][0]
82+
server_ids = [device['id'] for device in self.non_ap_devices
83+
if device['type'] == 'CHIPEndDevice']
84+
req_ids = [device['id'] for device in self.non_ap_devices
85+
if device['type'] == 'MobileDevice']
86+
87+
for server in server_ids:
88+
self.execute_device_cmd(
89+
server,
90+
("CHIPCirqueDaemon.py -- run gdb -batch -return-child-result -q -ex \"set pagination off\" "
91+
"-ex run -ex \"thread apply all bt\" --args {} --thread --discriminator {}").format(
92+
os.path.join(CHIP_REPO, "out/debug/lit_icd/lit-icd-app"), TEST_DISCRIMINATOR))
93+
94+
self.reset_thread_devices(server_ids)
95+
96+
req_device_id = req_ids[0]
97+
98+
self.execute_device_cmd(req_device_id, "pip3 install --break-system-packages {}".format(os.path.join(
99+
CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_clusters-0.0-py3-none-any.whl")))
100+
self.execute_device_cmd(req_device_id, "pip3 install --break-system-packages {}".format(os.path.join(
101+
CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_core-0.0-cp37-abi3-linux_x86_64.whl")))
102+
self.execute_device_cmd(req_device_id, "pip3 install --break-system-packages {}".format(os.path.join(
103+
CHIP_REPO, "out/debug/linux_x64_gcc/controller/python/chip_repl-0.0-py3-none-any.whl")))
104+
105+
command = ("gdb -batch -return-child-result -q -ex run -ex \"thread apply all bt\" "
106+
"--args python3 {} -t 300 -a {} --paa-trust-store-path {}").format(
107+
os.path.join(
108+
CHIP_REPO, "src/controller/python/test/test_scripts/icd_wait_for_device_test.py"), ethernet_ip,
109+
os.path.join(CHIP_REPO, MATTER_DEVELOPMENT_PAA_ROOT_CERTS))
110+
ret = self.execute_device_cmd(req_device_id, command)
111+
112+
self.assertEqual(ret['return_code'], '0',
113+
"Test failed: non-zero return code")
114+
115+
116+
if __name__ == "__main__":
117+
sys.exit(TestCommissioner(DEVICE_CONFIG).run_test())

0 commit comments

Comments
 (0)