Browse Source

twister: Add support for required snippets

Adds support for twister to require using snippets on tests

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
pull/62354/head
Jamie McCrae 2 years ago committed by Carles Cufí
parent
commit
bc97d8fb1e
  1. 1
      scripts/pylib/twister/twisterlib/config_parser.py
  2. 4
      scripts/pylib/twister/twisterlib/runner.py
  3. 42
      scripts/pylib/twister/twisterlib/testplan.py
  4. 10
      scripts/schemas/twister/testsuite-schema.yaml
  5. 16
      scripts/snippets.py
  6. 3
      scripts/twister
  7. 11
      scripts/west_commands/build.py

1
scripts/pylib/twister/twisterlib/config_parser.py

@ -48,6 +48,7 @@ class TwisterConfigParser: @@ -48,6 +48,7 @@ class TwisterConfigParser:
"extra_conf_files": {"type": "list", "default": []},
"extra_overlay_confs" : {"type": "list", "default": []},
"extra_dtc_overlay_files": {"type": "list", "default": []},
"required_snippets": {"type": "list"},
"build_only": {"type": "bool", "default": False},
"build_on_all": {"type": "bool", "default": False},
"skip": {"type": "bool", "default": False},

4
scripts/pylib/twister/twisterlib/runner.py

@ -359,6 +359,10 @@ class CMake: @@ -359,6 +359,10 @@ class CMake:
cmake_opts = ['-DBOARD={}'.format(self.platform.name)]
cmake_args.extend(cmake_opts)
if self.instance.testsuite.required_snippets:
cmake_opts = ['-DSNIPPET={}'.format(';'.join(self.instance.testsuite.required_snippets))]
cmake_args.extend(cmake_opts)
cmake = shutil.which('cmake')
cmd = [cmake] + cmake_args

42
scripts/pylib/twister/twisterlib/testplan.py

@ -16,6 +16,8 @@ import logging @@ -16,6 +16,8 @@ import logging
import copy
import shutil
import random
import snippets
from pathlib import Path
logger = logging.getLogger('twister')
logger.setLevel(logging.DEBUG)
@ -819,6 +821,46 @@ class TestPlan: @@ -819,6 +821,46 @@ class TestPlan:
if plat.only_tags and not set(plat.only_tags) & ts.tags:
instance.add_filter("Excluded tags per platform (only_tags)", Filters.PLATFORM)
if ts.required_snippets:
missing_snippet = False
snippet_args = {"snippets": ts.required_snippets}
found_snippets = snippets.find_snippets_in_roots(snippet_args, [Path(ZEPHYR_BASE), Path(ts.source_dir)])
# Search and check that all required snippet files are found
for this_snippet in snippet_args['snippets']:
if this_snippet not in found_snippets:
logger.error(f"Can't find snippet '%s' for test '%s'", this_snippet, ts.name)
instance.status = "error"
instance.reason = f"Snippet {this_snippet} not found"
missing_snippet = True
break
if not missing_snippet:
# Look for required snippets and check that they are applicable for these
# platforms/boards
for this_snippet in found_snippets:
matched_snippet_board = False
# If the "appends" key is present with at least one entry then this
# snippet applies to all boards and further platform-specific checks
# are not required
if found_snippets[this_snippet].appends:
continue
for this_board in found_snippets[this_snippet].board2appends:
if this_board.startswith('/'):
match = re.search(this_board[1:-1], plat.name)
if match is not None:
matched_snippet_board = True
break
elif this_board == plat.name:
matched_snippet_board = True
break
if matched_snippet_board is False:
instance.add_filter("Snippet not supported", Filters.PLATFORM)
break
# platform_key is a list of unique platform attributes that form a unique key a test
# will match against to determine if it should be scheduled to run. A key containing a
# field name that the platform does not have will filter the platform.

10
scripts/schemas/twister/testsuite-schema.yaml

@ -145,6 +145,11 @@ mapping: @@ -145,6 +145,11 @@ mapping:
matching: "all"
sequence:
- type: str
"required_snippets":
type: seq
required: false
sequence:
- type: str
"tags":
type: any
required: false
@ -243,6 +248,11 @@ mapping: @@ -243,6 +248,11 @@ mapping:
"extra_sections":
type: any
required: false
"required_snippets":
type: seq
required: false
sequence:
- type: str
"filter":
type: str
required: false

16
scripts/snippets.py

@ -238,6 +238,22 @@ def process_snippets(args: argparse.Namespace) -> Snippets: @@ -238,6 +238,22 @@ def process_snippets(args: argparse.Namespace) -> Snippets:
return snippets
def find_snippets_in_roots(requested_snippets, snippet_roots) -> Snippets:
'''Process snippet.yml files under each *snippet_root*
by recursive search. Return a Snippets object describing
the results of the search.
'''
# This will contain information about all the snippets
# we discover in each snippet_root element.
snippets = Snippets(requested=requested_snippets)
# Process each path in snippet_root in order, adjusting
# snippets as needed for each one.
for root in snippet_roots:
process_snippets_in(root, snippets)
return snippets
def process_snippets_in(root_dir: Path, snippets: Snippets) -> None:
'''Process snippet.yml files in *root_dir*,
updating *snippets* as needed.'''

3
scripts/twister

@ -44,6 +44,9 @@ pairs: @@ -44,6 +44,9 @@ pairs:
Extra configuration options to be merged with a master prj.conf
when building or running the test case.
required_snippets: <list of snippets>
Snippets that must be applied for the test case to run.
sysbuild: <True|False> (default False)
If true, build the sample using the sysbuild infrastructure. Filtering
will only be enabled for the main project, and is not supported for

11
scripts/west_commands/build.py

@ -293,6 +293,7 @@ class Build(Forceable): @@ -293,6 +293,7 @@ class Build(Forceable):
extra_dtc_overlay_files = []
extra_overlay_confs = []
extra_conf_files = []
required_snippets = []
for section in [common, item]:
if not section:
continue
@ -302,7 +303,8 @@ class Build(Forceable): @@ -302,7 +303,8 @@ class Build(Forceable):
'extra_configs',
'extra_conf_files',
'extra_overlay_confs',
'extra_dtc_overlay_files'
'extra_dtc_overlay_files',
'required_snippets'
]:
extra = section.get(data)
if not extra:
@ -325,6 +327,9 @@ class Build(Forceable): @@ -325,6 +327,9 @@ class Build(Forceable):
elif data == 'extra_dtc_overlay_files':
extra_dtc_overlay_files.extend(arg_list)
continue
elif data == 'required_snippets':
required_snippets.extend(arg_list)
continue
if self.args.cmake_opts:
self.args.cmake_opts.extend(args)
@ -343,6 +348,10 @@ class Build(Forceable): @@ -343,6 +348,10 @@ class Build(Forceable):
if extra_overlay_confs:
args.append(f"OVERLAY_CONFIG=\"{';'.join(extra_overlay_confs)}\"")
if required_snippets:
args.append(f"SNIPPET=\"{';'.join(required_snippets)}\"")
# Build the final argument list
args_expanded = ["-D{}".format(a.replace('"', '')) for a in args]

Loading…
Cancel
Save