summaryrefslogtreecommitdiff
path: root/tests/unit/modules
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/modules')
-rw-r--r--tests/unit/modules/test_vyos_bgp_address_family.py238
-rw-r--r--tests/unit/modules/test_vyos_bgp_global.py188
-rw-r--r--tests/unit/modules/test_vyos_facts.py97
-rw-r--r--tests/unit/modules/test_vyos_firewall_global.py190
-rw-r--r--tests/unit/modules/test_vyos_firewall_interfaces.py168
-rw-r--r--tests/unit/modules/test_vyos_firewall_rules.py203
-rw-r--r--tests/unit/modules/test_vyos_user.py172
7 files changed, 1256 insertions, 0 deletions
diff --git a/tests/unit/modules/test_vyos_bgp_address_family.py b/tests/unit/modules/test_vyos_bgp_address_family.py
new file mode 100644
index 0000000..fc080af
--- /dev/null
+++ b/tests/unit/modules/test_vyos_bgp_address_family.py
@@ -0,0 +1,238 @@
+# -*- 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_bgp_address_family import (
+ build_commands,
+ get_running_config,
+)
+
+
+_BASE = ["protocols", "bgp"]
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ with open(os.path.join(fixtures_dir, filename)) as f:
+ return json.load(f)
+
+
+class VyOSModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.fixture = load_fixture("bgp_af_running.json")
+ self.mock_vyos.get_config = MagicMock(return_value=self.fixture)
+
+
+class TestVyOSBgpAFGetRunning(VyOSModuleTestCase):
+
+ def test_parses_as_number(self):
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result["as_number"], 65000)
+
+ def test_parses_global_af_networks(self):
+ result = get_running_config(self.mock_vyos)
+ ipv4 = next(af for af in result["address_family"] if af["afi"] == "ipv4")
+ prefixes = [n["prefix"] for n in ipv4["networks"]]
+ self.assertIn("192.0.2.0/24", prefixes)
+ self.assertIn("192.0.3.0/24", prefixes)
+
+ def test_parses_global_af_redistribute(self):
+ result = get_running_config(self.mock_vyos)
+ ipv4 = next(af for af in result["address_family"] if af["afi"] == "ipv4")
+ protos = [r["protocol"] for r in ipv4["redistribute"]]
+ self.assertIn("connected", protos)
+ connected = next(r for r in ipv4["redistribute"] if r["protocol"] == "connected")
+ self.assertEqual(connected["metric"], 10)
+
+ def test_parses_neighbor_af(self):
+ result = get_running_config(self.mock_vyos)
+ nb = next(n for n in result["neighbors"] if n["neighbor_address"] == "192.0.2.1")
+ afis = [af["afi"] for af in nb["address_family"]]
+ self.assertIn("ipv4", afis)
+ self.assertIn("ipv6", afis)
+ ipv4 = next(af for af in nb["address_family"] if af["afi"] == "ipv4")
+ self.assertTrue(ipv4["nexthop_self"])
+ self.assertTrue(ipv4["soft_reconfiguration"])
+
+ def test_empty_config(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result, {})
+
+
+class TestVyOSBgpAFBuildCommands(unittest.TestCase):
+
+ def _have(self):
+ return {
+ "as_number": 65000,
+ "address_family": [
+ {
+ "afi": "ipv4",
+ "networks": [{"prefix": "192.0.2.0/24"}],
+ "redistribute": [{"protocol": "connected", "metric": 10}],
+ },
+ ],
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "address_family": [
+ {"afi": "ipv4", "soft_reconfiguration": True, "nexthop_self": True},
+ ],
+ },
+ ],
+ }
+
+ def test_deleted_removes_global_af(self):
+ cmds = build_commands({"as_number": 65000}, self._have(), "deleted")
+ self.assertIn(("delete", _BASE + ["address-family"]), cmds)
+
+ def test_deleted_removes_neighbor_af(self):
+ cmds = build_commands({"as_number": 65000}, self._have(), "deleted")
+ self.assertIn(
+ ("delete", _BASE + ["neighbor", "192.0.2.1", "address-family"]),
+ cmds,
+ )
+
+ def test_merged_network(self):
+ config = {
+ "as_number": 65000,
+ "address_family": [
+ {"afi": "ipv4", "networks": [{"prefix": "192.0.5.0/24"}]},
+ ],
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(
+ ("set", _BASE + ["address-family", "ipv4-unicast", "network", "192.0.5.0/24"]),
+ cmds,
+ )
+
+ def test_merged_redistribute(self):
+ config = {
+ "as_number": 65000,
+ "address_family": [
+ {"afi": "ipv4", "redistribute": [{"protocol": "connected", "metric": 10}]},
+ ],
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(
+ ("set", _BASE + ["address-family", "ipv4-unicast", "redistribute", "connected"]),
+ cmds,
+ )
+ self.assertIn(
+ (
+ "set",
+ _BASE
+ + [
+ "address-family",
+ "ipv4-unicast",
+ "redistribute",
+ "connected",
+ "metric",
+ "10",
+ ],
+ ),
+ cmds,
+ )
+
+ def test_merged_neighbor_soft_reconfig(self):
+ config = {
+ "as_number": 65000,
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "address_family": [
+ {"afi": "ipv4", "soft_reconfiguration": True},
+ ],
+ },
+ ],
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(
+ (
+ "set",
+ _BASE
+ + [
+ "neighbor",
+ "192.0.2.1",
+ "address-family",
+ "ipv4-unicast",
+ "soft-reconfiguration",
+ "inbound",
+ ],
+ ),
+ cmds,
+ )
+
+ def test_merged_idempotent(self):
+ have = self._have()
+ config = {
+ "as_number": 65000,
+ "address_family": [
+ {
+ "afi": "ipv4",
+ "networks": [{"prefix": "192.0.2.0/24"}],
+ "redistribute": [{"protocol": "connected", "metric": 10}],
+ },
+ ],
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "address_family": [
+ {"afi": "ipv4", "soft_reconfiguration": True, "nexthop_self": True},
+ ],
+ },
+ ],
+ }
+ cmds = build_commands(config, have, "merged")
+ self.assertEqual(cmds, [])
+
+ def test_replaced_idempotent(self):
+ have = self._have()
+ config = {
+ "as_number": 65000,
+ "address_family": [
+ {
+ "afi": "ipv4",
+ "networks": [{"prefix": "192.0.2.0/24"}],
+ "redistribute": [{"protocol": "connected", "metric": 10}],
+ },
+ ],
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "address_family": [
+ {"afi": "ipv4", "soft_reconfiguration": True, "nexthop_self": True},
+ ],
+ },
+ ],
+ }
+ cmds = build_commands(config, have, "replaced")
+ self.assertEqual(cmds, [])
+
+ def test_replaced_rebuilds_on_change(self):
+ have = self._have()
+ config = {
+ "as_number": 65000,
+ "address_family": [
+ {"afi": "ipv4", "networks": [{"prefix": "192.0.9.0/24"}]},
+ ],
+ }
+ cmds = build_commands(config, have, "replaced")
+ self.assertIn(("delete", _BASE + ["address-family"]), cmds)
+ self.assertIn(
+ ("set", _BASE + ["address-family", "ipv4-unicast", "network", "192.0.9.0/24"]),
+ cmds,
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/unit/modules/test_vyos_bgp_global.py b/tests/unit/modules/test_vyos_bgp_global.py
new file mode 100644
index 0000000..f91516b
--- /dev/null
+++ b/tests/unit/modules/test_vyos_bgp_global.py
@@ -0,0 +1,188 @@
+# -*- 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_bgp_global import (
+ build_commands,
+ get_running_config,
+)
+
+
+_BASE = ["protocols", "bgp"]
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ with open(os.path.join(fixtures_dir, filename)) as f:
+ return json.load(f)
+
+
+class VyOSModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.fixture = load_fixture("bgp_global_running.json")
+ self.mock_vyos.get_config = MagicMock(return_value=self.fixture)
+
+
+class TestVyOSBgpGlobalGetRunning(VyOSModuleTestCase):
+
+ def test_parses_as_number(self):
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result["as_number"], 65000)
+
+ def test_parses_parameters(self):
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result["parameters"]["router_id"], "192.0.1.1")
+ self.assertTrue(result["parameters"]["log_neighbor_changes"])
+
+ def test_parses_neighbors(self):
+ result = get_running_config(self.mock_vyos)
+ nb_addrs = [n["neighbor_address"] for n in result["neighbors"]]
+ self.assertIn("192.0.2.1", nb_addrs)
+ self.assertIn("192.0.2.2", nb_addrs)
+ nb1 = next(n for n in result["neighbors"] if n["neighbor_address"] == "192.0.2.1")
+ self.assertEqual(nb1["remote_as"], 65001)
+ self.assertEqual(nb1["description"], "peer1")
+ self.assertEqual(nb1["timers"]["holdtime"], 30)
+ self.assertEqual(nb1["timers"]["keepalive"], 10)
+ nb2 = next(n for n in result["neighbors"] if n["neighbor_address"] == "192.0.2.2")
+ self.assertEqual(nb2["ebgp_multihop"], 2)
+ self.assertEqual(nb2["update_source"], "eth0")
+
+ def test_parses_peer_groups(self):
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(len(result["peer_groups"]), 1)
+ self.assertEqual(result["peer_groups"][0]["peer_group"], "PG1")
+ self.assertEqual(result["peer_groups"][0]["remote_as"], 65003)
+
+ def test_empty_config(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result, {})
+
+
+class TestVyOSBgpGlobalBuildCommands(unittest.TestCase):
+
+ def _have(self):
+ return {
+ "as_number": 65000,
+ "parameters": {"router_id": "192.0.1.1"},
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "remote_as": 65001,
+ "description": "peer1",
+ },
+ ],
+ "peer_groups": [{"peer_group": "PG1", "remote_as": 65003}],
+ }
+
+ def test_deleted_with_have(self):
+ cmds = build_commands({}, self._have(), "deleted")
+ self.assertEqual(cmds, [("delete", _BASE)])
+
+ def test_deleted_without_have(self):
+ cmds = build_commands({}, {}, "deleted")
+ self.assertEqual(cmds, [])
+
+ def test_merged_as_number(self):
+ config = {"as_number": 65000}
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(("set", _BASE + ["system-as", "65000"]), cmds)
+
+ def test_merged_router_id(self):
+ config = {"as_number": 65000, "parameters": {"router_id": "192.0.1.1"}}
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(("set", _BASE + ["parameters", "router-id", "192.0.1.1"]), cmds)
+
+ def test_merged_neighbor(self):
+ config = {
+ "as_number": 65000,
+ "neighbors": [
+ {"neighbor_address": "192.0.2.1", "remote_as": 65001},
+ ],
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(("set", _BASE + ["neighbor", "192.0.2.1", "remote-as", "65001"]), cmds)
+
+ def test_merged_neighbor_timers(self):
+ config = {
+ "as_number": 65000,
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "remote_as": 65001,
+ "timers": {"holdtime": 30, "keepalive": 10},
+ },
+ ],
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(
+ ("set", _BASE + ["neighbor", "192.0.2.1", "timers", "holdtime", "30"]),
+ cmds,
+ )
+ self.assertIn(
+ ("set", _BASE + ["neighbor", "192.0.2.1", "timers", "keepalive", "10"]),
+ cmds,
+ )
+
+ def test_merged_idempotent(self):
+ have = self._have()
+ config = {
+ "as_number": 65000,
+ "parameters": {"router_id": "192.0.1.1"},
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "remote_as": 65001,
+ "description": "peer1",
+ },
+ ],
+ "peer_groups": [{"peer_group": "PG1", "remote_as": 65003}],
+ }
+ cmds = build_commands(config, have, "merged")
+ self.assertEqual(cmds, [])
+
+ def test_replaced_idempotent(self):
+ have = self._have()
+ config = {
+ "as_number": 65000,
+ "parameters": {"router_id": "192.0.1.1"},
+ "neighbors": [
+ {
+ "neighbor_address": "192.0.2.1",
+ "remote_as": 65001,
+ "description": "peer1",
+ },
+ ],
+ "peer_groups": [{"peer_group": "PG1", "remote_as": 65003}],
+ }
+ cmds = build_commands(config, have, "replaced")
+ self.assertEqual(cmds, [])
+
+ def test_replaced_rebuilds_on_change(self):
+ have = self._have()
+ config = {"as_number": 65000, "parameters": {"router_id": "192.0.1.2"}}
+ cmds = build_commands(config, have, "replaced")
+ self.assertEqual(cmds[0], ("delete", _BASE))
+ self.assertIn(("set", _BASE + ["parameters", "router-id", "192.0.1.2"]), cmds)
+
+ def test_merged_peer_group(self):
+ config = {
+ "as_number": 65000,
+ "peer_groups": [{"peer_group": "PG1", "remote_as": 65003}],
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(("set", _BASE + ["peer-group", "PG1", "remote-as", "65003"]), cmds)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/unit/modules/test_vyos_facts.py b/tests/unit/modules/test_vyos_facts.py
new file mode 100644
index 0000000..3fcf82e
--- /dev/null
+++ b/tests/unit/modules/test_vyos_facts.py
@@ -0,0 +1,97 @@
+# -*- 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_facts import (
+ gather_bgp,
+ gather_hostname,
+ gather_interfaces,
+ gather_logging,
+ gather_users,
+)
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ with open(os.path.join(fixtures_dir, filename)) as f:
+ return json.load(f)
+
+
+class TestVyOSFactsGather(unittest.TestCase):
+
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.system_fixture = load_fixture("facts_system.json")
+ self.interfaces_fixture = load_fixture("facts_interfaces.json")
+
+ def test_gather_hostname(self):
+ self.mock_vyos.get_config = MagicMock(return_value=self.system_fixture)
+ result = gather_hostname(self.mock_vyos)
+ self.assertEqual(result, "vyos-test")
+
+ def test_gather_hostname_empty(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = gather_hostname(self.mock_vyos)
+ self.assertEqual(result, "")
+
+ def test_gather_interfaces(self):
+ self.mock_vyos.get_config = MagicMock(return_value=self.interfaces_fixture)
+ result = gather_interfaces(self.mock_vyos)
+ self.assertIn("ethernet", result)
+ self.assertIn("eth0", result["ethernet"])
+ self.assertIn("eth1", result["ethernet"])
+ self.assertEqual(result["ethernet"]["eth1"]["description"], "uplink")
+
+ def test_gather_users(self):
+ self.mock_vyos.get_config = MagicMock(
+ return_value=self.system_fixture["login"],
+ )
+ result = gather_users(self.mock_vyos)
+ names = [u["name"] for u in result]
+ self.assertIn("vyos", names)
+ self.assertIn("alice", names)
+ alice = next(u for u in result if u["name"] == "alice")
+ self.assertEqual(alice["full_name"], "Alice Smith")
+ self.assertIn("alice-key", alice["public_keys"])
+
+ def test_gather_users_empty(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = gather_users(self.mock_vyos)
+ self.assertEqual(result, [])
+
+ def test_gather_users_none(self):
+ self.mock_vyos.get_config = MagicMock(return_value=None)
+ result = gather_users(self.mock_vyos)
+ self.assertEqual(result, [])
+
+ def test_gather_bgp(self):
+ data = {"system-as": "65000", "parameters": {"router-id": "192.0.1.1"}}
+ self.mock_vyos.get_config = MagicMock(return_value=data)
+ result = gather_bgp(self.mock_vyos)
+ self.assertEqual(result["system-as"], "65000")
+ self.assertEqual(result["parameters"]["router-id"], "192.0.1.1")
+
+ def test_gather_bgp_empty(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = gather_bgp(self.mock_vyos)
+ self.assertEqual(result, {})
+
+ def test_gather_logging(self):
+ self.mock_vyos.get_config = MagicMock(
+ return_value=self.system_fixture["syslog"],
+ )
+ result = gather_logging(self.mock_vyos)
+ self.assertIn("local", result)
+ self.assertIn("console", result)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/unit/modules/test_vyos_firewall_global.py b/tests/unit/modules/test_vyos_firewall_global.py
new file mode 100644
index 0000000..a507c0c
--- /dev/null
+++ b/tests/unit/modules/test_vyos_firewall_global.py
@@ -0,0 +1,190 @@
+# -*- 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_firewall_global import (
+ build_commands,
+ get_running_config,
+)
+
+
+_BASE = ["firewall", "group"]
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ with open(os.path.join(fixtures_dir, filename)) as f:
+ return json.load(f)
+
+
+class VyOSModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.fixture = load_fixture("firewall_global_running.json")
+ self.mock_vyos.get_config = MagicMock(return_value=self.fixture)
+
+
+class TestVyOSFirewallGlobalGetRunning(VyOSModuleTestCase):
+
+ def test_parses_address_groups(self):
+ result = get_running_config(self.mock_vyos)
+ groups = result["group"]["address_group"]
+ names = [g["name"] for g in groups]
+ self.assertIn("SERVERS", names)
+ self.assertIn("DNS", names)
+ servers = next(g for g in groups if g["name"] == "SERVERS")
+ self.assertEqual(servers["description"], "Web servers")
+ self.assertIn("192.168.1.10", servers["address"])
+ self.assertIn("192.168.1.11", servers["address"])
+
+ def test_parses_network_groups(self):
+ result = get_running_config(self.mock_vyos)
+ groups = result["group"]["network_group"]
+ dmz = next(g for g in groups if g["name"] == "DMZ")
+ self.assertIn("10.0.0.0/8", dmz["network"])
+ self.assertIn("172.16.0.0/12", dmz["network"])
+
+ def test_parses_port_groups(self):
+ result = get_running_config(self.mock_vyos)
+ groups = result["group"]["port_group"]
+ web = next(g for g in groups if g["name"] == "WEB-PORTS")
+ self.assertIn("80", web["port"])
+ self.assertIn("443", web["port"])
+
+ def test_parses_interface_groups(self):
+ result = get_running_config(self.mock_vyos)
+ groups = result["group"]["interface_group"]
+ lan = next(g for g in groups if g["name"] == "LAN-IFACES")
+ self.assertIn("eth1", lan["interface"])
+
+ def test_parses_ipv6_network_groups(self):
+ result = get_running_config(self.mock_vyos)
+ groups = result["group"]["ipv6_network_group"]
+ ipv6 = next(g for g in groups if g["name"] == "IPV6-LAN")
+ self.assertIn("2001:db8::/32", ipv6["network"])
+
+ def test_empty_config(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result, {})
+
+
+class TestVyOSFirewallGlobalBuildCommands(unittest.TestCase):
+
+ def _have(self):
+ return {
+ "group": {
+ "address_group": [
+ {"name": "SERVERS", "address": ["192.168.1.10", "192.168.1.11"]},
+ ],
+ "network_group": [
+ {"name": "LAN", "network": ["192.168.0.0/16"]},
+ ],
+ },
+ }
+
+ def test_deleted_with_have(self):
+ cmds = build_commands({}, self._have(), "deleted")
+ self.assertEqual(cmds, [("delete", _BASE)])
+
+ def test_deleted_without_have(self):
+ cmds = build_commands({}, {}, "deleted")
+ self.assertEqual(cmds, [])
+
+ def test_merged_address_group(self):
+ config = {
+ "group": {
+ "address_group": [
+ {"name": "SERVERS", "address": ["192.168.1.10"]},
+ ],
+ },
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(
+ ("set", _BASE + ["address-group", "SERVERS", "address", "192.168.1.10"]),
+ cmds,
+ )
+
+ def test_merged_network_group(self):
+ config = {
+ "group": {
+ "network_group": [
+ {"name": "LAN", "network": ["192.168.0.0/16"]},
+ ],
+ },
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(
+ ("set", _BASE + ["network-group", "LAN", "network", "192.168.0.0/16"]),
+ cmds,
+ )
+
+ def test_merged_port_group(self):
+ config = {
+ "group": {
+ "port_group": [
+ {"name": "WEB", "port": ["80", "443"]},
+ ],
+ },
+ }
+ cmds = build_commands(config, {}, "merged")
+ self.assertIn(
+ ("set", _BASE + ["port-group", "WEB", "port", "80"]),
+ cmds,
+ )
+
+ def test_merged_idempotent(self):
+ have = self._have()
+ config = {
+ "group": {
+ "address_group": [
+ {"name": "SERVERS", "address": ["192.168.1.10", "192.168.1.11"]},
+ ],
+ "network_group": [
+ {"name": "LAN", "network": ["192.168.0.0/16"]},
+ ],
+ },
+ }
+ cmds = build_commands(config, have, "merged")
+ self.assertEqual(cmds, [])
+
+ def test_replaced_removes_extra_group(self):
+ have = self._have()
+ config = {
+ "group": {
+ "network_group": [
+ {"name": "DMZ", "network": ["10.0.0.0/8"]},
+ ],
+ },
+ }
+ cmds = build_commands(config, have, "replaced")
+ paths = [c[1] for c in cmds]
+ self.assertIn(_BASE + ["address-group", "SERVERS"], paths)
+ self.assertIn(_BASE + ["network-group", "LAN"], paths)
+
+ def test_replaced_idempotent(self):
+ have = self._have()
+ config = {
+ "group": {
+ "address_group": [
+ {"name": "SERVERS", "address": ["192.168.1.10", "192.168.1.11"]},
+ ],
+ "network_group": [
+ {"name": "LAN", "network": ["192.168.0.0/16"]},
+ ],
+ },
+ }
+ cmds = build_commands(config, have, "replaced")
+ self.assertEqual(cmds, [])
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/unit/modules/test_vyos_firewall_interfaces.py b/tests/unit/modules/test_vyos_firewall_interfaces.py
new file mode 100644
index 0000000..66b3883
--- /dev/null
+++ b/tests/unit/modules/test_vyos_firewall_interfaces.py
@@ -0,0 +1,168 @@
+# -*- 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_firewall_interfaces import (
+ build_commands,
+ get_running_config,
+)
+
+
+_BASE = ["firewall"]
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ with open(os.path.join(fixtures_dir, filename)) as f:
+ return json.load(f)
+
+
+class VyOSModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.fixture = load_fixture("firewall_interfaces_running.json")
+
+ def _set_afi(self, afi):
+ data = self.fixture.get(afi, {})
+ self.mock_vyos.get_config = MagicMock(return_value=data)
+
+
+class TestVyOSFirewallInterfacesGetRunning(VyOSModuleTestCase):
+
+ def test_parses_ipv4_hooks(self):
+ self._set_afi("ipv4")
+ result = get_running_config(self.mock_vyos)
+ ipv4 = next((e for e in result if e["afi"] == "ipv4"), None)
+ self.assertIsNotNone(ipv4)
+ hook_names = [h["hook"] for h in ipv4["hooks"]]
+ self.assertIn("input", hook_names)
+ self.assertIn("forward", hook_names)
+ self.assertIn("output", hook_names)
+
+ def test_parses_input_rules(self):
+ self._set_afi("ipv4")
+ result = get_running_config(self.mock_vyos)
+ ipv4 = next(e for e in result if e["afi"] == "ipv4")
+ input_hook = next(h for h in ipv4["hooks"] if h["hook"] == "input")
+ self.assertEqual(input_hook["default_action"], "accept")
+ self.assertEqual(len(input_hook["rules"]), 2)
+ r10 = next(r for r in input_hook["rules"] if r["number"] == 10)
+ self.assertEqual(r10["action"], "accept")
+ self.assertEqual(r10["state"], "established")
+
+ def test_parses_ipv6_hooks(self):
+ self._set_afi("ipv6")
+ result = get_running_config(self.mock_vyos)
+ ipv6 = next((e for e in result if e["afi"] == "ipv6"), None)
+ self.assertIsNotNone(ipv6)
+ self.assertEqual(ipv6["hooks"][0]["hook"], "input")
+
+ def test_empty_config(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result, [])
+
+
+class TestVyOSFirewallInterfacesBuildCommands(unittest.TestCase):
+
+ def _have(self):
+ return [
+ {
+ "afi": "ipv4",
+ "hooks": [
+ {
+ "hook": "input",
+ "default_action": "accept",
+ "rules": [
+ {"number": 10, "action": "accept", "state": "established"},
+ {"number": 20, "action": "drop", "state": "invalid"},
+ ],
+ },
+ {"hook": "forward", "default_action": "accept"},
+ ],
+ },
+ ]
+
+ def test_deleted_all(self):
+ cmds = build_commands([], self._have(), "deleted")
+ paths = [c[1] for c in cmds]
+ self.assertIn(_BASE + ["ipv4", "input", "filter"], paths)
+ self.assertIn(_BASE + ["ipv4", "forward", "filter"], paths)
+
+ def test_deleted_specific(self):
+ config = [{"afi": "ipv4", "hooks": [{"hook": "input"}]}]
+ cmds = build_commands(config, self._have(), "deleted")
+ self.assertIn(("delete", _BASE + ["ipv4", "input", "filter"]), cmds)
+ paths = [c[1] for c in cmds]
+ self.assertNotIn(_BASE + ["ipv4", "forward", "filter"], paths)
+
+ def test_merged_hook(self):
+ config = [
+ {
+ "afi": "ipv4",
+ "hooks": [
+ {
+ "hook": "input",
+ "default_action": "accept",
+ "rules": [{"number": 10, "action": "accept", "state": "established"}],
+ },
+ ],
+ },
+ ]
+ cmds = build_commands(config, [], "merged")
+ self.assertIn(
+ ("set", _BASE + ["ipv4", "input", "filter", "default-action", "accept"]),
+ cmds,
+ )
+ self.assertIn(
+ ("set", _BASE + ["ipv4", "input", "filter", "rule", "10", "action", "accept"]),
+ cmds,
+ )
+
+ def test_merged_idempotent(self):
+ have = self._have()
+ config = [
+ {
+ "afi": "ipv4",
+ "hooks": [
+ {
+ "hook": "input",
+ "default_action": "accept",
+ "rules": [
+ {"number": 10, "action": "accept", "state": "established"},
+ {"number": 20, "action": "drop", "state": "invalid"},
+ ],
+ },
+ {"hook": "forward", "default_action": "accept"},
+ ],
+ },
+ ]
+ cmds = build_commands(config, have, "merged")
+ self.assertEqual(cmds, [])
+
+ def test_overridden_removes_extra_hook(self):
+ have = self._have()
+ config = [
+ {
+ "afi": "ipv4",
+ "hooks": [
+ {"hook": "output", "default_action": "accept"},
+ ],
+ },
+ ]
+ cmds = build_commands(config, have, "overridden")
+ paths = [c[1] for c in cmds]
+ self.assertIn(_BASE + ["ipv4", "input", "filter"], paths)
+ self.assertIn(_BASE + ["ipv4", "forward", "filter"], paths)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/unit/modules/test_vyos_firewall_rules.py b/tests/unit/modules/test_vyos_firewall_rules.py
new file mode 100644
index 0000000..4eaad9e
--- /dev/null
+++ b/tests/unit/modules/test_vyos_firewall_rules.py
@@ -0,0 +1,203 @@
+# -*- 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_firewall_rules import (
+ build_commands,
+ get_running_config,
+)
+
+
+_BASE = ["firewall"]
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ with open(os.path.join(fixtures_dir, filename)) as f:
+ return json.load(f)
+
+
+class VyOSModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.fixture = load_fixture("firewall_rules_running.json")
+
+ def _set_afi(self, afi):
+ data = self.fixture.get(afi, {})
+ self.mock_vyos.get_config = MagicMock(return_value=data)
+
+
+class TestVyOSFirewallRulesGetRunning(VyOSModuleTestCase):
+
+ def test_parses_ipv4_rule_sets(self):
+ self._set_afi("ipv4")
+ result = get_running_config(self.mock_vyos)
+ ipv4 = next((e for e in result if e["afi"] == "ipv4"), None)
+ self.assertIsNotNone(ipv4)
+ rs = next(rs for rs in ipv4["rule_sets"] if rs["name"] == "RULE-SET1")
+ self.assertEqual(rs["default_action"], "drop")
+ self.assertEqual(len(rs["rules"]), 2)
+ r10 = next(r for r in rs["rules"] if r["number"] == 10)
+ self.assertEqual(r10["action"], "accept")
+ self.assertEqual(r10["protocol"], "tcp")
+ self.assertEqual(r10["source"]["address"], "192.168.1.0/24")
+ self.assertEqual(r10["destination"]["port"], "80")
+
+ def test_parses_rule_state(self):
+ self._set_afi("ipv4")
+ result = get_running_config(self.mock_vyos)
+ ipv4 = next(e for e in result if e["afi"] == "ipv4")
+ rs = ipv4["rule_sets"][0]
+ r20 = next(r for r in rs["rules"] if r["number"] == 20)
+ self.assertEqual(r20["state"], "invalid")
+
+ def test_empty_config(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result, [])
+
+
+class TestVyOSFirewallRulesBuildCommands(unittest.TestCase):
+
+ def _have(self):
+ return [
+ {
+ "afi": "ipv4",
+ "rule_sets": [
+ {
+ "name": "RULE-SET1",
+ "default_action": "drop",
+ "rules": [
+ {"number": 10, "action": "accept", "protocol": "tcp"},
+ {"number": 20, "action": "drop", "state": "invalid"},
+ ],
+ },
+ ],
+ },
+ ]
+
+ def test_deleted_all(self):
+ cmds = build_commands([], self._have(), "deleted")
+ self.assertIn(("delete", _BASE), cmds)
+
+ def test_deleted_specific(self):
+ config = [{"afi": "ipv4", "rule_sets": [{"name": "RULE-SET1"}]}]
+ cmds = build_commands(config, self._have(), "deleted")
+ self.assertIn(("delete", _BASE + ["ipv4", "name", "RULE-SET1"]), cmds)
+
+ def test_merged_rule_set(self):
+ config = [
+ {
+ "afi": "ipv4",
+ "rule_sets": [
+ {
+ "name": "NEW-SET",
+ "default_action": "accept",
+ "rules": [{"number": 10, "action": "accept"}],
+ },
+ ],
+ },
+ ]
+ cmds = build_commands(config, [], "merged")
+ self.assertIn(
+ ("set", _BASE + ["ipv4", "name", "NEW-SET", "default-action", "accept"]),
+ cmds,
+ )
+ self.assertIn(
+ ("set", _BASE + ["ipv4", "name", "NEW-SET", "rule", "10", "action", "accept"]),
+ cmds,
+ )
+
+ def test_merged_rule_with_protocol_and_source(self):
+ config = [
+ {
+ "afi": "ipv4",
+ "rule_sets": [
+ {
+ "name": "RULE-SET1",
+ "rules": [
+ {
+ "number": 10,
+ "action": "accept",
+ "protocol": "tcp",
+ "source": {"address": "10.0.0.0/8"},
+ },
+ ],
+ },
+ ],
+ },
+ ]
+ cmds = build_commands(config, [], "merged")
+ self.assertIn(
+ ("set", _BASE + ["ipv4", "name", "RULE-SET1", "rule", "10", "protocol", "tcp"]),
+ cmds,
+ )
+ self.assertIn(
+ (
+ "set",
+ _BASE
+ + [
+ "ipv4",
+ "name",
+ "RULE-SET1",
+ "rule",
+ "10",
+ "source",
+ "address",
+ "10.0.0.0/8",
+ ],
+ ),
+ cmds,
+ )
+
+ def test_merged_idempotent(self):
+ have = self._have()
+ config = [
+ {
+ "afi": "ipv4",
+ "rule_sets": [
+ {
+ "name": "RULE-SET1",
+ "default_action": "drop",
+ "rules": [
+ {"number": 10, "action": "accept", "protocol": "tcp"},
+ {"number": 20, "action": "drop", "state": "invalid"},
+ ],
+ },
+ ],
+ },
+ ]
+ cmds = build_commands(config, have, "merged")
+ self.assertEqual(cmds, [])
+
+ def test_overridden_removes_extra_rule_set(self):
+ have = self._have()
+ config = [
+ {
+ "afi": "ipv4",
+ "rule_sets": [
+ {
+ "name": "NEW-SET",
+ "default_action": "accept",
+ "rules": [{"number": 10, "action": "accept"}],
+ },
+ ],
+ },
+ ]
+ cmds = build_commands(config, have, "overridden")
+ self.assertIn(
+ ("delete", _BASE + ["ipv4", "name", "RULE-SET1"]),
+ cmds,
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/unit/modules/test_vyos_user.py b/tests/unit/modules/test_vyos_user.py
new file mode 100644
index 0000000..511ecef
--- /dev/null
+++ b/tests/unit/modules/test_vyos_user.py
@@ -0,0 +1,172 @@
+# -*- 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_user import (
+ build_commands,
+ get_running_config,
+)
+
+
+_BASE = ["system", "login", "user"]
+
+
+def load_fixture(filename):
+ fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "fixtures")
+ with open(os.path.join(fixtures_dir, filename)) as f:
+ return json.load(f)
+
+
+class VyOSModuleTestCase(unittest.TestCase):
+ def setUp(self):
+ self.mock_vyos = MagicMock()
+ self.fixture = load_fixture("user_running.json")
+ self.mock_vyos.get_config = MagicMock(return_value=self.fixture)
+
+
+class TestVyOSUserGetRunning(VyOSModuleTestCase):
+
+ def test_parses_users(self):
+ result = get_running_config(self.mock_vyos)
+ names = [u["name"] for u in result]
+ self.assertIn("vyos", names)
+ self.assertIn("alice", names)
+
+ def test_parses_full_name(self):
+ result = get_running_config(self.mock_vyos)
+ alice = next(u for u in result if u["name"] == "alice")
+ self.assertEqual(alice["full_name"], "Alice Smith")
+
+ def test_parses_encrypted_password(self):
+ result = get_running_config(self.mock_vyos)
+ alice = next(u for u in result if u["name"] == "alice")
+ self.assertEqual(alice["encrypted_password"], "$6$def456")
+
+ def test_parses_public_keys(self):
+ result = get_running_config(self.mock_vyos)
+ alice = next(u for u in result if u["name"] == "alice")
+ self.assertEqual(len(alice["public_keys"]), 1)
+ key = alice["public_keys"][0]
+ self.assertEqual(key["name"], "alice-laptop")
+ self.assertEqual(key["type"], "ssh-rsa")
+ self.assertEqual(key["key"], "AAAAB3NzaC1yc2EAAAA")
+
+ def test_empty_config(self):
+ self.mock_vyos.get_config = MagicMock(return_value={})
+ result = get_running_config(self.mock_vyos)
+ self.assertEqual(result, [])
+
+
+class TestVyOSUserBuildCommands(unittest.TestCase):
+
+ def _have(self):
+ return [
+ {"name": "vyos", "encrypted_password": "$6$abc123"},
+ {
+ "name": "alice",
+ "full_name": "Alice Smith",
+ "encrypted_password": "$6$def456",
+ },
+ ]
+
+ def test_present_new_user_with_password(self):
+ users = [
+ {
+ "name": "bob",
+ "full_name": "Bob Jones",
+ "password": "secret",
+ "update_password": "always",
+ },
+ ]
+ cmds = build_commands(users, self._have(), "present")
+ self.assertIn(("set", _BASE + ["bob", "full-name", "Bob Jones"]), cmds)
+ self.assertIn(
+ ("set", _BASE + ["bob", "authentication", "plaintext-password", "secret"]),
+ cmds,
+ )
+
+ def test_present_update_password_always(self):
+ users = [{"name": "alice", "password": "newpass", "update_password": "always"}]
+ cmds = build_commands(users, self._have(), "present")
+ self.assertIn(
+ ("set", _BASE + ["alice", "authentication", "plaintext-password", "newpass"]),
+ cmds,
+ )
+
+ def test_present_update_password_on_create_existing(self):
+ users = [{"name": "alice", "password": "newpass", "update_password": "on_create"}]
+ cmds = build_commands(users, self._have(), "present")
+ paths = [c[1] for c in cmds]
+ self.assertNotIn(
+ _BASE + ["alice", "authentication", "plaintext-password", "newpass"],
+ paths,
+ )
+
+ def test_present_update_password_on_create_new(self):
+ users = [{"name": "bob", "password": "secret", "update_password": "on_create"}]
+ cmds = build_commands(users, self._have(), "present")
+ self.assertIn(
+ ("set", _BASE + ["bob", "authentication", "plaintext-password", "secret"]),
+ cmds,
+ )
+
+ def test_present_idempotent_full_name(self):
+ users = [{"name": "alice", "full_name": "Alice Smith"}]
+ cmds = build_commands(users, self._have(), "present")
+ self.assertEqual(cmds, [])
+
+ def test_present_update_full_name(self):
+ users = [{"name": "alice", "full_name": "Alice Updated"}]
+ cmds = build_commands(users, self._have(), "present")
+ self.assertIn(
+ ("set", _BASE + ["alice", "full-name", "Alice Updated"]),
+ cmds,
+ )
+
+ def test_absent_existing_user(self):
+ users = [{"name": "alice"}]
+ cmds = build_commands(users, self._have(), "absent")
+ self.assertIn(("delete", _BASE + ["alice"]), cmds)
+
+ def test_absent_nonexistent_user(self):
+ users = [{"name": "bob"}]
+ cmds = build_commands(users, self._have(), "absent")
+ self.assertEqual(cmds, [])
+
+ def test_present_public_key(self):
+ users = [
+ {
+ "name": "alice",
+ "public_keys": [
+ {"name": "new-key", "key": "AAAAB3...", "type": "ssh-ed25519"},
+ ],
+ },
+ ]
+ cmds = build_commands(users, self._have(), "present")
+ self.assertIn(
+ (
+ "set",
+ _BASE + ["alice", "authentication", "public-keys", "new-key", "key", "AAAAB3..."],
+ ),
+ cmds,
+ )
+ self.assertIn(
+ (
+ "set",
+ _BASE
+ + ["alice", "authentication", "public-keys", "new-key", "type", "ssh-ed25519"],
+ ),
+ cmds,
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()