From 24e28282bb52e9715dd25ccc35dd196696849d44 Mon Sep 17 00:00:00 2001 From: shauneccles Date: Sat, 11 Jul 2026 15:34:14 +1000 Subject: [PATCH] Run the live test suite on one event loop The module shares one GLinet client and one aiohttp session, but with pytest-asyncio >= 0.26 the session-scoped event_loop fixture is ignored and each test gets its own function-scoped loop, so every test after the first fails with 'RuntimeError: Event loop is closed'. Mark the module with loop_scope="module" and drop the obsolete fixture and the now-redundant per-test markers. Verified against a GL-MT6000 (firmware 4.9.0), logs in the PR. Co-Authored-By: Claude Fable 5 --- tests/test_glinet.py | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/tests/test_glinet.py b/tests/test_glinet.py index 3c3cb35..543c937 100644 --- a/tests/test_glinet.py +++ b/tests/test_glinet.py @@ -7,6 +7,10 @@ from gli4py.error_handling import NonZeroResponse from gli4py.glinet import GLinet, NEW_VPN_CLIENT_VERSION +# All tests share one GLinet client (and one aiohttp session), so they must +# run on a single event loop. +pytestmark = pytest.mark.asyncio(loop_scope="module") + router = GLinet(base_url="http://192.168.0.1/rpc") PERFORM_DISTRUPTIVE_TESTS = False @@ -41,16 +45,6 @@ ] -@pytest.fixture(scope="session") -def event_loop(): - """Create a new event loop for each test session.""" - policy = asyncio.get_event_loop_policy() - loop = policy.new_event_loop() - yield loop - loop.close() - - -@pytest.mark.asyncio async def test_router_reachable() -> None: """Test if the router is reachable.""" response = await router.router_reachable() @@ -58,7 +52,6 @@ async def test_router_reachable() -> None: print(response) -@pytest.mark.asyncio async def test_login() -> None: """Test logging into the router.""" with open("router_pwd", "r", encoding="utf-8") as file: @@ -69,7 +62,6 @@ async def test_login() -> None: print(router.sid) -@pytest.mark.asyncio async def test_router_info() -> None: """Test retrieving router information.""" response = await router.router_info() @@ -79,7 +71,6 @@ async def test_router_info() -> None: print(response) -@pytest.mark.asyncio async def test_router_get_status() -> None: """Test retrieving router status.""" response = await router.router_get_status() @@ -93,7 +84,6 @@ async def test_router_get_status() -> None: print(response) -@pytest.mark.asyncio async def test_router_get_load() -> None: """Test retrieving router load information.""" response = await router.router_get_load() @@ -103,7 +93,6 @@ async def test_router_get_load() -> None: print(response) -@pytest.mark.asyncio async def test_router_mac() -> None: """Test retrieving the router's MAC address.""" response = await router.router_mac() @@ -111,7 +100,6 @@ async def test_router_mac() -> None: print(response) -@pytest.mark.asyncio async def test_connected_clients() -> None: """Test retrieving connected clients.""" clients = await router.connected_clients() @@ -119,7 +107,6 @@ async def test_connected_clients() -> None: assert len(clients) > 0 -@pytest.mark.asyncio async def test_wifi_ifaces_get() -> None: """Test retrieving WiFi interfaces.""" wifi_ifaces = await router.wifi_ifaces_get() @@ -131,7 +118,6 @@ async def test_wifi_ifaces_get() -> None: assert "key" in iface -@pytest.mark.asyncio async def test_wifi_ifaces_set_enabled() -> None: """Test enabling/disabling a WiFi interface.""" @@ -151,7 +137,6 @@ async def test_wifi_ifaces_set_enabled() -> None: assert iface_enabled_after != iface_enabled -@pytest.mark.asyncio async def test_connected_to_internet() -> None: """Test checking if the router is connected to the internet.""" response = await router.connected_to_internet() @@ -160,7 +145,6 @@ async def test_connected_to_internet() -> None: assert "ip" in response -@pytest.mark.asyncio async def test_ping() -> None: """Test pinging a host.""" response = await router.ping("google.com") @@ -172,7 +156,6 @@ async def test_ping() -> None: assert not response -@pytest.mark.asyncio async def test_wireguard_client_list() -> None: """Test retrieving the list of WireGuard clients.""" response = await router.wireguard_client_list() @@ -180,7 +163,6 @@ async def test_wireguard_client_list() -> None: # assert(response['enable'] in [True,False]) -@pytest.mark.asyncio async def test_wireguard_client_state() -> None: """Test retrieving the state of the WireGuard client.""" # We need to get the proper firmware version for this @@ -198,7 +180,6 @@ async def test_wireguard_client_state() -> None: assert first_status["status"] in [0, 1, 2] -@pytest.mark.asyncio async def test_wireguard_start() -> None: """Test starting the WireGuard client.""" assert PERFORM_DISTRUPTIVE_TESTS, ( @@ -236,7 +217,6 @@ async def test_wireguard_start() -> None: pytest.fail("WireGuard client took too long to connect.") -@pytest.mark.asyncio async def test_wireguard_stop() -> None: """Test stopping the WireGuard client.""" assert PERFORM_DISTRUPTIVE_TESTS, ( @@ -278,7 +258,6 @@ async def test_wireguard_stop() -> None: pytest.fail("WireGuard client took too long to disconnect.") -@pytest.mark.asyncio async def test_tailscale_status() -> None: """Test retrieving the Tailscale status.""" response = await router._tailscale_status() # pylint: disable=protected-access @@ -286,7 +265,6 @@ async def test_tailscale_status() -> None: assert dict(response).get("status", 0) in [1, 2, 3, 4] or response == [] -@pytest.mark.asyncio async def test_tailscale_connection() -> None: """Test retrieving the Tailscale connection state.""" response = await router.tailscale_connection_state() @@ -294,7 +272,6 @@ async def test_tailscale_connection() -> None: assert response in [TailscaleConnection.DISCONNECTED, TailscaleConnection.CONNECTED] -@pytest.mark.asyncio async def test_tailscale_configured() -> None: """Test checking if Tailscale is configured.""" response = await router.tailscale_configured() @@ -302,7 +279,6 @@ async def test_tailscale_configured() -> None: assert response in [True, False] -@pytest.mark.asyncio async def test_tailscale_get_config() -> None: """Test retrieving the Tailscale configuration.""" response = await router._tailscale_get_config() # pylint: disable=protected-access @@ -310,7 +286,6 @@ async def test_tailscale_get_config() -> None: assert response["enabled"] in [True, False] -@pytest.mark.asyncio async def test_tailscale_start() -> None: """Test starting Tailscale.""" assert PERFORM_DISTRUPTIVE_TESTS, ( @@ -321,7 +296,6 @@ async def test_tailscale_start() -> None: assert result in [True, False] -@pytest.mark.asyncio async def test_tailscale_stop() -> None: """Test stopping Tailscale.""" assert PERFORM_DISTRUPTIVE_TESTS, ( @@ -332,7 +306,6 @@ async def test_tailscale_stop() -> None: assert result in [True, False] -@pytest.mark.asyncio async def test_router_reboot() -> None: """Test rebooting the router.""" assert PERFORM_DISTRUPTIVE_TESTS, (