From c1193b589c7b2d3e0b40442c2b5d67a725742cab Mon Sep 17 00:00:00 2001 From: Daniel Fetti Date: Tue, 29 Oct 2024 09:41:46 +0200 Subject: [PATCH] Increase constrains in link state testcases Previously the link state testcase scenarios were structured like setup, do some interaction between peers, sleep for a while and check the reported link states. This approach did not consider the timings of the events. Proposed solution consists in checking the state constantly during the scenario, not only at the end of it. Signed-off-by: Daniel Fetti --- .unreleased/LLT-5683 | 1 + nat-lab/tests/telio.py | 29 +++++ nat-lab/tests/test_events_link_state.py | 154 ++++++++++++++++-------- 3 files changed, 134 insertions(+), 50 deletions(-) create mode 100644 .unreleased/LLT-5683 diff --git a/.unreleased/LLT-5683 b/.unreleased/LLT-5683 new file mode 100644 index 000000000..d53e83c73 --- /dev/null +++ b/.unreleased/LLT-5683 @@ -0,0 +1 @@ +Increase constrains in link state testcases \ No newline at end of file diff --git a/nat-lab/tests/telio.py b/nat-lab/tests/telio.py index 858f00b47..319a20a7f 100644 --- a/nat-lab/tests/telio.py +++ b/nat-lab/tests/telio.py @@ -129,6 +129,13 @@ async def notify_peer_state( return await asyncio.sleep(0.1) + async def notify_link_state(self, public_key: str, states: List[LinkState]) -> None: + while True: + peer = self.get_peer_info(public_key) + if peer and peer.link_state in states: + return + await asyncio.sleep(0.1) + async def notify_peer_event( self, public_key: str, @@ -262,6 +269,16 @@ async def wait_for_state_peer( timeout, ) + async def wait_for_link_state( + self, + public_key: str, + state: List[LinkState], + timeout: Optional[float] = None, + ) -> None: + await asyncio.wait_for( + self._runtime.notify_link_state(public_key, state), timeout + ) + async def wait_for_event_peer( self, public_key: str, @@ -539,6 +556,18 @@ async def wait_for_state_peer( link_state, ) + async def wait_for_link_state( + self, + public_key: str, + states: List[LinkState], + timeout: Optional[float] = None, + ) -> None: + await self.get_events().wait_for_link_state( + public_key, + states, + timeout, + ) + async def wait_for_event_peer( self, public_key: str, diff --git a/nat-lab/tests/test_events_link_state.py b/nat-lab/tests/test_events_link_state.py index f172cab8b..f48d610a8 100644 --- a/nat-lab/tests/test_events_link_state.py +++ b/nat-lab/tests/test_events_link_state.py @@ -140,14 +140,27 @@ async def test_event_link_state_peers_idle_all_time( alpha, beta = env.nodes client_alpha, client_beta = env.clients - # Expect no link event while peers are idle - await asyncio.sleep(20) - alpha_events = client_beta.get_link_state_events(alpha.public_key) - beta_events = client_alpha.get_link_state_events(beta.public_key) + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.UP]) + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP]) - # 1 down event when Connecting, 1 up event when Connected - assert alpha_events == [LinkState.DOWN, LinkState.UP] - assert beta_events == [LinkState.DOWN, LinkState.UP] + # Expect no link event while peers are idle + with pytest.raises(asyncio.TimeoutError): + await asyncio.wait( + [ + asyncio.create_task( + client_alpha.wait_for_link_state( + beta.public_key, [LinkState.DOWN] + ) + ), + asyncio.create_task( + client_beta.wait_for_link_state( + alpha.public_key, [LinkState.DOWN] + ) + ), + ], + timeout=20, + return_when=asyncio.FIRST_COMPLETED, + ) @pytest.mark.asyncio @@ -163,18 +176,15 @@ async def test_event_link_state_peers_exchanging_data_for_a_long_time( conn.connection for conn in env.connections ] + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.UP]) + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP]) + for _ in range(0, 40): await asyncio.sleep(1) await ping(connection_alpha, beta.ip_addresses[0]) await ping(connection_beta, alpha.ip_addresses[0]) - - # Expect no nolink event while peers are active - alpha_events = client_beta.get_link_state_events(alpha.public_key) - beta_events = client_alpha.get_link_state_events(beta.public_key) - - # 1 down event when Connecting, 1 up event when Connected - assert alpha_events == [LinkState.DOWN, LinkState.UP] - assert beta_events == [LinkState.DOWN, LinkState.UP] + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.UP], 1) + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP], 1) @pytest.mark.asyncio @@ -190,21 +200,56 @@ async def test_event_link_state_peers_exchanging_data_then_idling_then_resume( conn.connection for conn in env.connections ] + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.UP]) + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP]) + await ping(connection_alpha, beta.ip_addresses[0]) await ping(connection_beta, alpha.ip_addresses[0]) # Expect no link event while peers are idle - await asyncio.sleep(20) + with pytest.raises(asyncio.TimeoutError): + await asyncio.wait( + [ + asyncio.create_task( + client_alpha.wait_for_link_state( + beta.public_key, [LinkState.DOWN] + ) + ), + asyncio.create_task( + client_beta.wait_for_link_state( + alpha.public_key, [LinkState.DOWN] + ) + ), + ], + timeout=25, + return_when=asyncio.FIRST_COMPLETED, + ) await ping(connection_alpha, beta.ip_addresses[0]) await ping(connection_beta, alpha.ip_addresses[0]) - alpha_events = client_beta.get_link_state_events(alpha.public_key) - beta_events = client_alpha.get_link_state_events(beta.public_key) - - # 1 down event when Connecting, 1 up event when Connected - assert alpha_events == [LinkState.DOWN, LinkState.UP] - assert beta_events == [LinkState.DOWN, LinkState.UP] + # Wait for another 5 seconds + with pytest.raises(asyncio.TimeoutError): + await asyncio.wait( + [ + asyncio.create_task( + client_alpha.wait_for_link_state( + beta.public_key, [LinkState.DOWN] + ) + ), + asyncio.create_task( + client_beta.wait_for_link_state( + alpha.public_key, [LinkState.DOWN] + ) + ), + ], + timeout=5, + return_when=asyncio.FIRST_COMPLETED, + ) + + # Expect the links are still UP + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.UP], 1) + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP], 1) @pytest.mark.asyncio @@ -220,24 +265,28 @@ async def test_event_link_state_peer_goes_offline( conn.connection for conn in env.connections ] + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.UP]) + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP]) + await ping(connection_alpha, beta.ip_addresses[0]) await ping(connection_beta, alpha.ip_addresses[0]) await client_beta.stop_device() - await asyncio.sleep(1) - with pytest.raises(asyncio.TimeoutError): - await ping(connection_alpha, beta.ip_addresses[0], 5) + await ping(connection_alpha, beta.ip_addresses[0], 3) - await asyncio.sleep(25) - alpha_events = client_beta.get_link_state_events(alpha.public_key) - beta_events = client_alpha.get_link_state_events(beta.public_key) + with pytest.raises(asyncio.TimeoutError): + await client_alpha.wait_for_link_state( + beta.public_key, [LinkState.DOWN], 10 + ) - # 1 down event when Connecting, 1 up event when Connected - assert alpha_events == [LinkState.DOWN, LinkState.UP] - # 1 down event when Connecting, 1 up event when Connected, 1 down event when client is stopped - assert beta_events == [LinkState.DOWN, LinkState.UP, LinkState.DOWN] + # Expect the link down event + # It should arrive in 11-15 seconds after the link is cut and ping mod disabled + # And 22-25 seconds if the ping mod is enabled + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.DOWN], 30) + # Although the beta device has been stopped, it should still see alpha as up + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP], 5) @pytest.mark.asyncio @@ -315,24 +364,29 @@ async def test_event_link_state_peer_doesnt_respond( conn.connection for conn in env.connections ] + await client_alpha.wait_for_link_state(beta.public_key, [LinkState.UP]) + await client_beta.wait_for_link_state(alpha.public_key, [LinkState.UP]) + async with ICMP_control(connection_beta): with pytest.raises(asyncio.TimeoutError): - await ping(connection_alpha, beta.ip_addresses[0], 8) - - alpha_events = client_beta.get_link_state_events(alpha.public_key) - beta_events = client_alpha.get_link_state_events(beta.public_key) - - # The connection is normal and events should be: initial down, then several up events but no more down events - assert alpha_events.count(LinkState.DOWN) == 1 - assert beta_events.count(LinkState.DOWN) == 1 - - # wait enough to pass 10 second mark since our ping request, which should trigger passive-keepalive by wireguard - await asyncio.sleep(5) + await ping(connection_alpha, beta.ip_addresses[0], 5) - alpha_events = client_beta.get_link_state_events(alpha.public_key) - beta_events = client_alpha.get_link_state_events(beta.public_key) - - # there should be no additional link down event - - assert alpha_events.count(LinkState.DOWN) == 1 - assert beta_events.count(LinkState.DOWN) == 1 + # Wait enough to pass 10 second mark since our ping request, which should trigger passive-keepalive by wireguard + # + some delay for ping mode + with pytest.raises(asyncio.TimeoutError): + await asyncio.wait( + [ + asyncio.create_task( + client_alpha.wait_for_link_state( + beta.public_key, [LinkState.DOWN] + ) + ), + asyncio.create_task( + client_beta.wait_for_link_state( + alpha.public_key, [LinkState.DOWN] + ) + ), + ], + timeout=25, + return_when=asyncio.FIRST_COMPLETED, + )