hardpy 0.14.0__py3-none-any.whl → 0.15.1__py3-none-any.whl
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.
- hardpy/__init__.py +45 -10
- hardpy/cli/cli.py +30 -28
- hardpy/common/config.py +0 -4
- hardpy/common/stand_cloud/connector.py +2 -2
- hardpy/hardpy_panel/api.py +13 -3
- hardpy/pytest_hardpy/db/base_store.py +23 -0
- hardpy/pytest_hardpy/db/const.py +40 -19
- hardpy/pytest_hardpy/db/schema/v1.py +139 -326
- hardpy/pytest_hardpy/plugin.py +32 -1
- hardpy/pytest_hardpy/pytest_call.py +329 -21
- hardpy/pytest_hardpy/pytest_wrapper.py +25 -34
- hardpy/pytest_hardpy/reporter/hook_reporter.py +53 -2
- hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +1 -5
- hardpy/pytest_hardpy/utils/__init__.py +25 -11
- hardpy/pytest_hardpy/utils/const.py +72 -0
- hardpy/pytest_hardpy/utils/exception.py +7 -32
- hardpy/pytest_hardpy/utils/node_info.py +55 -1
- hardpy/pytest_hardpy/utils/stand_type.py +198 -0
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/METADATA +2 -1
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/RECORD +23 -22
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/WHEEL +0 -0
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/entry_points.txt +0 -0
- {hardpy-0.14.0.dist-info → hardpy-0.15.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,7 +6,7 @@ from dataclasses import dataclass
|
|
|
6
6
|
from inspect import stack
|
|
7
7
|
from os import environ
|
|
8
8
|
from time import sleep
|
|
9
|
-
from typing import Any
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
10
|
from uuid import uuid4
|
|
11
11
|
|
|
12
12
|
from pycouchdb.exceptions import NotFound
|
|
@@ -19,17 +19,21 @@ from hardpy.pytest_hardpy.db import (
|
|
|
19
19
|
)
|
|
20
20
|
from hardpy.pytest_hardpy.reporter import RunnerReporter
|
|
21
21
|
from hardpy.pytest_hardpy.utils import (
|
|
22
|
+
Chart,
|
|
22
23
|
DialogBox,
|
|
23
|
-
|
|
24
|
-
DuplicateSerialNumberError,
|
|
25
|
-
DuplicateTestStandLocationError,
|
|
26
|
-
DuplicateTestStandNameError,
|
|
27
|
-
DuplicateTestStandNumberError,
|
|
24
|
+
DuplicateParameterError,
|
|
28
25
|
HTMLComponent,
|
|
29
26
|
ImageComponent,
|
|
27
|
+
Instrument,
|
|
28
|
+
NumericMeasurement,
|
|
29
|
+
StringMeasurement,
|
|
30
|
+
SubUnit,
|
|
30
31
|
TestStandNumberError,
|
|
31
32
|
)
|
|
32
33
|
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from collections.abc import Mapping
|
|
36
|
+
|
|
33
37
|
|
|
34
38
|
@dataclass
|
|
35
39
|
class CurrentTestInfo:
|
|
@@ -39,6 +43,42 @@ class CurrentTestInfo:
|
|
|
39
43
|
case_id: str
|
|
40
44
|
|
|
41
45
|
|
|
46
|
+
class ErrorCodeMeta(type):
|
|
47
|
+
"""Error code metaclass."""
|
|
48
|
+
|
|
49
|
+
def __call__(cls, code: int, message: str | None = None) -> str | None:
|
|
50
|
+
"""Add error code to document.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
code (int): non-negative error code.
|
|
54
|
+
message (str | None): error message.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
str | None: error message
|
|
58
|
+
"""
|
|
59
|
+
if code < 0:
|
|
60
|
+
msg = "error code must be greater than 0"
|
|
61
|
+
raise ValueError(msg)
|
|
62
|
+
reporter = RunnerReporter()
|
|
63
|
+
key = reporter.generate_key(DF.ERROR_CODE)
|
|
64
|
+
if reporter.get_field(key) is None:
|
|
65
|
+
reporter.set_doc_value(key, code)
|
|
66
|
+
reporter.update_db_by_doc()
|
|
67
|
+
if message: # noqa: RET503
|
|
68
|
+
return message
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class ErrorCode(metaclass=ErrorCodeMeta):
|
|
72
|
+
"""Save error code and return error message.
|
|
73
|
+
|
|
74
|
+
It must be called from an assert.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
code (int): error code.
|
|
78
|
+
message (str): error message.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
|
|
42
82
|
def get_current_report() -> ResultRunStore | None:
|
|
43
83
|
"""Get current report from runstore database.
|
|
44
84
|
|
|
@@ -56,11 +96,68 @@ def get_current_report() -> ResultRunStore | None:
|
|
|
56
96
|
return None
|
|
57
97
|
|
|
58
98
|
|
|
59
|
-
def
|
|
60
|
-
"""
|
|
99
|
+
def set_user_name(name: str) -> None:
|
|
100
|
+
"""Set operator panel user name.
|
|
61
101
|
|
|
62
102
|
Args:
|
|
63
|
-
|
|
103
|
+
name (str): user name
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
DuplicateParameterError: if user name is already set
|
|
107
|
+
"""
|
|
108
|
+
reporter = RunnerReporter()
|
|
109
|
+
key = reporter.generate_key(DF.USER)
|
|
110
|
+
if reporter.get_field(key):
|
|
111
|
+
msg = "user_name"
|
|
112
|
+
raise DuplicateParameterError(msg)
|
|
113
|
+
reporter.set_doc_value(key, name)
|
|
114
|
+
reporter.update_db_by_doc()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def set_batch_serial_number(serial_number: str) -> None:
|
|
118
|
+
"""Add batch serial number to document.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
serial_number (str): batch serial number
|
|
122
|
+
|
|
123
|
+
Raises:
|
|
124
|
+
DuplicateParameterError: if batch serial number is already set
|
|
125
|
+
"""
|
|
126
|
+
reporter = RunnerReporter()
|
|
127
|
+
key = reporter.generate_key(DF.BATCH_SN)
|
|
128
|
+
if reporter.get_field(key):
|
|
129
|
+
msg = "batch_serial_number"
|
|
130
|
+
raise DuplicateParameterError(msg)
|
|
131
|
+
reporter.set_doc_value(key, serial_number)
|
|
132
|
+
reporter.update_db_by_doc()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def set_dut_sub_unit(sub_unit: SubUnit) -> int:
|
|
136
|
+
"""Add sub unit to DUT sub units list.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
sub_unit (SubUnit): Sub unit object of DUT.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
int: sub unit index
|
|
143
|
+
"""
|
|
144
|
+
reporter = RunnerReporter()
|
|
145
|
+
key = reporter.generate_key(DF.DUT, DF.SUB_UNITS)
|
|
146
|
+
|
|
147
|
+
sub_units = reporter.get_field(key) or []
|
|
148
|
+
sub_units.append({k: v for k, v in vars(sub_unit).items() if v is not None})
|
|
149
|
+
|
|
150
|
+
reporter.set_doc_value(key, sub_units)
|
|
151
|
+
reporter.update_db_by_doc()
|
|
152
|
+
|
|
153
|
+
return len(sub_units) - 1
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def set_dut_info(info: Mapping[str, str | int | float]) -> None:
|
|
157
|
+
"""Set DUT info to document.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
info (Mapping): DUT info
|
|
64
161
|
"""
|
|
65
162
|
reporter = RunnerReporter()
|
|
66
163
|
for dut_key, dut_value in info.items():
|
|
@@ -76,12 +173,13 @@ def set_dut_serial_number(serial_number: str) -> None:
|
|
|
76
173
|
serial_number (str): DUT serial number
|
|
77
174
|
|
|
78
175
|
Raises:
|
|
79
|
-
|
|
176
|
+
DuplicateParameterError: if serial number is already set
|
|
80
177
|
"""
|
|
81
178
|
reporter = RunnerReporter()
|
|
82
179
|
key = reporter.generate_key(DF.DUT, DF.SERIAL_NUMBER)
|
|
83
180
|
if reporter.get_field(key):
|
|
84
|
-
|
|
181
|
+
msg = "dut_serial_number"
|
|
182
|
+
raise DuplicateParameterError(msg)
|
|
85
183
|
reporter.set_doc_value(
|
|
86
184
|
key,
|
|
87
185
|
serial_number if isinstance(serial_number, str) else str(serial_number),
|
|
@@ -96,16 +194,71 @@ def set_dut_part_number(part_number: str) -> None:
|
|
|
96
194
|
part_number (str): DUT part number
|
|
97
195
|
|
|
98
196
|
Raises:
|
|
99
|
-
|
|
197
|
+
DuplicateParameterError: if part number is already set
|
|
100
198
|
"""
|
|
101
199
|
reporter = RunnerReporter()
|
|
102
200
|
key = reporter.generate_key(DF.DUT, DF.PART_NUMBER)
|
|
103
201
|
if reporter.get_field(key):
|
|
104
|
-
|
|
202
|
+
msg = "dut_part_number"
|
|
203
|
+
raise DuplicateParameterError(msg)
|
|
105
204
|
reporter.set_doc_value(key, part_number)
|
|
106
205
|
reporter.update_db_by_doc()
|
|
107
206
|
|
|
108
207
|
|
|
208
|
+
def set_dut_name(name: str) -> None:
|
|
209
|
+
"""Set DUT name to document.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
name (str): DUT name
|
|
213
|
+
|
|
214
|
+
Raises:
|
|
215
|
+
DuplicateParameterError: if DUT name is already set
|
|
216
|
+
"""
|
|
217
|
+
reporter = RunnerReporter()
|
|
218
|
+
key = reporter.generate_key(DF.DUT, DF.NAME)
|
|
219
|
+
if reporter.get_field(key):
|
|
220
|
+
msg = "dut_name"
|
|
221
|
+
raise DuplicateParameterError(msg)
|
|
222
|
+
reporter.set_doc_value(key, name)
|
|
223
|
+
reporter.update_db_by_doc()
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def set_dut_type(dut_type: str) -> None:
|
|
227
|
+
"""Set DUT type to document.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
dut_type (str): DUT type
|
|
231
|
+
|
|
232
|
+
Raises:
|
|
233
|
+
DuplicateParameterError: if DUT type is already set
|
|
234
|
+
"""
|
|
235
|
+
reporter = RunnerReporter()
|
|
236
|
+
key = reporter.generate_key(DF.DUT, DF.TYPE)
|
|
237
|
+
if reporter.get_field(key):
|
|
238
|
+
msg = "dut_type"
|
|
239
|
+
raise DuplicateParameterError(msg)
|
|
240
|
+
reporter.set_doc_value(key, dut_type)
|
|
241
|
+
reporter.update_db_by_doc()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def set_dut_revision(revision: str) -> None:
|
|
245
|
+
"""Set DUT revision to document.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
revision (str): DUT revision
|
|
249
|
+
|
|
250
|
+
Raises:
|
|
251
|
+
DuplicateParameterError: if DUT revision is already set
|
|
252
|
+
"""
|
|
253
|
+
reporter = RunnerReporter()
|
|
254
|
+
key = reporter.generate_key(DF.DUT, DF.REVISION)
|
|
255
|
+
if reporter.get_field(key):
|
|
256
|
+
msg = "dut_revision"
|
|
257
|
+
raise DuplicateParameterError(msg)
|
|
258
|
+
reporter.set_doc_value(key, revision)
|
|
259
|
+
reporter.update_db_by_doc()
|
|
260
|
+
|
|
261
|
+
|
|
109
262
|
def set_stand_name(name: str) -> None:
|
|
110
263
|
"""Add test stand name to document.
|
|
111
264
|
|
|
@@ -113,21 +266,23 @@ def set_stand_name(name: str) -> None:
|
|
|
113
266
|
name (str): test stand name
|
|
114
267
|
|
|
115
268
|
Raises:
|
|
116
|
-
|
|
269
|
+
DuplicateParameterError: if test stand name is already set
|
|
117
270
|
"""
|
|
118
271
|
reporter = RunnerReporter()
|
|
119
272
|
key = reporter.generate_key(DF.TEST_STAND, DF.NAME)
|
|
120
273
|
if reporter.get_field(key):
|
|
121
|
-
|
|
274
|
+
msg = "stand_name"
|
|
275
|
+
raise DuplicateParameterError(msg)
|
|
122
276
|
reporter.set_doc_value(key, name)
|
|
123
277
|
reporter.update_db_by_doc()
|
|
124
278
|
|
|
125
279
|
|
|
126
|
-
def set_stand_info(info:
|
|
280
|
+
def set_stand_info(info: Mapping[str, str | int | float]) -> None:
|
|
127
281
|
"""Add test stand info to document.
|
|
128
282
|
|
|
129
283
|
Args:
|
|
130
|
-
info (
|
|
284
|
+
info (Mapping[str, str | int | float ]): test stand info as a mapping
|
|
285
|
+
where keys are strings and values can be strings, integers, floats objects
|
|
131
286
|
"""
|
|
132
287
|
reporter = RunnerReporter()
|
|
133
288
|
for stand_key, stand_value in info.items():
|
|
@@ -143,12 +298,13 @@ def set_stand_location(location: str) -> None:
|
|
|
143
298
|
location (str): test stand location
|
|
144
299
|
|
|
145
300
|
Raises:
|
|
146
|
-
|
|
301
|
+
DuplicateParameterError: if test stand location is already set
|
|
147
302
|
"""
|
|
148
303
|
reporter = RunnerReporter()
|
|
149
304
|
key = reporter.generate_key(DF.TEST_STAND, DF.LOCATION)
|
|
150
305
|
if reporter.get_field(key):
|
|
151
|
-
|
|
306
|
+
msg = "stand_location"
|
|
307
|
+
raise DuplicateParameterError(msg)
|
|
152
308
|
reporter.set_doc_value(key, location)
|
|
153
309
|
reporter.update_db_by_doc()
|
|
154
310
|
|
|
@@ -160,7 +316,7 @@ def set_stand_number(number: int) -> None:
|
|
|
160
316
|
number (int): test stand number (non negative integer)
|
|
161
317
|
|
|
162
318
|
Raises:
|
|
163
|
-
|
|
319
|
+
DuplicateParameterError: if stand number is already set
|
|
164
320
|
TestStandNumberError: if stand number is incorrect (negative or non integer)
|
|
165
321
|
"""
|
|
166
322
|
reporter = RunnerReporter()
|
|
@@ -168,11 +324,30 @@ def set_stand_number(number: int) -> None:
|
|
|
168
324
|
if not isinstance(number, int) or number < 0:
|
|
169
325
|
raise TestStandNumberError
|
|
170
326
|
if reporter.get_field(key):
|
|
171
|
-
|
|
327
|
+
msg = "stand_number"
|
|
328
|
+
raise DuplicateParameterError(msg)
|
|
172
329
|
reporter.set_doc_value(key, number)
|
|
173
330
|
reporter.update_db_by_doc()
|
|
174
331
|
|
|
175
332
|
|
|
333
|
+
def set_stand_revision(revision: str) -> None:
|
|
334
|
+
"""Add test stand revision to document.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
revision (str): test stand revision
|
|
338
|
+
|
|
339
|
+
Raises:
|
|
340
|
+
DuplicateParameterError: if test stand revision is already set
|
|
341
|
+
"""
|
|
342
|
+
reporter = RunnerReporter()
|
|
343
|
+
key = reporter.generate_key(DF.TEST_STAND, DF.REVISION)
|
|
344
|
+
if reporter.get_field(key):
|
|
345
|
+
msg = "stand_revision"
|
|
346
|
+
raise DuplicateParameterError(msg)
|
|
347
|
+
reporter.set_doc_value(key, revision)
|
|
348
|
+
reporter.update_db_by_doc()
|
|
349
|
+
|
|
350
|
+
|
|
176
351
|
def set_message(msg: str, msg_key: str | None = None) -> None:
|
|
177
352
|
"""Add or update message in current test.
|
|
178
353
|
|
|
@@ -291,6 +466,135 @@ def set_driver_info(drivers: dict) -> None:
|
|
|
291
466
|
reporter.update_db_by_doc()
|
|
292
467
|
|
|
293
468
|
|
|
469
|
+
def set_instrument(instrument: Instrument) -> int:
|
|
470
|
+
"""Add instrument to test stand instruments list.
|
|
471
|
+
|
|
472
|
+
Args:
|
|
473
|
+
instrument (Instrument): Instrument object containing all instrument data
|
|
474
|
+
|
|
475
|
+
Returns:
|
|
476
|
+
int: instrument index
|
|
477
|
+
"""
|
|
478
|
+
reporter = RunnerReporter()
|
|
479
|
+
key = reporter.generate_key(DF.TEST_STAND, DF.INSTRUMENTS)
|
|
480
|
+
|
|
481
|
+
instruments = reporter.get_field(key) or []
|
|
482
|
+
instruments.append({k: v for k, v in vars(instrument).items() if v is not None})
|
|
483
|
+
|
|
484
|
+
reporter.set_doc_value(key, instruments)
|
|
485
|
+
reporter.update_db_by_doc()
|
|
486
|
+
|
|
487
|
+
return len(instruments) - 1
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def set_process_name(name: str) -> None:
|
|
491
|
+
"""Set process name to document.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
name (str): process name
|
|
495
|
+
|
|
496
|
+
Raises:
|
|
497
|
+
DuplicateParameterError: if process name is already set
|
|
498
|
+
"""
|
|
499
|
+
reporter = RunnerReporter()
|
|
500
|
+
key = reporter.generate_key(DF.PROCESS, DF.NAME)
|
|
501
|
+
if reporter.get_field(key):
|
|
502
|
+
msg = "process_name"
|
|
503
|
+
raise DuplicateParameterError(msg)
|
|
504
|
+
reporter.set_doc_value(key, name)
|
|
505
|
+
reporter.update_db_by_doc()
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def set_process_number(number: int) -> None:
|
|
509
|
+
"""Set process number to document.
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
number (int): process number
|
|
513
|
+
|
|
514
|
+
Raises:
|
|
515
|
+
DuplicateParameterError: if process number is already set
|
|
516
|
+
"""
|
|
517
|
+
reporter = RunnerReporter()
|
|
518
|
+
key = reporter.generate_key(DF.PROCESS, DF.NUMBER)
|
|
519
|
+
if reporter.get_field(key):
|
|
520
|
+
msg = "process_number"
|
|
521
|
+
raise DuplicateParameterError(msg)
|
|
522
|
+
reporter.set_doc_value(key, number)
|
|
523
|
+
reporter.update_db_by_doc()
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def set_process_info(info: Mapping[str, str | int | float]) -> None:
|
|
527
|
+
"""Set process info to document.
|
|
528
|
+
|
|
529
|
+
Args:
|
|
530
|
+
info (Mapping): process info
|
|
531
|
+
"""
|
|
532
|
+
reporter = RunnerReporter()
|
|
533
|
+
for key, value in info.items():
|
|
534
|
+
full_key = reporter.generate_key(DF.PROCESS, DF.INFO, key)
|
|
535
|
+
reporter.set_doc_value(full_key, value)
|
|
536
|
+
reporter.update_db_by_doc()
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def set_case_measurement(measurement: NumericMeasurement | StringMeasurement) -> int:
|
|
540
|
+
"""Add measurement to document.
|
|
541
|
+
|
|
542
|
+
Args:
|
|
543
|
+
measurement (NumericMeasurement | StringMeasurement): measurement object
|
|
544
|
+
|
|
545
|
+
Returns:
|
|
546
|
+
int: measurement index from measurements list
|
|
547
|
+
"""
|
|
548
|
+
current_test = _get_current_test()
|
|
549
|
+
reporter = RunnerReporter()
|
|
550
|
+
|
|
551
|
+
key = reporter.generate_key(
|
|
552
|
+
DF.MODULES,
|
|
553
|
+
current_test.module_id,
|
|
554
|
+
DF.CASES,
|
|
555
|
+
current_test.case_id,
|
|
556
|
+
DF.MEASUREMENTS,
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
measurements = reporter.get_field(key) or []
|
|
560
|
+
measurements.append({k: v for k, v in vars(measurement).items() if v is not None})
|
|
561
|
+
|
|
562
|
+
reporter.set_doc_value(key, measurements)
|
|
563
|
+
reporter.update_db_by_doc()
|
|
564
|
+
|
|
565
|
+
return len(measurements) - 1
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def set_case_chart(chart: Chart) -> None:
|
|
569
|
+
"""Add chart to document.
|
|
570
|
+
|
|
571
|
+
Args:
|
|
572
|
+
chart (Chart): chart object
|
|
573
|
+
"""
|
|
574
|
+
if not chart.x_data or not chart.y_data:
|
|
575
|
+
msg = "x_data and y_data must be set"
|
|
576
|
+
raise ValueError(msg)
|
|
577
|
+
current_test = _get_current_test()
|
|
578
|
+
reporter = RunnerReporter()
|
|
579
|
+
|
|
580
|
+
key = reporter.generate_key(
|
|
581
|
+
DF.MODULES,
|
|
582
|
+
current_test.module_id,
|
|
583
|
+
DF.CASES,
|
|
584
|
+
current_test.case_id,
|
|
585
|
+
DF.CHART,
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
if reporter.get_field(key):
|
|
589
|
+
msg = "chart"
|
|
590
|
+
raise DuplicateParameterError(msg)
|
|
591
|
+
|
|
592
|
+
chart_dict = {k: v for k, v in vars(chart).items() if v is not None}
|
|
593
|
+
|
|
594
|
+
reporter.set_doc_value(key, chart_dict)
|
|
595
|
+
reporter.update_db_by_doc()
|
|
596
|
+
|
|
597
|
+
|
|
294
598
|
def run_dialog_box(dialog_box_data: DialogBox) -> Any: # noqa: ANN401
|
|
295
599
|
"""Display a dialog box.
|
|
296
600
|
|
|
@@ -373,6 +677,10 @@ def set_operator_message( # noqa: PLR0913
|
|
|
373
677
|
msg = "The 'font_size' argument cannot be less than 1"
|
|
374
678
|
raise ValueError(msg)
|
|
375
679
|
|
|
680
|
+
if not msg:
|
|
681
|
+
msg = "The 'msg' argument cannot be empty"
|
|
682
|
+
raise ValueError(msg)
|
|
683
|
+
|
|
376
684
|
msg_data = {
|
|
377
685
|
DF.MSG: msg,
|
|
378
686
|
DF.TITLE: title,
|
|
@@ -25,7 +25,7 @@ class PyTestWrapper:
|
|
|
25
25
|
self.config = ConfigManager().get_config()
|
|
26
26
|
self.collect(is_clear_database=True)
|
|
27
27
|
|
|
28
|
-
def start(self) -> bool:
|
|
28
|
+
def start(self, start_args: dict | None = None) -> bool:
|
|
29
29
|
"""Start pytest subprocess.
|
|
30
30
|
|
|
31
31
|
Returns:
|
|
@@ -37,44 +37,35 @@ class PyTestWrapper:
|
|
|
37
37
|
if self.is_running():
|
|
38
38
|
return False
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
cmd = [
|
|
41
|
+
self.python_executable,
|
|
42
|
+
"-m",
|
|
43
|
+
"pytest",
|
|
44
|
+
"--hardpy-db-url",
|
|
45
|
+
self.config.database.connection_url(),
|
|
46
|
+
"--hardpy-tests-name",
|
|
47
|
+
self.config.tests_name,
|
|
48
|
+
"--sc-address",
|
|
49
|
+
self.config.stand_cloud.address,
|
|
50
|
+
]
|
|
51
|
+
if self.config.stand_cloud.connection_only:
|
|
52
|
+
cmd.append("--sc-connection-only")
|
|
53
|
+
cmd.append("--hardpy-pt")
|
|
54
|
+
if start_args:
|
|
55
|
+
for key, value in start_args.items():
|
|
56
|
+
arg_str = f"{key}={value}"
|
|
57
|
+
cmd.extend(["--hardpy-start-arg", arg_str])
|
|
58
|
+
|
|
59
|
+
if system() == "Windows":
|
|
41
60
|
self._proc = subprocess.Popen( # noqa: S603
|
|
42
|
-
|
|
43
|
-
self.python_executable,
|
|
44
|
-
"-m",
|
|
45
|
-
"pytest",
|
|
46
|
-
"--hardpy-db-url",
|
|
47
|
-
self.config.database.connection_url(),
|
|
48
|
-
"--hardpy-tests-name",
|
|
49
|
-
self.config.tests_name,
|
|
50
|
-
"--sc-address",
|
|
51
|
-
self.config.stand_cloud.address,
|
|
52
|
-
"--sc-connection-only"
|
|
53
|
-
if self.config.stand_cloud.connection_only
|
|
54
|
-
else "",
|
|
55
|
-
"--hardpy-pt",
|
|
56
|
-
],
|
|
61
|
+
cmd,
|
|
57
62
|
cwd=ConfigManager().get_tests_path(),
|
|
63
|
+
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
|
|
58
64
|
)
|
|
59
|
-
|
|
65
|
+
if system() == "Linux":
|
|
60
66
|
self._proc = subprocess.Popen( # noqa: S603
|
|
61
|
-
|
|
62
|
-
self.python_executable,
|
|
63
|
-
"-m",
|
|
64
|
-
"pytest",
|
|
65
|
-
"--hardpy-db-url",
|
|
66
|
-
self.config.database.connection_url(),
|
|
67
|
-
"--hardpy-tests-name",
|
|
68
|
-
self.config.tests_name,
|
|
69
|
-
"--sc-address",
|
|
70
|
-
self.config.stand_cloud.address,
|
|
71
|
-
"--sc-connection-only"
|
|
72
|
-
if self.config.stand_cloud.connection_only
|
|
73
|
-
else "",
|
|
74
|
-
"--hardpy-pt",
|
|
75
|
-
],
|
|
67
|
+
cmd,
|
|
76
68
|
cwd=ConfigManager().get_tests_path(),
|
|
77
|
-
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, # type: ignore
|
|
78
69
|
)
|
|
79
70
|
|
|
80
71
|
return True
|
|
@@ -31,6 +31,10 @@ class HookReporter(BaseReporter):
|
|
|
31
31
|
doc_name (str): test run name
|
|
32
32
|
"""
|
|
33
33
|
self.set_doc_value(DF.NAME, doc_name)
|
|
34
|
+
self.set_doc_value(DF.USER, None)
|
|
35
|
+
self.set_doc_value(DF.BATCH_SN, None)
|
|
36
|
+
self.set_doc_value(DF.CAUSED_DUT_FAILURE_ID, None)
|
|
37
|
+
self.set_doc_value(DF.ERROR_CODE, None)
|
|
34
38
|
self.set_doc_value(DF.STATUS, TestStatus.READY)
|
|
35
39
|
self.set_doc_value(DF.START_TIME, None)
|
|
36
40
|
self.set_doc_value(DF.STOP_TIME, None)
|
|
@@ -217,7 +221,7 @@ class HookReporter(BaseReporter):
|
|
|
217
221
|
case_id,
|
|
218
222
|
DF.ATTEMPT,
|
|
219
223
|
)
|
|
220
|
-
self.set_doc_value(key, attempt
|
|
224
|
+
self.set_doc_value(key, attempt)
|
|
221
225
|
|
|
222
226
|
def get_module_start_time(self, module_id: str) -> int:
|
|
223
227
|
"""Get module start time.
|
|
@@ -237,6 +241,26 @@ class HookReporter(BaseReporter):
|
|
|
237
241
|
key = self.generate_key(DF.MODULES, module_id, DF.CASES, case_id, DF.START_TIME)
|
|
238
242
|
return self._statestore.get_field(key)
|
|
239
243
|
|
|
244
|
+
def set_caused_dut_failure_id(self, module_id: str, case_id: str) -> None:
|
|
245
|
+
"""Set caused DUT failure id.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
module_id (str): module id
|
|
249
|
+
case_id (str): case id
|
|
250
|
+
"""
|
|
251
|
+
key = self.generate_key(DF.CAUSED_DUT_FAILURE_ID)
|
|
252
|
+
failure_id = f"{module_id}::{case_id}"
|
|
253
|
+
self.set_doc_value(key, failure_id)
|
|
254
|
+
|
|
255
|
+
def get_caused_dut_failure_id(self) -> str | None:
|
|
256
|
+
"""Get caused DUT failure id.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
str | None: failure id
|
|
260
|
+
"""
|
|
261
|
+
key = self.generate_key(DF.CAUSED_DUT_FAILURE_ID)
|
|
262
|
+
return self._statestore.get_field(key)
|
|
263
|
+
|
|
240
264
|
def update_node_order(self, nodes: dict) -> None:
|
|
241
265
|
"""Update node order.
|
|
242
266
|
|
|
@@ -267,6 +291,7 @@ class HookReporter(BaseReporter):
|
|
|
267
291
|
module_default = {
|
|
268
292
|
DF.STATUS: TestStatus.READY,
|
|
269
293
|
DF.NAME: self._get_module_name(node_info),
|
|
294
|
+
DF.GROUP: self._get_module_group(node_info),
|
|
270
295
|
DF.START_TIME: None,
|
|
271
296
|
DF.STOP_TIME: None,
|
|
272
297
|
DF.CASES: {},
|
|
@@ -274,10 +299,14 @@ class HookReporter(BaseReporter):
|
|
|
274
299
|
case_default = {
|
|
275
300
|
DF.STATUS: TestStatus.READY,
|
|
276
301
|
DF.NAME: self._get_case_name(node_info),
|
|
302
|
+
DF.GROUP: self._get_case_group(node_info),
|
|
277
303
|
DF.START_TIME: None,
|
|
278
304
|
DF.STOP_TIME: None,
|
|
279
305
|
DF.ASSERTION_MSG: None,
|
|
280
306
|
DF.MSG: None,
|
|
307
|
+
DF.ATTEMPT: 0,
|
|
308
|
+
DF.MEASUREMENTS: [],
|
|
309
|
+
DF.CHART: None,
|
|
281
310
|
}
|
|
282
311
|
|
|
283
312
|
if item.get(node_info.module_id) is None:
|
|
@@ -287,6 +316,7 @@ class HookReporter(BaseReporter):
|
|
|
287
316
|
else:
|
|
288
317
|
item[node_info.module_id][DF.STATUS] = TestStatus.READY
|
|
289
318
|
item[node_info.module_id][DF.NAME] = self._get_module_name(node_info)
|
|
319
|
+
item[node_info.module_id][DF.GROUP] = self._get_module_group(node_info)
|
|
290
320
|
item[node_info.module_id][DF.START_TIME] = None
|
|
291
321
|
item[node_info.module_id][DF.STOP_TIME] = None
|
|
292
322
|
item[node_info.module_id][DF.NAME] = self._get_module_name(node_info)
|
|
@@ -296,7 +326,6 @@ class HookReporter(BaseReporter):
|
|
|
296
326
|
|
|
297
327
|
if is_only_statestore:
|
|
298
328
|
case_default[DF.DIALOG_BOX] = {}
|
|
299
|
-
case_default[DF.ATTEMPT] = 0
|
|
300
329
|
item[node_info.module_id][DF.CASES][node_info.case_id] = case_default
|
|
301
330
|
|
|
302
331
|
def _remove_outdate_node(
|
|
@@ -378,6 +407,28 @@ class HookReporter(BaseReporter):
|
|
|
378
407
|
"""
|
|
379
408
|
return node_info.module_name if node_info.module_name else node_info.module_id
|
|
380
409
|
|
|
410
|
+
def _get_module_group(self, node_info: NodeInfo) -> str:
|
|
411
|
+
"""Get module group from markers or use default.
|
|
412
|
+
|
|
413
|
+
Args:
|
|
414
|
+
node_info (NodeInfo): node info
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
str: module group
|
|
418
|
+
"""
|
|
419
|
+
return node_info.module_group
|
|
420
|
+
|
|
421
|
+
def _get_case_group(self, node_info: NodeInfo) -> str:
|
|
422
|
+
"""Get case group from markers or use default.
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
node_info (NodeInfo): node info
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
str: case group
|
|
429
|
+
"""
|
|
430
|
+
return node_info.case_group
|
|
431
|
+
|
|
381
432
|
def _get_case_name(self, node_info: NodeInfo) -> str:
|
|
382
433
|
"""Get case name from markers or use default.
|
|
383
434
|
|
|
@@ -88,11 +88,7 @@ class CouchdbReader:
|
|
|
88
88
|
str: report status
|
|
89
89
|
"""
|
|
90
90
|
doc = self._db.get(report_name)
|
|
91
|
-
|
|
92
|
-
if status not in {TestStatus.PASSED, TestStatus.FAILED, TestStatus.SKIPPED}:
|
|
93
|
-
msg = "Invalid report status"
|
|
94
|
-
raise ValueError(msg)
|
|
95
|
-
return status
|
|
91
|
+
return doc[DF.STATUS]
|
|
96
92
|
|
|
97
93
|
def get_report_infos(self) -> list[ReportInfo]:
|
|
98
94
|
"""Get a list of information about all reports in the database.
|