Disclaimer: I'm new to using asyncio
so this might be an easy fix.
I'm trying to write tests for the endpoints of an asynchronous grpc-server. The server has to regularly check something using a function that runs in an infinite loop, and still be responsive when the infinite loop is sleeping - which is why I'm using grpc-asyncio
and pytest-asyncio
.
example test (event_loop created by pytest-asyncio):
@pytest.mark.asyncio
async def test_endpoint(
event_loop,
test_client: test_pb2_grpc.TesterStub,
):
await serve() # THIS BLOCKS THE REST OF THE TEST
response = await test_client.TemporaryEndpointForTesting(request=test_pb2.TmpRequest())
assert response
client fixture:
@pytest.fixture
def test_client() -> test_pb2_grpc.TesterStub:
port = 50551
channel = aio.insecure_channel(f'localhost:{port}')
stub = test_pb2_grpc.TesterStub(channel)
return stub
server endpoints:
class Servicer(test_pb2_grpc.TesterServicer):
# ENDPOINT
async def TemporaryEndpointForTesting(self, request, context):
print("request received!")
return test_pb2.TmpResponse()
async def infinite_loop(self):
await asyncio.sleep(1.0)
print("<looping>")
return asyncio.ensure_future(self.infinite_loop())
server startup:
async def serve():
port = 50551
server: aio.Server = aio.server()
servicer = Servicer()
test_pb2_grpc.add_TesterServicer_to_server(servicer, server)
server.add_insecure_port(f'[::]:{port}')
task_1 = asyncio.create_task(servicer.infinite_loop())
task_2 = asyncio.create_task(server.start())
task_3 = asyncio.create_task(server.wait_for_termination())
await task_1
await task_2
await task_3
The goal is to set up the server, and then send requests to it to see if it responds as expected. When I start the server separately using await serve()
and then run my tests, it seems to work flawlessly. But when I try to start it from the testcase, it gets stuck ... which I sort of get, since it's awaiting the (infinite) server-tasks to finish, but I don't know how to get around this. I thought using a different event_loop
for the server-tasks would do the trick ...
new_event_loop = asyncio.new_event_loop()
task_1 = new_event_loop.create_task(servicer.infinite_loop())
task_2 = new_event_loop.create_task(server.start())
task_3 = new_event_loop.create_task(server.wait_for_termination())
but that didn't work either.
Best-case would be a way to start up the server within a fixture so I can just pass it to all test functions. I'm guessing this could also be done using threading, but that seems a bit superfluous considering the server is already using asyncio
.
I've been at this all day, any help would be well appreciated.
(using Python 3.9)