Skip to content

Commit 669c200

Browse files
authored
Rename metadata_parser module to chip.testing (#35615)
* Rename metadata_parser module to chip.testing * MCORE_FS_1_4: Use Subprocess from chip.testing * MCORE_FS_1_3: Use Subprocess from chip.testing * Cleanup unused arguments * Restyled by isort * Fix test case to work on CI
1 parent 2106492 commit 669c200

File tree

14 files changed

+228
-171
lines changed

14 files changed

+228
-171
lines changed

BUILD.gn

+3-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
8181
"//examples/common/pigweed/rpc_console/py:chip_rpc",
8282
"//integrations/mobly:chip_mobly",
8383
"//scripts/py_matter_yamltests:matter_yamltests",
84-
"//src/python_testing/matter_testing_infrastructure:metadata_parser",
84+
"//src/python_testing/matter_testing_infrastructure:chip-testing",
8585
]
8686

8787
pw_python_venv("matter_build_venv") {
@@ -122,7 +122,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
122122
deps = [
123123
"${chip_root}/scripts:matter_yamltests_distribution.wheel",
124124
"${chip_root}/src/controller/python:chip-repl",
125-
"${chip_root}/src/python_testing/matter_testing_infrastructure:metadata_parser.wheel",
125+
"${chip_root}/src/python_testing/matter_testing_infrastructure:chip-testing.wheel",
126126
]
127127
}
128128
}
@@ -249,7 +249,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
249249
"//scripts/py_matter_idl:matter_idl.tests",
250250
"//scripts/py_matter_yamltests:matter_yamltests.tests",
251251
"//src:tests_run",
252-
"//src/python_testing/matter_testing_infrastructure:metadata_parser.tests",
252+
"//src/python_testing/matter_testing_infrastructure:chip-testing.tests",
253253
]
254254

