mockserver-client 5.16.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.
- mockserver/__init__.py +85 -0
- mockserver/async_client.py +425 -0
- mockserver/client.py +207 -0
- mockserver/exceptions.py +21 -0
- mockserver/fluent.py +116 -0
- mockserver/models.py +1358 -0
- mockserver/websocket_client.py +314 -0
- mockserver_client-5.16.0.dist-info/METADATA +291 -0
- mockserver_client-5.16.0.dist-info/RECORD +11 -0
- mockserver_client-5.16.0.dist-info/WHEEL +5 -0
- mockserver_client-5.16.0.dist-info/top_level.txt +1 -0
mockserver/__init__.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from mockserver.models import (
|
|
2
|
+
AfterAction,
|
|
3
|
+
Body,
|
|
4
|
+
ConnectionOptions,
|
|
5
|
+
Delay,
|
|
6
|
+
DelayDistribution,
|
|
7
|
+
Expectation,
|
|
8
|
+
ExpectationId,
|
|
9
|
+
HttpClassCallback,
|
|
10
|
+
HttpError,
|
|
11
|
+
HttpForward,
|
|
12
|
+
HttpObjectCallback,
|
|
13
|
+
HttpOverrideForwardedRequest,
|
|
14
|
+
HttpRequest,
|
|
15
|
+
HttpRequestAndHttpResponse,
|
|
16
|
+
HttpResponse,
|
|
17
|
+
HttpSseResponse,
|
|
18
|
+
HttpTemplate,
|
|
19
|
+
HttpWebSocketResponse,
|
|
20
|
+
JsonRpcBody,
|
|
21
|
+
KeyToMultiValue,
|
|
22
|
+
OpenAPIDefinition,
|
|
23
|
+
OpenAPIExpectation,
|
|
24
|
+
Ports,
|
|
25
|
+
RequestDefinition,
|
|
26
|
+
SocketAddress,
|
|
27
|
+
SseEvent,
|
|
28
|
+
TimeToLive,
|
|
29
|
+
Times,
|
|
30
|
+
Verification,
|
|
31
|
+
VerificationSequence,
|
|
32
|
+
VerificationTimes,
|
|
33
|
+
WebSocketMessage,
|
|
34
|
+
)
|
|
35
|
+
from mockserver.exceptions import (
|
|
36
|
+
MockServerCallbackError,
|
|
37
|
+
MockServerConnectionError,
|
|
38
|
+
MockServerError,
|
|
39
|
+
MockServerVerificationError,
|
|
40
|
+
MockServerWebSocketError,
|
|
41
|
+
)
|
|
42
|
+
from mockserver.client import MockServerClient
|
|
43
|
+
from mockserver.async_client import AsyncMockServerClient
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
"AfterAction",
|
|
47
|
+
"AsyncMockServerClient",
|
|
48
|
+
"Body",
|
|
49
|
+
"ConnectionOptions",
|
|
50
|
+
"Delay",
|
|
51
|
+
"DelayDistribution",
|
|
52
|
+
"Expectation",
|
|
53
|
+
"ExpectationId",
|
|
54
|
+
"HttpClassCallback",
|
|
55
|
+
"HttpError",
|
|
56
|
+
"HttpForward",
|
|
57
|
+
"HttpObjectCallback",
|
|
58
|
+
"HttpOverrideForwardedRequest",
|
|
59
|
+
"HttpRequest",
|
|
60
|
+
"HttpRequestAndHttpResponse",
|
|
61
|
+
"HttpResponse",
|
|
62
|
+
"HttpSseResponse",
|
|
63
|
+
"HttpTemplate",
|
|
64
|
+
"HttpWebSocketResponse",
|
|
65
|
+
"JsonRpcBody",
|
|
66
|
+
"KeyToMultiValue",
|
|
67
|
+
"MockServerCallbackError",
|
|
68
|
+
"MockServerClient",
|
|
69
|
+
"MockServerConnectionError",
|
|
70
|
+
"MockServerError",
|
|
71
|
+
"MockServerVerificationError",
|
|
72
|
+
"MockServerWebSocketError",
|
|
73
|
+
"OpenAPIDefinition",
|
|
74
|
+
"OpenAPIExpectation",
|
|
75
|
+
"Ports",
|
|
76
|
+
"RequestDefinition",
|
|
77
|
+
"SocketAddress",
|
|
78
|
+
"SseEvent",
|
|
79
|
+
"TimeToLive",
|
|
80
|
+
"Times",
|
|
81
|
+
"Verification",
|
|
82
|
+
"VerificationSequence",
|
|
83
|
+
"VerificationTimes",
|
|
84
|
+
"WebSocketMessage",
|
|
85
|
+
]
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import socket
|
|
7
|
+
import ssl
|
|
8
|
+
import urllib.error
|
|
9
|
+
import urllib.parse
|
|
10
|
+
import urllib.request
|
|
11
|
+
from typing import Any, Callable
|
|
12
|
+
|
|
13
|
+
from mockserver.exceptions import (
|
|
14
|
+
MockServerConnectionError,
|
|
15
|
+
MockServerError,
|
|
16
|
+
MockServerVerificationError,
|
|
17
|
+
)
|
|
18
|
+
from mockserver.fluent import ForwardChainExpectation
|
|
19
|
+
from mockserver.models import (
|
|
20
|
+
Expectation,
|
|
21
|
+
HttpObjectCallback,
|
|
22
|
+
HttpRequest,
|
|
23
|
+
HttpRequestAndHttpResponse,
|
|
24
|
+
HttpResponse,
|
|
25
|
+
OpenAPIExpectation,
|
|
26
|
+
Ports,
|
|
27
|
+
TimeToLive,
|
|
28
|
+
Times,
|
|
29
|
+
Verification,
|
|
30
|
+
VerificationSequence,
|
|
31
|
+
VerificationTimes,
|
|
32
|
+
)
|
|
33
|
+
from mockserver.websocket_client import MockServerWebSocketClient
|
|
34
|
+
|
|
35
|
+
logger = logging.getLogger(__name__)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AsyncMockServerClient:
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
host: str,
|
|
42
|
+
port: int,
|
|
43
|
+
context_path: str = "",
|
|
44
|
+
secure: bool = False,
|
|
45
|
+
ca_cert_path: str | None = None,
|
|
46
|
+
tls_verify: bool = True,
|
|
47
|
+
) -> None:
|
|
48
|
+
self._host = host
|
|
49
|
+
self._port = port
|
|
50
|
+
self._context_path = context_path
|
|
51
|
+
self._secure = secure
|
|
52
|
+
self._ca_cert_path = ca_cert_path
|
|
53
|
+
self._tls_verify = tls_verify
|
|
54
|
+
self._websocket_clients: list[MockServerWebSocketClient] = []
|
|
55
|
+
|
|
56
|
+
scheme = "https" if secure else "http"
|
|
57
|
+
ctx_path = ""
|
|
58
|
+
if context_path:
|
|
59
|
+
ctx_path = context_path if context_path.startswith("/") else f"/{context_path}"
|
|
60
|
+
self._base_url = f"{scheme}://{host}:{port}{ctx_path}"
|
|
61
|
+
|
|
62
|
+
self._ssl_context: ssl.SSLContext | None = None
|
|
63
|
+
if secure:
|
|
64
|
+
self._ssl_context = ssl.create_default_context()
|
|
65
|
+
if ca_cert_path:
|
|
66
|
+
self._ssl_context.load_verify_locations(ca_cert_path)
|
|
67
|
+
elif not tls_verify:
|
|
68
|
+
self._ssl_context.check_hostname = False
|
|
69
|
+
self._ssl_context.verify_mode = ssl.CERT_NONE
|
|
70
|
+
|
|
71
|
+
async def _request(
|
|
72
|
+
self,
|
|
73
|
+
method: str,
|
|
74
|
+
path: str,
|
|
75
|
+
body: str | None = None,
|
|
76
|
+
query_params: dict[str, str] | None = None,
|
|
77
|
+
) -> tuple[int, str]:
|
|
78
|
+
url = f"{self._base_url}{path}"
|
|
79
|
+
if query_params:
|
|
80
|
+
url = f"{url}?{urllib.parse.urlencode(query_params)}"
|
|
81
|
+
|
|
82
|
+
data = body.encode("utf-8") if body else None
|
|
83
|
+
req = urllib.request.Request(url, data=data, method=method)
|
|
84
|
+
req.add_header("Content-Type", "application/json; charset=utf-8")
|
|
85
|
+
|
|
86
|
+
def _do_request() -> tuple[int, str]:
|
|
87
|
+
try:
|
|
88
|
+
response = urllib.request.urlopen(
|
|
89
|
+
req, context=self._ssl_context, timeout=60
|
|
90
|
+
)
|
|
91
|
+
return response.status, response.read().decode("utf-8")
|
|
92
|
+
except urllib.error.HTTPError as e:
|
|
93
|
+
return e.code, e.read().decode("utf-8")
|
|
94
|
+
except socket.timeout as e:
|
|
95
|
+
raise MockServerConnectionError(
|
|
96
|
+
f"Request to MockServer at {self._base_url} timed out: {e}"
|
|
97
|
+
) from e
|
|
98
|
+
except (urllib.error.URLError, OSError) as e:
|
|
99
|
+
raise MockServerConnectionError(
|
|
100
|
+
f"Failed to connect to MockServer at {self._base_url}: {e}"
|
|
101
|
+
) from e
|
|
102
|
+
|
|
103
|
+
return await asyncio.to_thread(_do_request)
|
|
104
|
+
|
|
105
|
+
async def upsert(self, *expectations: Expectation) -> list[Expectation]:
|
|
106
|
+
body = json.dumps([e.to_dict() for e in expectations])
|
|
107
|
+
status, response_body = await self._request("PUT", "/mockserver/expectation", body)
|
|
108
|
+
if status == 400:
|
|
109
|
+
raise MockServerError(f"Invalid expectation: {response_body}")
|
|
110
|
+
if status >= 400:
|
|
111
|
+
raise MockServerError(
|
|
112
|
+
f"Failed to upsert expectations (status={status}): {response_body}"
|
|
113
|
+
)
|
|
114
|
+
if response_body:
|
|
115
|
+
parsed = json.loads(response_body)
|
|
116
|
+
if isinstance(parsed, list):
|
|
117
|
+
return [Expectation.from_dict(e) for e in parsed]
|
|
118
|
+
return list(expectations)
|
|
119
|
+
|
|
120
|
+
async def open_api_expectation(self, expectation: OpenAPIExpectation) -> None:
|
|
121
|
+
body = json.dumps(expectation.to_dict())
|
|
122
|
+
status, response_body = await self._request("PUT", "/mockserver/openapi", body)
|
|
123
|
+
if status >= 400:
|
|
124
|
+
raise MockServerError(
|
|
125
|
+
f"Failed to create OpenAPI expectation (status={status}): {response_body}"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
async def clear(
|
|
129
|
+
self,
|
|
130
|
+
request: HttpRequest | None = None,
|
|
131
|
+
clear_type: str | None = None,
|
|
132
|
+
) -> None:
|
|
133
|
+
query_params = {}
|
|
134
|
+
if clear_type:
|
|
135
|
+
query_params["type"] = clear_type
|
|
136
|
+
body = json.dumps(request.to_dict()) if request else ""
|
|
137
|
+
status, response_body = await self._request(
|
|
138
|
+
"PUT", "/mockserver/clear", body, query_params or None
|
|
139
|
+
)
|
|
140
|
+
if status >= 400:
|
|
141
|
+
raise MockServerError(
|
|
142
|
+
f"Failed to clear (status={status}): {response_body}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
async def clear_by_id(
|
|
146
|
+
self,
|
|
147
|
+
expectation_id: str,
|
|
148
|
+
clear_type: str | None = None,
|
|
149
|
+
) -> None:
|
|
150
|
+
query_params = {}
|
|
151
|
+
if clear_type:
|
|
152
|
+
query_params["type"] = clear_type
|
|
153
|
+
body = json.dumps({"id": expectation_id})
|
|
154
|
+
status, response_body = await self._request(
|
|
155
|
+
"PUT", "/mockserver/clear", body, query_params or None
|
|
156
|
+
)
|
|
157
|
+
if status >= 400:
|
|
158
|
+
raise MockServerError(
|
|
159
|
+
f"Failed to clear by id (status={status}): {response_body}"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
async def reset(self) -> None:
|
|
163
|
+
status, response_body = await self._request("PUT", "/mockserver/reset")
|
|
164
|
+
if status >= 400:
|
|
165
|
+
raise MockServerError(
|
|
166
|
+
f"Failed to reset (status={status}): {response_body}"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
async def verify(
|
|
170
|
+
self,
|
|
171
|
+
request: HttpRequest,
|
|
172
|
+
times: VerificationTimes | None = None,
|
|
173
|
+
) -> None:
|
|
174
|
+
verification = Verification(http_request=request, times=times)
|
|
175
|
+
body = json.dumps(verification.to_dict())
|
|
176
|
+
status, response_body = await self._request("PUT", "/mockserver/verify", body)
|
|
177
|
+
if status == 406:
|
|
178
|
+
raise MockServerVerificationError(response_body)
|
|
179
|
+
if status >= 400:
|
|
180
|
+
raise MockServerError(
|
|
181
|
+
f"Failed to verify (status={status}): {response_body}"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
async def verify_sequence(self, *requests: HttpRequest) -> None:
|
|
185
|
+
verification = VerificationSequence(
|
|
186
|
+
http_requests=list(requests)
|
|
187
|
+
)
|
|
188
|
+
body = json.dumps(verification.to_dict())
|
|
189
|
+
status, response_body = await self._request(
|
|
190
|
+
"PUT", "/mockserver/verifySequence", body
|
|
191
|
+
)
|
|
192
|
+
if status == 406:
|
|
193
|
+
raise MockServerVerificationError(response_body)
|
|
194
|
+
if status >= 400:
|
|
195
|
+
raise MockServerError(
|
|
196
|
+
f"Failed to verify sequence (status={status}): {response_body}"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
async def verify_zero_interactions(self) -> None:
|
|
200
|
+
await self.verify(
|
|
201
|
+
HttpRequest(),
|
|
202
|
+
VerificationTimes(at_most=0),
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
async def retrieve_recorded_requests(
|
|
206
|
+
self, request: HttpRequest | None = None
|
|
207
|
+
) -> list[HttpRequest]:
|
|
208
|
+
body = json.dumps(request.to_dict()) if request else ""
|
|
209
|
+
status, response_body = await self._request(
|
|
210
|
+
"PUT",
|
|
211
|
+
"/mockserver/retrieve",
|
|
212
|
+
body,
|
|
213
|
+
{"type": "REQUESTS", "format": "JSON"},
|
|
214
|
+
)
|
|
215
|
+
if status >= 400:
|
|
216
|
+
raise MockServerError(
|
|
217
|
+
f"Failed to retrieve recorded requests (status={status}): {response_body}"
|
|
218
|
+
)
|
|
219
|
+
if response_body:
|
|
220
|
+
parsed = json.loads(response_body)
|
|
221
|
+
if isinstance(parsed, list):
|
|
222
|
+
return [HttpRequest.from_dict(r) for r in parsed]
|
|
223
|
+
return []
|
|
224
|
+
|
|
225
|
+
async def retrieve_active_expectations(
|
|
226
|
+
self, request: HttpRequest | None = None
|
|
227
|
+
) -> list[Expectation]:
|
|
228
|
+
body = json.dumps(request.to_dict()) if request else ""
|
|
229
|
+
status, response_body = await self._request(
|
|
230
|
+
"PUT",
|
|
231
|
+
"/mockserver/retrieve",
|
|
232
|
+
body,
|
|
233
|
+
{"type": "ACTIVE_EXPECTATIONS", "format": "JSON"},
|
|
234
|
+
)
|
|
235
|
+
if status >= 400:
|
|
236
|
+
raise MockServerError(
|
|
237
|
+
f"Failed to retrieve active expectations (status={status}): {response_body}"
|
|
238
|
+
)
|
|
239
|
+
if response_body:
|
|
240
|
+
parsed = json.loads(response_body)
|
|
241
|
+
if isinstance(parsed, list):
|
|
242
|
+
return [Expectation.from_dict(e) for e in parsed]
|
|
243
|
+
return []
|
|
244
|
+
|
|
245
|
+
async def retrieve_recorded_expectations(
|
|
246
|
+
self, request: HttpRequest | None = None
|
|
247
|
+
) -> list[Expectation]:
|
|
248
|
+
body = json.dumps(request.to_dict()) if request else ""
|
|
249
|
+
status, response_body = await self._request(
|
|
250
|
+
"PUT",
|
|
251
|
+
"/mockserver/retrieve",
|
|
252
|
+
body,
|
|
253
|
+
{"type": "RECORDED_EXPECTATIONS", "format": "JSON"},
|
|
254
|
+
)
|
|
255
|
+
if status >= 400:
|
|
256
|
+
raise MockServerError(
|
|
257
|
+
f"Failed to retrieve recorded expectations (status={status}): {response_body}"
|
|
258
|
+
)
|
|
259
|
+
if response_body:
|
|
260
|
+
parsed = json.loads(response_body)
|
|
261
|
+
if isinstance(parsed, list):
|
|
262
|
+
return [Expectation.from_dict(e) for e in parsed]
|
|
263
|
+
return []
|
|
264
|
+
|
|
265
|
+
async def retrieve_recorded_requests_and_responses(
|
|
266
|
+
self, request: HttpRequest | None = None
|
|
267
|
+
) -> list[HttpRequestAndHttpResponse]:
|
|
268
|
+
body = json.dumps(request.to_dict()) if request else ""
|
|
269
|
+
status, response_body = await self._request(
|
|
270
|
+
"PUT",
|
|
271
|
+
"/mockserver/retrieve",
|
|
272
|
+
body,
|
|
273
|
+
{"type": "REQUEST_RESPONSES", "format": "JSON"},
|
|
274
|
+
)
|
|
275
|
+
if status >= 400:
|
|
276
|
+
raise MockServerError(
|
|
277
|
+
f"Failed to retrieve request/responses (status={status}): {response_body}"
|
|
278
|
+
)
|
|
279
|
+
if response_body:
|
|
280
|
+
parsed = json.loads(response_body)
|
|
281
|
+
if isinstance(parsed, list):
|
|
282
|
+
return [HttpRequestAndHttpResponse.from_dict(rr) for rr in parsed]
|
|
283
|
+
return []
|
|
284
|
+
|
|
285
|
+
async def retrieve_log_messages(
|
|
286
|
+
self, request: HttpRequest | None = None
|
|
287
|
+
) -> list[str]:
|
|
288
|
+
body = json.dumps(request.to_dict()) if request else ""
|
|
289
|
+
status, response_body = await self._request(
|
|
290
|
+
"PUT",
|
|
291
|
+
"/mockserver/retrieve",
|
|
292
|
+
body,
|
|
293
|
+
{"type": "LOGS"},
|
|
294
|
+
)
|
|
295
|
+
if status >= 400:
|
|
296
|
+
raise MockServerError(
|
|
297
|
+
f"Failed to retrieve log messages (status={status}): {response_body}"
|
|
298
|
+
)
|
|
299
|
+
if response_body:
|
|
300
|
+
try:
|
|
301
|
+
parsed = json.loads(response_body)
|
|
302
|
+
if isinstance(parsed, list):
|
|
303
|
+
return parsed
|
|
304
|
+
except json.JSONDecodeError:
|
|
305
|
+
return response_body.split("------------------------------------\n")
|
|
306
|
+
return []
|
|
307
|
+
|
|
308
|
+
async def bind(self, *ports: int) -> list[int]:
|
|
309
|
+
body = json.dumps(Ports(ports=list(ports)).to_dict())
|
|
310
|
+
status, response_body = await self._request("PUT", "/mockserver/bind", body)
|
|
311
|
+
if status >= 400:
|
|
312
|
+
raise MockServerError(
|
|
313
|
+
f"Failed to bind ports (status={status}): {response_body}"
|
|
314
|
+
)
|
|
315
|
+
if response_body:
|
|
316
|
+
parsed = json.loads(response_body)
|
|
317
|
+
return Ports.from_dict(parsed).ports
|
|
318
|
+
return []
|
|
319
|
+
|
|
320
|
+
async def stop(self) -> None:
|
|
321
|
+
try:
|
|
322
|
+
await self._request("PUT", "/mockserver/stop")
|
|
323
|
+
except MockServerConnectionError:
|
|
324
|
+
pass
|
|
325
|
+
|
|
326
|
+
async def has_started(self, attempts: int = 10, timeout: float = 0.5) -> bool:
|
|
327
|
+
for i in range(attempts):
|
|
328
|
+
try:
|
|
329
|
+
status, _ = await self._request("PUT", "/mockserver/status")
|
|
330
|
+
if status == 200:
|
|
331
|
+
return True
|
|
332
|
+
except MockServerConnectionError:
|
|
333
|
+
pass
|
|
334
|
+
if i < attempts - 1:
|
|
335
|
+
await asyncio.sleep(timeout)
|
|
336
|
+
return False
|
|
337
|
+
|
|
338
|
+
def when(
|
|
339
|
+
self,
|
|
340
|
+
request: HttpRequest,
|
|
341
|
+
times: Times | None = None,
|
|
342
|
+
time_to_live: TimeToLive | None = None,
|
|
343
|
+
priority: int | None = None,
|
|
344
|
+
) -> ForwardChainExpectation:
|
|
345
|
+
expectation = Expectation(
|
|
346
|
+
http_request=request,
|
|
347
|
+
times=times,
|
|
348
|
+
time_to_live=time_to_live,
|
|
349
|
+
priority=priority,
|
|
350
|
+
)
|
|
351
|
+
return ForwardChainExpectation(self, expectation)
|
|
352
|
+
|
|
353
|
+
async def mock_with_callback(
|
|
354
|
+
self,
|
|
355
|
+
request: HttpRequest,
|
|
356
|
+
callback: Callable,
|
|
357
|
+
times: Times | None = None,
|
|
358
|
+
time_to_live: TimeToLive | None = None,
|
|
359
|
+
) -> list[Expectation]:
|
|
360
|
+
client_id = await self._register_websocket_callback("response", callback)
|
|
361
|
+
expectation = Expectation(
|
|
362
|
+
http_request=request,
|
|
363
|
+
http_response_object_callback=HttpObjectCallback(client_id=client_id),
|
|
364
|
+
times=times,
|
|
365
|
+
time_to_live=time_to_live,
|
|
366
|
+
)
|
|
367
|
+
return await self.upsert(expectation)
|
|
368
|
+
|
|
369
|
+
async def mock_with_forward_callback(
|
|
370
|
+
self,
|
|
371
|
+
request: HttpRequest,
|
|
372
|
+
forward_callback: Callable,
|
|
373
|
+
response_callback: Callable | None = None,
|
|
374
|
+
times: Times | None = None,
|
|
375
|
+
time_to_live: TimeToLive | None = None,
|
|
376
|
+
) -> list[Expectation]:
|
|
377
|
+
client_id = await self._register_websocket_callback(
|
|
378
|
+
"forward", forward_callback, response_callback
|
|
379
|
+
)
|
|
380
|
+
obj_callback = HttpObjectCallback(client_id=client_id)
|
|
381
|
+
if response_callback is not None:
|
|
382
|
+
obj_callback.response_callback = True
|
|
383
|
+
expectation = Expectation(
|
|
384
|
+
http_request=request,
|
|
385
|
+
http_forward_object_callback=obj_callback,
|
|
386
|
+
times=times,
|
|
387
|
+
time_to_live=time_to_live,
|
|
388
|
+
)
|
|
389
|
+
return await self.upsert(expectation)
|
|
390
|
+
|
|
391
|
+
async def _register_websocket_callback(
|
|
392
|
+
self,
|
|
393
|
+
callback_type: str,
|
|
394
|
+
callback_fn: Callable,
|
|
395
|
+
forward_response_fn: Callable | None = None,
|
|
396
|
+
) -> str:
|
|
397
|
+
ws_client = MockServerWebSocketClient()
|
|
398
|
+
client_id = await ws_client.connect(
|
|
399
|
+
self._host,
|
|
400
|
+
self._port,
|
|
401
|
+
self._context_path,
|
|
402
|
+
self._secure,
|
|
403
|
+
self._ca_cert_path,
|
|
404
|
+
tls_verify=self._tls_verify,
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
if callback_type == "response":
|
|
408
|
+
ws_client.register_response_callback(callback_fn)
|
|
409
|
+
elif callback_type == "forward":
|
|
410
|
+
ws_client.register_forward_callback(callback_fn, forward_response_fn)
|
|
411
|
+
|
|
412
|
+
ws_client._listen_task = asyncio.create_task(ws_client.listen())
|
|
413
|
+
self._websocket_clients.append(ws_client)
|
|
414
|
+
return client_id
|
|
415
|
+
|
|
416
|
+
async def close(self) -> None:
|
|
417
|
+
for ws_client in self._websocket_clients:
|
|
418
|
+
await ws_client.close()
|
|
419
|
+
self._websocket_clients.clear()
|
|
420
|
+
|
|
421
|
+
async def __aenter__(self) -> AsyncMockServerClient:
|
|
422
|
+
return self
|
|
423
|
+
|
|
424
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
425
|
+
await self.close()
|