diff --git a/.unreleased/make_node_diff_more_clear b/.unreleased/make_node_diff_more_clear new file mode 100644 index 000000000..e69de29bb diff --git a/nat-lab/Pipfile b/nat-lab/Pipfile index a192b4fa3..1953b4185 100644 --- a/nat-lab/Pipfile +++ b/nat-lab/Pipfile @@ -51,6 +51,7 @@ asyncssh = "==2.14.2" aiodocker = "*" scapy="2.5" paho-mqtt = "*" +deepdiff = "*" [dev-packages] diff --git a/nat-lab/Pipfile.lock b/nat-lab/Pipfile.lock index 3f6e737f7..d9eca10ee 100644 --- a/nat-lab/Pipfile.lock +++ b/nat-lab/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "af3aea0124a9146df2dc6d36dbc8b6505477a791e0781b3a7d479b3778d6d73b" + "sha256": "33fb29011128808ad1d36860d40aaf9d0e2de793c801963cfa202f515a6f6c00" }, "pipfile-spec": 6, "requires": {}, @@ -387,6 +387,15 @@ "markers": "python_version >= '3.7' and python_version < '4.0'", "version": "==0.6.7" }, + "deepdiff": { + "hashes": [ + "sha256:b0231fa3afb0f7184e82535f2b4a36636442ed21e94a0cf3aaa7982157e7ebca", + "sha256:dd7bc7d5c8b51b5b90f01b0e2fe23c801fd8b4c6a7ee7e31c5a3c3663fcc7ceb" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==8.1.1" + }, "exceptiongroup": { "hashes": [ "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", @@ -752,6 +761,14 @@ "markers": "python_version >= '3.5'", "version": "==1.0.0" }, + "orderly-set": { + "hashes": [ + "sha256:571ed97c5a5fca7ddeb6b2d26c19aca896b0ed91f334d9c109edd2f265fb3017", + "sha256:d357cedcf67f4ebff0d4cbd5b0997e98eeb65dd24fdf5c990a501ae9e82c7d34" + ], + "markers": "python_version >= '3.8'", + "version": "==5.2.3" + }, "packaging": { "hashes": [ "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", diff --git a/nat-lab/tests/test_events.py b/nat-lab/tests/test_events.py index 10d6b7508..7d5b9ffc0 100644 --- a/nat-lab/tests/test_events.py +++ b/nat-lab/tests/test_events.py @@ -3,9 +3,11 @@ import pytest import timeouts from contextlib import AsyncExitStack +from deepdiff import DeepDiff from helpers import SetupParameters, setup_environment, setup_mesh_nodes, setup_api from mesh_api import API from telio import Client +from typing import Optional from utils import stun from utils.bindings import ( features_with_endpoint_providers, @@ -27,39 +29,24 @@ from utils.router import IPStack -def node_cmp(left: TelioNode, right: TelioNode): - return ( - left.identifier == right.identifier - and left.public_key == right.public_key - and left.state == right.state - and ( - left.link_state is None - or right.link_state is None - or left.link_state == right.link_state - ) - and left.is_exit == right.is_exit - and left.is_vpn == right.is_vpn - and left.ip_addresses == right.ip_addresses - and left.allowed_ips == right.allowed_ips - and ( - left.endpoint is None - or right.endpoint is None - or left.endpoint == right.endpoint - ) - and ( - left.hostname is None - or right.hostname is None - or left.hostname == right.hostname - ) - and ( - left.nickname is None - or right.nickname is None - or left.nickname == right.nickname - ) - and left.allow_incoming_connections == right.allow_incoming_connections - and left.allow_peer_send_files == right.allow_peer_send_files - and left.path == right.path +def node_diff(left: TelioNode, right: TelioNode) -> Optional[str]: + exclude_paths = [] + for attr in ["link_state", "endpoint", "hostname", "nickname"]: + if getattr(left, attr) is None or getattr(right, attr) is None: + exclude_paths.append(f"root['{attr}']") + + diff = DeepDiff( + left.__dict__, + right.__dict__, + exclude_paths=exclude_paths, + ignore_order=True, + report_repetition=True, + verbose_level=2, ) + if not diff: + return None + + return diff.pretty() @pytest.mark.asyncio @@ -157,36 +144,42 @@ async def test_event_content_meshnet( beta_node_state = client_alpha.get_node_state(beta.public_key) assert beta_node_state - assert node_cmp( - beta_node_state, - telio_node( - identifier=beta.id, - public_key=beta.public_key, - state=NodeState.CONNECTED, - ip_addresses=beta.ip_addresses, - allowed_ips=env.api.get_allowed_ip_list(beta.ip_addresses), - nickname="BETA", - hostname=beta.name + ".nord", - allow_incoming_connections=True, - allow_peer_send_files=True, - ), + assert ( + node_diff( + beta_node_state, + telio_node( + identifier=beta.id, + public_key=beta.public_key, + state=NodeState.CONNECTED, + ip_addresses=beta.ip_addresses, + allowed_ips=env.api.get_allowed_ip_list(beta.ip_addresses), + nickname="BETA", + hostname=beta.name + ".nord", + allow_incoming_connections=True, + allow_peer_send_files=True, + ), + ) + is None ) alpha_node_state = client_beta.get_node_state(alpha.public_key) assert alpha_node_state - assert node_cmp( - alpha_node_state, - telio_node( - identifier=alpha.id, - public_key=alpha.public_key, - state=NodeState.CONNECTED, - ip_addresses=alpha.ip_addresses, - allowed_ips=env.api.get_allowed_ip_list(alpha.ip_addresses), - nickname="alpha", - hostname=alpha.name + ".nord", - allow_incoming_connections=True, - allow_peer_send_files=True, - ), + assert ( + node_diff( + alpha_node_state, + telio_node( + identifier=alpha.id, + public_key=alpha.public_key, + state=NodeState.CONNECTED, + ip_addresses=alpha.ip_addresses, + allowed_ips=env.api.get_allowed_ip_list(alpha.ip_addresses), + nickname="alpha", + hostname=alpha.name + ".nord", + allow_incoming_connections=True, + allow_peer_send_files=True, + ), + ) + is None ) api.remove(beta.id) @@ -200,20 +193,23 @@ async def test_event_content_meshnet( beta_node_state = client_alpha.get_node_state(beta.public_key) assert beta_node_state - assert node_cmp( - beta_node_state, - telio_node( - identifier=beta.id, - public_key=beta.public_key, - state=NodeState.DISCONNECTED, - ip_addresses=beta.ip_addresses, - allowed_ips=env.api.get_allowed_ip_list(beta.ip_addresses), - nickname="BETA", - hostname=beta.name + ".nord", - allow_incoming_connections=True, - allow_peer_send_files=True, - path=PathType.DIRECT, - ), + assert ( + node_diff( + beta_node_state, + telio_node( + identifier=beta.id, + public_key=beta.public_key, + state=NodeState.DISCONNECTED, + ip_addresses=beta.ip_addresses, + allowed_ips=env.api.get_allowed_ip_list(beta.ip_addresses), + nickname="BETA", + hostname=beta.name + ".nord", + allow_incoming_connections=True, + allow_peer_send_files=True, + path=PathType.DIRECT, + ), + ) + is None ) @@ -319,22 +315,27 @@ async def test_event_content_vpn_connection( wg_node_state = client_alpha.get_node_state(str(wg_server["public_key"])) assert wg_node_state - assert node_cmp( - wg_node_state, - telio_node( - identifier="natlab", - public_key=str(wg_server["public_key"]), - state=NodeState.CONNECTED, - is_exit=True, - is_vpn=True, - ip_addresses=[ - "10.5.0.1", - "100.64.0.1", - ], - allowed_ips=["0.0.0.0/0", "::/0"], - endpoint=f'{wg_server["ipv4"]}:{wg_server["port"]}', - path=PathType.DIRECT, - ), + assert ( + node_diff( + wg_node_state, + telio_node( + identifier="natlab", + public_key=str(wg_server["public_key"]), + state=NodeState.CONNECTED, + is_exit=True, + is_vpn=True, + ip_addresses=[ + "10.5.0.1", + "100.64.0.1", + ], + allowed_ips=["0.0.0.0/0", "::/0"], + endpoint=f'{wg_server["ipv4"]}:{wg_server["port"]}', + path=PathType.DIRECT, + allow_multicast=False, + peer_allows_multicast=False, + ), + ) + is None ) ip = await stun.get(connection, config.STUN_SERVER) @@ -347,21 +348,26 @@ async def test_event_content_vpn_connection( wg_node_state = client_alpha.get_node_state(str(wg_server["public_key"])) assert wg_node_state - assert node_cmp( - wg_node_state, - telio_node( - identifier="natlab", - public_key=str(wg_server["public_key"]), - is_exit=True, - is_vpn=True, - ip_addresses=[ - "10.5.0.1", - "100.64.0.1", - ], - allowed_ips=["0.0.0.0/0", "::/0"], - endpoint=f'{wg_server["ipv4"]}:{wg_server["port"]}', - path=PathType.DIRECT, - ), + assert ( + node_diff( + wg_node_state, + telio_node( + identifier="natlab", + public_key=str(wg_server["public_key"]), + is_exit=True, + is_vpn=True, + ip_addresses=[ + "10.5.0.1", + "100.64.0.1", + ], + allowed_ips=["0.0.0.0/0", "::/0"], + endpoint=f'{wg_server["ipv4"]}:{wg_server["port"]}', + path=PathType.DIRECT, + allow_multicast=False, + peer_allows_multicast=False, + ), + ) + is None ) @@ -466,17 +472,20 @@ async def test_event_content_exit_through_peer( beta_node_state = client_alpha.get_node_state(beta.public_key) assert beta_node_state - assert node_cmp( - beta_node_state, - telio_node( - identifier=beta.id, - public_key=beta.public_key, - state=NodeState.CONNECTED, - ip_addresses=beta.ip_addresses, - allowed_ips=env.api.get_allowed_ip_list(beta.ip_addresses), - nickname="BETA", - hostname=beta.name + ".nord", - ), + assert ( + node_diff( + beta_node_state, + telio_node( + identifier=beta.id, + public_key=beta.public_key, + state=NodeState.CONNECTED, + ip_addresses=beta.ip_addresses, + allowed_ips=env.api.get_allowed_ip_list(beta.ip_addresses), + nickname="BETA", + hostname=beta.name + ".nord", + ), + ) + is None ) await client_beta.get_router().create_exit_node_route() @@ -490,18 +499,21 @@ async def test_event_content_exit_through_peer( beta_node_state = client_alpha.get_node_state(beta.public_key) assert beta_node_state - assert node_cmp( - beta_node_state, - telio_node( - identifier=beta.id, - public_key=beta.public_key, - state=NodeState.CONNECTED, - is_exit=True, - ip_addresses=beta.ip_addresses, - allowed_ips=["0.0.0.0/0", "::/0"], - nickname="BETA", - hostname=beta.name + ".nord", - ), + assert ( + node_diff( + beta_node_state, + telio_node( + identifier=beta.id, + public_key=beta.public_key, + state=NodeState.CONNECTED, + is_exit=True, + ip_addresses=beta.ip_addresses, + allowed_ips=["0.0.0.0/0", "::/0"], + nickname="BETA", + hostname=beta.name + ".nord", + ), + ) + is None ) @@ -655,19 +667,22 @@ async def test_event_content_meshnet_node_upgrade_direct( beta_node_state = client_alpha.get_node_state(beta.public_key) assert beta_node_state - assert node_cmp( - beta_node_state, - telio_node( - identifier=beta.id, - public_key=beta.public_key, - state=NodeState.CONNECTED, - ip_addresses=beta.ip_addresses, - allowed_ips=api.get_allowed_ip_list(beta.ip_addresses), - nickname="BETA", - hostname=beta.name + ".nord", - allow_incoming_connections=True, - allow_peer_send_files=True, - ), + assert ( + node_diff( + beta_node_state, + telio_node( + identifier=beta.id, + public_key=beta.public_key, + state=NodeState.CONNECTED, + ip_addresses=beta.ip_addresses, + allowed_ips=api.get_allowed_ip_list(beta.ip_addresses), + nickname="BETA", + hostname=beta.name + ".nord", + allow_incoming_connections=True, + allow_peer_send_files=True, + ), + ) + is None ) assert ( beta_node_state.endpoint @@ -676,19 +691,22 @@ async def test_event_content_meshnet_node_upgrade_direct( alpha_node_state = client_beta.get_node_state(alpha.public_key) assert alpha_node_state - assert node_cmp( - alpha_node_state, - telio_node( - identifier=alpha.id, - public_key=alpha.public_key, - state=NodeState.CONNECTED, - ip_addresses=alpha.ip_addresses, - allowed_ips=api.get_allowed_ip_list(alpha.ip_addresses), - nickname="alpha", - hostname=alpha.name + ".nord", - allow_incoming_connections=True, - allow_peer_send_files=True, - ), + assert ( + node_diff( + alpha_node_state, + telio_node( + identifier=alpha.id, + public_key=alpha.public_key, + state=NodeState.CONNECTED, + ip_addresses=alpha.ip_addresses, + allowed_ips=api.get_allowed_ip_list(alpha.ip_addresses), + nickname="alpha", + hostname=alpha.name + ".nord", + allow_incoming_connections=True, + allow_peer_send_files=True, + ), + ) + is None ) assert ( alpha_node_state.endpoint @@ -721,39 +739,45 @@ async def test_event_content_meshnet_node_upgrade_direct( beta_node_state = client_alpha.get_node_state(beta.public_key) assert beta_node_state - assert node_cmp( - beta_node_state, - telio_node( - identifier=beta.id, - public_key=beta.public_key, - state=NodeState.CONNECTED, - ip_addresses=beta.ip_addresses, - allowed_ips=api.get_allowed_ip_list(beta.ip_addresses), - nickname="BETA", - hostname=beta.name + ".nord", - allow_incoming_connections=True, - allow_peer_send_files=True, - path=PathType.DIRECT, - ), + assert ( + node_diff( + beta_node_state, + telio_node( + identifier=beta.id, + public_key=beta.public_key, + state=NodeState.CONNECTED, + ip_addresses=beta.ip_addresses, + allowed_ips=api.get_allowed_ip_list(beta.ip_addresses), + nickname="BETA", + hostname=beta.name + ".nord", + allow_incoming_connections=True, + allow_peer_send_files=True, + path=PathType.DIRECT, + ), + ) + is None ) assert beta_node_state.endpoint and beta_public_ip in beta_node_state.endpoint alpha_node_state = client_beta.get_node_state(alpha.public_key) assert alpha_node_state - assert node_cmp( - alpha_node_state, - telio_node( - identifier=alpha.id, - public_key=alpha.public_key, - state=NodeState.CONNECTED, - ip_addresses=alpha.ip_addresses, - allowed_ips=api.get_allowed_ip_list(alpha.ip_addresses), - nickname="alpha", - hostname=alpha.name + ".nord", - allow_incoming_connections=True, - allow_peer_send_files=True, - path=PathType.DIRECT, - ), + assert ( + node_diff( + alpha_node_state, + telio_node( + identifier=alpha.id, + public_key=alpha.public_key, + state=NodeState.CONNECTED, + ip_addresses=alpha.ip_addresses, + allowed_ips=api.get_allowed_ip_list(alpha.ip_addresses), + nickname="alpha", + hostname=alpha.name + ".nord", + allow_incoming_connections=True, + allow_peer_send_files=True, + path=PathType.DIRECT, + ), + ) + is None ) assert ( alpha_node_state.endpoint and alpha_public_ip in alpha_node_state.endpoint diff --git a/nat-lab/tests/utils/bindings.py b/nat-lab/tests/utils/bindings.py index 333e575bd..cb668762b 100644 --- a/nat-lab/tests/utils/bindings.py +++ b/nat-lab/tests/utils/bindings.py @@ -72,8 +72,8 @@ def telio_node( # pylint: disable=dangerous-default-value allow_peer_traffic_routing: bool = False, allow_peer_local_network_access: bool = False, link_state: Optional[LinkState] = None, - allow_multicast: bool = False, - peer_allows_multicast: bool = False, + allow_multicast: bool = True, + peer_allows_multicast: bool = True, ) -> TelioNode: return TelioNode( identifier=identifier,