summaryrefslogtreecommitdiff
path: root/tests/unit/cliconf
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/cliconf')
-rw-r--r--tests/unit/cliconf/__init__.py0
-rw-r--r--tests/unit/cliconf/test_utils_vyosconf.py217
2 files changed, 217 insertions, 0 deletions
diff --git a/tests/unit/cliconf/__init__.py b/tests/unit/cliconf/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/unit/cliconf/__init__.py
diff --git a/tests/unit/cliconf/test_utils_vyosconf.py b/tests/unit/cliconf/test_utils_vyosconf.py
new file mode 100644
index 00000000..dbc296e6
--- /dev/null
+++ b/tests/unit/cliconf/test_utils_vyosconf.py
@@ -0,0 +1,217 @@
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import, division, print_function
+
+
+__metaclass__ = type
+
+import unittest
+
+from ansible_collections.vyos.vyos.plugins.cliconf_utils.vyosconf import (
+ KEEP_EXISTING_VALUES,
+ VyosConf,
+)
+
+
+class TestListElements(unittest.TestCase):
+ def test_add(self):
+ conf = VyosConf()
+ conf.set_entry(["a", "b"], "c")
+ self.assertEqual(conf.config, {"a": {"b": {"c": {}}}})
+ conf.set_entry(["a", "b"], "d")
+ self.assertEqual(conf.config, {"a": {"b": {"c": {}, "d": {}}}})
+ conf.set_entry(["a", "c"], "b")
+ self.assertEqual(
+ conf.config,
+ {"a": {"b": {"c": {}, "d": {}}, "c": {"b": {}}}},
+ )
+ conf.set_entry(["a", "c", "b"], "d")
+ self.assertEqual(
+ conf.config,
+ {"a": {"b": {"c": {}, "d": {}}, "c": {"b": {"d": {}}}}},
+ )
+
+ def test_del(self):
+ conf = VyosConf()
+ conf.set_entry(["a", "b"], "c")
+ conf.set_entry(["a", "c", "b"], "d")
+ conf.set_entry(["a", "b"], "d")
+ self.assertEqual(
+ conf.config,
+ {"a": {"b": {"c": {}, "d": {}}, "c": {"b": {"d": {}}}}},
+ )
+ conf.del_entry(["a", "c", "b"], "d")
+ self.assertEqual(conf.config, {"a": {"b": {"c": {}, "d": {}}}})
+ conf.set_entry(["a", "b", "c"], "d")
+ conf.del_entry(["a", "b", "c"], "d")
+ self.assertEqual(conf.config, {"a": {"b": {"d": {}}}})
+
+ def test_del_missing_leaf_is_noop(self):
+ """
+ Deleting a leaf that was never set must leave the config unchanged.
+ Regression test: del_entry() used to raise KeyError when the leaf's
+ parent had siblings, and could delete an unrelated ancestor subtree
+ (or the entire config) when the parent path had no siblings.
+ """
+ # parent has siblings: previously raised KeyError
+ conf = VyosConf()
+ conf.set_entry(["a", "b"], "c")
+ conf.set_entry(["a", "b"], "d")
+ conf.del_entry(["a", "b"], "nonexistent")
+ self.assertEqual(conf.config, {"a": {"b": {"c": {}, "d": {}}}})
+
+ # parent path is an unbranched chain: previously deleted the
+ # entire config instead of no-op'ing
+ conf = VyosConf()
+ conf.set_entry(["a", "b"], "d")
+ conf.del_entry(["a", "b"], "c")
+ self.assertEqual(conf.config, {"a": {"b": {"d": {}}}})
+
+ # missing intermediate path element already behaved correctly;
+ # confirm it still does
+ conf = VyosConf()
+ conf.set_entry(["a", "b"], "c")
+ conf.del_entry(["a", "x"], "c")
+ self.assertEqual(conf.config, {"a": {"b": {"c": {}}}})
+
+ def test_parse(self):
+ conf = VyosConf()
+ self.assertListEqual(
+ conf.parse_line("set a b c"),
+ ["set", ["a", "b"], "c"],
+ )
+ self.assertListEqual(
+ conf.parse_line('set a b "c"'),
+ ["set", ["a", "b"], "c"],
+ )
+ self.assertListEqual(
+ conf.parse_line("set a b 'c d'"),
+ ["set", ["a", "b"], "c d"],
+ )
+ self.assertListEqual(
+ conf.parse_line("set a b 'c'"),
+ ["set", ["a", "b"], "c"],
+ )
+ self.assertListEqual(
+ conf.parse_line("delete a b 'c'"),
+ ["delete", ["a", "b"], "c"],
+ )
+ self.assertListEqual(
+ conf.parse_line("del a b 'c'"),
+ ["del", ["a", "b"], "c"],
+ )
+ self.assertListEqual(
+ conf.parse_line("set a b '\"c'"),
+ ["set", ["a", "b"], '"c'],
+ )
+ self.assertListEqual(
+ conf.parse_line("set a b 'c' #this is a comment"),
+ ["set", ["a", "b"], "c"],
+ )
+ self.assertListEqual(
+ conf.parse_line("set a b '#c'"),
+ ["set", ["a", "b"], "#c"],
+ )
+
+ def test_run_commands(self):
+ self.assertEqual(
+ VyosConf(["set a b 'c'", "set a c 'b'"]).config,
+ {"a": {"b": {"c": {}}, "c": {"b": {}}}},
+ )
+ self.assertEqual(
+ VyosConf(["set a b c 'd'", "set a c 'b'", "del a b c d"]).config,
+ {"a": {"c": {"b": {}}}},
+ )
+
+ def test_build_commands(self):
+ self.assertEqual(
+ sorted(
+ VyosConf(
+ [
+ "set a b 'c a'",
+ "set a c a",
+ "set a c b",
+ "delete a c a",
+ ],
+ ).build_commands(),
+ ),
+ sorted(["set a b 'c a'", "set a c b"]),
+ )
+ self.assertEqual(
+ sorted(
+ VyosConf(
+ [
+ "set a b 10.0.0.1/24",
+ "set a c ABCabc123+/=",
+ "set a d $6$ABC.abc.123.+./=..",
+ ],
+ ).build_commands(),
+ ),
+ sorted(
+ [
+ "set a b 10.0.0.1/24",
+ "set a c 'ABCabc123+/='",
+ "set a d '$6$ABC.abc.123.+./=..'",
+ ],
+ ),
+ )
+
+ def test_check_commands(self):
+ conf = VyosConf(["set a b 'c a'", "set a c b"])
+ self.assertListEqual(
+ conf.check_commands(
+ ["set a b 'c a'", "del a c b", "set a b 'c'", "del a a a"],
+ ),
+ [True, False, False, True],
+ )
+
+ def test_diff_commands_to(self):
+ conf = VyosConf(["set a b 'c a'", "set a c b"])
+
+ self.assertListEqual(
+ conf.diff_commands_to(VyosConf(["set a c b"])),
+ ["delete a b"],
+ )
+ self.assertListEqual(
+ conf.diff_commands_to(VyosConf(["set a b 'c a'", "set a c b"])),
+ [],
+ )
+
+ # KEEP_EXISTING_VALUES is no longer reachable via 'set'/'delete'
+ # command text (see #6): a literal "..." leaf is now an ordinary
+ # value, not a sentinel, so nothing is suppressed here.
+ self.assertListEqual(
+ conf.diff_commands_to(VyosConf(["set a b ..."])),
+ ["delete a b 'c a'", "delete a c", "set a b ..."],
+ )
+
+ def test_diff_commands_to_keep_existing_values_sentinel(self):
+ # KEEP_EXISTING_VALUES is only reachable via the Python API now.
+ # Build the candidate tree directly to prove diff_to() still
+ # honours it when used that way.
+ conf = VyosConf(["set a b 'c a'", "set a c b"])
+ candidate = VyosConf()
+ candidate.config = {"a": {"b": {KEEP_EXISTING_VALUES: {}}}}
+
+ self.assertListEqual(
+ conf.diff_commands_to(candidate),
+ ["delete a c"],
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()