2Mocks for the gRPC servers.
4@sa @ref scripts/docs/en/userver/tutorial/grpc_service.md
11from typing
import Callable
12from typing
import List
13from typing
import Optional
18from testsuite.utils
import callinfo
24 def __init__(self, servicer, methods):
29 def get(self, method, default):
30 return self.
_methods.get(method, default)
32 def reset_handlers(self):
35 @contextlib.contextmanager
42 def install_handler(self, method: str):
46 f
'Trying to mock unknown grpc method {method}',
49 wrapped = callinfo.acallqueue(func)
56@pytest.fixture(scope='session')
59 Returns the gRPC endpoint to start the mocking server that is set by
60 command line `--grpc-mockserver-host` and `--grpc-mockserver-port` options.
62 For port 0, picks some free port.
64 Override this fixture to customize the endpoint used by gRPC mockserver.
66 @snippet samples/grpc_service/tests/conftest.py Prepare configs
67 @ingroup userver_testsuite_fixtures
69 port = pytestconfig.option.grpc_mockserver_port
70 if pytestconfig.option.service_wait
or pytestconfig.option.service_disable:
71 port = port
or DEFAULT_PORT
73 port = get_free_port()
74 return f
'{pytestconfig.option.grpc_mockserver_host}:{port}'
77@pytest.fixture(scope='session')
80 Returns the gRPC mocking server.
82 @snippet samples/grpc_service/tests/conftest.py Prepare server mock
83 @ingroup userver_testsuite_fixtures
85 server = grpc.aio.server()
86 server.add_insecure_port(grpc_mockserver_endpoint)
93 async def stop_server():
94 await server.stop(grace=
None)
95 await server.wait_for_termination()
97 stop_server_task = asyncio.shield(asyncio.create_task(stop_server()))
101 await stop_server_task
102 except asyncio.CancelledError:
103 await stop_server_task
108@pytest.fixture(scope='session')
111 Creates the gRPC mock server for the provided type.
113 @snippet samples/grpc_service/tests/conftest.py Prepare server mock
114 @ingroup userver_testsuite_fixtures
116 return _create_servicer_mock
119def pytest_addoption(parser):
120 group = parser.getgroup(
'grpc-mockserver')
122 '--grpc-mockserver-host',
124 help=
'gRPC mockserver hostname, default is [::]',
127 '--grpc-mockserver-port',
130 help=
'gRPC mockserver port, by default random port is used',
134def _create_servicer_mock(
135 servicer_class: type,
137 stream_method_names: Optional[List[str]] =
None,
138 before_call_hook: Optional[Callable[...,
None]] =
None,
140 def wrap_grpc_method(name, default_method, is_stream):
141 @functools.wraps(default_method)
142 async def run_method(self, *args, **kwargs):
143 if before_call_hook
is not None:
144 before_call_hook(*args, **kwargs)
146 method = mock.get(name,
None)
147 if method
is not None:
148 return await method(*args, **kwargs)
150 return default_method(self, *args, **kwargs)
152 @functools.wraps(default_method)
153 async def run_stream_method(self, *args, **kwargs):
154 if before_call_hook
is not None:
155 before_call_hook(*args, **kwargs)
157 method = mock.get(name,
None)
158 async for response
in await method(*args, **kwargs):
161 return run_stream_method
if is_stream
else run_method
164 for attname, value
in servicer_class.__dict__.items():
166 methods[attname] = wrap_grpc_method(
168 default_method=value,
169 is_stream=attname
in (stream_method_names
or []),
172 mocked_servicer_class = type(
173 f
'Mock{servicer_class.__name__}', (servicer_class,), methods,
175 servicer = mocked_servicer_class()