diff --git a/scripts/pylib/twister/twisterlib/harness.py b/scripts/pylib/twister/twisterlib/harness.py index 96b4a2e3461..6ae2622c810 100644 --- a/scripts/pylib/twister/twisterlib/harness.py +++ b/scripts/pylib/twister/twisterlib/harness.py @@ -245,19 +245,20 @@ class Pytest(Harness): def generate_command(self): config = self.instance.testsuite.harness_config - pytest_root = config.get('pytest_root', 'pytest') if config else 'pytest' + pytest_root = config.get('pytest_root', ['pytest']) if config else ['pytest'] pytest_args = config.get('pytest_args', []) if config else [] command = [ 'pytest', '--twister-harness', '-s', '-v', - os.path.join(self.source_dir, pytest_root), f'--build-dir={self.running_dir}', f'--junit-xml={self.report_file}', '--log-file-level=DEBUG', '--log-file-format=%(asctime)s.%(msecs)d:%(levelname)s:%(name)s: %(message)s', f'--log-file={self.pytest_log_file_path}' ] + command.extend([os.path.normpath(os.path.join( + self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root]) command.extend(pytest_args) handler: Handler = self.instance.handler diff --git a/scripts/schemas/twister/testsuite-schema.yaml b/scripts/schemas/twister/testsuite-schema.yaml index 116c1a43379..96a121767a5 100644 --- a/scripts/schemas/twister/testsuite-schema.yaml +++ b/scripts/schemas/twister/testsuite-schema.yaml @@ -95,8 +95,10 @@ mapping: type: int required: false "pytest_root": - type: str + type: seq required: false + sequence: + - type: str "pytest_args": type: seq required: false @@ -293,8 +295,10 @@ mapping: type: int required: false "pytest_root": - type: str + type: seq required: false + sequence: + - type: str "pytest_args": type: seq required: false diff --git a/scripts/tests/twister/pytest_integration/test_harness_pytest.py b/scripts/tests/twister/pytest_integration/test_harness_pytest.py index db7bf389fbd..e1b27a0cf02 100644 --- a/scripts/tests/twister/pytest_integration/test_harness_pytest.py +++ b/scripts/tests/twister/pytest_integration/test_harness_pytest.py @@ -48,6 +48,67 @@ def test_pytest_command(testinstance: TestInstance, device_type): assert c in command +@pytest.mark.parametrize( + ('pytest_root', 'expected'), + [ + ( + ['pytest/test_shell_help.py'], + ['samples/hello/pytest/test_shell_help.py'] + ), + ( + ['pytest/test_shell_help.py', 'pytest/test_shell_version.py', 'test_dir'], + ['samples/hello/pytest/test_shell_help.py', + 'samples/hello/pytest/test_shell_version.py', + 'samples/hello/test_dir'] + ), + ( + ['../shell/pytest/test_shell.py'], + ['samples/shell/pytest/test_shell.py'] + ), + ( + ['/tmp/test_temp.py'], + ['/tmp/test_temp.py'] + ), + ( + ['~/tmp/test_temp.py'], + ['/home/joe/tmp/test_temp.py'] + ), + ( + ['$ZEPHYR_BASE/samples/subsys/testsuite/pytest/shell/pytest'], + ['/zephyr_base/samples/subsys/testsuite/pytest/shell/pytest'] + ), + ( + ['pytest/test_shell_help.py::test_A', 'pytest/test_shell_help.py::test_B'], + ['samples/hello/pytest/test_shell_help.py::test_A', + 'samples/hello/pytest/test_shell_help.py::test_B'] + ), + ( + ['pytest/test_shell_help.py::test_A[param_a]'], + ['samples/hello/pytest/test_shell_help.py::test_A[param_a]'] + ) + ], + ids=[ + 'one_file', + 'more_files', + 'relative_path', + 'absollute_path', + 'user_dir', + 'with_env_var', + 'subtests', + 'subtest_with_param' + ] +) +def test_pytest_handle_source_list(testinstance: TestInstance, monkeypatch, pytest_root, expected): + monkeypatch.setenv('ZEPHYR_BASE', '/zephyr_base') + monkeypatch.setenv('HOME', '/home/joe') + testinstance.testsuite.harness_config['pytest_root'] = pytest_root + pytest_harness = Pytest() + pytest_harness.configure(testinstance) + command = pytest_harness.generate_command() + for pytest_src in expected: + assert pytest_src in command + + def test_if_report_is_parsed(pytester, testinstance: TestInstance): test_file_content = textwrap.dedent(""" def test_1():