diff --git a/.github/workflows/twister_tests_blackbox.yml b/.github/workflows/twister_tests_blackbox.yml index 8845c7eddd4..b19bce0c535 100644 --- a/.github/workflows/twister_tests_blackbox.yml +++ b/.github/workflows/twister_tests_blackbox.yml @@ -44,7 +44,8 @@ jobs: west init -l . || true # we do not depend on any hals, tools or bootloader, save some time and space... - west config manifest.group-filter -- -hal,-tools,-bootloader + west config manifest.group-filter -- -hal,-tools,-bootloader,-babblesim + west config manifest.project-filter -- -nrf_hw_models west config --global update.narrow true west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || west update --path-cache /github/cache/zephyrproject 2>&1 1> west.update.log || ( rm -rf ../modules ../bootloader ../tools && west update --path-cache /github/cache/zephyrproject) west forall -c 'git reset --hard HEAD' diff --git a/doc/develop/test/twister.rst b/doc/develop/test/twister.rst index a362c79861a..0cc391e5b89 100644 --- a/doc/develop/test/twister.rst +++ b/doc/develop/test/twister.rst @@ -1255,6 +1255,25 @@ using an external J-Link probe. The ``probe_id`` keyword overrides the runner: jlink serial: null +Using Single Board For Multiple Variants +++++++++++++++++++++++++++++++++++++++++ + + The ``platform`` attribute can be a list of names or a string + with names separated by spaces. This allows to run tests for + different platform variants on the same physical board, without + re-configuring the hardware map file for each variant. For example: + +.. code-block:: yaml + + - connected: true + id: '001234567890' + platform: + - nrf5340dk/nrf5340/cpuapp + - nrf5340dk/nrf5340/cpuapp/ns + product: J-Link + runner: nrfjprog + serial: /dev/ttyACM1 + Quarantine ++++++++++ diff --git a/scripts/pylib/twister/twisterlib/handlers.py b/scripts/pylib/twister/twisterlib/handlers.py index 0ebab95434b..14e45d2c811 100755 --- a/scripts/pylib/twister/twisterlib/handlers.py +++ b/scripts/pylib/twister/twisterlib/handlers.py @@ -21,6 +21,7 @@ import threading import time +from contextlib import contextmanager from pathlib import Path from queue import Queue, Empty from twisterlib.environment import ZEPHYR_BASE, strip_ansi_sequences @@ -458,6 +459,17 @@ def monitor_serial(self, ser, halt_event, harness): log_out_fp.close() + @staticmethod + @contextmanager + def acquire_dut_locks(duts): + try: + for d in duts: + d.lock.acquire() + yield + finally: + for d in duts: + d.lock.release() + def device_is_available(self, instance): device = instance.platform.name fixture = instance.testsuite.harness_config.get("fixture") @@ -475,15 +487,16 @@ def device_is_available(self, instance): # Select an available DUT with less failures for d in sorted(duts_found, key=lambda _dut: _dut.failures): - d.lock.acquire() - avail = False - if d.available: - d.available = 0 - d.counter_increment() - avail = True - logger.debug(f"Retain DUT:{d.platform}, Id:{d.id}, " - f"counter:{d.counter}, failures:{d.failures}") - d.lock.release() + duts_shared_hw = [_d for _d in self.duts if _d.id == d.id] # get all DUTs with the same id + with self.acquire_dut_locks(duts_shared_hw): + avail = False + if d.available: + for _d in duts_shared_hw: + _d.available = 0 + d.counter_increment() + avail = True + logger.debug(f"Retain DUT:{d.platform}, Id:{d.id}, " + f"counter:{d.counter}, failures:{d.failures}") if avail: return d @@ -494,7 +507,10 @@ def make_dut_available(self, dut): dut.failures_increment() logger.debug(f"Release DUT:{dut.platform}, Id:{dut.id}, " f"counter:{dut.counter}, failures:{dut.failures}") - dut.available = 1 + duts_shared_hw = [_d for _d in self.duts if _d.id == dut.id] # get all DUTs with the same id + with self.acquire_dut_locks(duts_shared_hw): + for _d in duts_shared_hw: + _d.available = 1 @staticmethod def run_custom_script(script, timeout): diff --git a/scripts/pylib/twister/twisterlib/hardwaremap.py b/scripts/pylib/twister/twisterlib/hardwaremap.py index 6ca6dbcdb7d..fad8ace910a 100644 --- a/scripts/pylib/twister/twisterlib/hardwaremap.py +++ b/scripts/pylib/twister/twisterlib/hardwaremap.py @@ -259,7 +259,13 @@ def load(self, map_file): flash_before = dut.get('flash_before') if flash_before is None: flash_before = self.options.flash_before and (not (flash_with_test or serial_pty)) - platform = dut.get('platform') + platform = dut.get('platform') + if isinstance(platform, str): + platforms = platform.split() + elif isinstance(platform, list): + platforms = platform + else: + raise ValueError(f"Invalid platform value: {platform}") id = dut.get('id') runner = dut.get('runner') runner_params = dut.get('runner_params') @@ -268,28 +274,29 @@ def load(self, map_file): baud = dut.get('baud', None) product = dut.get('product') fixtures = dut.get('fixtures', []) - connected= dut.get('connected') and ((serial or serial_pty) is not None) + connected = dut.get('connected') and ((serial or serial_pty) is not None) if not connected: continue - new_dut = DUT(platform=platform, - product=product, - runner=runner, - runner_params=runner_params, - id=id, - serial_pty=serial_pty, - serial=serial, - serial_baud=baud, - connected=connected, - pre_script=pre_script, - flash_before=flash_before, - post_script=post_script, - post_flash_script=post_flash_script, - script_param=script_param, - flash_timeout=flash_timeout, - flash_with_test=flash_with_test) - new_dut.fixtures = fixtures - new_dut.counter = 0 - self.duts.append(new_dut) + for plat in platforms: + new_dut = DUT(platform=plat, + product=product, + runner=runner, + runner_params=runner_params, + id=id, + serial_pty=serial_pty, + serial=serial, + serial_baud=baud, + connected=connected, + pre_script=pre_script, + flash_before=flash_before, + post_script=post_script, + post_flash_script=post_flash_script, + script_param=script_param, + flash_timeout=flash_timeout, + flash_with_test=flash_with_test) + new_dut.fixtures = fixtures + new_dut.counter = 0 + self.duts.append(new_dut) def scan(self, persistent=False): from serial.tools import list_ports diff --git a/scripts/schemas/twister/hwmap-schema.yaml b/scripts/schemas/twister/hwmap-schema.yaml index f45bd8f79c7..142d4a1969b 100644 --- a/scripts/schemas/twister/hwmap-schema.yaml +++ b/scripts/schemas/twister/hwmap-schema.yaml @@ -16,7 +16,7 @@ sequence: type: str required: false "platform": - type: str + type: any required: true "probe_id": type: str diff --git a/scripts/tests/twister/test_handlers.py b/scripts/tests/twister/test_handlers.py index 3475c65197e..8e539a04a46 100644 --- a/scripts/tests/twister/test_handlers.py +++ b/scripts/tests/twister/test_handlers.py @@ -1273,6 +1273,7 @@ def mock_serial(*args, **kwargs): dut = DUT() dut.available = 0 dut.failures = 0 + handler.duts = [dut] hardware_baud = 14400 flash_timeout = 60 diff --git a/scripts/tests/twister_blackbox/test_coverage.py b/scripts/tests/twister_blackbox/test_coverage.py index 0d5e035ecd2..56fe73845ce 100644 --- a/scripts/tests/twister_blackbox/test_coverage.py +++ b/scripts/tests/twister_blackbox/test_coverage.py @@ -46,7 +46,7 @@ class TestCoverage: 'coverage.log', 'coverage.json', 'coverage' ], - r'{"files": \[], "gcovr/format_version": ".*"}' + r'{"files": \[\], "gcovr/format_version": ".*"}' ), ] TESTDATA_4 = [ @@ -243,7 +243,7 @@ def test_coverage_basedir(self, capfd, test_path, test_platforms, out_path, file with open(path, "r") as json_file: json_content = json.load(json_file) pattern = re.compile(expected_content) - assert pattern.match(json.dumps(json_content)) + assert pattern.match(json.dumps(json_content, sort_keys=True)) if os.path.exists(base_dir): os.rmdir(base_dir)