pytest-embedded 2.0.0a0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/PKG-INFO +1 -1
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/__init__.py +1 -1
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/dut.py +2 -3
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/dut_factory.py +14 -10
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/log.py +18 -14
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/plugin.py +29 -4
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/tests/test_base.py +0 -1
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/LICENSE +0 -0
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/README.md +0 -0
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pyproject.toml +0 -0
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/app.py +0 -0
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/unity.py +0 -0
- {pytest_embedded-2.0.0a0 → pytest_embedded-2.1.0}/pytest_embedded/utils.py +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import logging
|
|
3
|
-
import multiprocessing
|
|
4
3
|
import os.path
|
|
5
4
|
import re
|
|
6
5
|
from collections.abc import Callable
|
|
@@ -10,7 +9,7 @@ from typing import AnyStr
|
|
|
10
9
|
import pexpect
|
|
11
10
|
|
|
12
11
|
from .app import App
|
|
13
|
-
from .log import PexpectProcess
|
|
12
|
+
from .log import MessageQueue, PexpectProcess
|
|
14
13
|
from .unity import UNITY_SUMMARY_LINE_REGEX, TestSuite
|
|
15
14
|
from .utils import Meta, _InjectMixinCls, remove_asci_color_code, to_bytes, to_list
|
|
16
15
|
|
|
@@ -29,7 +28,7 @@ class Dut(_InjectMixinCls):
|
|
|
29
28
|
def __init__(
|
|
30
29
|
self,
|
|
31
30
|
pexpect_proc: PexpectProcess,
|
|
32
|
-
msg_queue:
|
|
31
|
+
msg_queue: MessageQueue,
|
|
33
32
|
app: App,
|
|
34
33
|
pexpect_logfile: str,
|
|
35
34
|
test_case_name: str,
|
|
@@ -28,10 +28,7 @@ def _drop_none_kwargs(kwargs: dict[t.Any, t.Any]):
|
|
|
28
28
|
return {k: v for k, v in kwargs.items() if v is not None}
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
_ctx = multiprocessing.get_context('fork')
|
|
33
|
-
else:
|
|
34
|
-
_ctx = multiprocessing.get_context()
|
|
31
|
+
_ctx = multiprocessing.get_context('spawn')
|
|
35
32
|
|
|
36
33
|
_stdout = sys.__stdout__
|
|
37
34
|
|
|
@@ -45,10 +42,6 @@ DUT_GLOBAL_INDEX = 0
|
|
|
45
42
|
PARAMETRIZED_FIXTURES_CACHE = {}
|
|
46
43
|
|
|
47
44
|
|
|
48
|
-
def msg_queue_gn() -> MessageQueue:
|
|
49
|
-
return MessageQueue()
|
|
50
|
-
|
|
51
|
-
|
|
52
45
|
def _listen(q: MessageQueue, filepath: str, with_timestamp: bool = True, count: int = 1, total: int = 1) -> None:
|
|
53
46
|
shall_add_prefix = True
|
|
54
47
|
while True:
|
|
@@ -145,6 +138,7 @@ def _fixture_classes_and_options_fn(
|
|
|
145
138
|
qemu_prog_path,
|
|
146
139
|
qemu_cli_args,
|
|
147
140
|
qemu_extra_args,
|
|
141
|
+
qemu_efuse_path,
|
|
148
142
|
wokwi_diagram,
|
|
149
143
|
skip_regenerate_image,
|
|
150
144
|
encrypt,
|
|
@@ -179,6 +173,7 @@ def _fixture_classes_and_options_fn(
|
|
|
179
173
|
'encrypt': encrypt,
|
|
180
174
|
'keyfile': keyfile,
|
|
181
175
|
'qemu_prog_path': qemu_prog_path,
|
|
176
|
+
'qemu_efuse_path': qemu_efuse_path,
|
|
182
177
|
}
|
|
183
178
|
)
|
|
184
179
|
else:
|
|
@@ -310,6 +305,7 @@ def _fixture_classes_and_options_fn(
|
|
|
310
305
|
'qemu_prog_path': qemu_prog_path,
|
|
311
306
|
'qemu_cli_args': qemu_cli_args,
|
|
312
307
|
'qemu_extra_args': qemu_extra_args,
|
|
308
|
+
'qemu_efuse_path': qemu_efuse_path,
|
|
313
309
|
'app': None,
|
|
314
310
|
'meta': _meta,
|
|
315
311
|
'dut_index': dut_index,
|
|
@@ -681,6 +677,7 @@ class DutFactory:
|
|
|
681
677
|
qemu_prog_path: str | None = None,
|
|
682
678
|
qemu_cli_args: str | None = None,
|
|
683
679
|
qemu_extra_args: str | None = None,
|
|
680
|
+
qemu_efuse_path: str | None = None,
|
|
684
681
|
wokwi_diagram: str | None = None,
|
|
685
682
|
skip_regenerate_image: bool | None = None,
|
|
686
683
|
encrypt: bool | None = None,
|
|
@@ -727,6 +724,7 @@ class DutFactory:
|
|
|
727
724
|
qemu_prog_path: QEMU program path.
|
|
728
725
|
qemu_cli_args: QEMU CLI arguments.
|
|
729
726
|
qemu_extra_args: Additional QEMU arguments.
|
|
727
|
+
qemu_efuse_path: Efuse binary path.
|
|
730
728
|
wokwi_diagram: Wokwi diagram path.
|
|
731
729
|
skip_regenerate_image: Skip image regeneration flag.
|
|
732
730
|
encrypt: Encryption flag.
|
|
@@ -741,10 +739,15 @@ class DutFactory:
|
|
|
741
739
|
"""
|
|
742
740
|
layout = []
|
|
743
741
|
try:
|
|
744
|
-
|
|
745
|
-
|
|
742
|
+
from .plugin import _MP_MANAGER # avoid circular import
|
|
743
|
+
|
|
744
|
+
if _MP_MANAGER is None:
|
|
745
|
+
raise SystemExit('The _MP_MANAGER is not initialized, please use this function under pytest.')
|
|
746
|
+
|
|
747
|
+
msg_queue = _MP_MANAGER.MessageQueue()
|
|
746
748
|
layout.append(msg_queue)
|
|
747
749
|
|
|
750
|
+
global PARAMETRIZED_FIXTURES_CACHE
|
|
748
751
|
_pexpect_logfile = os.path.join(
|
|
749
752
|
PARAMETRIZED_FIXTURES_CACHE['_meta'].logdir, f'custom-dut-{DUT_GLOBAL_INDEX}.txt'
|
|
750
753
|
)
|
|
@@ -789,6 +792,7 @@ class DutFactory:
|
|
|
789
792
|
'qemu_prog_path': qemu_prog_path,
|
|
790
793
|
'qemu_cli_args': qemu_cli_args,
|
|
791
794
|
'qemu_extra_args': qemu_extra_args,
|
|
795
|
+
'qemu_efuse_path': qemu_efuse_path,
|
|
792
796
|
'wokwi_diagram': wokwi_diagram,
|
|
793
797
|
'skip_regenerate_image': skip_regenerate_image,
|
|
794
798
|
'encrypt': encrypt,
|
|
@@ -3,11 +3,11 @@ import logging
|
|
|
3
3
|
import multiprocessing
|
|
4
4
|
import os
|
|
5
5
|
import subprocess
|
|
6
|
-
import sys
|
|
7
6
|
import tempfile
|
|
8
7
|
import textwrap
|
|
9
8
|
import uuid
|
|
10
9
|
from multiprocessing import queues
|
|
10
|
+
from multiprocessing.managers import BaseManager
|
|
11
11
|
from typing import AnyStr
|
|
12
12
|
|
|
13
13
|
import pexpect.fdpexpect
|
|
@@ -16,10 +16,11 @@ from pexpect.utils import poll_ignore_interrupts, select_ignore_interrupts
|
|
|
16
16
|
|
|
17
17
|
from .utils import Meta, remove_asci_color_code, to_bytes, to_str, utcnow_str
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
_ctx = multiprocessing.get_context('spawn')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MessageQueueManager(BaseManager):
|
|
23
|
+
pass
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class MessageQueue(queues.Queue):
|
|
@@ -40,7 +41,7 @@ class MessageQueue(queues.Queue):
|
|
|
40
41
|
_b = to_bytes(obj)
|
|
41
42
|
try:
|
|
42
43
|
super().put(_b, **kwargs)
|
|
43
|
-
except: #
|
|
44
|
+
except Exception: # queue might be closed
|
|
44
45
|
pass
|
|
45
46
|
|
|
46
47
|
def write(self, s: AnyStr):
|
|
@@ -53,6 +54,9 @@ class MessageQueue(queues.Queue):
|
|
|
53
54
|
return True
|
|
54
55
|
|
|
55
56
|
|
|
57
|
+
MessageQueueManager.register('MessageQueue', MessageQueue)
|
|
58
|
+
|
|
59
|
+
|
|
56
60
|
class PexpectProcess(pexpect.fdpexpect.fdspawn):
|
|
57
61
|
"""
|
|
58
62
|
Use a temp file to gather multiple inputs into one output, and do `pexpect.expect()` from one place.
|
|
@@ -146,16 +150,16 @@ def live_print_call(*args, msg_queue: MessageQueue | None = None, expect_returnc
|
|
|
146
150
|
|
|
147
151
|
class _PopenRedirectProcess(_ctx.Process):
|
|
148
152
|
def __init__(self, msg_queue: MessageQueue, logfile: str):
|
|
149
|
-
self.
|
|
150
|
-
|
|
151
|
-
self.logfile = logfile
|
|
152
|
-
|
|
153
|
-
super().__init__(target=self._forward_io, daemon=True) # killed by the main process
|
|
153
|
+
super().__init__(target=self._forward_io, args=(msg_queue, logfile), daemon=True)
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
@staticmethod
|
|
156
|
+
def _forward_io(msg_queue, logfile) -> None:
|
|
157
|
+
with open(logfile) as fr:
|
|
157
158
|
while True:
|
|
158
|
-
|
|
159
|
+
try:
|
|
160
|
+
msg_queue.put(fr.read()) # msg_queue may be closed
|
|
161
|
+
except Exception:
|
|
162
|
+
break
|
|
159
163
|
|
|
160
164
|
|
|
161
165
|
class DuplicateStdoutPopen(subprocess.Popen):
|
|
@@ -36,7 +36,6 @@ from .dut_factory import (
|
|
|
36
36
|
app_fn,
|
|
37
37
|
dut_gn,
|
|
38
38
|
gdb_gn,
|
|
39
|
-
msg_queue_gn,
|
|
40
39
|
openocd_gn,
|
|
41
40
|
pexpect_proc_fn,
|
|
42
41
|
qemu_gn,
|
|
@@ -44,7 +43,7 @@ from .dut_factory import (
|
|
|
44
43
|
set_parametrized_fixtures_cache,
|
|
45
44
|
wokwi_gn,
|
|
46
45
|
)
|
|
47
|
-
from .log import MessageQueue, PexpectProcess
|
|
46
|
+
from .log import MessageQueue, MessageQueueManager, PexpectProcess
|
|
48
47
|
from .unity import JunitMerger, UnityTestReportMode, escape_illegal_xml_chars
|
|
49
48
|
from .utils import (
|
|
50
49
|
SERVICE_LIB_NAMES,
|
|
@@ -275,6 +274,10 @@ def pytest_addoption(parser):
|
|
|
275
274
|
'--qemu-extra-args',
|
|
276
275
|
help='QEMU cli extra arguments, will append to the argument list. (Default: None)',
|
|
277
276
|
)
|
|
277
|
+
qemu_group.addoption(
|
|
278
|
+
'--qemu-efuse-path',
|
|
279
|
+
help='This option makes it possible to use efuse in QEMU when it is set up.',
|
|
280
|
+
)
|
|
278
281
|
qemu_group.addoption(
|
|
279
282
|
'--skip-regenerate-image',
|
|
280
283
|
help='y/yes/true for True and n/no/false for False. '
|
|
@@ -300,6 +303,7 @@ def pytest_addoption(parser):
|
|
|
300
303
|
# helpers #
|
|
301
304
|
###########
|
|
302
305
|
_COUNT = 1
|
|
306
|
+
_MP_MANAGER: MessageQueueManager | None = None
|
|
303
307
|
|
|
304
308
|
|
|
305
309
|
def _gte_one_int(v) -> int:
|
|
@@ -630,6 +634,19 @@ def port_app_cache() -> dict[str, str]:
|
|
|
630
634
|
return {}
|
|
631
635
|
|
|
632
636
|
|
|
637
|
+
@pytest.fixture(scope='session', autouse=True)
|
|
638
|
+
def _mp_manager():
|
|
639
|
+
manager = MessageQueueManager()
|
|
640
|
+
manager.start()
|
|
641
|
+
|
|
642
|
+
global _MP_MANAGER
|
|
643
|
+
_MP_MANAGER = manager
|
|
644
|
+
|
|
645
|
+
yield manager
|
|
646
|
+
|
|
647
|
+
manager.shutdown()
|
|
648
|
+
|
|
649
|
+
|
|
633
650
|
@pytest.fixture
|
|
634
651
|
def test_case_tempdir(test_case_name: str, session_tempdir: str) -> str:
|
|
635
652
|
"""Function scoped temp dir for pytest-embedded"""
|
|
@@ -668,8 +685,8 @@ def _pexpect_logfile(test_case_tempdir, logfile_extension, dut_index, dut_total)
|
|
|
668
685
|
|
|
669
686
|
@pytest.fixture
|
|
670
687
|
@multi_dut_generator_fixture
|
|
671
|
-
def msg_queue() -> MessageQueue: # kwargs passed by `multi_dut_generator_fixture()`
|
|
672
|
-
return
|
|
688
|
+
def msg_queue(_mp_manager) -> MessageQueue: # kwargs passed by `multi_dut_generator_fixture()`
|
|
689
|
+
return _mp_manager.MessageQueue()
|
|
673
690
|
|
|
674
691
|
|
|
675
692
|
@pytest.fixture
|
|
@@ -950,6 +967,13 @@ def qemu_extra_args(request: FixtureRequest) -> str | None:
|
|
|
950
967
|
return _request_param_or_config_option_or_default(request, 'qemu_extra_args', None)
|
|
951
968
|
|
|
952
969
|
|
|
970
|
+
@pytest.fixture
|
|
971
|
+
@multi_dut_argument
|
|
972
|
+
def qemu_efuse_path(request: FixtureRequest) -> str | None:
|
|
973
|
+
"""Enable parametrization for the same cli option"""
|
|
974
|
+
return _request_param_or_config_option_or_default(request, 'qemu_efuse_path', None)
|
|
975
|
+
|
|
976
|
+
|
|
953
977
|
@pytest.fixture
|
|
954
978
|
@multi_dut_argument
|
|
955
979
|
def skip_regenerate_image(request: FixtureRequest) -> str | None:
|
|
@@ -1037,6 +1061,7 @@ def parametrize_fixtures(
|
|
|
1037
1061
|
qemu_prog_path,
|
|
1038
1062
|
qemu_cli_args,
|
|
1039
1063
|
qemu_extra_args,
|
|
1064
|
+
qemu_efuse_path,
|
|
1040
1065
|
wokwi_diagram,
|
|
1041
1066
|
skip_regenerate_image,
|
|
1042
1067
|
encrypt,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|