-
Notifications
You must be signed in to change notification settings - Fork 222
/
Copy pathconftest.py
207 lines (160 loc) · 6.95 KB
/
conftest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#!/usr/bin/python
# Copyright 2021-2024 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import annotations
import multiprocessing
import time
from typing import Optional, Generator, cast
import pytest
from _pytest.config import Config, Notset
from _pytest.config.argparsing import Parser
from _pytest.fixtures import FixtureRequest
from erpc.arbitrator import TransportArbitrator
from erpc.basic_codec import BasicCodec
from erpc.client import ClientManager
from erpc.server import Service
from erpc.simple_server import SimpleServer
from erpc.transport import TCPTransport, SerialTransport
from .test_const.service.erpc_outputs import test_unit_test_common
from .test_const.service.erpc_outputs.test_unit_test_common.client import CommonClient
from .test_const.service.erpc_outputs.test_unit_test_common.server import CommonService
def pytest_addoption(parser: Parser):
parser.addoption("--client", action="store_true", default=False, help="run all combinations")
parser.addoption("--server", action="store_true", default=False, help="run all combinations")
parser.addoption("--host", action="store", default='localhost', help="run all combinations")
parser.addoption("--port", action="store", default='40', help="run all combinations")
parser.addoption("--serial", action="store", default=None, help="run all combinations")
parser.addoption("--baud", action="store", default='115200', help="run all combinations")
###############################################################################
# Classes
###############################################################################
global_server: SimpleServer | None = None
class TransportFactory:
"""
Build a concreate transport layer based on pytestconfig.
This class can be passed to new process and then build new transport layer (concreate transport layer cannot be
passed to new process because of thread lock, so we have to pass it this way).
"""
def __init__(self, config: Config):
self.port = int(cast(int, config.getoption("port")))
self.host = config.getoption("host")
self.serial = config.getoption("serial")
self.baud = int(cast(int, config.getoption("baud")))
self.arbitrator = None
def build_transport(self, is_server: bool,
create_arbitrator: bool = False) -> TCPTransport | SerialTransport | TransportArbitrator:
if self.serial:
transport = SerialTransport(self.serial, self.baud)
else:
transport = TCPTransport(self.host, self.port, is_server)
if create_arbitrator:
transport = TransportArbitrator(transport, BasicCodec())
return transport
class CommonTestServiceHandler(test_unit_test_common.interface.ICommon):
"""
Common handler to stop and quit the server
"""
def quit(self):
global global_server
if global_server:
global_server.stop()
def getServerAllocated(self):
return 0
###############################################################################
# Fixtures
###############################################################################
@pytest.fixture(scope="session")
def config(request: FixtureRequest, pytestconfig: Config) -> Generator[Config, None, None]:
device_object = None
if pytestconfig.getoption("twister_harness", default=False):
device_object = request.getfixturevalue('device_object')
device_object.launch()
device_object.disconnect()
time.sleep(1)
pytestconfig.option.serial = pytestconfig.getoption("device_serial")
pytestconfig.option.baud = pytestconfig.getoption("device_serial_baud")
pytestconfig.option.client = True
pytestconfig.option.server = False
yield pytestconfig
if device_object is not None:
device_object.close()
@pytest.fixture(scope="module")
def transport_factory(config: Config):
"""
Fixture for transport factory
:param config: pytest config
:return: new transport factory
"""
return TransportFactory(config)
@pytest.fixture(scope="module")
def client_manager(config: Config, transport_factory: TransportFactory, server: SimpleServer) -> ClientManager:
"""
Fixture for client manager, that is used by all tests for creating client.
:param config: pytestconfig
:param transport_factory: TransportFactory to use
:param server: Ensure that server is created before client
:return: new client manager
"""
if not config.getoption("client"):
pytest.skip("No test's client, skipping.")
else:
time.sleep(0.1) # Add delay to allow server run
return ClientManager(transport_factory.build_transport(False), BasicCodec)
@pytest.fixture(scope="module")
def common_client(client_manager: ClientManager) -> CommonClient:
"""
This client is used in all tests to stop the server
:param client_manager:
:return: new CommonClient
"""
return CommonClient(client_manager)
def run_server(transport_factory: TransportFactory, services: list[Service]) -> SimpleServer:
"""
Auxiliary function, that create SimpleServer using TransportFactory, add CommonService and services specified by
current test and run it.
Created server is assigned to global_server variable.
:param transport_factory: TransportFactory to use
:param services: list of services defined by current test
:return: new server
"""
global global_server
global_server = SimpleServer(transport_factory.build_transport(True), BasicCodec)
global_server.add_service(CommonService(CommonTestServiceHandler()))
for service in services:
global_server.add_service(service)
global_server.run()
print("Server: started")
return global_server
@pytest.fixture(scope="module", autouse=True)
def server(config: Config,
transport_factory: TransportFactory,
services: list[Service]) -> Generator[SimpleServer | None, None, None]:
"""
Create server if necessary. If server and client should run together, spawn new process with Server.
:param config: pytestconfig
:param transport_factory: Transport factory to use or pass to server (new process)
:param services: list of services defined by current test
:return: new server or None if executed in new process
"""
global global_server
p: Optional[multiprocessing.Process] = None
# We don't need the server
if not config.getoption("server"):
yield
return
if config.getoption("server") and config.getoption("client"):
# Create server in new process
p = multiprocessing.Process(
target=run_server,
args=(transport_factory, services,)
)
p.start()
else:
run_server(transport_factory, services)
yield global_server
if config.getoption("server") and config.getoption("client"):
assert p is not None
# Wait for server's process to stop
p.join()
print("Server: stopped")