From 2fc4682a9d0cd4def42cdab60dd30c57e97433f0 Mon Sep 17 00:00:00 2001 From: Karel van Klink <karel.vanklink@geant.org> Date: Thu, 11 Jan 2024 16:55:07 +0100 Subject: [PATCH] Add unit test for IP Trunk validation workflow --- gso/translations/en-GB.json | 4 +- gso/workflows/iptrunk/validate_iptrunk.py | 18 +-- .../iptrunk/test_validate_iptrunk.py | 119 ++++++++++++++++++ 3 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 test/workflows/iptrunk/test_validate_iptrunk.py diff --git a/gso/translations/en-GB.json b/gso/translations/en-GB.json index c8046f41..3131efde 100644 --- a/gso/translations/en-GB.json +++ b/gso/translations/en-GB.json @@ -43,9 +43,6 @@ "create_router": "Create Router", "create_site": "Create Site", "deploy_twamp": "Deploy TWAMP", - "import_iptrunk": "Import IP Trunk", - "import_router": "Import Router", - "import_site": "Import Site", "migrate_iptrunk": "Migrate IP Trunk", "modify_isis_metric": "Modify the ISIS metric", "modify_site": "Modify Site", @@ -65,6 +62,7 @@ "import_iptrunk": "NOT FOR HUMANS -- Finalize import into an IP trunk product", "import_office_router": "NOT FOR HUMANS -- Finalize import into an Office router product", "import_super_pop_switch": "NOT FOR HUMANS -- Finalize import into a Super PoP switch", + "validate_iptrunk": "Validate IP Trunk configuration", "validate_router": "Validate router configuration" } } diff --git a/gso/workflows/iptrunk/validate_iptrunk.py b/gso/workflows/iptrunk/validate_iptrunk.py index 8d4f7be2..47d30dc5 100644 --- a/gso/workflows/iptrunk/validate_iptrunk.py +++ b/gso/workflows/iptrunk/validate_iptrunk.py @@ -39,11 +39,13 @@ def verify_ipam_loopback(subscription: Iptrunk) -> None: ipam_v6_network = infoblox.find_network_by_cidr(subscription.iptrunk.iptrunk_ipv6_network) if not ipam_v4_network or not ipam_v6_network: - ipam_errors += ( - "Missing IP trunk IPAM records, found the following instead.\n" - f"IPv4 expected {subscription.iptrunk.iptrunk_ipv4_network}, actual: {ipam_v4_network}\n" - f"IPv6 expected {subscription.iptrunk.iptrunk_ipv6_network}, actual: {ipam_v6_network}" - ) + ipam_errors += [ + ( + "Missing IP trunk IPAM records, found the following instead.\n" + f"IPv4 expected {subscription.iptrunk.iptrunk_ipv4_network}, actual: {ipam_v4_network}\n" + f"IPv6 expected {subscription.iptrunk.iptrunk_ipv6_network}, actual: {ipam_v6_network}" + ) + ] # Validate both sides of the trunk. for trunk_side in subscription.iptrunk.iptrunk_sides: @@ -51,9 +53,9 @@ def verify_ipam_loopback(subscription: Iptrunk) -> None: # Validate both IPv4 and IPv6 records. for record in [infoblox.find_host_by_fqdn(lag_fqdn), infoblox.find_v6_host_by_fqdn(lag_fqdn)]: if not record: - ipam_errors += f"Missing IPAM record for LAG interface {lag_fqdn}." - elif subscription.subscription_id not in record.comment: - ipam_errors += f"Found a misconfigured IPAM entry for {lag_fqdn}. Received: {record}" + ipam_errors += [f"Missing IPAM record for LAG interface {lag_fqdn}."] + elif str(subscription.subscription_id) not in record.comment: + ipam_errors += [f"Found a misconfigured IPAM entry for {lag_fqdn}. Received: {record}"] if ipam_errors: raise ProcessFailureError(str(ipam_errors)) diff --git a/test/workflows/iptrunk/test_validate_iptrunk.py b/test/workflows/iptrunk/test_validate_iptrunk.py new file mode 100644 index 00000000..8e8990c1 --- /dev/null +++ b/test/workflows/iptrunk/test_validate_iptrunk.py @@ -0,0 +1,119 @@ +from unittest.mock import patch + +import pytest +from infoblox_client import objects + +from gso.products.product_types.iptrunk import Iptrunk +from test.workflows import ( + assert_complete, + assert_pp_interaction_success, + extract_state, + run_workflow, +) + + +@pytest.mark.workflow() +@patch("gso.services.infoblox.find_network_by_cidr") +@patch("gso.services.infoblox.find_v6_host_by_fqdn") +@patch("gso.services.infoblox.find_host_by_fqdn") +@patch("gso.workflows.iptrunk.validate_iptrunk.execute_playbook") +def test_validate_router_success( + mock_validate_iptrunk, + mock_find_host_by_fqdn, + mock_find_v6_host_by_fqdn, + mock_find_network_by_cidr, + faker, + data_config_filename, + iptrunk_subscription_factory, +): + # Mock value setup + subscription_id = iptrunk_subscription_factory() + trunk = Iptrunk.from_subscription(subscription_id).iptrunk + mock_find_network_by_cidr.side_effects = [ + objects.Network(connector=None, ipv4addrs=[trunk.iptrunk_ipv4_network]), + objects.NetworkV6(connector=None, ipv6addrs=[trunk.iptrunk_ipv6_network]), + ] + mock_find_host_by_fqdn.side_effect = [ + objects.HostRecord( + connector=None, + aliases=[trunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn], + comment=subscription_id, + ipv4addrs=[ + objects.IPv4( + ipv4addr=str(trunk.iptrunk_ipv4_network[0]), + configure_for_dhcp=False, + mac="00:00:00:00:00:00", + ip=str(trunk.iptrunk_ipv4_network[0]), + host=f"{trunk.iptrunk_sides[0].iptrunk_side_ae_iface}.{trunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}", + ), + ], + name=trunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn, + ), + objects.HostRecord( + connector=None, + aliases=[trunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn], + comment=subscription_id, + ipv4addrs=[ + objects.IPv4( + ipv4addr=str(trunk.iptrunk_ipv4_network[1]), + configure_for_dhcp=False, + mac="00:00:00:00:00:00", + ip=str(trunk.iptrunk_ipv4_network[1]), + host=f"{trunk.iptrunk_sides[1].iptrunk_side_ae_iface}.{trunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}", + ), + ], + name=trunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn, + ), + ] + + mock_find_v6_host_by_fqdn.side_effect = [ + objects.HostRecordV6( + connector=None, + aliases=[trunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn], + comment=subscription_id, + ipv4addrs=[ + objects.IPv6( + ipv6addr=str(trunk.iptrunk_ipv6_network[0]), + configure_for_dhcp=False, + mac="00:00:00:00:00:00", + ip=str(trunk.iptrunk_ipv6_network[0]), + host=f"{trunk.iptrunk_sides[0].iptrunk_side_ae_iface}.{trunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn}", + ), + ], + name=trunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn, + ), + objects.HostRecordV6( + connector=None, + aliases=[trunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn], + comment=subscription_id, + ipv4addrs=[ + objects.IPv6( + ipv4addr=str(trunk.iptrunk_ipv6_network[1]), + configure_for_dhcp=False, + mac="00:00:00:00:00:00", + ip=str(trunk.iptrunk_ipv6_network[1]), + host=f"{trunk.iptrunk_sides[1].iptrunk_side_ae_iface}.{trunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn}", + ), + ], + name=trunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn, + ), + ] + + # Run workflow + initial_router_data = [{"subscription_id": subscription_id}] + result, process_stat, step_log = run_workflow("validate_iptrunk", initial_router_data) + + state = extract_state(result) + subscription_id = state["subscription_id"] + + result, step_log = assert_pp_interaction_success(result, process_stat, step_log) + + assert_complete(result) + + subscription = Iptrunk.from_subscription(subscription_id) + + assert subscription.status == "active" + assert mock_validate_iptrunk.call_count == 1 + assert mock_find_host_by_fqdn.call_count == 2 + assert mock_find_v6_host_by_fqdn.call_count == 2 + assert mock_find_network_by_cidr.call_count == 2 -- GitLab