255255
if (current_os == "linux" || current_os == "mac") {

examples/fabric-admin/scripts/fabric-sync-app.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,11 @@ async def forward_stdin(f_out: asyncio.StreamWriter):
7979

8080
class Subprocess:
8181

82-
def __init__(self, tag: str, program: str, *args, stdout_cb=None):
82+
def __init__(self, tag: str, program: str, *args):
8383
self.event = asyncio.Event()
8484
self.tag = tag.encode()
8585
self.program = program
8686
self.args = args
87-
self.stdout_cb = stdout_cb
8887
self.expected_output = None
8988

9089
def _check_output(self, line: bytes):
@@ -122,8 +121,7 @@ def terminate(self):
122121
self.p.terminate()
123122

124123

125-
async def run_admin(program, stdout_cb=None, storage_dir=None,
126-
rpc_admin_port=None, rpc_bridge_port=None,
124+
async def run_admin(program, storage_dir=None, rpc_admin_port=None, rpc_bridge_port=None,
127125
paa_trust_store_path=None, commissioner_name=None,
128126
commissioner_node_id=None, commissioner_vendor_id=None):
129127
args = []
@@ -141,8 +139,7 @@ async def run_admin(program, stdout_cb=None, storage_dir=None,
141139
args.extend(["--commissioner-nodeid", str(commissioner_node_id)])
142140
if commissioner_vendor_id is not None:
143141
args.extend(["--commissioner-vendor-id", str(commissioner_vendor_id)])
144-
p = Subprocess("[FS-ADMIN]", program, "interactive", "start", *args,
145-
stdout_cb=stdout_cb)
142+
p = Subprocess("[FS-ADMIN]", program, "interactive", "start", *args)
146143
await p.run()
147144
return p
148145

scripts/build_python.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ ninja -C "$OUTPUT_ROOT" python_wheels
198198
WHEEL=("$OUTPUT_ROOT"/controller/python/chip*.whl)
199199

200200
# Add the matter_testing_infrastructure wheel
201-
WHEEL+=("$OUTPUT_ROOT"/python/obj/src/python_testing/matter_testing_infrastructure/metadata_parser._build_wheel/metadata_parser-*.whl)
201+
WHEEL+=("$OUTPUT_ROOT"/python/obj/src/python_testing/matter_testing_infrastructure/chip-testing._build_wheel/chip_testing-*.whl)
202202

203203
if [ -n "$extra_packages" ]; then
204204
WHEEL+=("$extra_packages")

scripts/tests/run_python_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131

3232
import click
3333
import coloredlogs
34+
from chip.testing.metadata import Metadata, MetadataReader
3435
from colorama import Fore, Style
35-
from metadata_parser.metadata import Metadata, MetadataReader
3636

3737
DEFAULT_CHIP_ROOT = os.path.abspath(
3838
os.path.join(os.path.dirname(__file__), '..', '..'))

src/python_testing/TC_MCORE_FS_1_3.py

+13-46
Original file line numberDiff line numberDiff line change
@@ -36,67 +36,33 @@
3636
import logging
3737
import os
3838
import random
39-
import subprocess
40-
import sys
4139
import tempfile
42-
import threading
4340

4441
import chip.clusters as Clusters
4542
from chip import ChipDeviceCtrl
4643
from chip.interaction_model import Status
44+
from chip.testing.tasks import Subprocess
4745
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches
4846
from mobly import asserts
4947

5048

51-
# TODO: Make this class more generic. Issue #35348
52-
class Subprocess(threading.Thread):
53-
54-
def __init__(self, args: list = [], tag="", **kw):
55-
super().__init__(**kw)
56-
self.tag = f"[{tag}] " if tag else ""
57-
self.args = args
58-
59-
def forward_f(self, f_in, f_out):
60-
while True:
61-
line = f_in.readline()
62-
if not line:
63-
break
64-
f_out.write(f"{self.tag}{line}")
65-
f_out.flush()
66-
67-
def run(self):
68-
logging.info("RUN: %s", " ".join(self.args))
69-
self.p = subprocess.Popen(self.args, errors="ignore", stdin=subprocess.PIPE,
70-
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
71-
# Forward stdout and stderr with a tag attached.
72-
t1 = threading.Thread(target=self.forward_f, args=[self.p.stdout, sys.stdout])
73-
t1.start()
74-
t2 = threading.Thread(target=self.forward_f, args=[self.p.stderr, sys.stderr])
75-
t2.start()
76-
# Wait for the process to finish.
77-
self.p.wait()
78-
t1.join()
79-
t2.join()
80-
81-
def stop(self):
82-
self.p.terminate()
83-
self.join()
84-
85-
8649
class AppServer:
8750

8851
def __init__(self, app, storage_dir, port=None, discriminator=None, passcode=None):
89-
90-
args = [app]
91-
args.extend(["--KVS", tempfile.mkstemp(dir=storage_dir, prefix="kvs-app-")[1]])
52+
args = [
53+
"--KVS", tempfile.mkstemp(dir=storage_dir, prefix="kvs-app-")[1],
54+
]
9255
args.extend(['--secured-device-port', str(port)])
9356
args.extend(["--discriminator", str(discriminator)])
9457
args.extend(["--passcode", str(passcode)])
95-
self.app = Subprocess(args, tag="SERVER")
96-
self.app.start()
58+
self.app = Subprocess(app, *args, prefix="[SERVER]")
59+
60+
def start(self):
61+
# Start process and block until it prints the expected output.
62+
self.app.start(expected_output="Server initialization complete")
9763

98-
def stop(self):
99-
self.app.stop()
64+
def terminate(self):
65+
self.app.terminate()
10066

10167

10268
class TC_MCORE_FS_1_3(MatterBaseTest):
@@ -134,10 +100,11 @@ def setup_class(self):
134100
port=self.th_server_port,
135101
discriminator=self.th_server_discriminator,
136102
passcode=self.th_server_passcode)
103+
self.th_server.start()
137104

138105
def teardown_class(self):
139106
if self.th_server is not None:
140-
self.th_server.stop()
107+
self.th_server.terminate()
141108
if self.storage is not None:
142109
self.storage.cleanup()
143110
super().teardown_class()

src/python_testing/TC_MCORE_FS_1_4.py

+34-103
Original file line numberDiff line numberDiff line change
@@ -36,86 +36,32 @@
3636
import logging
3737
import os
3838
import random
39-
import subprocess
40-
import sys
4139
import tempfile
42-
import threading
4340

4441
import chip.clusters as Clusters
4542
from chip import ChipDeviceCtrl
4643
from chip.interaction_model import Status
44+
from chip.testing.tasks import Subprocess
4745
from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main, type_matches
4846
from mobly import asserts
4947

50-
# TODO: Make this class more generic. Issue #35348
51-
52-
53-
class Subprocess(threading.Thread):
54-
55-
def __init__(self, args: list = [], stdout_cb=None, tag="", **kw):
56-
super().__init__(**kw)
57-
self.tag = f"[{tag}] " if tag else ""
58-
self.stdout_cb = stdout_cb
59-
self.args = args
60-
61-
def forward_f(self, f_in, f_out):
62-
while True:
63-
line = f_in.readline()
64-
if not line:
65-
break
66-
f_out.write(f"{self.tag}{line}")
67-
f_out.flush()
68-
if self.stdout_cb is not None:
69-
self.stdout_cb(line)
70-
71-
def run(self):
72-
logging.info("RUN: %s", " ".join(self.args))
73-
self.p = subprocess.Popen(self.args, errors="ignore", stdin=subprocess.PIPE,
74-
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
75-
# Forward stdout and stderr with a tag attached.
76-
forwarding_stdout_thread = threading.Thread(target=self.forward_f, args=[self.p.stdout, sys.stdout])
77-
forwarding_stdout_thread.start()
78-
forwarding_stderr_thread = threading.Thread(target=self.forward_f, args=[self.p.stderr, sys.stderr])
79-
forwarding_stderr_thread.start()
80-
# Wait for the process to finish.
81-
self.p.wait()
82-
forwarding_stdout_thread.join()
83-
forwarding_stderr_thread.join()
84-
85-
def stop(self):
86-
self.p.terminate()
87-
self.join()
88-
8948

9049
class FabricSyncApp:
9150

92-
def _process_admin_output(self, line):
93-
if self.wait_for_text_text is not None and self.wait_for_text_text in line:
94-
self.wait_for_text_event.set()
95-
96-
def wait_for_text(self, timeout=30):
97-
if not self.wait_for_text_event.wait(timeout=timeout):
98-
raise Exception(f"Timeout waiting for text: {self.wait_for_text_text}")
99-
self.wait_for_text_event.clear()
100-
self.wait_for_text_text = None
101-
10251
def __init__(self, fabric_sync_app_path, fabric_admin_app_path, fabric_bridge_app_path,
10352
storage_dir, fabric_name=None, node_id=None, vendor_id=None,
10453
paa_trust_store_path=None, bridge_port=None, bridge_discriminator=None,
10554
bridge_passcode=None):
106-
107-
self.wait_for_text_event = threading.Event()
108-
self.wait_for_text_text = None
109-
110-
args = [fabric_sync_app_path]
111-
args.append(f"--app-admin={fabric_admin_app_path}")
112-
args.append(f"--app-bridge={fabric_bridge_app_path}")
113-
# Override default ports, so it will be possible to run
114-
# our TH_FSA alongside the DUT_FSA during CI testing.
115-
args.append("--app-admin-rpc-port=44000")
116-
args.append("--app-bridge-rpc-port=44001")
117-
# Keep the storage directory in a temporary location.
118-
args.append(f"--storage-dir={storage_dir}")
55+
args = [
56+
f"--app-admin={fabric_admin_app_path}",
57+
f"--app-bridge={fabric_bridge_app_path}",
58+
# Override default ports, so it will be possible to run
59+
# our TH_FSA alongside the DUT_FSA during CI testing.
60+
"--app-admin-rpc-port=44000",
61+
"--app-bridge-rpc-port=44001",
62+
# Keep the storage directory in a temporary location.
63+
f"--storage-dir={storage_dir}",
64+
]
11965
if paa_trust_store_path is not None:
12066
args.append(f"--paa-trust-store-path={paa_trust_store_path}")
12167
if fabric_name is not None:
@@ -127,55 +73,38 @@ def __init__(self, fabric_sync_app_path, fabric_admin_app_path, fabric_bridge_ap
12773
args.append(f"--discriminator={bridge_discriminator}")
12874
args.append(f"--passcode={bridge_passcode}")
12975

130-
self.fabric_sync_app = Subprocess(args, stdout_cb=self._process_admin_output)
131-
self.wait_for_text_text = "Successfully opened pairing window on the device"
132-
self.fabric_sync_app.start()
76+
self.fabric_sync_app = Subprocess(fabric_sync_app_path, *args)
13377

134-
# Wait for the fabric-sync-app to be ready.
135-
self.wait_for_text()
78+
def start(self):
79+
# Start process and block until it prints the expected output.
80+
self.fabric_sync_app.start(expected_output="Successfully opened pairing window on the device")
13681

137-
def commission_on_network(self, node_id, setup_pin_code=None, filter_type=None, filter=None):
138-
self.wait_for_text_text = f"Commissioning complete for node ID {node_id:#018x}: success"
139-
# Send the commissioning command to the admin.
140-
self.fabric_sync_app.p.stdin.write(f"pairing onnetwork {node_id} {setup_pin_code}\n")
141-
self.fabric_sync_app.p.stdin.flush()
142-
# Wait for success message.
143-
self.wait_for_text()
82+
def terminate(self):
83+
self.fabric_sync_app.terminate()
14484

145-
def stop(self):
146-
self.fabric_sync_app.stop()
85+
def commission_on_network(self, node_id, setup_pin_code=None, filter_type=None, filter=None):
86+
self.fabric_sync_app.send(
87+
f"pairing onnetwork {node_id} {setup_pin_code}",
88+
expected_output=f"Commissioning complete for node ID {node_id:#018x}: success")
14789

14890

14991
class AppServer:
15092

151-
def _process_admin_output(self, line):
152-
if self.wait_for_text_text is not None and self.wait_for_text_text in line:
153-
self.wait_for_text_event.set()
154-
155-
def wait_for_text(self, timeout=30):
156-
if not self.wait_for_text_event.wait(timeout=timeout):
157-
raise Exception(f"Timeout waiting for text: {self.wait_for_text_text}")
158-
self.wait_for_text_event.clear()
159-
self.wait_for_text_text = None
160-
16193
def __init__(self, app, storage_dir, port=None, discriminator=None, passcode=None):
162-
self.wait_for_text_event = threading.Event()
163-
self.wait_for_text_text = None
164-
165-
args = [app]
166-
args.extend(["--KVS", tempfile.mkstemp(dir=storage_dir, prefix="kvs-app-")[1]])
94+
args = [
95+
"--KVS", tempfile.mkstemp(dir=storage_dir, prefix="kvs-app-")[1],
96+
]
16797
args.extend(['--secured-device-port', str(port)])
16898
args.extend(["--discriminator", str(discriminator)])
16999
args.extend(["--passcode", str(passcode)])
170-
self.app = Subprocess(args, stdout_cb=self._process_admin_output, tag="SERVER")
171-
self.wait_for_text_text = "Server initialization complete"
172-
self.app.start()
100+
self.app = Subprocess(app, *args, prefix="[SERVER]")
173101

174-
# Wait for the server-app to be ready.
175-
self.wait_for_text()
102+
def start(self):
103+
# Start process and block until it prints the expected output.
104+
self.app.start(expected_output="Server initialization complete")
176105

177-
def stop(self):
178-
self.app.stop()
106+
def terminate(self):
107+
self.app.terminate()
179108

180109

181110
class TC_MCORE_FS_1_4(MatterBaseTest):
@@ -237,6 +166,7 @@ def setup_class(self):
237166
bridge_discriminator=self.th_fsa_bridge_discriminator,
238167
bridge_passcode=self.th_fsa_bridge_passcode,
239168
vendor_id=0xFFF1)
169+
self.th_fsa_controller.start()
240170

241171
# Get the named pipe path for the DUT_FSA app input from the user params.
242172
dut_fsa_stdin_pipe = self.user_params.get("dut_fsa_stdin_pipe", None)
@@ -254,12 +184,13 @@ def setup_class(self):
254184
port=self.th_server_port,
255185
discriminator=self.th_server_discriminator,
256186
passcode=self.th_server_passcode)
187+
self.th_server.start()
257188

258189
def teardown_class(self):
259190
if self.th_fsa_controller is not None:
260-
self.th_fsa_controller.stop()
191+
self.th_fsa_controller.terminate()
261192
if self.th_server is not None:
262-
self.th_server.stop()
193+
self.th_server.terminate()
263194
if self.storage is not None:
264195
self.storage.cleanup()
265196
super().teardown_class()

src/python_testing/matter_testing_infrastructure/BUILD.gn

+9-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import("//build_overrides/chip.gni")
1818
import("//build_overrides/pigweed.gni")
1919
import("$dir_pw_build/python.gni")
2020

21-
pw_python_package("metadata_parser") {
21+
# Python package for CHIP testing support.
22+
pw_python_package("chip-testing") {
2223
setup = [
2324
"setup.py",
2425
"setup.cfg",
@@ -28,9 +29,13 @@ pw_python_package("metadata_parser") {
2829
inputs = [ "env_test.yaml" ]
2930

3031
sources = [
31-
"metadata_parser/__init__.py",
32-
"metadata_parser/metadata.py",
32+
"chip/testing/__init__.py",
33+
"chip/testing/metadata.py",
34+
"chip/testing/tasks.py",
3335
]
3436

35-
tests = [ "metadata_parser/test_metadata.py" ]
37+
tests = [
38+
"chip/testing/test_metadata.py",
39+
"chip/testing/test_tasks.py",
40+
]
3641
}

0 commit comments

Comments
 (0)