openmodule-test 15.2.0__tar.gz → 16.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-15.2.0 → openmodule_test-16.0.0}/PKG-INFO +1 -1
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/database.py +4 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/gate.py +4 -4
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/interrupt.py +0 -3
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/io_simulator.py +6 -6
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/openmodule_test.egg-info/PKG-INFO +1 -1
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/presence.py +10 -10
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/rpc.py +11 -2
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/settings.py +4 -3
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/signal_simulator.py +1 -1
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/zeromq.py +2 -4
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/__init__.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/alert.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/connection_status.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/core.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/eventlistener.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/files.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/health.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/openmodule_test.egg-info/SOURCES.txt +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/openmodule_test.egg-info/dependency_links.txt +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/openmodule_test.egg-info/not-zip-safe +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/openmodule_test.egg-info/requires.txt +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/openmodule_test.egg-info/top_level.txt +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/package_reader.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/sentry.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/setup.cfg +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/setup.py +0 -0
- {openmodule_test-15.2.0 → openmodule_test-16.0.0}/utils.py +0 -0
|
@@ -41,6 +41,7 @@ class SQLiteTestMixin(TestCase):
|
|
|
41
41
|
alembic_path = "../src/database"
|
|
42
42
|
database_name = "database"
|
|
43
43
|
main_process_migration = True # change if migration should be performed in a separate process
|
|
44
|
+
delete_backups = True # if True, all database backups are deleted on teardown
|
|
44
45
|
|
|
45
46
|
@classmethod
|
|
46
47
|
def get_database_folder(cls):
|
|
@@ -81,6 +82,9 @@ class SQLiteTestMixin(TestCase):
|
|
|
81
82
|
super().tearDown()
|
|
82
83
|
if self.create_database:
|
|
83
84
|
truncate_all_tables(self.database)
|
|
85
|
+
if self.delete_backups:
|
|
86
|
+
for file in glob(os.path.join(self.get_database_folder(), f"{self.database_name}_*.sqlite3.backup")):
|
|
87
|
+
os.unlink(file)
|
|
84
88
|
|
|
85
89
|
@classmethod
|
|
86
90
|
def tearDownClass(cls):
|
|
@@ -25,10 +25,8 @@ class TestGate:
|
|
|
25
25
|
def __init__(self, gate: str, direction: Direction, dispatcher: MessageDispatcher):
|
|
26
26
|
self.gate = gate
|
|
27
27
|
self.direction = direction
|
|
28
|
-
dispatcher.register_handler("access_accept", TestGateAccessMessage, self._access_accept,
|
|
29
|
-
|
|
30
|
-
dispatcher.register_handler("access_reject", TestGateAccessMessage, self._access_reject,
|
|
31
|
-
register_schema=False, match_type=False)
|
|
28
|
+
dispatcher.register_handler("access_accept", TestGateAccessMessage, self._access_accept, match_type=False)
|
|
29
|
+
dispatcher.register_handler("access_reject", TestGateAccessMessage, self._access_reject, match_type=False)
|
|
32
30
|
_all_gates.add(self)
|
|
33
31
|
|
|
34
32
|
@classmethod
|
|
@@ -42,10 +40,12 @@ class TestGate:
|
|
|
42
40
|
self._wait_called_since_reset = False
|
|
43
41
|
|
|
44
42
|
def _access_accept(self, message: TestGateAccessMessage):
|
|
43
|
+
""" increment open_count if correct gate """
|
|
45
44
|
if message.gateway.gate == self.gate:
|
|
46
45
|
self.open_count += 1
|
|
47
46
|
|
|
48
47
|
def _access_reject(self, message: TestGateAccessMessage):
|
|
48
|
+
""" increment reject_count if correct gate """
|
|
49
49
|
if message.gateway.gate == self.gate:
|
|
50
50
|
self.reject_count += 1
|
|
51
51
|
|
|
@@ -13,7 +13,6 @@ from unittest import TestCase
|
|
|
13
13
|
import multiprocessing_logging
|
|
14
14
|
|
|
15
15
|
from openmodule.core import shutdown_openmodule
|
|
16
|
-
from openmodule.utils.schema import Schema
|
|
17
16
|
from openmodule_test.health import HealthTestMixin
|
|
18
17
|
|
|
19
18
|
|
|
@@ -26,7 +25,6 @@ class ExceptionProcess(Process):
|
|
|
26
25
|
def run(self):
|
|
27
26
|
try:
|
|
28
27
|
super().run()
|
|
29
|
-
Schema.to_file()
|
|
30
28
|
self.is_finished.set()
|
|
31
29
|
except Exception as e:
|
|
32
30
|
logging.exception(e)
|
|
@@ -96,7 +94,6 @@ class InterruptTestMixin(TestCase):
|
|
|
96
94
|
|
|
97
95
|
def tearDown(self):
|
|
98
96
|
super().tearDown()
|
|
99
|
-
Schema.to_file()
|
|
100
97
|
self._kill_process()
|
|
101
98
|
|
|
102
99
|
def wait_for_setup(self):
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
2
|
from typing import Callable
|
|
3
3
|
|
|
4
|
-
from openmodule.models.base import Gateway
|
|
4
|
+
from openmodule.models.base import Gateway, Direction
|
|
5
5
|
from openmodule.models.io import IoMessage, IoState
|
|
6
6
|
from openmodule.utils.misc_functions import utcnow
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def generate_example_states(count: int
|
|
9
|
+
def generate_example_states(count: int=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.
|
|
@@ -17,7 +17,7 @@ def generate_example_states(count: int | None = 8) -> dict[str, IoState]:
|
|
|
17
17
|
states: dict[str, IoState] = defaultdict(IoState)
|
|
18
18
|
for i in range(count):
|
|
19
19
|
gate = int(i/4)
|
|
20
|
-
direction =
|
|
20
|
+
direction = Direction.IN if gate % 2 == 0 else Direction.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
23
|
last_timestamp=utcnow())
|
|
@@ -75,11 +75,11 @@ class IoSimulator:
|
|
|
75
75
|
def set_pin_high(self, pin: str):
|
|
76
76
|
self._emit(pin, 1)
|
|
77
77
|
|
|
78
|
-
def emit_custom_io_message(self, pin: str, value: int = None, physical: int
|
|
79
|
-
edge: int = None):
|
|
78
|
+
def emit_custom_io_message(self, pin: str, value: int | None = None, physical: int | None = None,
|
|
79
|
+
inverted: bool | None = None, edge: int | None = None):
|
|
80
80
|
state = self.pin_states[pin]
|
|
81
81
|
if edge is None:
|
|
82
|
-
if state.value != value or state.
|
|
82
|
+
if state.value != value or state.inverted != inverted:
|
|
83
83
|
edge = 1
|
|
84
84
|
else:
|
|
85
85
|
edge = 0
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import random
|
|
2
2
|
import time
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import Callable
|
|
4
|
+
from typing import Callable, Self
|
|
5
5
|
|
|
6
6
|
from openmodule.models.base import Direction, Gateway, datetime_to_timestamp
|
|
7
7
|
from openmodule.models.presence import PresenceBaseMessage, PresenceEnterMessage, PresenceLeaveMessage, \
|
|
@@ -36,11 +36,11 @@ class VehicleBuilder:
|
|
|
36
36
|
leave_time=self.leave_time
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
-
def id(self, id: int) ->
|
|
39
|
+
def id(self, id: int) -> Self:
|
|
40
40
|
self.vehicle_id = id
|
|
41
41
|
return self
|
|
42
42
|
|
|
43
|
-
def lpr(self, country: str | None, plate: str | None = None, state="") ->
|
|
43
|
+
def lpr(self, country: str | None, plate: str | None = None, state="") -> Self:
|
|
44
44
|
if country is None:
|
|
45
45
|
self.medium.lpr = None
|
|
46
46
|
else:
|
|
@@ -50,40 +50,40 @@ class VehicleBuilder:
|
|
|
50
50
|
)
|
|
51
51
|
return self
|
|
52
52
|
|
|
53
|
-
def nfc(self, id: str | None) ->
|
|
53
|
+
def nfc(self, id: str | None) -> Self:
|
|
54
54
|
if id is None:
|
|
55
55
|
self.medium.nfc = id
|
|
56
56
|
else:
|
|
57
57
|
self.medium.nfc = Medium(id=id, type=MediumType.nfc)
|
|
58
58
|
return self
|
|
59
59
|
|
|
60
|
-
def qr(self, id: str | None, binary: str | None = None) ->
|
|
60
|
+
def qr(self, id: str | None, binary: str | None = None) -> Self:
|
|
61
61
|
if id is None:
|
|
62
62
|
self.medium.qr = id
|
|
63
63
|
else:
|
|
64
64
|
self.medium.qr = QRMedium(id=id, binary=binary)
|
|
65
65
|
return self
|
|
66
66
|
|
|
67
|
-
def pin(self, id: str | None) ->
|
|
67
|
+
def pin(self, id: str | None) -> Self:
|
|
68
68
|
if id is None:
|
|
69
69
|
self.medium.pin = id
|
|
70
70
|
else:
|
|
71
71
|
self.medium.pin = Medium(id=id, type=MediumType.pin)
|
|
72
72
|
return self
|
|
73
73
|
|
|
74
|
-
def set_make_model(self, make_model) ->
|
|
74
|
+
def set_make_model(self, make_model) -> Self:
|
|
75
75
|
self.make_model = make_model
|
|
76
76
|
return self
|
|
77
77
|
|
|
78
|
-
def set_enter_direction(self, enter_direction: EnterDirection) ->
|
|
78
|
+
def set_enter_direction(self, enter_direction: EnterDirection) -> Self:
|
|
79
79
|
self.enter_direction = enter_direction
|
|
80
80
|
return self
|
|
81
81
|
|
|
82
|
-
def set_enter_time(self, enter_time: datetime) ->
|
|
82
|
+
def set_enter_time(self, enter_time: datetime) -> Self:
|
|
83
83
|
self.enter_time = enter_time
|
|
84
84
|
return self
|
|
85
85
|
|
|
86
|
-
def set_leave_time(self, leave_time: datetime) ->
|
|
86
|
+
def set_leave_time(self, leave_time: datetime) -> Self:
|
|
87
87
|
self.leave_time = leave_time
|
|
88
88
|
return self
|
|
89
89
|
|
|
@@ -7,7 +7,7 @@ from typing import Any, Callable
|
|
|
7
7
|
|
|
8
8
|
from pydantic.main import BaseModel
|
|
9
9
|
|
|
10
|
-
from openmodule.models.base import OpenModuleModel
|
|
10
|
+
from openmodule.models.base import OpenModuleModel, ZMQMessage
|
|
11
11
|
from openmodule.models.rpc import RPCErrorResult, RPCServerError
|
|
12
12
|
from openmodule.rpc import RPCClient
|
|
13
13
|
from openmodule_test.zeromq import ZMQTestMixin
|
|
@@ -18,6 +18,14 @@ class _EmptyModel(BaseModel):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class RPCServerTestMixin(ZMQTestMixin):
|
|
21
|
+
def setUp(self):
|
|
22
|
+
ZMQMessage._ALLOW_CUSTOM_TIMESTAMP = True
|
|
23
|
+
return super().setUp()
|
|
24
|
+
|
|
25
|
+
def tearDown(self):
|
|
26
|
+
ZMQMessage._ALLOW_CUSTOM_TIMESTAMP = False
|
|
27
|
+
return super().tearDown()
|
|
28
|
+
|
|
21
29
|
def wait_for_rpc_response(self, channel: str, type: str, request: BaseModel, response_type: type[OpenModuleModel]):
|
|
22
30
|
"""
|
|
23
31
|
waits until a rpc server is responding to the channel/type
|
|
@@ -37,6 +45,7 @@ class RPCServerTestMixin(ZMQTestMixin):
|
|
|
37
45
|
message_received = False
|
|
38
46
|
|
|
39
47
|
def handler(_, __):
|
|
48
|
+
""" handler to set message_received true """
|
|
40
49
|
nonlocal message_received
|
|
41
50
|
message_received = True
|
|
42
51
|
|
|
@@ -48,7 +57,7 @@ class RPCServerTestMixin(ZMQTestMixin):
|
|
|
48
57
|
assert server.handlers, "you need to register the handlers beforehand"
|
|
49
58
|
random_channel = "_test" + "".join(random.choices(string.ascii_letters, k=10))
|
|
50
59
|
|
|
51
|
-
server.register_handler(random_channel, "ping", _EmptyModel, _EmptyModel, handler
|
|
60
|
+
server.register_handler(random_channel, "ping", _EmptyModel, _EmptyModel, handler)
|
|
52
61
|
|
|
53
62
|
for x in range(self.zmq_client.startup_check_iterations):
|
|
54
63
|
self.rpc_no_response(random_channel, "ping", {})
|
|
@@ -85,10 +85,9 @@ class SettingsRPCMocker:
|
|
|
85
85
|
for setting, value in settings.items():
|
|
86
86
|
if setting[0] in serialization._model_mapping:
|
|
87
87
|
serialization.parse_setting_from_obj(setting[0], value)
|
|
88
|
-
rpc_server.register_handler("settings", "get", SettingsGetRequest, SettingsGetResponse, self._get_handler
|
|
89
|
-
register_schema=False)
|
|
88
|
+
rpc_server.register_handler("settings", "get", SettingsGetRequest, SettingsGetResponse, self._get_handler)
|
|
90
89
|
rpc_server.register_handler("settings", "get_many", SettingsGetManyRequest, SettingsGetManyResponse,
|
|
91
|
-
self._get_many_handler
|
|
90
|
+
self._get_many_handler)
|
|
92
91
|
self.settings = settings
|
|
93
92
|
self.result_mode = SettingsRPCMocker.ResultMode.ok
|
|
94
93
|
self.error_code = "no such setting"
|
|
@@ -109,10 +108,12 @@ class SettingsRPCMocker:
|
|
|
109
108
|
raise RuntimeError()
|
|
110
109
|
|
|
111
110
|
def _get_handler(self, request: SettingsGetRequest, _) -> SettingsGetResponse:
|
|
111
|
+
""" either raise set error or return requested value """
|
|
112
112
|
self._do_errors()
|
|
113
113
|
return self._get_setting(request.key, request.scope)
|
|
114
114
|
|
|
115
115
|
def _get_many_handler(self, request: SettingsGetManyRequest, _) -> SettingsGetManyResponse:
|
|
116
|
+
""" either raise set error or return requested values """
|
|
116
117
|
self._do_errors()
|
|
117
118
|
return SettingsGetManyResponse(settings={key: self._get_setting(key, request.scope, i)
|
|
118
119
|
for i, key in enumerate(request.key)})
|
|
@@ -18,7 +18,7 @@ class SignalSimulator:
|
|
|
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 = signal_type.value
|
|
21
|
+
signal_name: str = signal_type.value # type: ignore (just pycharm)
|
|
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:
|
|
@@ -24,7 +24,6 @@ from openmodule.dispatcher import SubscribingMessageDispatcher
|
|
|
24
24
|
from openmodule.models.base import OpenModuleModel
|
|
25
25
|
from openmodule.models.rpc import RPCResponse
|
|
26
26
|
from openmodule.rpc import RPCClient
|
|
27
|
-
from openmodule.utils.schema import Schema
|
|
28
27
|
from openmodule_test.utils import DeveloperError
|
|
29
28
|
|
|
30
29
|
|
|
@@ -433,7 +432,7 @@ class ZMQTestMixin(TestCase):
|
|
|
433
432
|
and if it is connected, all previous subscriptions will also be connected
|
|
434
433
|
"""
|
|
435
434
|
random_topic = "_test" + "".join(random.choices(string.ascii_letters, k=10))
|
|
436
|
-
dispatcher.register_handler(random_topic, OpenModuleModel, handler,
|
|
435
|
+
dispatcher.register_handler(random_topic, OpenModuleModel, handler, match_type=False)
|
|
437
436
|
|
|
438
437
|
for _ in range(self.zmq_client.startup_check_iterations):
|
|
439
438
|
self.zmq_client.send(random_topic, {"type": "connection-check"})
|
|
@@ -469,7 +468,6 @@ class ZMQTestMixin(TestCase):
|
|
|
469
468
|
)
|
|
470
469
|
self._cleanup()
|
|
471
470
|
super(ZMQTestMixin, self).tearDown()
|
|
472
|
-
Schema.to_file()
|
|
473
471
|
|
|
474
472
|
def rpc(self, channel: str, type: str, request, response_type: type[OpenModuleModel], timeout=3, resource=None) \
|
|
475
473
|
-> str | OpenModuleModel:
|
|
@@ -507,7 +505,7 @@ class ZMQTestMixin(TestCase):
|
|
|
507
505
|
except TimeoutError:
|
|
508
506
|
raise RPCClient.TimeoutError()
|
|
509
507
|
entry = RPCClient.RPCEntry(0) # timeout 0 because timeout is handled above, so we never have to wait here
|
|
510
|
-
entry.response = RPCResponse(
|
|
508
|
+
entry.response = RPCResponse.model_validate(response).response
|
|
511
509
|
return entry.result(response_type)
|
|
512
510
|
|
|
513
511
|
def assertSubscription(self, *topics: str):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openmodule_test-15.2.0 → openmodule_test-16.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|