diff options
| author | omnom62 <75066712+omnom62@users.noreply.github.com> | 2026-09-17 18:31:48 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-17 11:31:48 +0300 |
| commit | ecff3e2cfa93ca7c3694559c79bce65300c5fc7d (patch) | |
| tree | e73c023ac24711c87ac4169b89cc3c4c41d5859a /tests/unit/cliconf | |
| parent | 762c276f61dd8fb599d9600df93c1a2992a8cf2e (diff) | |
| download | vyos.vyos-main.tar.gz vyos.vyos-main.zip | |
* T6828: PR190 revive, vyos_conf match "enforced"
Diffstat (limited to 'tests/unit/cliconf')
| -rw-r--r-- | tests/unit/cliconf/__init__.py | 0 | ||||
| -rw-r--r-- | tests/unit/cliconf/test_utils_vyosconf.py | 217 |
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() |
