@@ -972,18 +972,6 @@ def __init__(self, *args):
972
972
# The named pipe name must be set in the derived classes
973
973
self .app_pipe = None
974
974
975
- async def commission_devices (self ) -> bool :
976
- conf = self .matter_test_config
977
-
978
- for commission_idx , node_id in enumerate (conf .dut_node_ids ):
979
- logging .info (
980
- f"Starting commissioning for root index { conf .root_of_trust_index } , fabric ID 0x{ conf .fabric_id :016X} , node ID 0x{ node_id :016X} " )
981
- logging .info (f"Commissioning method: { conf .commissioning_method } " )
982
-
983
- await CommissionDeviceTest .commission_device (self , commission_idx )
984
-
985
- return True
986
-
987
975
def get_test_steps (self , test : str ) -> list [TestStep ]:
988
976
''' Retrieves the test step list for the given test
989
977
@@ -1168,17 +1156,14 @@ def setup_test(self):
1168
1156
self .step (1 )
1169
1157
1170
1158
def teardown_class (self ):
1171
- """Final teardown after all tests: log all problems"""
1172
- if len (self .problems ) == 0 :
1173
- return
1174
-
1175
- logging .info ("###########################################################" )
1176
- logging .info ("Problems found:" )
1177
- logging .info ("===============" )
1178
- for problem in self .problems :
1179
- logging .info (str (problem ))
1180
- logging .info ("###########################################################" )
1181
-
1159
+ """Final teardown after all tests: log all problems."""
1160
+ if len (self .problems ) > 0 :
1161
+ logging .info ("###########################################################" )
1162
+ logging .info ("Problems found:" )
1163
+ logging .info ("===============" )
1164
+ for problem in self .problems :
1165
+ logging .info (str (problem ))
1166
+ logging .info ("###########################################################" )
1182
1167
super ().teardown_class ()
1183
1168
1184
1169
def check_pics (self , pics_key : str ) -> bool :
@@ -2107,8 +2092,7 @@ def parse_matter_test_args(argv: Optional[List[str]] = None) -> MatterTestConfig
2107
2092
2108
2093
def _async_runner (body , self : MatterBaseTest , * args , ** kwargs ):
2109
2094
timeout = self .matter_test_config .timeout if self .matter_test_config .timeout is not None else self .default_timeout
2110
- runner_with_timeout = asyncio .wait_for (body (self , * args , ** kwargs ), timeout = timeout )
2111
- return asyncio .run (runner_with_timeout )
2095
+ return self .event_loop .run_until_complete (asyncio .wait_for (body (self , * args , ** kwargs ), timeout = timeout ))
2112
2096
2113
2097
2114
2098
def async_test_body (body ):
@@ -2301,7 +2285,7 @@ def run_on_singleton_matching_endpoint(accept_function: EndpointCheckFunction):
2301
2285
def run_on_singleton_matching_endpoint_internal (body ):
2302
2286
def matching_runner (self : MatterBaseTest , * args , ** kwargs ):
2303
2287
runner_with_timeout = asyncio .wait_for (_get_all_matching_endpoints (self , accept_function ), timeout = 30 )
2304
- matching = asyncio . run (runner_with_timeout )
2288
+ matching = self . event_loop . run_until_complete (runner_with_timeout )
2305
2289
asserts .assert_less_equal (len (matching ), 1 , "More than one matching endpoint found for singleton test." )
2306
2290
if not matching :
2307
2291
logging .info ("Test is not applicable to any endpoint - skipping test" )
@@ -2348,7 +2332,7 @@ def run_if_endpoint_matches(accept_function: EndpointCheckFunction):
2348
2332
def run_if_endpoint_matches_internal (body ):
2349
2333
def per_endpoint_runner (self : MatterBaseTest , * args , ** kwargs ):
2350
2334
runner_with_timeout = asyncio .wait_for (should_run_test_on_endpoint (self , accept_function ), timeout = 60 )
2351
- should_run_test = asyncio . run (runner_with_timeout )
2335
+ should_run_test = self . event_loop . run_until_complete (runner_with_timeout )
2352
2336
if not should_run_test :
2353
2337
logging .info ("Test is not applicable to this endpoint - skipping test" )
2354
2338
asserts .skip ('Endpoint does not match test requirements' )
@@ -2367,14 +2351,25 @@ def __init__(self, *args):
2367
2351
self .is_commissioning = True
2368
2352
2369
2353
def test_run_commissioning (self ):
2370
- if not asyncio .run (self .commission_devices ()):
2371
- raise signals .TestAbortAll ("Failed to commission node" )
2354
+ if not self .event_loop .run_until_complete (self .commission_devices ()):
2355
+ raise signals .TestAbortAll ("Failed to commission node(s)" )
2356
+
2357
+ async def commission_devices (self ) -> bool :
2358
+ conf = self .matter_test_config
2372
2359
2373
- async def commission_device (instance : MatterBaseTest , i ) -> bool :
2374
- dev_ctrl = instance .default_controller
2375
- conf = instance .matter_test_config
2360
+ commissioned = []
2361
+ setup_payloads = self .get_setup_payload_info ()
2362
+ for node_id , setup_payload in zip (conf .dut_node_ids , setup_payloads ):
2363
+ logging .info (f"Starting commissioning for root index { conf .root_of_trust_index } , "
2364
+ f"fabric ID 0x{ conf .fabric_id :016X} , node ID 0x{ node_id :016X} " )
2365
+ logging .info (f"Commissioning method: { conf .commissioning_method } " )
2366
+ commissioned .append (await self .commission_device (node_id , setup_payload ))
2376
2367
2377
- info = instance .get_setup_payload_info ()[i ]
2368
+ return all (commissioned )
2369
+
2370
+ async def commission_device (self , node_id : int , info : SetupPayloadInfo ) -> bool :
2371
+ dev_ctrl = self .default_controller
2372
+ conf = self .matter_test_config
2378
2373
2379
2374
if conf .tc_version_to_simulate is not None and conf .tc_user_response_to_simulate is not None :
2380
2375
logging .debug (
@@ -2384,7 +2379,7 @@ async def commission_device(instance: MatterBaseTest, i) -> bool:
2384
2379
if conf .commissioning_method == "on-network" :
2385
2380
try :
2386
2381
await dev_ctrl .CommissionOnNetwork (
2387
- nodeId = conf . dut_node_ids [ i ] ,
2382
+ nodeId = node_id ,
2388
2383
setupPinCode = info .passcode ,
2389
2384
filterType = info .filter_type ,
2390
2385
filter = info .filter_value
@@ -2398,7 +2393,7 @@ async def commission_device(instance: MatterBaseTest, i) -> bool:
2398
2393
await dev_ctrl .CommissionWiFi (
2399
2394
info .filter_value ,
2400
2395
info .passcode ,
2401
- conf . dut_node_ids [ i ] ,
2396
+ node_id ,
2402
2397
conf .wifi_ssid ,
2403
2398
conf .wifi_passphrase ,
2404
2399
isShortDiscriminator = (info .filter_type == DiscoveryFilterType .SHORT_DISCRIMINATOR )
@@ -2412,7 +2407,7 @@ async def commission_device(instance: MatterBaseTest, i) -> bool:
2412
2407
await dev_ctrl .CommissionThread (
2413
2408
info .filter_value ,
2414
2409
info .passcode ,
2415
- conf . dut_node_ids [ i ] ,
2410
+ node_id ,
2416
2411
conf .thread_operational_dataset ,
2417
2412
isShortDiscriminator = (info .filter_type == DiscoveryFilterType .SHORT_DISCRIMINATOR )
2418
2413
)
@@ -2425,7 +2420,8 @@ async def commission_device(instance: MatterBaseTest, i) -> bool:
2425
2420
logging .warning ("==== USING A DIRECT IP COMMISSIONING METHOD NOT SUPPORTED IN THE LONG TERM ====" )
2426
2421
await dev_ctrl .CommissionIP (
2427
2422
ipaddr = conf .commissionee_ip_address_just_for_testing ,
2428
- setupPinCode = info .passcode , nodeid = conf .dut_node_ids [i ]
2423
+ setupPinCode = info .passcode ,
2424
+ nodeid = node_id ,
2429
2425
)
2430
2426
return True
2431
2427
except ChipStackError as e :
@@ -2441,10 +2437,10 @@ def default_matter_test_main():
2441
2437
In this case, only one test class in a test script is allowed.
2442
2438
To make your test script executable, add the following to your file:
2443
2439
.. code-block:: python
2444
- from chip.testing.matter_testing.py import default_matter_test_main
2440
+ from chip.testing.matter_testing import default_matter_test_main
2445
2441
...
2446
2442
if __name__ == '__main__':
2447
- default_matter_test_main.main ()
2443
+ default_matter_test_main()
2448
2444
"""
2449
2445
2450
2446
matter_test_config = parse_matter_test_args ()
@@ -2473,7 +2469,15 @@ def get_test_info(test_class: MatterBaseTest, matter_test_config: MatterTestConf
2473
2469
return info
2474
2470
2475
2471
2476
- def run_tests_no_exit (test_class : MatterBaseTest , matter_test_config : MatterTestConfig , hooks : TestRunnerHooks , default_controller = None , external_stack = None ) -> bool :
2472
+ def run_tests_no_exit (test_class : MatterBaseTest , matter_test_config : MatterTestConfig ,
2473
+ event_loop : asyncio .AbstractEventLoop , hooks : TestRunnerHooks ,
2474
+ default_controller = None , external_stack = None ) -> bool :
2475
+
2476
+ # NOTE: It's not possible to pass event loop via Mobly TestRunConfig user params, because the
2477
+ # Mobly deep copies the user params before passing them to the test class and the event
2478
+ # loop is not serializable. So, we are setting the event loop as a test class member.
2479
+ CommissionDeviceTest .event_loop = event_loop
2480
+ test_class .event_loop = event_loop
2477
2481
2478
2482
get_test_info (test_class , matter_test_config )
2479
2483
@@ -2553,9 +2557,13 @@ def run_tests_no_exit(test_class: MatterBaseTest, matter_test_config: MatterTest
2553
2557
duration = (datetime .now (timezone .utc ) - runner_start_time ) / timedelta (microseconds = 1 )
2554
2558
hooks .stop (duration = duration )
2555
2559
2556
- # Shutdown the stack when all done
2557
2560
if not external_stack :
2558
- stack .Shutdown ()
2561
+ async def shutdown ():
2562
+ stack .Shutdown ()
2563
+ # Shutdown the stack when all done. Use the async runner to ensure that
2564
+ # during the shutdown callbacks can use tha same async context which was used
2565
+ # during the initialization.
2566
+ event_loop .run_until_complete (shutdown ())
2559
2567
2560
2568
if ok :
2561
2569
logging .info ("Final result: PASS !" )
@@ -2564,6 +2572,9 @@ def run_tests_no_exit(test_class: MatterBaseTest, matter_test_config: MatterTest
2564
2572
return ok
2565
2573
2566
2574
2567
- def run_tests (test_class : MatterBaseTest , matter_test_config : MatterTestConfig , hooks : TestRunnerHooks , default_controller = None , external_stack = None ) -> None :
2568
- if not run_tests_no_exit (test_class , matter_test_config , hooks , default_controller , external_stack ):
2569
- sys .exit (1 )
2575
+ def run_tests (test_class : MatterBaseTest , matter_test_config : MatterTestConfig ,
2576
+ hooks : TestRunnerHooks , default_controller = None , external_stack = None ) -> None :
2577
+ with asyncio .Runner () as runner :
2578
+ if not run_tests_no_exit (test_class , matter_test_config , runner .get_loop (),
2579
+ hooks , default_controller , external_stack ):
2580
+ sys .exit (1 )
0 commit comments