Skip to content

Commit fffe0b9

Browse files
gchwierMaureenHelm
authored andcommitted
twister: pytest: Parametrize scope of the dut fixture
Added pytest_dut_scope keyword under harness_config section. New keyword is used to determine the scope of dut and shell fixtures in pytest-twister-harness plugin. Signed-off-by: Grzegorz Chwierut <[email protected]>
1 parent e57e7f2 commit fffe0b9

File tree

7 files changed

+57
-7
lines changed

7 files changed

+57
-7
lines changed

doc/develop/test/pytest.rst

+7-2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ DUT (initialize logging, flash device, connect serial etc).
6969
This fixture yields a device prepared according to the requested type
7070
(native posix, qemu, hardware, etc.). All types of devices share the same API.
7171
This allows for writing tests which are device-type-agnostic.
72+
Scope of this fixture is determined by the ``pytest_dut_scope``
73+
keyword placed under ``harness_config`` section.
74+
7275

7376
.. code-block:: python
7477
@@ -81,8 +84,10 @@ shell
8184
-----
8285

8386
Provide an object with methods used to interact with shell application.
84-
It calls `wait_for_promt` method, to not start scenario until DUT is ready.
85-
Note that it uses `dut` fixture, so `dut` can be skipped when `shell` is used.
87+
It calls ``wait_for_promt`` method, to not start scenario until DUT is ready.
88+
Note that it uses ``dut`` fixture, so ``dut`` can be skipped when ``shell`` is used.
89+
Scope of this fixture is determined by the ``pytest_dut_scope``
90+
keyword placed under ``harness_config`` section.
8691

8792
.. code-block:: python
8893

doc/develop/test/twister.rst

+5
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,11 @@ harness_config: <harness configuration options>
514514
pytest_args: <list of arguments> (default empty)
515515
Specify a list of additional arguments to pass to ``pytest``.
516516

517+
pytest_dut_scope: <function|class|module|package|session> (default function)
518+
The scope for which ``dut`` and ``shell`` pytest fixtures are shared.
519+
If the scope is set to ``function``, DUT is launched for every test case
520+
in python script. For ``session`` scope, DUT is launched only once.
521+
517522
robot_test_path: <robot file path> (default empty)
518523
Specify a path to a file containing a Robot Framework test suite to be run.
519524

scripts/pylib/pytest-twister-harness/src/twister_harness/fixtures.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,24 @@ def device_object(twister_harness_config: TwisterHarnessConfig) -> Generator[Dev
3636
device_object.close()
3737

3838

39-
@pytest.fixture(scope='function')
39+
def determine_scope(fixture_name, config):
40+
if dut_scope := config.getoption("--dut-scope", None):
41+
return dut_scope
42+
return 'function'
43+
44+
45+
@pytest.fixture(scope=determine_scope)
4046
def dut(request: pytest.FixtureRequest, device_object: DeviceAdapter) -> Generator[DeviceAdapter, None, None]:
4147
"""Return launched device - with run application."""
42-
test_name = request.node.name
43-
device_object.initialize_log_files(test_name)
48+
device_object.initialize_log_files(request.node.name)
4449
try:
4550
device_object.launch()
4651
yield device_object
4752
finally: # to make sure we close all running processes execution
4853
device_object.close()
4954

5055

51-
@pytest.fixture(scope='function')
56+
@pytest.fixture(scope=determine_scope)
5257
def shell(dut: DeviceAdapter) -> Shell:
5358
"""Return ready to use shell interface"""
5459
shell = Shell(dut, timeout=20.0)

scripts/pylib/pytest-twister-harness/src/twister_harness/plugin.py

+5
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ def pytest_addoption(parser: pytest.Parser):
100100
metavar='PATH',
101101
help='Script executed after closing serial connection.'
102102
)
103+
twister_harness_group.addoption(
104+
'--dut-scope',
105+
choices=('function', 'class', 'module', 'package', 'session'),
106+
help='The scope for which `dut` and `shell` fixtures are shared.'
107+
)
103108

104109

105110
def pytest_configure(config: pytest.Config):

scripts/pylib/twister/twisterlib/harness.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ def generate_command(self):
268268
config = self.instance.testsuite.harness_config
269269
pytest_root = config.get('pytest_root', ['pytest']) if config else ['pytest']
270270
pytest_args = config.get('pytest_args', []) if config else []
271+
pytest_dut_scope = config.get('pytest_dut_scope', None) if config else None
271272
command = [
272273
'pytest',
273274
'--twister-harness',
@@ -281,6 +282,8 @@ def generate_command(self):
281282
command.extend([os.path.normpath(os.path.join(
282283
self.source_dir, os.path.expanduser(os.path.expandvars(src)))) for src in pytest_root])
283284
command.extend(pytest_args)
285+
if pytest_dut_scope:
286+
command.append(f'--dut-scope={pytest_dut_scope}')
284287

285288
handler: Handler = self.instance.handler
286289

@@ -427,7 +430,7 @@ def _parse_report_file(self, report):
427430
self.instance.execution_time = float(elem_ts.get('time'))
428431

429432
for elem_tc in elem_ts.findall('testcase'):
430-
tc = self.instance.get_case_or_create(f"{self.id}.{elem_tc.get('name')}")
433+
tc = self.instance.add_testcase(f"{self.id}.{elem_tc.get('name')}")
431434
tc.duration = float(elem_tc.get('time'))
432435
elem = elem_tc.find('*')
433436
if elem is None:

scripts/schemas/twister/testsuite-schema.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ mapping:
104104
required: false
105105
sequence:
106106
- type: str
107+
"pytest_dut_scope":
108+
type: str
109+
enum: ["function", "class", "module", "package", "session"]
110+
required: false
107111
"regex":
108112
type: seq
109113
required: false
@@ -304,6 +308,10 @@ mapping:
304308
required: false
305309
sequence:
306310
- type: str
311+
"pytest_dut_scope":
312+
type: str
313+
enum: ["function", "class", "module", "package", "session"]
314+
required: false
307315
"regex":
308316
type: seq
309317
required: false

scripts/tests/twister/pytest_integration/test_harness_pytest.py

+19
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ def test_pytest_command(testinstance: TestInstance, device_type):
4848
assert c in command
4949

5050

51+
def test_pytest_command_dut_scope(testinstance: TestInstance):
52+
pytest_harness = Pytest()
53+
dut_scope = 'session'
54+
testinstance.testsuite.harness_config['pytest_dut_scope'] = dut_scope
55+
pytest_harness.configure(testinstance)
56+
command = pytest_harness.generate_command()
57+
assert f'--dut-scope={dut_scope}' in command
58+
59+
60+
def test_pytest_command_extra_args(testinstance: TestInstance):
61+
pytest_harness = Pytest()
62+
pytest_args = ['-k test1', '-m mark1']
63+
testinstance.testsuite.harness_config['pytest_args'] = pytest_args
64+
pytest_harness.configure(testinstance)
65+
command = pytest_harness.generate_command()
66+
for c in pytest_args:
67+
assert c in command
68+
69+
5170
@pytest.mark.parametrize(
5271
('pytest_root', 'expected'),
5372
[

0 commit comments

Comments
 (0)