Skip to content

Commit fd72eae

Browse files
vatsalghelani-csaandy31415restyled-commits
authored
Added scripts to get metadata (runner arguments) associated with the python_testing scripts for automating the process (project-chip#32752)
* Create unit test to test metadata parser * Create test script metadata parser * Create test environment file * Added Copyright Code * Added Copyright code * Added copyright code * Added run arguments comment header * Created BUILD.gn for metadata parser * Added reference to the metadata parser BUILD.gn * Added TC_RR_1_1_Test.py for testing purpose * Reverted back the testing changes done to the original file * Updated TC_RR_1_1_Test.py with comments as it was * Update test_metadata.py to correct the location for TC_RR* test script * Updated BUILD.gn with the correct naming tests * Rename env.yaml to test_env.yaml as it is for testing only * Updated test_metadata.py with the corrected test env file * Updated and rename TC_RR_1_1_Test.py to simple_run_args.py Just keeping the runner arguments required for testing purpose and removing all the unwanted test script code for this current testing use case * Updated test_metadata.py to the new name reference of the testing file * Renamed test method to test_run_metadata_parser * Removed the unwanted print method * Removed handling for int/bool/hex args and trace args * Remove try-catch block * Replaced == to is for null comparsion * Removed argument validation method * Added the dataclass to be optional * Updated the test script to be a .txt file and changed the designed to be all run arguments in one line * Rename simple_run_args.py to simple_run_args.txt * Updated BUILD.gn * Rename scripts/tests/py/test_env.yaml to env_example.yaml * Rename env_example.yaml to scripts/tests/py/env_example.yaml * Updated path of the environment file * Change the test script file type * Updated metadata_parser reference * Rename env_example.yaml to env_test.yaml * Update environment file name * Created __init__.py file * Added reference for __init__.py in the source * Created pyproject.toml file * Created setup.py file * Created setup.cfg file * Changed the path of the folder where the scripts are located * Added print statement * Updated print statement * Added inputs to the BUILD.gn file * Updated paths for file references * Added test script path to the inputs * Added sources for the file not find error fix * Updated metadata.py changes as suggested in the PR comments review * Updated test script * Updated license comment * Removed from pathlib import Path * Added Print Statement * Removed the print debug line * Updated it to use relative path instead of absolute path * Changed copyright year and removed unwanted sources * Updated copyright year to be 2024 * Updated copyright year to be 2024 * Updated copyright year to be 2024 * Updated copyright year to be 2024 * Updated copyright year to be 2024 * Updated copyright year to be 2024 * Update comment Co-authored-by: Andrei Litvin <andy314@gmail.com> * Updated the class name to MetadataReader * Updated class name to MetadataReader * Removed optional on factoryreset * Renamed env_yaml_file_path and solved inline inside constructor * Update metadata.py * Update metadata.py * Delete scripts/tests/py/simple_run_args.txt * Update BUILD.gn * Updated test_metadata.py * Updated metadata.py * Create simple_run_args.txt * Update BUILD.gn * Delete scripts/tests/py/simple_run_args.txt * Update BUILD.gn * Updated test_metadata.py * Restyled by whitespace * Restyled by gn * Restyled by prettier-yaml * Restyled by autopep8 * Restyled by isort * Fixed the spell error * Fixed comments from the PR * Removed extra print line * Restyled by autopep8 * Test via comment space * Test via removed comment space * Test via comment space * Restyled by autopep8 * Fixed mypy erros and test script line readability fixes * Restyled by autopep8 * Removed unawanted variables * Removing unused Union * Restyled by autopep8 --------- Co-authored-by: Andrei Litvin <andy314@gmail.com> Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 03d2fa8 commit fd72eae

9 files changed

+393
-0
lines changed

BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
233233
"//scripts/build:build_examples.tests",
234234
"//scripts/py_matter_idl:matter_idl.tests",
235235
"//scripts/py_matter_yamltests:matter_yamltests.tests",
236+
"//scripts/tests/py:metadata_parser.tests",
236237
"//src:tests_run",
237238
]
238239

scripts/tests/py/BUILD.gn

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import("//build_overrides/build.gni")
16+
import("//build_overrides/chip.gni")
17+
18+
import("//build_overrides/pigweed.gni")
19+
import("$dir_pw_build/python.gni")
20+
21+
pw_python_package("metadata_parser") {
22+
setup = [
23+
"setup.py",
24+
"setup.cfg",
25+
"pyproject.toml",
26+
]
27+
28+
inputs = [ "env_test.yaml" ]
29+
30+
sources = [
31+
"__init__.py",
32+
"metadata.py",
33+
]
34+
35+
tests = [ "test_metadata.py" ]
36+
}

