1

Hello everyone, I'm writing tests for a game that is written in the python websockets library. When running the test test_game_started an error appears that asyncio loop is not running, but the test passes.

I provide the entire test code and the error below:

Code of HelpTest class:

class HelpTest:
    def __init__(self, loop):
        self.loop = loop
        self.ws1 = None
        self.ws2 = None
        self.msg1 = None
        self.msg2 = None
        self.tasks = []

    async def listen1(self):
        async with websockets.connect(f"ws://localhost:27000") as websocket:
            self.ws1 = websocket
            while True:
                try:
                    self.msg1 = await websocket.recv()
                    await asyncio.sleep(0.1)
                except RuntimeError:
                    break

    async def listen2(self):
        async with websockets.connect(f"ws://localhost:27000") as websocket:
            self.ws2 = websocket
            while True:
                try:
                    self.msg2 = await websocket.recv()
                    await asyncio.sleep(0.1)
                except RuntimeError:
                    break

    async def in_game_helper(self, mapData1, mapData2):
        self.tasks.extend([self.loop.create_task(self.listen1()), self.loop.create_task(self.listen2())])
        await asyncio.wait(self.tasks)
        await asyncio.sleep(1)
        await self.ws1.send(generate_payload("knock-knock", {"nick": 'a'}))
        await asyncio.sleep(0.4)
        await self.ws2.send(generate_payload("knock-knock", {"nick": 'b'}))
        await asyncio.sleep(0.4)
        await self.ws1.send(json.dumps({"header": "send_map", 'data': mapData1}))
        await asyncio.sleep(0.4)
        await self.ws1.send(json.dumps({"header": "send_map", 'data': mapData2}))
        await asyncio.sleep(3)
        #for task in self.tasks:
          #  print(task)
         #   task.cancel()
        #self.loop.stop()
        return json.loads(self.msg1)

    async def kill_helper(self, coords):
        pass

    async def miss_helper(self, coords):
        pass

Code of TestServer class with tests:

class TestServer:
    # main()
    def setup_class(self):
        self.loop = asyncio.new_event_loop()
        self.ws1 = None
        self.ws2 = None
        self.msg1 = None
        self.msg2 = None
        self.tasks = []

    @pytest.fixture
    def mapData1(self):
        f = open("map1.json", 'r').read()
        data = json.loads(f)
        return data

    @pytest.fixture
    def mapData2(self):
        f = open("map2.json", 'r').read()
        data = json.loads(f)
        return data

    @pytest.fixture
    def event_loop(self):
        loop = asyncio.get_event_loop()
        yield loop
        loop.close()

    @pytest.mark.asyncio
    async def test_knock(self):
        async with websockets.connect(f"ws://localhost:27000") as websocket:
            await websocket.send(generate_payload("knock-knock", {"nick": 'a'}))
            for i in range(3):
                msg = json.loads(await websocket.recv())
                await asyncio.sleep(0.5)
            assert msg['header'] == 'registered'

    @pytest.mark.asyncio
    async def test_send1(self, mapData1):
        async with websockets.connect(f"ws://localhost:27000") as websocket:
            await websocket.send(generate_payload("knock-knock", {"nick": 'a'}))
            for i in range(3):
                await websocket.recv()
                await asyncio.sleep(0.5)
            await websocket.send(json.dumps({"header": "send_map", 'data': mapData1}))
            msg = json.loads(await websocket.recv())
            assert msg['header'] == 'ready'
            await websocket.close()

    @pytest.mark.asyncio
    async def test_send2(self, mapData2):
        async with websockets.connect(f"ws://localhost:27000") as websocket:
            await websocket.send(generate_payload("knock-knock", {"nick": 'b'}))
            for i in range(4):
                await websocket.recv()
                await asyncio.sleep(0.5)
            await websocket.send(json.dumps({"header": "send_map", 'data': mapData2}))
            msg = json.loads(await websocket.recv())
            assert msg['header'] == 'ready'
            await websocket.close()

    @pytest.mark.asyncio
    async def test_game_started(self, mapData1, mapData2, event_loop):
        helper = HelpTest(event_loop)
        answer = await helper.in_game_helper(mapData1, mapData2)
        print(answer)
        assert answer['header'] == "in_game!!!"

Traceback of runned test:

Traceback (most recent call last):
  File "tests.py", line 40, in listen2
    break
  File "SeaBattle\venv\lib\site-packages\websockets\legacy\client.py", line 650, in __aexit__
    await self.protocol.close()
  File "SeaBattle\venv\lib\site-packages\websockets\legacy\protocol.py", line 768, in close
    await asyncio.wait_for(
  File "C:\Users\zayyc\AppData\Local\Programs\Python\Python39\lib\asyncio\tasks.py", line 435, in wait_for
    loop = events.get_running_loop()
RuntimeError: no running event loop

I've tried to use pytest,mark.asyncio loop, but it did not help. I think the problem is that the tasks listen1() and listen2() keep running after the loop is closed, I tried to stop them, but the error still persists. I will be very happy with your decisions.

  • I managed to solve the problem. I sent a task to a long sleep and forcibly disconnected from the websocket. After such manipulations, the program did not give errors and the cycles were quietly closed. You can look at the repositories for details: https://github.com/zayycev22/SeaBattle/blob/main/tests.py – Юрий Зайцев Oct 30 '22 at 23:11

0 Answers0