openmodule-test 14.2.0__tar.gz → 15.0.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.
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/PKG-INFO +13 -8
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/core.py +1 -3
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/database.py +8 -6
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/health.py +2 -4
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/interrupt.py +4 -4
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/io_simulator.py +7 -7
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/openmodule_test.egg-info/PKG-INFO +14 -9
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/openmodule_test.egg-info/SOURCES.txt +0 -4
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/package_reader.py +12 -13
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/presence.py +20 -19
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/rpc.py +14 -14
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/sentry.py +4 -5
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/settings.py +7 -7
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/setup.cfg +1 -2
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/signal_simulator.py +6 -6
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/utils.py +2 -2
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/zeromq.py +19 -17
- openmodule_test-14.2.0/AUTHORS +0 -11
- openmodule_test-14.2.0/ChangeLog +0 -217
- openmodule_test-14.2.0/openmodule_test.egg-info/pbr.json +0 -1
- openmodule_test-14.2.0/requirements.txt +0 -2
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/__init__.py +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/alert.py +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/connection_status.py +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/eventlistener.py +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/files.py +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/gate.py +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/openmodule_test.egg-info/dependency_links.txt +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/openmodule_test.egg-info/not-zip-safe +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/openmodule_test.egg-info/requires.txt +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/openmodule_test.egg-info/top_level.txt +0 -0
- {openmodule_test-14.2.0 → openmodule_test-15.0.0}/setup.py +0 -0
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: openmodule_test
|
|
3
|
-
Version:
|
|
3
|
+
Version: 15.0.0
|
|
4
4
|
Summary: Libraries for testing openmodule services
|
|
5
5
|
Home-page: https://gitlab.com/arivo-public/device-python/openmodule.git
|
|
6
6
|
Author: ARIVO
|
|
7
7
|
Author-email: support@arivo.co
|
|
8
8
|
License: GNU General Public License v2 (GPLv2)
|
|
9
9
|
Keywords: arivo openmodule openmodule_test test
|
|
10
|
-
Platform: UNKNOWN
|
|
11
10
|
Classifier: Intended Audience :: Developers
|
|
12
11
|
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
|
|
13
12
|
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Dist: multiprocessing_logging
|
|
15
|
+
Requires-Dist: freezegun
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: keywords
|
|
21
|
+
Dynamic: license
|
|
22
|
+
Dynamic: requires-dist
|
|
23
|
+
Dynamic: summary
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Dict
|
|
2
|
-
|
|
3
1
|
from openmodule.core import init_openmodule, shutdown_openmodule, OpenModuleCore
|
|
4
2
|
from openmodule_test.health import HealthTestMixin
|
|
5
3
|
|
|
@@ -9,7 +7,7 @@ class OpenModuleCoreTestMixin(HealthTestMixin):
|
|
|
9
7
|
Mixin which creates a core, zmq, and health mixin
|
|
10
8
|
"""
|
|
11
9
|
|
|
12
|
-
init_kwargs:
|
|
10
|
+
init_kwargs: dict = {}
|
|
13
11
|
core: OpenModuleCore
|
|
14
12
|
|
|
15
13
|
def get_init_kwargs(self):
|
|
@@ -5,7 +5,7 @@ from unittest import TestCase
|
|
|
5
5
|
|
|
6
6
|
from alembic import command
|
|
7
7
|
from alembic.runtime.migration import MigrationContext
|
|
8
|
-
from sqlalchemy import MetaData
|
|
8
|
+
from sqlalchemy import MetaData, text
|
|
9
9
|
from sqlalchemy.ext.automap import automap_base
|
|
10
10
|
|
|
11
11
|
from openmodule.config import settings
|
|
@@ -19,8 +19,8 @@ _first_start = True
|
|
|
19
19
|
|
|
20
20
|
def truncate_all_tables(database: Database, keep=("alembic_version",)):
|
|
21
21
|
assert any(x in database.db_folder for x in ["/test/"]), "deleting all tables is only for testing"
|
|
22
|
-
metadata = MetaData(
|
|
23
|
-
metadata.reflect()
|
|
22
|
+
metadata = MetaData()
|
|
23
|
+
metadata.reflect(bind=database._engine)
|
|
24
24
|
with database._engine.connect() as con:
|
|
25
25
|
trans = con.begin()
|
|
26
26
|
for table in reversed(metadata.sorted_tables):
|
|
@@ -123,7 +123,7 @@ class AlembicMigrationTestMixin(SQLiteTestMixin):
|
|
|
123
123
|
|
|
124
124
|
def reload_models(self):
|
|
125
125
|
self.base = automap_base()
|
|
126
|
-
self.base.prepare(self.connection
|
|
126
|
+
self.base.prepare(autoload_with=self.connection)
|
|
127
127
|
|
|
128
128
|
def alembic_config(self):
|
|
129
129
|
alembic_path = self.alembic_path or os.path.join(os.getcwd(), "database")
|
|
@@ -134,13 +134,15 @@ class AlembicMigrationTestMixin(SQLiteTestMixin):
|
|
|
134
134
|
def migrate_up(self, revision="head"):
|
|
135
135
|
config = self.alembic_config()
|
|
136
136
|
command.upgrade(config, revision)
|
|
137
|
-
|
|
137
|
+
with self.connection.connect() as connection:
|
|
138
|
+
assert connection.execute(text("PRAGMA foreign_keys")).fetchone()[0] == 1, "foreign keys are not enabled"
|
|
138
139
|
self.reload_models()
|
|
139
140
|
|
|
140
141
|
def migrate_down(self, revision="base"):
|
|
141
142
|
config = self.alembic_config()
|
|
142
143
|
command.downgrade(config, revision)
|
|
143
|
-
|
|
144
|
+
with self.connection.connect() as connection:
|
|
145
|
+
assert connection.execute(text("PRAGMA foreign_keys")).fetchone()[0] == 1, "foreign keys are not enabled"
|
|
144
146
|
self.reload_models()
|
|
145
147
|
|
|
146
148
|
def current_revision(self):
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
from openmodule_test.zeromq import ZMQTestMixin
|
|
4
2
|
|
|
5
3
|
|
|
@@ -10,7 +8,7 @@ def _get_health_filter(name):
|
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
class HealthTestMixin(ZMQTestMixin):
|
|
13
|
-
def get_health(self, name:
|
|
11
|
+
def get_health(self, name: str | None = None, timeout: float = 3):
|
|
14
12
|
self.assertSubscription("healthpong")
|
|
15
13
|
self.zmq_client.send("healthz", {"type": "ping", "ping": "ping"})
|
|
16
14
|
_, message = self.zmq_client.wait_for_message(
|
|
@@ -29,7 +27,7 @@ class HealthTestMixin(ZMQTestMixin):
|
|
|
29
27
|
pong = message.get("pong", {})
|
|
30
28
|
self.assertEqual("error", pong.get("status"))
|
|
31
29
|
|
|
32
|
-
def wait_for_health(self, name:
|
|
30
|
+
def wait_for_health(self, name: str | None = None):
|
|
33
31
|
"""
|
|
34
32
|
:param name: if specified the function waits for a specific service name on startup
|
|
35
33
|
"""
|
|
@@ -7,7 +7,7 @@ import traceback
|
|
|
7
7
|
from multiprocessing import Process, Event
|
|
8
8
|
from signal import SIGINT, SIGKILL
|
|
9
9
|
from textwrap import dedent
|
|
10
|
-
from typing import Callable
|
|
10
|
+
from typing import Callable
|
|
11
11
|
from unittest import TestCase
|
|
12
12
|
|
|
13
13
|
import multiprocessing_logging
|
|
@@ -76,7 +76,7 @@ class InterruptTestMixin(TestCase):
|
|
|
76
76
|
for usage, look at file tests/test_interrupt
|
|
77
77
|
"""
|
|
78
78
|
|
|
79
|
-
process:
|
|
79
|
+
process: ExceptionProcess | None = None
|
|
80
80
|
|
|
81
81
|
def _kill_process(self):
|
|
82
82
|
# this is called in tear down and as a cleanup to make sure that under any circumstances the process is killed
|
|
@@ -132,13 +132,13 @@ class InterruptTestMixin(TestCase):
|
|
|
132
132
|
else:
|
|
133
133
|
raise AssertionError("Process did not finish gracefully")
|
|
134
134
|
|
|
135
|
-
def send_signal_to_process(self, process: ExceptionProcess, signal:
|
|
135
|
+
def send_signal_to_process(self, process: ExceptionProcess, signal: type[KeyboardInterrupt] | int):
|
|
136
136
|
self.assertFalse(process.is_finished.is_set(), msg="process crashed before we could send the signal")
|
|
137
137
|
if signal == KeyboardInterrupt:
|
|
138
138
|
signal = SIGINT
|
|
139
139
|
os.kill(process.pid, signal)
|
|
140
140
|
|
|
141
|
-
def signal_in_function(self, f: Callable, signal:
|
|
141
|
+
def signal_in_function(self, f: Callable, signal: type[KeyboardInterrupt] | int, *,
|
|
142
142
|
raise_exception_after: float = 3.0, shutdown_timeout: float = 3.0):
|
|
143
143
|
"""
|
|
144
144
|
wraps the helper functions into a single function because apparently everybody likes
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
|
-
from
|
|
3
|
-
from typing import Callable, Dict, Optional
|
|
2
|
+
from typing import Callable
|
|
4
3
|
|
|
5
4
|
from openmodule.models.base import Gateway
|
|
6
5
|
from openmodule.models.io import IoMessage, IoState
|
|
6
|
+
from openmodule.utils.misc_functions import utcnow
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def generate_example_states(count:
|
|
9
|
+
def generate_example_states(count: int | None = 8) -> dict[str, IoState]:
|
|
10
10
|
"""
|
|
11
11
|
Creates a dict with pin as key and IoState as value.
|
|
12
12
|
param count: how many pins should be created.
|
|
@@ -14,13 +14,13 @@ def generate_example_states(count: Optional[int] = 8) -> Dict[str, IoState]:
|
|
|
14
14
|
Gateways with even x have direction in, odds have out.
|
|
15
15
|
All pins created low and not inverted.
|
|
16
16
|
"""
|
|
17
|
-
states:
|
|
17
|
+
states: dict[str, IoState] = defaultdict(IoState)
|
|
18
18
|
for i in range(count):
|
|
19
19
|
gate = int(i/4)
|
|
20
20
|
direction = "in" if gate % 2 == 0 else "out"
|
|
21
21
|
gateway = Gateway(gate="gate_{}".format(gate), direction=direction)
|
|
22
22
|
state = IoState(pin="", gateway=gateway, value=0, physical=0, inverted=False, type="input",
|
|
23
|
-
last_timestamp=
|
|
23
|
+
last_timestamp=utcnow())
|
|
24
24
|
if i % 4 == 0:
|
|
25
25
|
state.pin = "gate_{}_button".format(gate)
|
|
26
26
|
elif i % 4 == 1:
|
|
@@ -45,14 +45,14 @@ class IoSimulator:
|
|
|
45
45
|
There can be a race condition during init if the emitted messages have not yet been received by
|
|
46
46
|
an io handler. See tests.test_io_listen.IoTest's comment in setUp()
|
|
47
47
|
"""
|
|
48
|
-
def __init__(self, states:
|
|
48
|
+
def __init__(self, states: dict[str, IoState], emit: Callable[[IoMessage], None]):
|
|
49
49
|
self.pin_states = states
|
|
50
50
|
self.emit = emit
|
|
51
51
|
for state in self.pin_states.values():
|
|
52
52
|
self.emit(IoMessage(gateway=state.gateway, type=state.type, pin=state.pin, value=state.value,
|
|
53
53
|
inverted=state.inverted, physical=state.physical, edge=1))
|
|
54
54
|
|
|
55
|
-
def get_pin_states(self) ->
|
|
55
|
+
def get_pin_states(self) -> dict[str, IoState]:
|
|
56
56
|
return self.pin_states
|
|
57
57
|
|
|
58
58
|
def change_pin_sate(self, pin: str):
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name:
|
|
3
|
-
Version:
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openmodule_test
|
|
3
|
+
Version: 15.0.0
|
|
4
4
|
Summary: Libraries for testing openmodule services
|
|
5
5
|
Home-page: https://gitlab.com/arivo-public/device-python/openmodule.git
|
|
6
6
|
Author: ARIVO
|
|
7
7
|
Author-email: support@arivo.co
|
|
8
8
|
License: GNU General Public License v2 (GPLv2)
|
|
9
9
|
Keywords: arivo openmodule openmodule_test test
|
|
10
|
-
Platform: UNKNOWN
|
|
11
10
|
Classifier: Intended Audience :: Developers
|
|
12
11
|
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
|
|
13
12
|
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Dist: multiprocessing_logging
|
|
15
|
+
Requires-Dist: freezegun
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: keywords
|
|
21
|
+
Dynamic: license
|
|
22
|
+
Dynamic: requires-dist
|
|
23
|
+
Dynamic: summary
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
AUTHORS
|
|
2
|
-
ChangeLog
|
|
3
|
-
requirements.txt
|
|
4
1
|
setup.cfg
|
|
5
2
|
setup.py
|
|
6
3
|
./__init__.py
|
|
@@ -26,6 +23,5 @@ openmodule_test.egg-info/PKG-INFO
|
|
|
26
23
|
openmodule_test.egg-info/SOURCES.txt
|
|
27
24
|
openmodule_test.egg-info/dependency_links.txt
|
|
28
25
|
openmodule_test.egg-info/not-zip-safe
|
|
29
|
-
openmodule_test.egg-info/pbr.json
|
|
30
26
|
openmodule_test.egg-info/requires.txt
|
|
31
27
|
openmodule_test.egg-info/top_level.txt
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import random
|
|
3
|
-
from typing import Optional, Dict, List
|
|
4
3
|
|
|
5
4
|
from openmodule.utils.package_reader import ServiceSetting, PackageReader, PackageData
|
|
6
5
|
|
|
@@ -28,9 +27,9 @@ class FakeServiceRepo(dict):
|
|
|
28
27
|
self[settings.name] = settings
|
|
29
28
|
self._resolve_parents()
|
|
30
29
|
|
|
31
|
-
def add_hardware_package(self, name, env:
|
|
32
|
-
hardware_type:
|
|
33
|
-
revision:
|
|
30
|
+
def add_hardware_package(self, name, env: dict | None = None, yml: dict | None = None,
|
|
31
|
+
hardware_type: list[str] | None = None, ip: str | None = None,
|
|
32
|
+
revision: int | None = None, package_data: PackageData | None = None):
|
|
34
33
|
revision = revision or random.randint(0, 1000000000)
|
|
35
34
|
merged_yml = {}
|
|
36
35
|
if ip:
|
|
@@ -51,10 +50,10 @@ class FakeServiceRepo(dict):
|
|
|
51
50
|
self.add_package(ServiceSetting(env=merged_env, yml=merged_yml, name=name,
|
|
52
51
|
revision=revision, package_data=package_data))
|
|
53
52
|
|
|
54
|
-
def add_software_package(self, name, env:
|
|
55
|
-
parent_type:
|
|
56
|
-
parent:
|
|
57
|
-
software_type:
|
|
53
|
+
def add_software_package(self, name, env: dict | None = None, yml: dict | None = None,
|
|
54
|
+
parent_type: list[str] | None = None, revision: int | None = None,
|
|
55
|
+
parent: str | None = None, package_data: PackageData | None = None,
|
|
56
|
+
software_type: list[str] | None = None):
|
|
58
57
|
revision = revision or random.randint(0, 1000000000)
|
|
59
58
|
merged_env = {
|
|
60
59
|
"NAME": name,
|
|
@@ -83,10 +82,10 @@ class MockPackageReader(PackageReader):
|
|
|
83
82
|
|
|
84
83
|
self._services = FakeServiceRepo()
|
|
85
84
|
|
|
86
|
-
def get_service_by_name(self, service: str) ->
|
|
85
|
+
def get_service_by_name(self, service: str) -> ServiceSetting | None:
|
|
87
86
|
return self._services.get(service)
|
|
88
87
|
|
|
89
|
-
def list_all_services(self, prefix:
|
|
88
|
+
def list_all_services(self, prefix: str | None = None, compute_id: int | None = None) -> list[ServiceSetting]:
|
|
90
89
|
"""
|
|
91
90
|
:param compute_id: compute unit id, if None packages from all units are returned
|
|
92
91
|
:param prefix: prefix of the package id, if none is passed all are returned
|
|
@@ -98,7 +97,7 @@ class MockPackageReader(PackageReader):
|
|
|
98
97
|
(compute_id is None or (x.env.get("COMPUTE_ID") or '1') == compute_id_str)
|
|
99
98
|
]
|
|
100
99
|
|
|
101
|
-
def list_by_hardware_type(self, prefix: str, compute_id:
|
|
100
|
+
def list_by_hardware_type(self, prefix: str, compute_id: int | None = None):
|
|
102
101
|
"""
|
|
103
102
|
lists all packages with a certain hardware type (prefix). Note that these can only be hardware packages
|
|
104
103
|
i.e. their name starts with "hw_"
|
|
@@ -115,7 +114,7 @@ class MockPackageReader(PackageReader):
|
|
|
115
114
|
(compute_id is None or (x.env.get("COMPUTE_ID") or '1') == compute_id_str)
|
|
116
115
|
]
|
|
117
116
|
|
|
118
|
-
def list_by_parent_type(self, prefix: str, compute_id:
|
|
117
|
+
def list_by_parent_type(self, prefix: str, compute_id: int | None = None):
|
|
119
118
|
"""
|
|
120
119
|
lists all packages with a certain parent type (prefix). Note that these can only be software packages
|
|
121
120
|
i.e. their name starts with "om_"
|
|
@@ -132,7 +131,7 @@ class MockPackageReader(PackageReader):
|
|
|
132
131
|
(compute_id is None or (x.env.get("COMPUTE_ID") or '1') == compute_id_str)
|
|
133
132
|
]
|
|
134
133
|
|
|
135
|
-
def list_by_software_type(self, prefix: str, compute_id:
|
|
134
|
+
def list_by_software_type(self, prefix: str, compute_id: int | None = None):
|
|
136
135
|
"""
|
|
137
136
|
lists all packages with a certain software type (prefix). Note that these can only be software packages
|
|
138
137
|
i.e. their name starts with "om_"
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import random
|
|
2
2
|
import time
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Callable
|
|
5
5
|
|
|
6
6
|
from openmodule.models.base import Direction, Gateway, datetime_to_timestamp
|
|
7
7
|
from openmodule.models.presence import PresenceBaseMessage, PresenceEnterMessage, PresenceLeaveMessage, \
|
|
8
8
|
PresenceForwardMessage, PresenceBackwardMessage, PresenceMedia, PresenceChangeMessage
|
|
9
9
|
from openmodule.models.vehicle import LPRMedium, LPRCountry, Medium, Vehicle, MakeModel, PresenceAllIds, \
|
|
10
10
|
EnterDirection, QRMedium, MediumType
|
|
11
|
+
from openmodule.utils.misc_functions import utcnow
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class VehicleBuilder:
|
|
@@ -19,7 +20,7 @@ class VehicleBuilder:
|
|
|
19
20
|
self.medium = PresenceMedia()
|
|
20
21
|
self.make_model = MakeModel(make="UNKNOWN", make_confidence=0.7, model="UNKNOWN", model_confidence=-1.0)
|
|
21
22
|
self.enter_direction = EnterDirection.unknown
|
|
22
|
-
self.enter_time =
|
|
23
|
+
self.enter_time = utcnow()
|
|
23
24
|
self.leave_time = None
|
|
24
25
|
|
|
25
26
|
def vehicle(self) -> Vehicle:
|
|
@@ -39,7 +40,7 @@ class VehicleBuilder:
|
|
|
39
40
|
self.vehicle_id = id
|
|
40
41
|
return self
|
|
41
42
|
|
|
42
|
-
def lpr(self, country:
|
|
43
|
+
def lpr(self, country: str | None, plate: str | None = None, state="") -> 'VehicleBuilder':
|
|
43
44
|
if country is None:
|
|
44
45
|
self.medium.lpr = None
|
|
45
46
|
else:
|
|
@@ -49,21 +50,21 @@ class VehicleBuilder:
|
|
|
49
50
|
)
|
|
50
51
|
return self
|
|
51
52
|
|
|
52
|
-
def nfc(self, id:
|
|
53
|
+
def nfc(self, id: str | None) -> 'VehicleBuilder':
|
|
53
54
|
if id is None:
|
|
54
55
|
self.medium.nfc = id
|
|
55
56
|
else:
|
|
56
57
|
self.medium.nfc = Medium(id=id, type=MediumType.nfc)
|
|
57
58
|
return self
|
|
58
59
|
|
|
59
|
-
def qr(self, id:
|
|
60
|
+
def qr(self, id: str | None, binary: str | None = None) -> 'VehicleBuilder':
|
|
60
61
|
if id is None:
|
|
61
62
|
self.medium.qr = id
|
|
62
63
|
else:
|
|
63
64
|
self.medium.qr = QRMedium(id=id, binary=binary)
|
|
64
65
|
return self
|
|
65
66
|
|
|
66
|
-
def pin(self, id:
|
|
67
|
+
def pin(self, id: str | None) -> 'VehicleBuilder':
|
|
67
68
|
if id is None:
|
|
68
69
|
self.medium.pin = id
|
|
69
70
|
else:
|
|
@@ -88,10 +89,10 @@ class VehicleBuilder:
|
|
|
88
89
|
|
|
89
90
|
|
|
90
91
|
class PresenceSimulator:
|
|
91
|
-
current_present:
|
|
92
|
+
current_present: VehicleBuilder | None = None
|
|
92
93
|
|
|
93
94
|
def __init__(self, gate: str, direction: Direction, emit: Callable[[PresenceBaseMessage], None],
|
|
94
|
-
present_area_name:
|
|
95
|
+
present_area_name: str | None = None):
|
|
95
96
|
self.gateway = Gateway(gate=gate, direction=direction)
|
|
96
97
|
self.emit = emit
|
|
97
98
|
self.present_area_name = present_area_name or f"{self.gateway.gate}-present"
|
|
@@ -100,7 +101,7 @@ class PresenceSimulator:
|
|
|
100
101
|
return VehicleBuilder()
|
|
101
102
|
|
|
102
103
|
def _common_kwargs(self, vehicle):
|
|
103
|
-
timestamp = datetime_to_timestamp(
|
|
104
|
+
timestamp = datetime_to_timestamp(utcnow())
|
|
104
105
|
all_ids = PresenceAllIds(lpr=None if vehicle.medium.lpr is None else [vehicle.medium.lpr],
|
|
105
106
|
qr=None if vehicle.medium.qr is None else [vehicle.medium.qr],
|
|
106
107
|
nfc=None if vehicle.medium.nfc is None else [vehicle.medium.nfc],
|
|
@@ -120,45 +121,45 @@ class PresenceSimulator:
|
|
|
120
121
|
"leave_time": vehicle.leave_time
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
def enter(self, vehicle: VehicleBuilder, enter_time:
|
|
124
|
+
def enter(self, vehicle: VehicleBuilder, enter_time: datetime | None = None):
|
|
124
125
|
vehicle.enter_time = enter_time or vehicle.enter_time
|
|
125
126
|
if self.current_present:
|
|
126
127
|
self.leave()
|
|
127
128
|
self.current_present = vehicle
|
|
128
129
|
self.emit(PresenceEnterMessage(**self._common_kwargs(vehicle)))
|
|
129
130
|
|
|
130
|
-
def enter_without_dropping_present_vehicle(self, vehicle: VehicleBuilder, enter_time:
|
|
131
|
+
def enter_without_dropping_present_vehicle(self, vehicle: VehicleBuilder, enter_time: datetime | None = None):
|
|
131
132
|
vehicle.enter_time = enter_time or vehicle.enter_time
|
|
132
133
|
self.current_present = vehicle
|
|
133
134
|
self.emit(PresenceEnterMessage(**self._common_kwargs(vehicle)))
|
|
134
135
|
|
|
135
|
-
def leave(self, leave_time:
|
|
136
|
-
self.current_present.leave_time = leave_time or self.current_present.leave_time or
|
|
136
|
+
def leave(self, leave_time: datetime | None = None) -> VehicleBuilder:
|
|
137
|
+
self.current_present.leave_time = leave_time or self.current_present.leave_time or utcnow()
|
|
137
138
|
self.emit(PresenceLeaveMessage(**self._common_kwargs(self.current_present)))
|
|
138
139
|
temp = self.current_present
|
|
139
140
|
self.current_present = None
|
|
140
141
|
return temp
|
|
141
142
|
|
|
142
|
-
def leave_without_present(self, vehicle: VehicleBuilder, leave_time:
|
|
143
|
-
vehicle.leave_time = leave_time or vehicle.leave_time or
|
|
143
|
+
def leave_without_present(self, vehicle: VehicleBuilder, leave_time: datetime | None = None):
|
|
144
|
+
vehicle.leave_time = leave_time or vehicle.leave_time or utcnow()
|
|
144
145
|
self.emit(PresenceLeaveMessage(**self._common_kwargs(vehicle)))
|
|
145
146
|
|
|
146
|
-
def forward(self, vehicle:
|
|
147
|
+
def forward(self, vehicle: VehicleBuilder | None = None):
|
|
147
148
|
assert vehicle or self.current_present, "a vehicle must be present, or you have to pass a vehicle"
|
|
148
149
|
if not vehicle:
|
|
149
150
|
vehicle = self.leave()
|
|
150
151
|
if vehicle.leave_time is None: # if leave was not called for this vehicle
|
|
151
|
-
vehicle.leave_time =
|
|
152
|
+
vehicle.leave_time = utcnow()
|
|
152
153
|
self.emit(PresenceForwardMessage(
|
|
153
154
|
**self._common_kwargs(vehicle)
|
|
154
155
|
))
|
|
155
156
|
|
|
156
|
-
def backward(self, vehicle:
|
|
157
|
+
def backward(self, vehicle: VehicleBuilder | None = None):
|
|
157
158
|
assert vehicle or self.current_present, "a vehicle must be present, or you have to pass a vehicle"
|
|
158
159
|
if not vehicle:
|
|
159
160
|
vehicle = self.leave()
|
|
160
161
|
if vehicle.leave_time is None: # if leave was not called for this vehicle
|
|
161
|
-
vehicle.leave_time =
|
|
162
|
+
vehicle.leave_time = utcnow()
|
|
162
163
|
self.emit(PresenceBackwardMessage(
|
|
163
164
|
**self._common_kwargs(vehicle)
|
|
164
165
|
))
|
|
@@ -3,7 +3,7 @@ import string
|
|
|
3
3
|
import threading
|
|
4
4
|
import time
|
|
5
5
|
from functools import partial
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Any, Callable
|
|
7
7
|
|
|
8
8
|
from pydantic.main import BaseModel
|
|
9
9
|
|
|
@@ -18,7 +18,7 @@ class _EmptyModel(BaseModel):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class RPCServerTestMixin(ZMQTestMixin):
|
|
21
|
-
def wait_for_rpc_response(self, channel: str, type: str, request: BaseModel, response_type:
|
|
21
|
+
def wait_for_rpc_response(self, channel: str, type: str, request: BaseModel, response_type: type[OpenModuleModel]):
|
|
22
22
|
"""
|
|
23
23
|
waits until a rpc server is responding to the channel/type
|
|
24
24
|
"""
|
|
@@ -67,21 +67,21 @@ class MockRPCEntry(RPCClient.RPCEntry):
|
|
|
67
67
|
def _run_callback(self):
|
|
68
68
|
try:
|
|
69
69
|
res = self.callback()
|
|
70
|
-
self.response = {"status": "ok", **(res if isinstance(res, dict) else res.
|
|
70
|
+
self.response = {"status": "ok", **(res if isinstance(res, dict) else res.model_dump())}
|
|
71
71
|
except Exception:
|
|
72
|
-
self.response = RPCErrorResult(status=RPCServerError.handler_error).
|
|
72
|
+
self.response = RPCErrorResult(status=RPCServerError.handler_error).model_dump()
|
|
73
73
|
self.ready.set()
|
|
74
74
|
|
|
75
|
-
def result(self, response_type:
|
|
75
|
+
def result(self, response_type: type[OpenModuleModel], timeout=None):
|
|
76
76
|
thread = threading.Thread(target=self._run_callback, daemon=True)
|
|
77
77
|
thread.start()
|
|
78
78
|
return super().result(response_type, timeout)
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
class MockRPCClient:
|
|
82
|
-
def __init__(self, callbacks:
|
|
83
|
-
responses:
|
|
84
|
-
immediate_callbacks:
|
|
82
|
+
def __init__(self, callbacks: dict[tuple[str, str], Callable[[OpenModuleModel, Any], Any]] | None = None,
|
|
83
|
+
responses: dict[tuple[str, str], Any] | None = None,
|
|
84
|
+
immediate_callbacks: dict[tuple[str, str], Callable[[OpenModuleModel, Any], Any]] | None = None,
|
|
85
85
|
default_timeout=1.0):
|
|
86
86
|
"""
|
|
87
87
|
:param callbacks: callback functions executed on rpc_entry.result()
|
|
@@ -95,7 +95,7 @@ class MockRPCClient:
|
|
|
95
95
|
self.last_request = {}
|
|
96
96
|
self.default_timeout = default_timeout
|
|
97
97
|
|
|
98
|
-
def rpc_non_blocking(self, channel: str, type: str, request:
|
|
98
|
+
def rpc_non_blocking(self, channel: str, type: str, request: dict | BaseModel, timeout: float | None = None) \
|
|
99
99
|
-> RPCClient.RPCEntry:
|
|
100
100
|
self.last_request[(channel, type)] = request
|
|
101
101
|
if timeout is None:
|
|
@@ -103,17 +103,17 @@ class MockRPCClient:
|
|
|
103
103
|
if (channel, type) in self.callbacks:
|
|
104
104
|
entry = MockRPCEntry(timeout, partial(self.callbacks[(channel, type)], request, None))
|
|
105
105
|
elif (channel, type) in self.immediate_callbacks:
|
|
106
|
-
res = self.immediate_callbacks[(channel, type)](request, None).
|
|
106
|
+
res = self.immediate_callbacks[(channel, type)](request, None).model_dump()
|
|
107
107
|
entry = RPCClient.RPCEntry(timeout)
|
|
108
|
-
entry.response = {"status": "ok", **(res if isinstance(res, dict) else res.
|
|
108
|
+
entry.response = {"status": "ok", **(res if isinstance(res, dict) else res.model_dump())}
|
|
109
109
|
else:
|
|
110
110
|
entry = RPCClient.RPCEntry(timeout)
|
|
111
111
|
if (channel, type) in self.responses:
|
|
112
|
-
res = self.responses.get((channel, type)).
|
|
113
|
-
entry.response = {"status": "ok", **(res if isinstance(res, dict) else res.
|
|
112
|
+
res = self.responses.get((channel, type)).model_dump()
|
|
113
|
+
entry.response = {"status": "ok", **(res if isinstance(res, dict) else res.model_dump())}
|
|
114
114
|
return entry
|
|
115
115
|
|
|
116
|
-
def rpc(self, channel: str, type: str, request:
|
|
116
|
+
def rpc(self, channel: str, type: str, request: dict | BaseModel, response_type: type[OpenModuleModel],
|
|
117
117
|
timeout: float = None) -> OpenModuleModel:
|
|
118
118
|
entry = self.rpc_non_blocking(channel, type, request, timeout)
|
|
119
119
|
return entry.result(response_type, timeout=timeout)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import threading
|
|
2
|
-
from typing import List
|
|
3
2
|
from unittest import TestCase, mock
|
|
4
3
|
|
|
5
4
|
import sentry_sdk
|
|
@@ -16,14 +15,14 @@ class SentryTestTransport(sentry_sdk.transport.Transport):
|
|
|
16
15
|
|
|
17
16
|
def __init__(self, options=None):
|
|
18
17
|
super().__init__(options)
|
|
19
|
-
self.envelopes:
|
|
18
|
+
self.envelopes: list[Envelope] = []
|
|
20
19
|
self.envelopes_lock = threading.Lock()
|
|
21
20
|
|
|
22
21
|
def capture_envelope(self, envelope: Envelope):
|
|
23
22
|
with self.envelopes_lock:
|
|
24
23
|
self.envelopes.append(envelope)
|
|
25
24
|
|
|
26
|
-
def get_envelopes(self, clear: bool = True) ->
|
|
25
|
+
def get_envelopes(self, clear: bool = True) -> list[Envelope]:
|
|
27
26
|
with self.envelopes_lock:
|
|
28
27
|
envelopes = self.envelopes
|
|
29
28
|
if clear:
|
|
@@ -59,9 +58,9 @@ class SentryTestMixin(TestCase):
|
|
|
59
58
|
self.assertIsInstance(transport, SentryTestTransport)
|
|
60
59
|
return transport
|
|
61
60
|
|
|
62
|
-
def _get_envelopes(self) ->
|
|
61
|
+
def _get_envelopes(self) -> list[Envelope]:
|
|
63
62
|
return self.sentry_transport.get_envelopes(clear=False)
|
|
64
63
|
|
|
65
|
-
def get_sent_envelopes(self, timeout: float = 0, clear: bool = True) ->
|
|
64
|
+
def get_sent_envelopes(self, timeout: float = 0, clear: bool = True) -> list[Envelope]:
|
|
66
65
|
wait_for_value(self._get_envelopes, target=[], invert_target=True, timeout=timeout)
|
|
67
66
|
return self.sentry_transport.get_envelopes(clear=clear)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import time
|
|
2
|
-
from enum import
|
|
3
|
-
from typing import
|
|
2
|
+
from enum import StrEnum
|
|
3
|
+
from typing import Any, TypeVar
|
|
4
4
|
|
|
5
5
|
from settings_models import serialization
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@ class SettingsMocker:
|
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
22
|
# noinspection PyMissingConstructor
|
|
23
|
-
def __init__(self, settings:
|
|
23
|
+
def __init__(self, settings: dict[tuple[str, str], Any],
|
|
24
24
|
allow_unknown_settings: bool = False, allow_wrong_values: bool = False):
|
|
25
25
|
if not allow_unknown_settings:
|
|
26
26
|
for setting in settings:
|
|
@@ -32,7 +32,7 @@ class SettingsMocker:
|
|
|
32
32
|
self.settings = settings
|
|
33
33
|
self.exception = None
|
|
34
34
|
|
|
35
|
-
def get(self, key: str, scope: str = "", custom_type:
|
|
35
|
+
def get(self, key: str, scope: str = "", custom_type: type[T] | None = None) -> T | None:
|
|
36
36
|
if self.exception:
|
|
37
37
|
raise self.exception
|
|
38
38
|
value = self.settings.get((key, scope))
|
|
@@ -43,7 +43,7 @@ class SettingsMocker:
|
|
|
43
43
|
except Exception:
|
|
44
44
|
return None
|
|
45
45
|
|
|
46
|
-
def get_many(self, keys_with_types:
|
|
46
|
+
def get_many(self, keys_with_types: dict[str, type[T]], scope: str = "") -> dict[str, T]:
|
|
47
47
|
if self.exception:
|
|
48
48
|
raise self.exception
|
|
49
49
|
else:
|
|
@@ -69,14 +69,14 @@ class SettingsRPCMocker:
|
|
|
69
69
|
use result_mode to simulate errors
|
|
70
70
|
"""
|
|
71
71
|
|
|
72
|
-
class ResultMode(
|
|
72
|
+
class ResultMode(StrEnum):
|
|
73
73
|
ok = "ok" # successful
|
|
74
74
|
error = "error" # raise error in callback
|
|
75
75
|
timeout = "timeout" # sleep in callback for 1 second
|
|
76
76
|
fail = "fail" # return success false
|
|
77
77
|
first_fail = "first_fail" # return success false for first in get_many
|
|
78
78
|
|
|
79
|
-
def __init__(self, rpc_server: RPCServer, settings:
|
|
79
|
+
def __init__(self, rpc_server: RPCServer, settings: dict[tuple[str, str], Any],
|
|
80
80
|
allow_unknown_settings: bool = False, allow_wrong_values: bool = False):
|
|
81
81
|
if not allow_unknown_settings:
|
|
82
82
|
for setting in settings:
|
|
@@ -10,8 +10,7 @@ classifier =
|
|
|
10
10
|
Intended Audience :: Developers
|
|
11
11
|
License :: OSI Approved :: GNU General Public License v2 (GPLv2)
|
|
12
12
|
Programming Language :: Python
|
|
13
|
-
Programming Language :: Python :: 3.
|
|
14
|
-
Programming Language :: Python :: 3.8
|
|
13
|
+
Programming Language :: Python :: 3.12
|
|
15
14
|
|
|
16
15
|
[bdist_wheel]
|
|
17
16
|
universal = 1
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Callable
|
|
1
|
+
from typing import Callable
|
|
2
2
|
|
|
3
3
|
from openmodule.models.signals import SignalMessage, TriggerSignalsRequest, TriggerSignalsResponse, \
|
|
4
4
|
GetSignalValueRequest, GetSignalValueResponse, SignalType
|
|
@@ -10,15 +10,15 @@ class SignalSimulator:
|
|
|
10
10
|
self.emit = emit
|
|
11
11
|
self._signals = {}
|
|
12
12
|
|
|
13
|
-
def add_signal(self, value: bool, additional_data:
|
|
14
|
-
gate:
|
|
15
|
-
signal_name:
|
|
13
|
+
def add_signal(self, value: bool, additional_data: dict | None, signal_type: SignalType,
|
|
14
|
+
gate: str | None = None, parking_area_id: str | None = None,
|
|
15
|
+
signal_name: str | None = None):
|
|
16
16
|
if signal_type == SignalType.custom:
|
|
17
17
|
assert signal_name is not None
|
|
18
18
|
signal_msg = SignalMessage(signal=signal_name, type=signal_type, gate=gate, parking_area_id=parking_area_id,
|
|
19
19
|
value=value, additional_data=additional_data)
|
|
20
20
|
elif signal_type == SignalType.parkinglot_full:
|
|
21
|
-
signal_name =
|
|
21
|
+
signal_name = signal_type.value
|
|
22
22
|
signal_msg = SignalMessage(signal=signal_name, type=signal_type,
|
|
23
23
|
value=value, additional_data=additional_data)
|
|
24
24
|
elif signal_type == SignalType.area_full:
|
|
@@ -36,7 +36,7 @@ class SignalSimulator:
|
|
|
36
36
|
def remove_signal(self, signal: str):
|
|
37
37
|
self._signals.pop(signal, None)
|
|
38
38
|
|
|
39
|
-
def set_signal(self, signal: str, value: bool, additional_data:
|
|
39
|
+
def set_signal(self, signal: str, value: bool, additional_data: dict | None = None):
|
|
40
40
|
self._signals[signal].value = value
|
|
41
41
|
self._signals[signal].additional_data = additional_data
|
|
42
42
|
self.emit(self._signals[signal])
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import time
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Callable, TypeVar
|
|
3
3
|
|
|
4
4
|
T = TypeVar("T")
|
|
5
5
|
NoTarget = object()
|
|
@@ -16,7 +16,7 @@ class DeveloperError(Exception):
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def wait_for_value(getter: Callable[[],
|
|
19
|
+
def wait_for_value(getter: Callable[[], T | None], target: T | None = NoTarget, invert_target: bool = False,
|
|
20
20
|
timeout: float = 3, sleep_time: float = 0.01) -> T:
|
|
21
21
|
"""
|
|
22
22
|
Waits until the getter returns the target value or the target value.
|
|
@@ -10,8 +10,8 @@ import types
|
|
|
10
10
|
import warnings
|
|
11
11
|
from _weakrefset import WeakSet
|
|
12
12
|
from contextlib import closing
|
|
13
|
-
from enum import
|
|
14
|
-
from typing import
|
|
13
|
+
from enum import StrEnum
|
|
14
|
+
from typing import Callable
|
|
15
15
|
from unittest import TestCase
|
|
16
16
|
from uuid import uuid4, UUID
|
|
17
17
|
|
|
@@ -141,7 +141,7 @@ class TestClient(threading.Thread):
|
|
|
141
141
|
|
|
142
142
|
_command_topic: str
|
|
143
143
|
subscribed_topics: set
|
|
144
|
-
pending_topics:
|
|
144
|
+
pending_topics: dict[str, None]
|
|
145
145
|
zmq_dispatcher: SubscribingMessageDispatcher
|
|
146
146
|
|
|
147
147
|
pub: zmq.Socket = None
|
|
@@ -251,7 +251,7 @@ class TestClient(threading.Thread):
|
|
|
251
251
|
|
|
252
252
|
if isinstance(_message, BaseModel):
|
|
253
253
|
with self.send_lock:
|
|
254
|
-
self.pub.send_multipart((topic.encode("utf8"), orjson.dumps(_message.
|
|
254
|
+
self.pub.send_multipart((topic.encode("utf8"), orjson.dumps(_message.model_dump())))
|
|
255
255
|
else:
|
|
256
256
|
assert not (_message and kwargs), (
|
|
257
257
|
"pass the message dict as the first parameter, or use the kwargs, not both"
|
|
@@ -270,7 +270,7 @@ class TestClient(threading.Thread):
|
|
|
270
270
|
self.has_messages.clear()
|
|
271
271
|
return msg
|
|
272
272
|
|
|
273
|
-
def wait_for_message(self, filter: Callable[[str, dict], bool], timeout=3) ->
|
|
273
|
+
def wait_for_message(self, filter: Callable[[str, dict], bool], timeout=3) -> tuple[str, dict]:
|
|
274
274
|
"""
|
|
275
275
|
:param filter: filter function of type (topic: str, message: dict) -> bool
|
|
276
276
|
:return: tuple containing [topic, message]
|
|
@@ -323,7 +323,7 @@ class TestClient(threading.Thread):
|
|
|
323
323
|
self.join()
|
|
324
324
|
|
|
325
325
|
|
|
326
|
-
def fake_config(broker:
|
|
326
|
+
def fake_config(broker: TestBroker | None = None, **kwargs):
|
|
327
327
|
result = {
|
|
328
328
|
"NAME": "test",
|
|
329
329
|
"RESOURCE": "test-resource",
|
|
@@ -357,11 +357,11 @@ class _TestRPCRequest(BaseModel):
|
|
|
357
357
|
we do not want to depend on openmodule, this is a minimal version of the zmq message for the rpc function
|
|
358
358
|
"""
|
|
359
359
|
timestamp: float = Field(default_factory=time.time)
|
|
360
|
-
resource:
|
|
360
|
+
resource: str | None = None
|
|
361
361
|
name: str
|
|
362
362
|
type: str
|
|
363
363
|
rpc_id: UUID
|
|
364
|
-
request:
|
|
364
|
+
request: dict | None = None
|
|
365
365
|
|
|
366
366
|
def __init__(self, **kwargs):
|
|
367
367
|
resource = kwargs.pop("resource")
|
|
@@ -372,14 +372,14 @@ class _TestRPCRequest(BaseModel):
|
|
|
372
372
|
super().__init__(resource=resource, **kwargs)
|
|
373
373
|
|
|
374
374
|
|
|
375
|
-
class ZMQProcotol(
|
|
375
|
+
class ZMQProcotol(StrEnum):
|
|
376
376
|
inproc = "inproc://"
|
|
377
377
|
tcp = "tcp://"
|
|
378
378
|
|
|
379
379
|
|
|
380
380
|
class ZMQTestMixin(TestCase):
|
|
381
|
-
topics:
|
|
382
|
-
rpc_channels:
|
|
381
|
+
topics: list[str] = []
|
|
382
|
+
rpc_channels: list[str] = []
|
|
383
383
|
protocol: ZMQProcotol = "inproc://"
|
|
384
384
|
|
|
385
385
|
zmq_broker: TestBroker = None
|
|
@@ -433,7 +433,7 @@ class ZMQTestMixin(TestCase):
|
|
|
433
433
|
and if it is connected, all previous subscriptions will also be connected
|
|
434
434
|
"""
|
|
435
435
|
random_topic = "_test" + "".join(random.choices(string.ascii_letters, k=10))
|
|
436
|
-
dispatcher.register_handler(random_topic,
|
|
436
|
+
dispatcher.register_handler(random_topic, OpenModuleModel, handler, register_schema=False, match_type=False)
|
|
437
437
|
|
|
438
438
|
for _ in range(self.zmq_client.startup_check_iterations):
|
|
439
439
|
self.zmq_client.send(random_topic, {"type": "connection-check"})
|
|
@@ -471,25 +471,27 @@ class ZMQTestMixin(TestCase):
|
|
|
471
471
|
super(ZMQTestMixin, self).tearDown()
|
|
472
472
|
Schema.to_file()
|
|
473
473
|
|
|
474
|
-
def rpc(self, channel: str, type: str, request, response_type:
|
|
475
|
-
->
|
|
474
|
+
def rpc(self, channel: str, type: str, request, response_type: type[OpenModuleModel], timeout=3, resource=None) \
|
|
475
|
+
-> str | OpenModuleModel:
|
|
476
476
|
"""
|
|
477
477
|
:return: the rpc response as parsed model
|
|
478
478
|
"""
|
|
479
479
|
rpc_id = self.rpc_no_response(channel, type, request, resource)
|
|
480
480
|
return self.receive_rpc_response(channel, rpc_id, response_type, timeout=timeout)
|
|
481
481
|
|
|
482
|
-
def rpc_no_response(self, channel: str,
|
|
482
|
+
def rpc_no_response(self, channel: str, type_: str, request, resource=None):
|
|
483
483
|
"""
|
|
484
484
|
:return: the rpc id, which can be used with `receive_rpc` to receive the response async
|
|
485
485
|
"""
|
|
486
486
|
rpc_id = str(uuid4())
|
|
487
|
-
|
|
487
|
+
if isinstance(request, BaseModel):
|
|
488
|
+
request = request.model_dump()
|
|
489
|
+
rpc_request = _TestRPCRequest(name="testclient", type=type_, rpc_id=rpc_id,
|
|
488
490
|
resource=resource, request=request)
|
|
489
491
|
self.zmq_client.send(f"rpc-req-{channel}", rpc_request)
|
|
490
492
|
return rpc_id
|
|
491
493
|
|
|
492
|
-
def receive_rpc_response(self, channel: str, rpc_id: str, response_type:
|
|
494
|
+
def receive_rpc_response(self, channel: str, rpc_id: str, response_type: type[OpenModuleModel], timeout=3) \
|
|
493
495
|
-> OpenModuleModel:
|
|
494
496
|
response_topic = f"rpc-rep-{channel}"
|
|
495
497
|
if response_topic not in self.zmq_client.subscribed_topics:
|
openmodule_test-14.2.0/AUTHORS
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
Bernhard Lippe <b.lippe@arivo.co>
|
|
2
|
-
Kevin Koller <k.koller@accessio.at>
|
|
3
|
-
Kevin Koller <k.koller@arivo.co>
|
|
4
|
-
Matthias Mietschnig <m.mietschnig@arivo.co>
|
|
5
|
-
Maximilian Bialek <m.bialek@arivo.co>
|
|
6
|
-
Philipp Reitter <i@philipp.ninja>
|
|
7
|
-
Philipp Reitter <p.reitter@accessio.at>
|
|
8
|
-
Philipp Reitter <p.reitter@gmail.com>
|
|
9
|
-
Stefan Bräuer <s.braeuer@arivo.co>
|
|
10
|
-
Thomas Senfter <t.senfter@accessio.at>
|
|
11
|
-
Thomas Senfter <t.senfter@arivo.co>
|
openmodule_test-14.2.0/ChangeLog
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
CHANGES
|
|
2
|
-
=======
|
|
3
|
-
|
|
4
|
-
v14.2.0
|
|
5
|
-
-------
|
|
6
|
-
|
|
7
|
-
* OM-1001: CostEntryData from settings models, added valid\_from and valid\_to to AccessCheckAccess and type hints for io/signals and io/inputs settings
|
|
8
|
-
* docs
|
|
9
|
-
* fixed testcase
|
|
10
|
-
* maybe fixing openmodule\_test
|
|
11
|
-
|
|
12
|
-
v14.2.0.rc0
|
|
13
|
-
-----------
|
|
14
|
-
|
|
15
|
-
* improvements for signal simulator
|
|
16
|
-
* test util for signals
|
|
17
|
-
* fixed testcase
|
|
18
|
-
* added SignalListener
|
|
19
|
-
|
|
20
|
-
v14.1.1
|
|
21
|
-
-------
|
|
22
|
-
|
|
23
|
-
* OM-1000: added --library flag for openmodule commands so "\_\_READABLE\_NAME" and "\_\_DESCRIPTION" are not added there
|
|
24
|
-
|
|
25
|
-
v14.1.0
|
|
26
|
-
-------
|
|
27
|
-
|
|
28
|
-
* newer settings-models (non-breaking)
|
|
29
|
-
* OM-901 Python 12 Support
|
|
30
|
-
|
|
31
|
-
v14.0.4
|
|
32
|
-
-------
|
|
33
|
-
|
|
34
|
-
* OM-945 Fix Trace parent in ZMQMessage
|
|
35
|
-
|
|
36
|
-
v14.0.3
|
|
37
|
-
-------
|
|
38
|
-
|
|
39
|
-
* OM-941 Sentry Bugfix
|
|
40
|
-
|
|
41
|
-
v14.0.2
|
|
42
|
-
-------
|
|
43
|
-
|
|
44
|
-
* Sentry improvements
|
|
45
|
-
|
|
46
|
-
v14.0.1
|
|
47
|
-
-------
|
|
48
|
-
|
|
49
|
-
* fixed sentry release name
|
|
50
|
-
|
|
51
|
-
v14.0.0
|
|
52
|
-
-------
|
|
53
|
-
|
|
54
|
-
* Add breaking changes to docs
|
|
55
|
-
* OM-693 Openmodule sentry v2
|
|
56
|
-
* Update known\_issues.md [skip ci]
|
|
57
|
-
|
|
58
|
-
v13.6.0
|
|
59
|
-
-------
|
|
60
|
-
|
|
61
|
-
* OM-697 OpenModule Verbesserungen
|
|
62
|
-
|
|
63
|
-
v13.5.0
|
|
64
|
-
-------
|
|
65
|
-
|
|
66
|
-
* document breaking changes
|
|
67
|
-
* OM-405: remove database imports from non-database services + isolate migration process to exclude alembic import in the main process
|
|
68
|
-
|
|
69
|
-
v13.4.0
|
|
70
|
-
-------
|
|
71
|
-
|
|
72
|
-
* Om 164: settings-models update for enforcment settings changes
|
|
73
|
-
|
|
74
|
-
v13.3.0
|
|
75
|
-
-------
|
|
76
|
-
|
|
77
|
-
* [OM-359] cleanup helper function
|
|
78
|
-
|
|
79
|
-
v13.2.0
|
|
80
|
-
-------
|
|
81
|
-
|
|
82
|
-
* OM 187 Alembic migration test mixin
|
|
83
|
-
* add a testcase for expiring session data while adding new models (noticed in OM-327)
|
|
84
|
-
* OM-184 Openmodule Database: Migration Backups and Fix in Operations "pre\_downgrade()" and "post\_downgrade()"
|
|
85
|
-
* Aktualisierung der Dokumentation
|
|
86
|
-
* OM-255
|
|
87
|
-
|
|
88
|
-
v13.1.4
|
|
89
|
-
-------
|
|
90
|
-
|
|
91
|
-
* fixed missing leave time in got better vehicle fake leave
|
|
92
|
-
|
|
93
|
-
v13.1.3
|
|
94
|
-
-------
|
|
95
|
-
|
|
96
|
-
* [OM-134] small changes in AccessCheck Models
|
|
97
|
-
|
|
98
|
-
v13.1.2
|
|
99
|
-
-------
|
|
100
|
-
|
|
101
|
-
* [OM-117] fixed error output on RPCs not sent by this RPCClient
|
|
102
|
-
|
|
103
|
-
v13.1.1
|
|
104
|
-
-------
|
|
105
|
-
|
|
106
|
-
* fixed bugs in edge cases in PresenceListener
|
|
107
|
-
|
|
108
|
-
v13.1.0
|
|
109
|
-
-------
|
|
110
|
-
|
|
111
|
-
* fixed testcase race condition
|
|
112
|
-
* improvements for PresenceSimulator and new commit to fix pipeline
|
|
113
|
-
|
|
114
|
-
v13.1.0.rc1
|
|
115
|
-
-----------
|
|
116
|
-
|
|
117
|
-
* settings model update
|
|
118
|
-
|
|
119
|
-
v13.1.0.rc0
|
|
120
|
-
-----------
|
|
121
|
-
|
|
122
|
-
* OM-61 Openmodule Anpassungen für Access Events
|
|
123
|
-
* [OM-56] added enter\_time and leave\_time to vehicle and implemented presence message changes
|
|
124
|
-
* fixes and refactoring of presencelistener
|
|
125
|
-
* Resolve OM-78 improved KVStore performance
|
|
126
|
-
* fixes INBOX-2510
|
|
127
|
-
|
|
128
|
-
v13.0.3
|
|
129
|
-
-------
|
|
130
|
-
|
|
131
|
-
* added garage\_settings mode "barrier\_bypass" in settings models removal of some unused imports
|
|
132
|
-
|
|
133
|
-
v13.0.2
|
|
134
|
-
-------
|
|
135
|
-
|
|
136
|
-
* added vehicle\_id to AccessCheckRequest removed unused code (AccessServiceWithSessions, AccessTime) fix in docs
|
|
137
|
-
|
|
138
|
-
v13.0.1
|
|
139
|
-
-------
|
|
140
|
-
|
|
141
|
-
* DEV-6522 Quick Task: Refactor für KVStore Update
|
|
142
|
-
|
|
143
|
-
v13.0.0
|
|
144
|
-
-------
|
|
145
|
-
|
|
146
|
-
* DEV-6382 KVSync Änderungen für mehrere Datenbank Models und DEV-6432 Access Service Anpassungen
|
|
147
|
-
|
|
148
|
-
v12.1.5
|
|
149
|
-
-------
|
|
150
|
-
|
|
151
|
-
* fixed crash when receiving broken messages
|
|
152
|
-
|
|
153
|
-
v12.1.4
|
|
154
|
-
-------
|
|
155
|
-
|
|
156
|
-
* fixed bug in presence listener with delayed forward and backward messages
|
|
157
|
-
* removed invalid volumn check from column rendering, because base.meta is sufficient
|
|
158
|
-
* fixed bug in the csv export documentation
|
|
159
|
-
|
|
160
|
-
v12.1.3
|
|
161
|
-
-------
|
|
162
|
-
|
|
163
|
-
* docs
|
|
164
|
-
* use hashlib to compute hash
|
|
165
|
-
|
|
166
|
-
v12.1.2
|
|
167
|
-
-------
|
|
168
|
-
|
|
169
|
-
* databox changed to rpc\_no\_blocking -> no exceptions and no waiting added immediate\_callbacks to MockRPCClient
|
|
170
|
-
|
|
171
|
-
v12.1.1
|
|
172
|
-
-------
|
|
173
|
-
|
|
174
|
-
* trigger requirements update for changes in settings-models
|
|
175
|
-
* docs and additional assertion in databox upload function
|
|
176
|
-
|
|
177
|
-
v12.1.0
|
|
178
|
-
-------
|
|
179
|
-
|
|
180
|
-
* additional test cases for export\_iterator
|
|
181
|
-
* first version of export iterator
|
|
182
|
-
|
|
183
|
-
v12.0.0
|
|
184
|
-
-------
|
|
185
|
-
|
|
186
|
-
* SettingsProvider rework and small changes
|
|
187
|
-
* docs update
|
|
188
|
-
* settings model 1.0
|
|
189
|
-
* small fix in test utils
|
|
190
|
-
|
|
191
|
-
v12.0.0.rc1
|
|
192
|
-
-----------
|
|
193
|
-
|
|
194
|
-
* removed debug entries from kv store removed cost\_entries from AccessCheckAccess
|
|
195
|
-
|
|
196
|
-
v12.0.0.rc0
|
|
197
|
-
-----------
|
|
198
|
-
|
|
199
|
-
* Removed parking\_area\_id from AccessCheckAccess changed gate permission check in AccessService to new behavior
|
|
200
|
-
|
|
201
|
-
v11.1.1
|
|
202
|
-
-------
|
|
203
|
-
|
|
204
|
-
* added state parameter to VehicleBuilder.lpr function
|
|
205
|
-
|
|
206
|
-
v11.1.0
|
|
207
|
-
-------
|
|
208
|
-
|
|
209
|
-
* csv export library, databox upload and schedule library tips
|
|
210
|
-
* removed mock rpcs from schema
|
|
211
|
-
|
|
212
|
-
v11.0.3
|
|
213
|
-
-------
|
|
214
|
-
|
|
215
|
-
* Fixed typo, added compute\_id as label to all metrics, convert all label values to string
|
|
216
|
-
* touch to get rid of skip ci on my commit
|
|
217
|
-
* docs update [skip ci]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"git_version": "3b899ae", "is_release": true}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openmodule_test-14.2.0 → openmodule_test-15.0.0}/openmodule_test.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|