scripts/tests/py/__init__.py

Whitespace-only changes.

scripts/tests/py/env_test.yaml

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# test environment argument definitions for metadata parser
16+
discriminator: 1234
17+
KVS: kvs1
18+
trace-to-appjson: json:out/trace_data/app-{SCRIPT_BASE_NAME}.json
19+
enable-key: 000102030405060708090a0b0c0d0e0f
20+
21+
storage-path: admin_storage.json
22+
commissioning-method: on-network
23+
passcode: 20202021
24+
endpoint: 1
25+
trace-to-testjson: json:out/trace_data/test-{SCRIPT_BASE_NAME}.json
26+
trace-to-testperfetto: perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto
27+
manual-code: 10054912339
28+
PICS: src/app/tests/suites/certification/ci-pics-values
29+
30+
app:
31+
all-clusters: out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app
32+
lock: out/linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-lock-app

scripts/tests/py/metadata.py

+217
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#!/usr/bin/python3
2+
# Copyright (c) 2024 Project CHIP Authors
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import re
17+
from dataclasses import dataclass
18+
from typing import Dict, List, Optional
19+
20+
import yaml
21+
22+
23+
@dataclass
24+
class Metadata:
25+
py_script_path: Optional[str] = None
26+
run: Optional[str] = None
27+
app: Optional[str] = None
28+
discriminator: Optional[str] = None
29+
passcode: Optional[str] = None
30+
31+
def copy_from_dict(self, attr_dict: Dict[str, str]) -> None:
32+
"""
33+
Sets the value of the attributes from a dictionary.
34+
35+
Attributes:
36+
37+
attr_dict:
38+
Dictionary that stores attributes value that should
39+
be transferred to this class.
40+
"""
41+
42+
if "app" in attr_dict:
43+
self.app = attr_dict["app"]
44+
45+
if "run" in attr_dict:
46+
self.run = attr_dict["run"]
47+
48+
if "discriminator" in attr_dict:
49+
self.discriminator = attr_dict["discriminator"]
50+
51+
if "passcode" in attr_dict:
52+
self.passcode = attr_dict["passcode"]
53+
54+
if "py_script_path" in attr_dict:
55+
self.py_script_path = attr_dict["py_script_path"]
56+
57+
# TODO - set other attributes as well
58+
59+
60+
class MetadataReader:
61+
"""
62+
A class to parse run arguments from the test scripts and
63+
resolve them to environment specific values.
64+
"""
65+
66+
def __init__(self, env_yaml_file_path: str):
67+
"""
68+
Reads the YAML file and Constructs the environment object
69+
70+
Parameters:
71+
72+
env_yaml_file_path:
73+
Path to the environment file that contains the YAML configuration.
74+
"""
75+
with open(env_yaml_file_path) as stream:
76+
self.env = yaml.safe_load(stream)
77+
78+
def __resolve_env_vals__(self, metadata_dict: Dict[str, str]) -> None:
79+
"""
80+
Resolves the argument defined in the test script to environment values.
81+
For example, if a test script defines "all_clusters" as the value for app
82+
name, we will check the environment configuration to see what raw value is
83+
assocaited with the "all_cluster" variable and set the value for "app" option
84+
to this raw value.
85+
86+
Parameter:
87+
88+
metadata_dict:
89+
Dictionary where each key represent a particular argument and its value represent
90+
the value for that argument defined in the test script.
91+
"""
92+
93+
for run_arg, run_arg_val in metadata_dict.items():
94+
95+
if not type(run_arg_val) == str or run_arg == "run":
96+
metadata_dict[run_arg] = run_arg_val
97+
continue
98+
99+
if run_arg_val is None:
100+
continue
101+
102+
sub_args = run_arg_val.split('/')
103+
104+
if len(sub_args) not in [1, 2]:
105+
err = """The argument is not in the correct format.
106+
The argument must follow the format of arg1 or arg1/arg2.
107+
For example, arg1 represents the argument type and optionally arg2
108+
represents a specific variable defined in the environment file whose
109+
value should be used as the argument value. If arg2 is not specified,
110+
we will just use the first value associated with arg1 in the environment file."""
111+
raise Exception(err)
112+
113+
if len(sub_args) == 1:
114+
run_arg_val = self.env.get(sub_args[0])
115+
116+
elif len(sub_args) == 2:
117+
run_arg_val = self.env.get(sub_args[0]).get(sub_args[1])
118+
119+
# if a argument has been specified in the comment header
120+
# but can't be found in the env file, consider it to be
121+
# boolean value.
122+
if run_arg_val is None:
123+
run_arg_val = True
124+
125+
metadata_dict[run_arg] = run_arg_val
126+
127+
def __read_args__(self, run_args_lines: List[str]) -> Dict[str, str]:
128+
"""
129+
Parses a list of lines and extracts argument
130+
values from it.
131+
132+
Parameters:
133+
134+
run_args_lines:
135+
Line in test script header that contains run argument definition.
136+
Each line will contain a list of run arguments separated by a space.
137+
Line below is one example of what the run argument line will look like:
138+
"app/all-clusters discriminator KVS storage-path"
139+
140+
In this case the line defines that app, discriminator, KVS, and storage-path
141+
are the arguments that should be used with this run.
142+
143+
An argument can be defined multiple times in the same line or in different lines.
144+
The last definition will override any previous definition. For example,
145+
"KVS/kvs1 KVS/kvs2 KVS/kvs3" line will lead to KVS value of kvs3.
146+
"""
147+
metadata_dict = {}
148+
149+
for run_line in run_args_lines:
150+
for run_arg_word in run_line.strip().split():
151+
'''
152+
We expect the run arg to be defined in one of the
153+
following two formats:
154+
1. run_arg
155+
2. run_arg/run_arg_val
156+
157+
Examples: "discriminator" and "app/all_clusters"
158+
159+
'''
160+
run_arg = run_arg_word.split('/', 1)[0]
161+
metadata_dict[run_arg] = run_arg_word
162+
163+
return metadata_dict
164+
165+
def parse_script(self, py_script_path: str) -> List[Metadata]:
166+
"""
167+
Parses a script and returns a list of metadata object where
168+
each element of that list representing run arguments associated
169+
with a particular run.
170+
171+
Parameter:
172+
173+
py_script_path:
174+
path to the python test script
175+
176+
Return:
177+
178+
List[Metadata]
179+
List of Metadata object where each Metadata element represents
180+
the run arguments associated with a particular run defined in
181+
the script file.
182+
"""
183+
184+
runs_def_ptrn = re.compile(r'^\s*#\s*test-runner-runs:\s*(.*)$')
185+
args_def_ptrn = re.compile(r'^\s*#\s*test-runner-run/([a-zA-Z0-9_]+):\s*(.*)$')
186+
187+
runs_arg_lines: Dict[str, List[str]] = {}
188+
runs_metadata = []
189+
190+
with open(py_script_path, 'r', encoding='utf8') as py_script:
191+
for line in py_script.readlines():
192+
193+
runs_match = runs_def_ptrn.match(line.strip())
194+
args_match = args_def_ptrn.match(line.strip())
195+
196+
if runs_match:
197+
for run in runs_match.group(1).strip().split():
198+
runs_arg_lines[run] = []
199+
200+
elif args_match:
201+
runs_arg_lines[args_match.group(1)].append(args_match.group(2))
202+
203+
for run, lines in runs_arg_lines.items():
204+
metadata_dict = self.__read_args__(lines)
205+
self.__resolve_env_vals__(metadata_dict)
206+
207+
# store the run value and script location in the
208+
# metadata object
209+
metadata_dict['py_script_path'] = py_script_path
210+
metadata_dict['run'] = run
211+
212+
metadata = Metadata()
213+
214+
metadata.copy_from_dict(metadata_dict)
215+
runs_metadata.append(metadata)
216+
217+
return runs_metadata

scripts/tests/py/pyproject.toml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
[build-system]
16+
requires = ['setuptools', 'wheel']
17+
build-backend = 'setuptools.build_meta'

scripts/tests/py/setup.cfg

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
[metadata]
16+
name = metadata_parser
17+
version = 0.0.1
18+
author = Project CHIP Authors
19+
description = Scripts to get metadata (runner arguments) associated with the python_testing scripts

scripts/tests/py/setup.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
"""The metadata_parser package."""
17+
18+
import setuptools # type: ignore
19+
20+
setuptools.setup() # Package definition in setup.cfg

0 commit comments

Comments
 (0)