userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
tcp_mockserver.py
1
import
asyncio
2
import
contextlib
3
import
socket
4
5
import
pytest
6
7
from
testsuite.utils
import
cached_property, net
8
9
10
class
Mockserver
:
11
"""TCP/IP mockserver."""
12
13
def
__init__(self, server):
14
self.
_handler
=
None
15
self.
_sockets
= tuple(server.sockets)
16
17
async def
_client_connected_cb(self, reader, writer):
18
try
:
19
if
self.
_handler
is
None
:
20
raise
RuntimeError(
21
'No client handler installed, use client_handler()'
,
22
)
23
return
await self.
_handler
(reader, writer)
24
except
Exception:
25
writer.close()
26
pytest.fail(
'Mockserver handler failure'
)
27
28
@cached_property
29
def
sockets
(self) -> tuple[socket.socket]:
30
"""Returns list of server sockets."""
31
return
self.
_sockets
32
33
@cached_property
34
def
address
(self) -> tuple[str, int]:
35
"""
36
Returns service address (host, port)
37
"""
38
assert
self.
_sockets
39
return
self.
_sockets
[0].getsockname()[:2]
40
41
@contextlib.asynccontextmanager
42
async def
open_connection
(self, timeout=10.0):
43
"""Async context manager creates connection to the service.
44
45
:param timeout: timeout to establish connection.
46
47
Returns pair (read, writer).
48
49
Connection is closed when context manager is done.
50
51
Wrapper around :func:`asyncio.open_connection`
52
53
54
.. code-block:: python
55
56
async with server.open_connection() as (reader, writer):
57
...
58
"""
59
host, port = self.
address
60
coro = asyncio.open_connection(host=host, port=port)
61
try
:
62
reader, writer = await asyncio.wait_for(coro, timeout=timeout)
63
yield
reader, writer
64
finally
:
65
writer.close()
66
67
@contextlib.contextmanager
68
def
client_handler
(self, handler):
69
"""Context manager to install per-test client handler.
70
71
.. code-block:: python
72
73
async def handle_client(reader, writer):
74
writer.write(b'hello\\r\\n')
75
await writer.drain()
76
writer.close()
77
78
with _tcp_mockserver.client_handler(handle_client):
79
...
80
"""
81
old_handler = self.
_handler
82
try
:
83
self.
_handler
= handler
84
yield
85
finally
:
86
self.
_handler
= old_handler
87
88
89
class
ProtocolFactory
:
90
def
__init__(self):
91
self.
client_handler
=
None
92
93
def
__call__(self):
94
if
self.
client_handler
is
None
:
95
pytest.fail(
'No client handler attached'
)
96
reader = asyncio.StreamReader()
97
protocol = asyncio.StreamReaderProtocol(
98
reader,
99
self.
client_handler
,
100
)
101
return
protocol
102
103
@contextlib.contextmanager
104
def
attach_client_handler(self, handler):
105
try
:
106
self.
client_handler
= handler
107
yield
108
finally
:
109
self.
client_handler
=
None
110
111
112
@pytest.fixture(scope='session')
113
async def
create_tcp_mockserver():
114
@contextlib.asynccontextmanager
115
async def
create_mockserver(
116
*,
117
host='localhost',
118
port=0,
119
sock=None,
120
**kwargs,
121
):
122
factory =
ProtocolFactory
()
123
async
with
net.create_tcp_server(
124
factory,
125
host=host,
126
port=port,
127
sock=sock,
128
**kwargs,
129
)
as
server:
130
mockserver =
Mockserver
(server)
131
with
factory.attach_client_handler(
132
mockserver._client_connected_cb,
133
):
134
yield
mockserver
135
136
return
create_mockserver
en
testsuite
plugins
tcp_mockserver.py
Generated on
for userver by
Doxygen
1.17.0