summaryrefslogtreecommitdiff
path: root/tests/unit/modules/test_vyos_lag_interfaces.py
diff options
context:
space:
mode:
authoromnom62 <75066712+omnom62@users.noreply.github.com>2026-08-22 01:04:18 +1000
committerGitHub <noreply@github.com>2026-08-21 10:04:18 -0500
commitcb738721c15ac01f49f66144dae80eb478331f77 (patch)
tree52f870ed414506aaa5cd6efa7ae6513d807e194b /tests/unit/modules/test_vyos_lag_interfaces.py
parent885b9462480712210ddeea9ca4a4b7a52e9ef587 (diff)
downloadrest.vyos-cb738721c15ac01f49f66144dae80eb478331f77.tar.gz
rest.vyos-cb738721c15ac01f49f66144dae80eb478331f77.zip
T8989: wave 2 modules: interfaces, l3_interfaces, lag_interfaces, lldp_interfaces, ospfv2/3, ospf_interfaces
* T8989: vyos_interfaces * T8989: vyos_interfaces changelog * T8989: vyos_interfaces changelog * T8989: changelog typo * T8989: vyos_l3_interfaces module * T8989: vyos_l3_interfaces module SIT and UAT * T8989: vyos_l3_interfaces doc * T8989: lag_interfaces * T8989: lag interfaces * T8989: lldp_interfaces * T8989: lldp_interfaces module * T8989: SIT updated * T8989: SIT updated * T8989: SIT updated * T8989: typo fixes * T8989: SIT and UAT updates * T8989: ospf_v3 module * T8989: ospf_v3 module * T8989: vyos_ospf_interfaces * T8989: vyos_ospf_interfaces SIT * T8989: vyos_ospf_interfaces SIT * T8989: vyos_ospfv3 SIT and UAT --------- Co-authored-by: John Estabrook <jestabro@vyos.io>
Diffstat (limited to 'tests/unit/modules/test_vyos_lag_interfaces.py')
-rw-r--r--tests/unit/modules/test_vyos_lag_interfaces.py293
1 files changed, 293 insertions, 0 deletions
diff --git a/tests/unit/modules/test_vyos_lag_interfaces.py b/tests/unit/modules/test_vyos_lag_interfaces.py
new file mode 100644
index 0000000..7c6df87
--- /dev/null
+++ b/tests/unit/modules/test_vyos_lag_interfaces.py
@@ -0,0 +1,293 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import json
+import os
+import unittest
+
+from unittest.mock import MagicMock
+
+from ansible_collections.vyos.rest.plugins.modules.vyos_lag_interfaces import (
+ _bond_base,
+ _bond_cmds,
+ _normalize,
+ build_commands,
+ get_running_config,
+)
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ path = os.path.join(fixtures_dir, filename)
+ with open(path) as f:
+ return json.load(f)
+
+
+class VyOSModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.mock_vyos.get_config = MagicMock(return_value={})
+
+ def set_running_config(self, data):
+ self.mock_vyos.get_config.return_value = data
+
+
+class TestVyOSLagInterfacesBondBase(unittest.TestCase):
+
+ def test_bond_base(self):
+ self.assertEqual(
+ _bond_base("bond0"),
+ ["interfaces", "bonding", "bond0"],
+ )
+
+
+class TestVyOSLagInterfacesGetRunningFixture(VyOSModuleTestCase):
+
+ def setUp(self):
+ super().setUp()
+ self.fixture = load_fixture("lag_interfaces_running.json")
+
+ def test_fixture_parses_bond0_mode(self):
+ self.set_running_config(self.fixture)
+ result = get_running_config(self.mock_vyos)
+ bond0 = next((e for e in result if e["name"] == "bond0"), None)
+ self.assertIsNotNone(bond0)
+ self.assertEqual(bond0["mode"], "active-backup")
+
+ def test_fixture_parses_hash_policy(self):
+ self.set_running_config(self.fixture)
+ result = get_running_config(self.mock_vyos)
+ bond0 = next(e for e in result if e["name"] == "bond0")
+ self.assertEqual(bond0["hash_policy"], "layer2")
+
+ def test_fixture_parses_arp_monitor(self):
+ self.set_running_config(self.fixture)
+ result = get_running_config(self.mock_vyos)
+ bond0 = next(e for e in result if e["name"] == "bond0")
+ self.assertIn("arp_monitor", bond0)
+ self.assertEqual(bond0["arp_monitor"]["interval"], 100)
+ self.assertIn("192.0.2.1", bond0["arp_monitor"]["target"])
+
+ def test_fixture_unwraps_bonding_key(self):
+ # wrap in extra "bonding" key as VyOS sometimes returns
+ wrapped = {"bonding": self.fixture}
+ self.set_running_config(wrapped)
+ result = get_running_config(self.mock_vyos)
+ self.assertTrue(len(result) > 0)
+ self.assertEqual(result[0]["name"], "bond0")
+
+
+class TestVyOSLagInterfacesGetRunning(VyOSModuleTestCase):
+
+ def test_empty_returns_empty_list(self):
+ self.set_running_config({})
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result, [])
+
+ def test_parses_mode(self):
+ self.set_running_config(
+ {
+ "bond0": {"mode": "802.3ad"},
+ },
+ )
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result[0]["mode"], "802.3ad")
+
+ def test_parses_hash_policy(self):
+ self.set_running_config(
+ {
+ "bond0": {"hash-policy": "layer2+3"},
+ },
+ )
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result[0]["hash_policy"], "layer2+3")
+
+ def test_parses_members(self):
+ self.set_running_config(
+ {
+ "bond0": {"member": {"interface": {"eth1": {}, "eth2": {}}}},
+ },
+ )
+ result = get_running_config(self.mock_vyos)
+ members = [m["member"] for m in result[0]["members"]]
+ self.assertIn("eth1", members)
+ self.assertIn("eth2", members)
+
+ def test_parses_arp_monitor_interval(self):
+ self.set_running_config(
+ {
+ "bond0": {"arp-monitor": {"interval": "100"}},
+ },
+ )
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result[0]["arp_monitor"]["interval"], 100)
+
+ def test_parses_arp_monitor_target_dict(self):
+ self.set_running_config(
+ {
+ "bond0": {"arp-monitor": {"target": {"192.0.2.1": {}}}},
+ },
+ )
+ result = get_running_config(self.mock_vyos)
+ self.assertIn("192.0.2.1", result[0]["arp_monitor"]["target"])
+
+ def test_skips_type_keys(self):
+ self.set_running_config(
+ {
+ "bonding": {"bond0": {"mode": "802.3ad"}},
+ },
+ )
+ result = get_running_config(self.mock_vyos)
+ # "bonding" key should be skipped
+ names = [e["name"] for e in result]
+ self.assertNotIn("bonding", names)
+
+
+class TestVyOSLagInterfacesNormalize(unittest.TestCase):
+
+ def test_normalize_basic(self):
+ config = [{"name": "bond0", "mode": "802.3ad", "hash_policy": "layer2"}]
+ result = _normalize(config)
+ self.assertIn("bond0", result)
+ self.assertEqual(result["bond0"]["mode"], "802.3ad")
+ self.assertEqual(result["bond0"]["hash_policy"], "layer2")
+
+ def test_normalize_members_sorted(self):
+ config = [
+ {
+ "name": "bond0",
+ "members": [{"member": "eth2"}, {"member": "eth1"}],
+ },
+ ]
+ result = _normalize(config)
+ self.assertEqual(result["bond0"]["members"], ["eth1", "eth2"])
+
+ def test_normalize_arp_targets_sorted(self):
+ config = [
+ {
+ "name": "bond0",
+ "arp_monitor": {"interval": 100, "target": ["192.0.2.2", "192.0.2.1"]},
+ },
+ ]
+ result = _normalize(config)
+ self.assertEqual(result["bond0"]["arp_targets"], ["192.0.2.1", "192.0.2.2"])
+
+ def test_normalize_empty(self):
+ result = _normalize([])
+ self.assertEqual(result, {})
+
+
+class TestVyOSLagInterfacesBondCmds(unittest.TestCase):
+
+ def test_set_mode(self):
+ want = {"mode": "802.3ad"}
+ cmds = _bond_cmds("bond0", want, {})
+ self.assertIn(
+ ("set", ["interfaces", "bonding", "bond0", "mode", "802.3ad"]),
+ cmds,
+ )
+
+ def test_set_hash_policy(self):
+ want = {"hash_policy": "layer2"}
+ cmds = _bond_cmds("bond0", want, {})
+ self.assertIn(
+ ("set", ["interfaces", "bonding", "bond0", "hash-policy", "layer2"]),
+ cmds,
+ )
+
+ def test_set_member(self):
+ want = {"members": ["eth1"]}
+ cmds = _bond_cmds("bond0", want, {})
+ self.assertIn(
+ ("set", ["interfaces", "bonding", "bond0", "member", "interface", "eth1"]),
+ cmds,
+ )
+
+ def test_set_arp_interval(self):
+ want = {"arp_interval": 100}
+ cmds = _bond_cmds("bond0", want, {})
+ self.assertIn(
+ ("set", ["interfaces", "bonding", "bond0", "arp-monitor", "interval", "100"]),
+ cmds,
+ )
+
+ def test_set_arp_target(self):
+ want = {"arp_targets": ["192.0.2.1"]}
+ cmds = _bond_cmds("bond0", want, {})
+ self.assertIn(
+ ("set", ["interfaces", "bonding", "bond0", "arp-monitor", "target", "192.0.2.1"]),
+ cmds,
+ )
+
+ def test_idempotent_mode(self):
+ want = {"mode": "802.3ad"}
+ have = {"mode": "802.3ad"}
+ cmds = _bond_cmds("bond0", want, have)
+ self.assertEqual(cmds, [])
+
+ def test_no_commands_when_empty_want(self):
+ cmds = _bond_cmds("bond0", {}, {})
+ self.assertEqual(cmds, [])
+
+
+class TestVyOSLagInterfacesBuildCommands(unittest.TestCase):
+
+ def _have_bond0(self):
+ return [
+ {
+ "name": "bond0",
+ "mode": "active-backup",
+ "hash_policy": "layer2",
+ "arp_monitor": {"interval": 100, "target": ["192.0.2.1"]},
+ },
+ ]
+
+ def test_merged_adds_bond(self):
+ config = [{"name": "bond0", "mode": "802.3ad"}]
+ cmds = build_commands(config, [], "merged")
+ self.assertIn(
+ ("set", ["interfaces", "bonding", "bond0", "mode", "802.3ad"]),
+ cmds,
+ )
+
+ def test_merged_idempotent(self):
+ cmds = build_commands(self._have_bond0(), self._have_bond0(), "merged")
+ self.assertEqual(cmds, [])
+
+ def test_deleted_no_config_removes_all(self):
+ cmds = build_commands([], self._have_bond0(), "deleted")
+ self.assertIn(
+ ("delete", ["interfaces", "bonding", "bond0"]),
+ cmds,
+ )
+
+ def test_deleted_with_name_removes_bond(self):
+ config = [{"name": "bond0"}]
+ cmds = build_commands(config, self._have_bond0(), "deleted")
+ self.assertIn(
+ ("delete", ["interfaces", "bonding", "bond0"]),
+ cmds,
+ )
+
+ def test_deleted_idempotent_when_empty(self):
+ cmds = build_commands([], [], "deleted")
+ self.assertEqual(cmds, [])
+
+ def test_replaced_idempotent(self):
+ cmds = build_commands(self._have_bond0(), self._have_bond0(), "replaced")
+ self.assertEqual(cmds, [])
+
+ def test_overridden_removes_unlisted_bond(self):
+ config = [{"name": "bond1", "mode": "802.3ad"}]
+ cmds = build_commands(config, self._have_bond0(), "overridden")
+ self.assertIn(
+ ("delete", ["interfaces", "bonding", "bond0"]),
+ cmds,
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()