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)
87 server_task = asyncio.create_task(server.start())
92 await asyncio.shield(server.stop(grace=
None))
93 await asyncio.shield(server.wait_for_termination())
94 await asyncio.shield(server_task)
97@pytest.fixture(scope='session')
100 Creates the gRPC mock server for the provided type.
102 @snippet samples/grpc_service/tests/conftest.py Prepare server mock
103 @ingroup userver_testsuite_fixtures
105 return _create_servicer_mock
108def pytest_addoption(parser):
109 group = parser.getgroup(
'grpc-mockserver')
111 '--grpc-mockserver-host',
113 help=
'gRPC mockserver hostname, default is [::]',
116 '--grpc-mockserver-port',
119 help=
'gRPC mockserver port, by default random port is used',
123def _create_servicer_mock(
124 servicer_class: type,
126 stream_method_names: Optional[List[str]] =
None,
127 before_call_hook: Optional[Callable[...,
None]] =
None,
129 def wrap_grpc_method(name, default_method, is_stream):
130 @functools.wraps(default_method)
131 async def run_method(self, *args, **kwargs):
132 if before_call_hook
is not None:
133 before_call_hook(*args, **kwargs)
135 method = mock.get(name,
None)
136 if method
is not None:
137 call = method(*args, **kwargs)
139 call = default_method(self, *args, **kwargs)
143 @functools.wraps(default_method)
144 async def run_stream_method(self, *args, **kwargs):
145 if before_call_hook
is not None:
146 before_call_hook(*args, **kwargs)
148 method = mock.get(name,
None)
149 async for response
in await method(*args, **kwargs):
152 return run_stream_method
if is_stream
else run_method
155 for attname, value
in servicer_class.__dict__.items():
157 methods[attname] = wrap_grpc_method(
159 default_method=value,
160 is_stream=attname
in (stream_method_names
or []),
163 mocked_servicer_class = type(
164 f
'Mock{servicer_class.__name__}', (servicer_class,), methods,
166 servicer = mocked_servicer_class()