hardpy 0.6.1__py3-none-any.whl → 0.8.0__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 +49 -49
- hardpy/cli/cli.py +8 -9
- hardpy/cli/template.py +6 -6
- hardpy/common/config.py +19 -18
- hardpy/hardpy_panel/api.py +9 -9
- hardpy/hardpy_panel/frontend/dist/asset-manifest.json +3 -3
- hardpy/hardpy_panel/frontend/dist/index.html +1 -1
- hardpy/hardpy_panel/frontend/dist/logo192.png +0 -0
- hardpy/hardpy_panel/frontend/dist/static/css/main.e8a862f1.css.map +1 -1
- hardpy/hardpy_panel/frontend/dist/static/js/main.6f09d61a.js +3 -0
- hardpy/hardpy_panel/frontend/dist/static/js/{main.7c954faf.js.map → main.6f09d61a.js.map} +1 -1
- hardpy/pytest_hardpy/db/__init__.py +4 -5
- hardpy/pytest_hardpy/db/base_connector.py +6 -5
- hardpy/pytest_hardpy/db/base_server.py +1 -1
- hardpy/pytest_hardpy/db/base_store.py +23 -9
- hardpy/pytest_hardpy/db/const.py +3 -1
- hardpy/pytest_hardpy/db/runstore.py +13 -15
- hardpy/pytest_hardpy/db/schema/__init__.py +9 -0
- hardpy/pytest_hardpy/db/{schema.py → schema/v1.py} +120 -79
- hardpy/pytest_hardpy/db/statestore.py +7 -20
- hardpy/pytest_hardpy/plugin.py +128 -85
- hardpy/pytest_hardpy/pytest_call.py +80 -32
- hardpy/pytest_hardpy/pytest_wrapper.py +8 -8
- hardpy/pytest_hardpy/reporter/__init__.py +2 -2
- hardpy/pytest_hardpy/reporter/base.py +32 -7
- hardpy/pytest_hardpy/reporter/hook_reporter.py +66 -37
- hardpy/pytest_hardpy/reporter/runner_reporter.py +6 -8
- hardpy/pytest_hardpy/result/__init__.py +2 -2
- hardpy/pytest_hardpy/result/couchdb_config.py +20 -16
- hardpy/pytest_hardpy/result/report_loader/couchdb_loader.py +2 -2
- hardpy/pytest_hardpy/result/report_reader/couchdb_reader.py +36 -20
- hardpy/pytest_hardpy/utils/__init__.py +34 -29
- hardpy/pytest_hardpy/utils/connection_data.py +6 -8
- hardpy/pytest_hardpy/utils/const.py +1 -1
- hardpy/pytest_hardpy/utils/dialog_box.py +105 -66
- hardpy/pytest_hardpy/utils/exception.py +14 -8
- hardpy/pytest_hardpy/utils/machineid.py +15 -0
- hardpy/pytest_hardpy/utils/node_info.py +45 -16
- hardpy/pytest_hardpy/utils/progress_calculator.py +4 -3
- hardpy/pytest_hardpy/utils/singleton.py +23 -16
- {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/METADATA +26 -33
- {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/RECORD +46 -43
- hardpy/hardpy_panel/frontend/dist/static/js/main.7c954faf.js +0 -3
- /hardpy/hardpy_panel/frontend/dist/static/js/{main.7c954faf.js.LICENSE.txt → main.6f09d61a.js.LICENSE.txt} +0 -0
- {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/WHEEL +0 -0
- {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/entry_points.txt +0 -0
- {hardpy-0.6.1.dist-info → hardpy-0.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
# Copyright (c) 2024 Everypin
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
3
|
|
|
4
|
-
from hardpy.pytest_hardpy.db.schema import ResultRunStore, ResultStateStore
|
|
5
|
-
from hardpy.pytest_hardpy.db.statestore import StateStore
|
|
6
|
-
from hardpy.pytest_hardpy.db.runstore import RunStore
|
|
7
4
|
from hardpy.pytest_hardpy.db.base_store import BaseStore
|
|
8
5
|
from hardpy.pytest_hardpy.db.const import DatabaseField
|
|
9
|
-
|
|
6
|
+
from hardpy.pytest_hardpy.db.runstore import RunStore
|
|
7
|
+
from hardpy.pytest_hardpy.db.schema import ResultRunStore, ResultStateStore
|
|
8
|
+
from hardpy.pytest_hardpy.db.statestore import StateStore
|
|
10
9
|
|
|
11
10
|
__all__ = [
|
|
12
11
|
"BaseStore",
|
|
13
12
|
"DatabaseField",
|
|
14
13
|
"ResultRunStore",
|
|
15
14
|
"ResultStateStore",
|
|
16
|
-
"StateStore",
|
|
17
15
|
"RunStore",
|
|
16
|
+
"StateStore",
|
|
18
17
|
]
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# Copyright (c) 2024 Everypin
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
3
|
|
|
4
|
-
from requests.exceptions import ConnectionError
|
|
5
|
-
|
|
6
4
|
from pycouchdb.client import Database
|
|
7
5
|
from pycouchdb.exceptions import Conflict, GenericError
|
|
6
|
+
from requests.exceptions import ConnectionError # noqa: A004
|
|
8
7
|
|
|
9
8
|
from hardpy.pytest_hardpy.db.base_server import BaseServer
|
|
10
9
|
|
|
@@ -12,7 +11,7 @@ from hardpy.pytest_hardpy.db.base_server import BaseServer
|
|
|
12
11
|
class BaseConnector(BaseServer):
|
|
13
12
|
"""Base class for CouchDB connector."""
|
|
14
13
|
|
|
15
|
-
def __init__(self, db_name: str):
|
|
14
|
+
def __init__(self, db_name: str) -> None:
|
|
16
15
|
super().__init__()
|
|
17
16
|
self._db_name = db_name
|
|
18
17
|
self._db = self._init_db()
|
|
@@ -25,6 +24,8 @@ class BaseConnector(BaseServer):
|
|
|
25
24
|
# database is already created
|
|
26
25
|
return self._db_srv.database(self._db_name)
|
|
27
26
|
except GenericError as exc:
|
|
28
|
-
|
|
27
|
+
msg = f"Error initializing database {exc}"
|
|
28
|
+
raise RuntimeError(msg) from exc
|
|
29
29
|
except ConnectionError as exc:
|
|
30
|
-
|
|
30
|
+
msg = f"Error initializing database: {exc}"
|
|
31
|
+
raise RuntimeError(msg) from exc
|
|
@@ -9,23 +9,23 @@ from pycouchdb.exceptions import Conflict, NotFound
|
|
|
9
9
|
from pydantic._internal._model_construction import ModelMetaclass
|
|
10
10
|
|
|
11
11
|
from hardpy.pytest_hardpy.db.base_connector import BaseConnector
|
|
12
|
-
from hardpy.pytest_hardpy.db.const import DatabaseField as DF
|
|
12
|
+
from hardpy.pytest_hardpy.db.const import DatabaseField as DF # noqa: N817
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class BaseStore(BaseConnector):
|
|
16
16
|
"""HardPy base storage interface for CouchDB."""
|
|
17
17
|
|
|
18
|
-
def __init__(self, db_name: str):
|
|
18
|
+
def __init__(self, db_name: str) -> None:
|
|
19
19
|
super().__init__(db_name)
|
|
20
20
|
self._log = getLogger(__name__)
|
|
21
21
|
self._doc: dict = self._init_doc()
|
|
22
22
|
self._schema: ModelMetaclass
|
|
23
23
|
|
|
24
|
-
def compact(self):
|
|
24
|
+
def compact(self) -> None:
|
|
25
25
|
"""Compact database."""
|
|
26
26
|
self._db.compact()
|
|
27
27
|
|
|
28
|
-
def get_field(self, key: str) -> Any:
|
|
28
|
+
def get_field(self, key: str) -> Any: # noqa: ANN401
|
|
29
29
|
"""Get field from the state store.
|
|
30
30
|
|
|
31
31
|
Args:
|
|
@@ -36,7 +36,7 @@ class BaseStore(BaseConnector):
|
|
|
36
36
|
"""
|
|
37
37
|
return glom(self._doc, key)
|
|
38
38
|
|
|
39
|
-
def update_doc(self, key: str, value):
|
|
39
|
+
def update_doc(self, key: str, value: Any) -> None: # noqa: ANN401
|
|
40
40
|
"""Update document.
|
|
41
41
|
|
|
42
42
|
HardPy collecting uses a simple key without dots.
|
|
@@ -52,7 +52,7 @@ class BaseStore(BaseConnector):
|
|
|
52
52
|
else:
|
|
53
53
|
self._doc[key] = value
|
|
54
54
|
|
|
55
|
-
def update_db(self):
|
|
55
|
+
def update_db(self) -> None:
|
|
56
56
|
"""Update database by current document."""
|
|
57
57
|
try:
|
|
58
58
|
self._doc = self._db.save(self._doc)
|
|
@@ -69,6 +69,15 @@ class BaseStore(BaseConnector):
|
|
|
69
69
|
self._doc = self._db.get(self._doc_id)
|
|
70
70
|
return self._schema(**self._doc)
|
|
71
71
|
|
|
72
|
+
def clear(self) -> None:
|
|
73
|
+
"""Clear database."""
|
|
74
|
+
try:
|
|
75
|
+
# Clear statestore and runstore databases before each launch
|
|
76
|
+
self._db.delete(self._doc_id)
|
|
77
|
+
except (Conflict, NotFound):
|
|
78
|
+
self._log.debug("Database will be created for the first time")
|
|
79
|
+
self._doc: dict = self._init_doc()
|
|
80
|
+
|
|
72
81
|
def _init_doc(self) -> dict:
|
|
73
82
|
try:
|
|
74
83
|
doc = self._db.get(self._doc_id)
|
|
@@ -82,18 +91,19 @@ class BaseStore(BaseConnector):
|
|
|
82
91
|
DF.INFO: {},
|
|
83
92
|
},
|
|
84
93
|
DF.TEST_STAND: {
|
|
94
|
+
DF.HW_ID: None,
|
|
85
95
|
DF.NAME: None,
|
|
96
|
+
DF.TIMEZONE: None,
|
|
97
|
+
DF.LOCATION: None,
|
|
98
|
+
DF.DRIVERS: {},
|
|
86
99
|
DF.INFO: {},
|
|
87
100
|
},
|
|
88
|
-
DF.DRIVERS: {},
|
|
89
101
|
}
|
|
90
102
|
|
|
91
103
|
# init document
|
|
92
104
|
if DF.MODULES not in doc:
|
|
93
105
|
doc[DF.MODULES] = {}
|
|
94
106
|
|
|
95
|
-
doc[DF.DRIVERS] = {}
|
|
96
|
-
|
|
97
107
|
doc[DF.DUT] = {
|
|
98
108
|
DF.SERIAL_NUMBER: None,
|
|
99
109
|
DF.PART_NUMBER: None,
|
|
@@ -101,7 +111,11 @@ class BaseStore(BaseConnector):
|
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
doc[DF.TEST_STAND] = {
|
|
114
|
+
DF.HW_ID: None,
|
|
104
115
|
DF.NAME: None,
|
|
116
|
+
DF.TIMEZONE: None,
|
|
117
|
+
DF.LOCATION: None,
|
|
118
|
+
DF.DRIVERS: {},
|
|
105
119
|
DF.INFO: {},
|
|
106
120
|
}
|
|
107
121
|
|
hardpy/pytest_hardpy/db/const.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
from enum import Enum
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class DatabaseField(str, Enum):
|
|
7
|
+
class DatabaseField(str, Enum):
|
|
8
8
|
"""Database field."""
|
|
9
9
|
|
|
10
10
|
NAME = "name"
|
|
@@ -27,3 +27,5 @@ class DatabaseField(str, Enum): # noqa: WPS600
|
|
|
27
27
|
DIALOG_BOX = "dialog_box"
|
|
28
28
|
OPERATOR_MSG = "operator_msg"
|
|
29
29
|
ATTEMPT = "attempt"
|
|
30
|
+
LOCATION = "location"
|
|
31
|
+
HW_ID = "hw_id"
|
|
@@ -6,25 +6,23 @@ from logging import getLogger
|
|
|
6
6
|
from pycouchdb.exceptions import Conflict, NotFound
|
|
7
7
|
|
|
8
8
|
from hardpy.pytest_hardpy.db.base_store import BaseStore
|
|
9
|
-
from hardpy.pytest_hardpy.db import ResultRunStore
|
|
10
|
-
from hardpy.pytest_hardpy.utils import
|
|
9
|
+
from hardpy.pytest_hardpy.db.schema import ResultRunStore
|
|
10
|
+
from hardpy.pytest_hardpy.utils import SingletonMeta
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class RunStore(
|
|
13
|
+
class RunStore(BaseStore, metaclass=SingletonMeta):
|
|
14
14
|
"""HardPy run storage interface for CouchDB.
|
|
15
15
|
|
|
16
16
|
Save state and case artifact.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
def __init__(self):
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
self._schema = ResultRunStore
|
|
30
|
-
self._initialized = True
|
|
19
|
+
def __init__(self) -> None:
|
|
20
|
+
super().__init__("runstore")
|
|
21
|
+
self._log = getLogger(__name__)
|
|
22
|
+
try:
|
|
23
|
+
# Clear the runstore database before each launch
|
|
24
|
+
self._db.delete(self._doc_id)
|
|
25
|
+
except (Conflict, NotFound):
|
|
26
|
+
self._log.debug("Runstore database will be created for the first time")
|
|
27
|
+
self._doc: dict = self._init_doc()
|
|
28
|
+
self._schema = ResultRunStore
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Copyright (c) 2024 Everypin
|
|
2
|
+
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
|
+
|
|
4
|
+
from hardpy.pytest_hardpy.db.schema.v1 import ResultRunStore, ResultStateStore
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"ResultRunStore",
|
|
8
|
+
"ResultStateStore",
|
|
9
|
+
]
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# Copyright (c) 2024 Everypin
|
|
2
2
|
# GNU General Public License v3.0 (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
3
|
+
from __future__ import annotations
|
|
3
4
|
|
|
4
|
-
from
|
|
5
|
+
from typing import ClassVar
|
|
5
6
|
|
|
6
|
-
from
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
8
|
+
|
|
9
|
+
from hardpy.pytest_hardpy.utils import TestStatus as Status # noqa: TC001
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
class IBaseResult(BaseModel):
|
|
@@ -21,7 +24,9 @@ class CaseStateStore(IBaseResult):
|
|
|
21
24
|
"""Test case description.
|
|
22
25
|
|
|
23
26
|
Example:
|
|
24
|
-
|
|
27
|
+
```
|
|
28
|
+
{
|
|
29
|
+
"test_one": {
|
|
25
30
|
"status": "passed",
|
|
26
31
|
"name": "Test 2",
|
|
27
32
|
"start_time": 1695817188,
|
|
@@ -39,7 +44,9 @@ class CaseStateStore(IBaseResult):
|
|
|
39
44
|
"type": "textinput"
|
|
40
45
|
}
|
|
41
46
|
}
|
|
47
|
+
}
|
|
42
48
|
}
|
|
49
|
+
```
|
|
43
50
|
"""
|
|
44
51
|
|
|
45
52
|
assertion_msg: str | None = None
|
|
@@ -52,44 +59,50 @@ class CaseRunStore(IBaseResult):
|
|
|
52
59
|
"""Test case description with artifact.
|
|
53
60
|
|
|
54
61
|
Example:
|
|
55
|
-
|
|
62
|
+
```
|
|
63
|
+
{
|
|
64
|
+
"test_one": {
|
|
56
65
|
"status": "passed",
|
|
57
66
|
"name": "Test 2",
|
|
58
67
|
"start_time": 1695817188,
|
|
59
68
|
"stop_time": 1695817189,
|
|
60
69
|
"assertion_msg": null,
|
|
61
70
|
"msg": null,
|
|
62
|
-
"attempt": 1,
|
|
63
71
|
"artifact": {}
|
|
72
|
+
}
|
|
64
73
|
}
|
|
74
|
+
```
|
|
65
75
|
"""
|
|
66
76
|
|
|
67
77
|
assertion_msg: str | None = None
|
|
68
78
|
msg: dict | None = None
|
|
69
79
|
artifact: dict = {}
|
|
70
|
-
attempt: int = 0
|
|
71
80
|
|
|
72
81
|
|
|
73
82
|
class ModuleStateStore(IBaseResult):
|
|
74
83
|
"""Test module description.
|
|
75
84
|
|
|
76
85
|
Example:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"
|
|
84
|
-
|
|
85
|
-
"
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
```
|
|
87
|
+
{
|
|
88
|
+
"test_2_b": {
|
|
89
|
+
"status": "passed",
|
|
90
|
+
"name": "Module 2",
|
|
91
|
+
"start_time": 1695816886,
|
|
92
|
+
"stop_time": 1695817016,
|
|
93
|
+
"cases": {
|
|
94
|
+
"test_one": {
|
|
95
|
+
"status": "passed",
|
|
96
|
+
"name": "Test 1",
|
|
97
|
+
"start_time": 1695817015,
|
|
98
|
+
"stop_time": 1695817016,
|
|
99
|
+
"assertion_msg": null,
|
|
100
|
+
"msg": null
|
|
101
|
+
}
|
|
90
102
|
}
|
|
91
103
|
}
|
|
92
104
|
}
|
|
105
|
+
```
|
|
93
106
|
"""
|
|
94
107
|
|
|
95
108
|
cases: dict[str, CaseStateStore] = {}
|
|
@@ -99,24 +112,28 @@ class ModuleRunStore(IBaseResult):
|
|
|
99
112
|
"""Test module description.
|
|
100
113
|
|
|
101
114
|
Example:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
"
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"
|
|
110
|
-
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
```
|
|
116
|
+
{
|
|
117
|
+
"test_2_b": {
|
|
118
|
+
"status": "passed",
|
|
119
|
+
"name": "Module 2",
|
|
120
|
+
"start_time": 1695816886,
|
|
121
|
+
"stop_time": 1695817016,
|
|
122
|
+
"artifact": {},
|
|
123
|
+
"cases": {
|
|
124
|
+
"test_one": {
|
|
125
|
+
"status": "passed",
|
|
126
|
+
"name": "Test 1",
|
|
127
|
+
"start_time": 1695817015,
|
|
128
|
+
"stop_time": 1695817016,
|
|
129
|
+
"assertion_msg": null,
|
|
130
|
+
"msg": null,
|
|
131
|
+
"artifact": {}
|
|
132
|
+
}
|
|
117
133
|
}
|
|
118
134
|
}
|
|
119
135
|
}
|
|
136
|
+
```
|
|
120
137
|
"""
|
|
121
138
|
|
|
122
139
|
cases: dict[str, CaseRunStore] = {}
|
|
@@ -127,14 +144,18 @@ class Dut(BaseModel):
|
|
|
127
144
|
"""Device under test description.
|
|
128
145
|
|
|
129
146
|
Example:
|
|
130
|
-
|
|
147
|
+
```
|
|
148
|
+
{
|
|
149
|
+
"dut": {
|
|
131
150
|
"serial_number": "a9ad8dca-2c64-4df8-a358-c21e832a32e4",
|
|
132
151
|
"part_number": "part_number_1",
|
|
133
152
|
"info": {
|
|
134
153
|
"batch": "test_batch",
|
|
135
154
|
"board_rev": "rev_1"
|
|
136
155
|
}
|
|
137
|
-
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
138
159
|
"""
|
|
139
160
|
|
|
140
161
|
model_config = ConfigDict(extra="forbid")
|
|
@@ -148,33 +169,48 @@ class TestStand(BaseModel):
|
|
|
148
169
|
"""Test stand description.
|
|
149
170
|
|
|
150
171
|
Example:
|
|
151
|
-
|
|
172
|
+
```
|
|
173
|
+
{
|
|
174
|
+
"test_stand": {
|
|
175
|
+
"hw_id": "840982098ca2459a7b22cc608eff65d4",
|
|
152
176
|
"name": "test_stand_1",
|
|
153
177
|
"info": {
|
|
154
|
-
"geo": "Belgrade"
|
|
155
|
-
}
|
|
156
|
-
|
|
178
|
+
"geo": "Belgrade"
|
|
179
|
+
},
|
|
180
|
+
"timezone": "Europe/Belgrade",
|
|
181
|
+
"drivers": {
|
|
182
|
+
"driver_1": "driver info",
|
|
183
|
+
"driver_2": {
|
|
184
|
+
"state": "active",
|
|
185
|
+
"port": 8000
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"location": "Belgrade_1"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
157
192
|
"""
|
|
158
193
|
|
|
159
194
|
model_config = ConfigDict(extra="forbid")
|
|
160
195
|
|
|
161
|
-
|
|
196
|
+
hw_id: str | None = None
|
|
197
|
+
name: str | None = None
|
|
198
|
+
timezone: str | None = None
|
|
199
|
+
drivers: dict = {}
|
|
162
200
|
info: dict = {}
|
|
201
|
+
location: str | None = None
|
|
163
202
|
|
|
164
203
|
|
|
165
204
|
class ResultStateStore(IBaseResult):
|
|
166
205
|
"""Test run description.
|
|
167
206
|
|
|
168
207
|
Example:
|
|
208
|
+
```
|
|
169
209
|
{
|
|
170
210
|
"_rev": "44867-3888ae85c19c428cc46685845953b483",
|
|
171
211
|
"_id": "current",
|
|
172
212
|
"progress": 100,
|
|
173
213
|
"stop_time": 1695817266,
|
|
174
|
-
"timezone": [
|
|
175
|
-
"CET",
|
|
176
|
-
"CET"
|
|
177
|
-
],
|
|
178
214
|
"start_time": 1695817263,
|
|
179
215
|
"status": "failed",
|
|
180
216
|
"name": "hardpy-stand",
|
|
@@ -187,15 +223,20 @@ class ResultStateStore(IBaseResult):
|
|
|
187
223
|
}
|
|
188
224
|
},
|
|
189
225
|
"test_stand": {
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
"
|
|
196
|
-
|
|
197
|
-
"
|
|
198
|
-
|
|
226
|
+
"hw_id": "840982098ca2459a7b22cc608eff65d4",
|
|
227
|
+
"name": "test_stand_1",
|
|
228
|
+
"info": {
|
|
229
|
+
"geo": "Belgrade"
|
|
230
|
+
},
|
|
231
|
+
"timezone": "Europe/Belgrade",
|
|
232
|
+
"drivers": {
|
|
233
|
+
"driver_1": "driver info",
|
|
234
|
+
"driver_2": {
|
|
235
|
+
"state": "active",
|
|
236
|
+
"port": 8000
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"location": "Belgrade_1"
|
|
199
240
|
},
|
|
200
241
|
"operator_msg": {
|
|
201
242
|
"msg": "Operator message",
|
|
@@ -238,11 +279,12 @@ class ResultStateStore(IBaseResult):
|
|
|
238
279
|
"msg": [
|
|
239
280
|
"Current minute 21"
|
|
240
281
|
]
|
|
241
|
-
}
|
|
282
|
+
}
|
|
242
283
|
}
|
|
243
|
-
}
|
|
284
|
+
}
|
|
244
285
|
}
|
|
245
286
|
}
|
|
287
|
+
```
|
|
246
288
|
"""
|
|
247
289
|
|
|
248
290
|
model_config = ConfigDict(extra="forbid")
|
|
@@ -250,11 +292,9 @@ class ResultStateStore(IBaseResult):
|
|
|
250
292
|
rev: str = Field(..., alias="_rev")
|
|
251
293
|
id: str = Field(..., alias="_id")
|
|
252
294
|
progress: int
|
|
253
|
-
timezone: tuple[str, str] | None = None
|
|
254
295
|
test_stand: TestStand
|
|
255
296
|
dut: Dut
|
|
256
297
|
modules: dict[str, ModuleStateStore] = {}
|
|
257
|
-
drivers: dict = {}
|
|
258
298
|
operator_msg: dict = {}
|
|
259
299
|
|
|
260
300
|
|
|
@@ -262,15 +302,11 @@ class ResultRunStore(IBaseResult):
|
|
|
262
302
|
"""Test run description.
|
|
263
303
|
|
|
264
304
|
Example:
|
|
305
|
+
```
|
|
265
306
|
{
|
|
266
307
|
"_rev": "44867-3888ae85c19c428cc46685845953b483",
|
|
267
308
|
"_id": "current",
|
|
268
|
-
"progress": 100,
|
|
269
309
|
"stop_time": 1695817266,
|
|
270
|
-
"timezone": [
|
|
271
|
-
"CET",
|
|
272
|
-
"CET"
|
|
273
|
-
],
|
|
274
310
|
"start_time": 1695817263,
|
|
275
311
|
"status": "failed",
|
|
276
312
|
"name": "hardpy-stand",
|
|
@@ -283,15 +319,20 @@ class ResultRunStore(IBaseResult):
|
|
|
283
319
|
}
|
|
284
320
|
},
|
|
285
321
|
"test_stand": {
|
|
286
|
-
"
|
|
287
|
-
"
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
"
|
|
292
|
-
|
|
293
|
-
"
|
|
294
|
-
|
|
322
|
+
"hw_id": "840982098ca2459a7b22cc608eff65d4",
|
|
323
|
+
"name": "test_stand_1",
|
|
324
|
+
"info": {
|
|
325
|
+
"geo": "Belgrade"
|
|
326
|
+
},
|
|
327
|
+
"timezone": "Europe/Belgrade",
|
|
328
|
+
"drivers": {
|
|
329
|
+
"driver_1": "driver info",
|
|
330
|
+
"driver_2": {
|
|
331
|
+
"state": "active",
|
|
332
|
+
"port": 8000
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
"location": "Belgrade_1"
|
|
295
336
|
},
|
|
296
337
|
"artifact": {},
|
|
297
338
|
"modules": {
|
|
@@ -309,7 +350,6 @@ class ResultRunStore(IBaseResult):
|
|
|
309
350
|
"stop_time": 1695817264,
|
|
310
351
|
"assertion_msg": null,
|
|
311
352
|
"msg": null,
|
|
312
|
-
"attempt": 1,
|
|
313
353
|
"artifact": {}
|
|
314
354
|
},
|
|
315
355
|
"test_minute_parity": {
|
|
@@ -321,7 +361,6 @@ class ResultRunStore(IBaseResult):
|
|
|
321
361
|
"msg": [
|
|
322
362
|
"Current minute 21"
|
|
323
363
|
],
|
|
324
|
-
"attempt": 1,
|
|
325
364
|
"artifact": {
|
|
326
365
|
"data_str": "123DATA",
|
|
327
366
|
"data_int": 12345,
|
|
@@ -329,21 +368,23 @@ class ResultRunStore(IBaseResult):
|
|
|
329
368
|
"test_key": "456DATA"
|
|
330
369
|
}
|
|
331
370
|
}
|
|
332
|
-
}
|
|
371
|
+
}
|
|
333
372
|
}
|
|
334
|
-
}
|
|
373
|
+
}
|
|
335
374
|
}
|
|
336
375
|
}
|
|
376
|
+
```
|
|
337
377
|
"""
|
|
338
378
|
|
|
339
379
|
model_config = ConfigDict(extra="forbid")
|
|
380
|
+
# Create the new schema class with version update
|
|
381
|
+
# when you change this class or fields in this class.
|
|
382
|
+
__version__: ClassVar[int] = 1
|
|
340
383
|
|
|
341
384
|
rev: str = Field(..., alias="_rev")
|
|
342
385
|
id: str = Field(..., alias="_id")
|
|
343
|
-
|
|
344
|
-
timezone: tuple[str, str] | None = None
|
|
386
|
+
|
|
345
387
|
test_stand: TestStand
|
|
346
388
|
dut: Dut
|
|
347
389
|
modules: dict[str, ModuleRunStore] = {}
|
|
348
|
-
drivers: dict = {}
|
|
349
390
|
artifact: dict = {}
|
|
@@ -3,28 +3,15 @@
|
|
|
3
3
|
|
|
4
4
|
from logging import getLogger
|
|
5
5
|
|
|
6
|
-
from pycouchdb.exceptions import Conflict, NotFound
|
|
7
|
-
|
|
8
6
|
from hardpy.pytest_hardpy.db.base_store import BaseStore
|
|
9
|
-
from hardpy.pytest_hardpy.db import ResultStateStore
|
|
10
|
-
from hardpy.pytest_hardpy.utils import
|
|
7
|
+
from hardpy.pytest_hardpy.db.schema import ResultStateStore
|
|
8
|
+
from hardpy.pytest_hardpy.utils import SingletonMeta
|
|
11
9
|
|
|
12
10
|
|
|
13
|
-
class StateStore(
|
|
11
|
+
class StateStore(BaseStore, metaclass=SingletonMeta):
|
|
14
12
|
"""HardPy state storage interface for CouchDB."""
|
|
15
13
|
|
|
16
|
-
def __init__(self):
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
self._schema = ResultStateStore
|
|
21
|
-
self._initialized = True
|
|
22
|
-
|
|
23
|
-
def clear(self):
|
|
24
|
-
"""Clear database."""
|
|
25
|
-
try:
|
|
26
|
-
# Clear the statestore database before each launch
|
|
27
|
-
self._db.delete(self._doc_id)
|
|
28
|
-
except (Conflict, NotFound):
|
|
29
|
-
self._log.debug("Statestore database will be created for the first time")
|
|
30
|
-
self._doc: dict = self._init_doc()
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
super().__init__("statestore")
|
|
16
|
+
self._log = getLogger(__name__)
|
|
17
|
+
self._schema = ResultStateStore
|