diff options
Diffstat (limited to 'src/tests')
| -rw-r--r-- | src/tests/helper.py | 2 | ||||
| -rw-r--r-- | src/tests/test_config_diff.py | 2 | ||||
| -rw-r--r-- | src/tests/test_config_merge.py | 50 | ||||
| -rw-r--r-- | src/tests/test_config_parser.py | 2 | ||||
| -rw-r--r-- | src/tests/test_config_tree.py | 48 | ||||
| -rw-r--r-- | src/tests/test_configd_inspect.py | 2 | ||||
| -rw-r--r-- | src/tests/test_configverify.py | 2 | ||||
| -rw-r--r-- | src/tests/test_dependency_graph.py | 2 | ||||
| -rw-r--r-- | src/tests/test_dict_search.py | 10 | ||||
| -rw-r--r-- | src/tests/test_find_device_file.py | 2 | ||||
| -rw-r--r-- | src/tests/test_initial_setup.py | 2 | ||||
| -rw-r--r-- | src/tests/test_op_mode.py | 2 | ||||
| -rw-r--r-- | src/tests/test_task_scheduler.py | 2 | ||||
| -rw-r--r-- | src/tests/test_template.py | 20 | ||||
| -rw-r--r-- | src/tests/test_utils.py | 66 | ||||
| -rw-r--r-- | src/tests/test_utils_auth.py | 75 | ||||
| -rw-r--r-- | src/tests/test_utils_file.py | 86 | ||||
| -rw-r--r-- | src/tests/test_utils_network.py | 11 |
18 files changed, 371 insertions, 15 deletions
diff --git a/src/tests/helper.py b/src/tests/helper.py index cc0710494..2c4421d0a 100644 --- a/src/tests/helper.py +++ b/src/tests/helper.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_config_diff.py b/src/tests/test_config_diff.py index 4017fff4d..edbc0804e 100644 --- a/src/tests/test_config_diff.py +++ b/src/tests/test_config_diff.py @@ -1,4 +1,4 @@ -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_config_merge.py b/src/tests/test_config_merge.py new file mode 100644 index 000000000..c9b4ad5c8 --- /dev/null +++ b/src/tests/test_config_merge.py @@ -0,0 +1,50 @@ +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +import vyos.configtree + +from unittest import TestCase + +class TestConfigDiff(TestCase): + def setUp(self): + with open('tests/data/config.left', 'r') as f: + config_string = f.read() + self.config_left = vyos.configtree.ConfigTree(config_string) + + with open('tests/data/config.right', 'r') as f: + config_string = f.read() + self.config_right = vyos.configtree.ConfigTree(config_string) + + def test_merge_destructive(self): + res = vyos.configtree.merge(self.config_left, self.config_right, + destructive=True) + right_value = self.config_right.return_value(['node1', 'tag_node', 'foo', 'single']) + merge_value = res.return_value(['node1', 'tag_node', 'foo', 'single']) + + # Check includes new value + self.assertEqual(right_value, merge_value) + + # Check preserves non-confliciting paths + self.assertTrue(res.exists(['node3'])) + + def test_merge_non_destructive(self): + res = vyos.configtree.merge(self.config_left, self.config_right) + left_value = self.config_left.return_value(['node1', 'tag_node', 'foo', 'single']) + merge_value = res.return_value(['node1', 'tag_node', 'foo', 'single']) + + # Check includes original value + self.assertEqual(left_value, merge_value) + + # Check preserves non-confliciting paths + self.assertTrue(res.exists(['node3'])) diff --git a/src/tests/test_config_parser.py b/src/tests/test_config_parser.py index 1b4a57311..823d5a7c1 100644 --- a/src/tests/test_config_parser.py +++ b/src/tests/test_config_parser.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_config_tree.py b/src/tests/test_config_tree.py new file mode 100644 index 000000000..d6339c570 --- /dev/null +++ b/src/tests/test_config_tree.py @@ -0,0 +1,48 @@ +# Copyright (C) VyOS Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +# +# + +import json +import unittest +from unittest import TestCase + +from vyos.configtree import ConfigTree +from vyos.referencetree import ReferenceTree +from vyos.derivedtree import subtree_from_list_of_partial_paths + + +class TestInitialSetup(TestCase): + def setUp(self): + with open('data/config.boot.default') as f: + config_str = f.read() + self.ct = ConfigTree(config_str) + + def test_subtree_from_partial(self): + reftree = ReferenceTree(cache_file='data/reftree.cache') + + # workaround since configtree.list_nodes does not take an empty path + d = json.loads(self.ct.to_json()) + top_nodes = list(d) + paths = [s.split() for s in top_nodes] + + reassemble = subtree_from_list_of_partial_paths( + self.ct, paths, reference_tree=reftree + ) + + self.assertEqual(self.ct, reassemble) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/tests/test_configd_inspect.py b/src/tests/test_configd_inspect.py index a0470221d..3363ab653 100644 --- a/src/tests/test_configd_inspect.py +++ b/src/tests/test_configd_inspect.py @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2025 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_configverify.py b/src/tests/test_configverify.py index f1ec65cd2..8f80365d7 100644 --- a/src/tests/test_configverify.py +++ b/src/tests/test_configverify.py @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_dependency_graph.py b/src/tests/test_dependency_graph.py index f3f1db376..12f50a1c4 100644 --- a/src/tests/test_dependency_graph.py +++ b/src/tests/test_dependency_graph.py @@ -1,4 +1,4 @@ -# Copyright (C) 2023-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_dict_search.py b/src/tests/test_dict_search.py index 6b4bc933a..cbc170ecf 100644 --- a/src/tests/test_dict_search.py +++ b/src/tests/test_dict_search.py @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -44,6 +44,14 @@ class TestDictSearch(TestCase): self.assertEqual(dict_search('non_existing', data), None) self.assertEqual(dict_search('non.existing.fancy.key', data), None) + def test_non_existing_keys_with_default_positional(self): + # TestDictSearch: Return a default value when querying for non-existent key (positional arg) + self.assertEqual(dict_search('non.existing.fancy.key', data, 'test'), 'test') + + def test_non_existing_keys_with_default_named(self): + # TestDictSearch: Return a default value when querying for non-existent key (named arg) + self.assertEqual(dict_search('non.existing.fancy.key', data, default='test'), 'test') + def test_string(self): # TestDictSearch: Return value when querying string self.assertEqual(dict_search('string', data), data['string']) diff --git a/src/tests/test_find_device_file.py b/src/tests/test_find_device_file.py index 5b90f2034..02a33c224 100644 --- a/src/tests/test_find_device_file.py +++ b/src/tests/test_find_device_file.py @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_initial_setup.py b/src/tests/test_initial_setup.py index 7737f9df5..09feea7ba 100644 --- a/src/tests/test_initial_setup.py +++ b/src/tests/test_initial_setup.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_op_mode.py b/src/tests/test_op_mode.py index 23f709653..848a9666d 100644 --- a/src/tests/test_op_mode.py +++ b/src/tests/test_op_mode.py @@ -1,4 +1,4 @@ -# Copyright (C) 2022-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_task_scheduler.py b/src/tests/test_task_scheduler.py index 795ffeb9d..0d0319495 100644 --- a/src/tests/test_task_scheduler.py +++ b/src/tests/test_task_scheduler.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as diff --git a/src/tests/test_template.py b/src/tests/test_template.py index 6377f6da5..e2548602d 100644 --- a/src/tests/test_template.py +++ b/src/tests/test_template.py @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -190,3 +190,21 @@ class TestVyOSTemplate(TestCase): for group_name, group_config in data['ike_group'].items(): ciphers = vyos.template.get_esp_ike_cipher(group_config) self.assertIn(IKEv2_DEFAULT, ','.join(ciphers)) + + def test_get_default_port(self): + from vyos.defaults import config_files + from vyos.defaults import internal_ports + + with self.assertRaises(RuntimeError): + vyos.template.get_default_config_file('UNKNOWN') + with self.assertRaises(RuntimeError): + vyos.template.get_default_port('UNKNOWN') + with self.assertRaises(RuntimeError): + vyos.template.nft_accept_invalid('UNKNOWN') + + self.assertEqual(vyos.template.get_default_config_file('sshd_user_ca'), + config_files['sshd_user_ca']) + self.assertEqual(vyos.template.get_default_port('certbot_haproxy'), + internal_ports['certbot_haproxy']) + self.assertEqual(vyos.template.nft_accept_invalid('arp'), + 'ct state invalid ether type arp counter accept') diff --git a/src/tests/test_utils.py b/src/tests/test_utils.py index 7bfd2618e..5022b24f6 100644 --- a/src/tests/test_utils.py +++ b/src/tests/test_utils.py @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -13,6 +13,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. from unittest import TestCase +from unittest.mock import patch + class TestVyOSUtils(TestCase): def test_key_mangling(self): from vyos.utils.dict import mangle_dict_keys @@ -23,4 +25,64 @@ class TestVyOSUtils(TestCase): def test_sysctl_read(self): from vyos.utils.system import sysctl_read - self.assertEqual(sysctl_read('net.ipv4.conf.lo.forwarding'), '1') + self.assertEqual(sysctl_read(['net', 'ipv4', 'conf', 'lo', 'forwarding']), '1') + + def test_sysctl_key_normalization(self): + from vyos.utils.system import sysctl_read + with patch('vyos.utils.system.run') as mock_run: + mock_run.return_value.stdout = b'1\n' + sysctl_read(['net', 'ipv4', 'conf', 'eth0.10', 'forwarding']) + mock_run.assert_called_with( + ['sysctl', '-nb', 'net.ipv4.conf.eth0/10.forwarding'], + capture_output=True, + ) + + def test_list_strip(self): + from vyos.utils.list import list_strip + + lst = ['a', 'b', 'c', 'd', 'e'] + sub = ['a', 'b'] + rsb = ['d', 'e'] + non = ['a', 'e'] + self.assertEqual(list_strip(lst, sub), ['c', 'd', 'e']) + self.assertEqual(list_strip(lst, rsb, right=True), ['a', 'b', 'c']) + self.assertEqual(list_strip(lst, non), []) + self.assertEqual(list_strip(sub, lst), []) + + def test_range_str_to_list(self): + from vyos.utils.convert import range_str_to_list + + # basic cases + self.assertEqual(range_str_to_list('1-3'), [1, 2, 3]) + self.assertEqual(range_str_to_list('1-3,5,7-8'), [1, 2, 3, 5, 7, 8]) + self.assertEqual(range_str_to_list('3'), [3]) + # empty string + self.assertEqual(range_str_to_list(''), []) + # unordered input + self.assertEqual(range_str_to_list('5,1-3,4'), [1, 2, 3, 4, 5]) + self.assertEqual(range_str_to_list('7-9,1-3'), [1, 2, 3, 7, 8, 9]) + # overlapping ranges + self.assertEqual(range_str_to_list('1-5,3-7'), [1, 2, 3, 4, 5, 6, 7]) + self.assertEqual(range_str_to_list('1-3,2-4,3-5'), [1, 2, 3, 4, 5]) + # duplicated values + self.assertEqual(range_str_to_list('1,1,2,2,3'), [1, 2, 3]) + self.assertEqual(range_str_to_list('5,1-3,2,3'), [1, 2, 3, 5]) + # adjacent ranges + self.assertEqual(range_str_to_list('1-3,4-6'), [1, 2, 3, 4, 5, 6]) + + def test_list_to_range_str(self): + from vyos.utils.convert import list_to_range_str + + # basic cases + self.assertEqual(list_to_range_str([1, 2, 3]), '1-3') + self.assertEqual(list_to_range_str([1, 2, 3, 5, 7, 8]), '1-3,5,7-8') + self.assertEqual(list_to_range_str([1, 3]), '1,3') + self.assertEqual(list_to_range_str([3]), '3') + # empty list + self.assertEqual(list_to_range_str([]), '') + # unordered input + self.assertEqual(list_to_range_str([5, 1, 2, 3, 4]), '1-5') + self.assertEqual(list_to_range_str([7, 8, 9, 1, 2, 3]), '1-3,7-9') + # duplicated values + self.assertEqual(list_to_range_str([1, 1, 2, 2, 3, 3]), '1-3') + self.assertEqual(list_to_range_str([5, 1, 2, 2, 3, 5]), '1-3,5') diff --git a/src/tests/test_utils_auth.py b/src/tests/test_utils_auth.py new file mode 100644 index 000000000..f3b52ab29 --- /dev/null +++ b/src/tests/test_utils_auth.py @@ -0,0 +1,75 @@ +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +import pwd +import unittest + +from vyos.utils import auth + +class TestVyOSUtilsAuth(unittest.TestCase): + def test_uid_root(self): + self.assertEqual(auth.get_local_passwd_entries(0).pw_name, 'root') + self.assertEqual(auth.get_local_passwd_entries(0).pw_uid, 0) + + def test_uid_daemon(self): + uid = None + for user in auth.get_local_passwd_entries(): + if user.pw_name == 'daemon': + uid = user.pw_uid + break + + self.assertEqual(auth.get_local_passwd_entries(uid).pw_name, 'daemon') + self.assertEqual(auth.get_local_passwd_entries(uid).pw_uid, uid) + + def test_uid_not_found(self): + self.assertEqual(auth.get_local_passwd_entries(5465487635), None) + + def test_get_local_users_returns_existing_usernames(self): + # Returned users exist, skip list is excluded, and UIDs are in range + + all_users = set(s_user.pw_name for s_user in pwd.getpwall()) + local_users = auth.get_local_users() + + # All returned users must really exist + for user in local_users: + self.assertIn(user, all_users) + + # Nobody in the skip list + for skipped in auth.SYSTEM_USER_SKIP_LIST: + self.assertNotIn(skipped, local_users) + + # All are within UID range + for s_user in pwd.getpwall(): + if s_user.pw_name in local_users: + self.assertGreaterEqual(s_user.pw_uid, auth.MIN_USER_UID) + self.assertLessEqual(s_user.pw_uid, auth.MAX_USER_UID) + + def test_get_user_home_dir_for_real_user(self): + # User's homedir is a non-empty string for a valid user + + local_users = auth.get_local_users() + if local_users: + for user in local_users: + home_dir = auth.get_user_home_dir(user) + self.assertIsInstance(home_dir, str) + self.assertTrue(bool(home_dir)) # Should not be empty + else: + self.skipTest("No suitable non-system users found on this system") + + def test_get_user_home_dir_invalid_user(self): + # Raises KeyError for nonexistent username + + user = "__this_user_does_not_exist__" # Test using unlikely username + with self.assertRaises(KeyError): + auth.get_user_home_dir(user) diff --git a/src/tests/test_utils_file.py b/src/tests/test_utils_file.py new file mode 100644 index 000000000..4519cf03c --- /dev/null +++ b/src/tests/test_utils_file.py @@ -0,0 +1,86 @@ +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +import tempfile +import unittest + +from pathlib import Path + +from vyos.utils.file import copy_recursive +from vyos.utils.file import move_recursive + + +class TestVyOSUtilsFile(unittest.TestCase): + def setUp(self): + """Create temporary directories for source and destination.""" + self.tmpdir = tempfile.TemporaryDirectory() + self.src = Path(self.tmpdir.name) / 'src' + self.dst = Path(self.tmpdir.name) / 'dst' + + # Create test directory structure in `src` + (self.src / 'subdir').mkdir(parents=True) + (self.dst).mkdir(parents=True) + + # Create files + (self.src / 'file1.txt').write_text('hello world') + (self.src / 'subdir' / 'file2.txt').write_text('subdir file') + + def tearDown(self): + """Cleanup temp directory.""" + self.tmpdir.cleanup() + + def test_copy_recursive_no_overwrite(self): + copy_recursive(str(self.src), str(self.dst), overwrite=False) + + self.assertTrue((self.dst / 'file1.txt').exists()) + self.assertTrue((self.dst / 'subdir' / 'file2.txt').exists()) + + def test_copy_recursive_skip_existing(self): + # Create conflicting file in destination + (self.dst / 'file1.txt').write_text('different content') + + copy_recursive(str(self.src), str(self.dst), overwrite=False) + + # Destination should remain the same (not overwritten) + content = (self.dst / 'file1.txt').read_text() + self.assertEqual(content, 'different content') + + def test_copy_recursive_overwrite(self): + (self.dst / 'file1.txt').write_text('different content') + + copy_recursive(str(self.src), str(self.dst), overwrite=True) + + # Destination should be overwritten with source content + content = (self.dst / 'file1.txt').read_text() + self.assertEqual(content, 'hello world') + + def test_move_recursive(self): + move_recursive(str(self.src), str(self.dst), overwrite=False) + + # Files should appear in destination + self.assertTrue((self.dst / 'file1.txt').exists()) + self.assertTrue((self.dst / 'subdir' / 'file2.txt').exists()) + + # Source should be removed + self.assertFalse(self.src.exists()) + + def test_move_recursive_overwrite(self): + # Prepare conflicting file in destination + (self.dst / 'file1.txt').write_text('conflicting') + + move_recursive(str(self.src), str(self.dst), overwrite=True) + + content = (self.dst / 'file1.txt').read_text() + self.assertEqual(content, 'hello world') # overwritten + self.assertFalse(self.src.exists()) # source cleaned up diff --git a/src/tests/test_utils_network.py b/src/tests/test_utils_network.py index d68dec16f..6d9a358c1 100644 --- a/src/tests/test_utils_network.py +++ b/src/tests/test_utils_network.py @@ -1,4 +1,4 @@ -# Copyright (C) 2020-2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -43,3 +43,12 @@ class TestVyOSUtilsNetwork(TestCase): self.assertFalse(vyos.utils.network.is_loopback_addr('::2')) self.assertFalse(vyos.utils.network.is_loopback_addr('192.0.2.1')) + + def test_check_port_availability(self): + self.assertTrue(vyos.utils.network.check_port_availability('::1', 8080)) + self.assertTrue(vyos.utils.network.check_port_availability('127.0.0.1', 8080)) + self.assertTrue(vyos.utils.network.check_port_availability(None, 8080, protocol='udp')) + # We do not have 192.0.2.1 configured on this system + self.assertFalse(vyos.utils.network.check_port_availability('192.0.2.1', 443)) + # We do not have 2001:db8::1 configured on this system + self.assertFalse(vyos.utils.network.check_port_availability('2001:db8::1', 80, protocol='udp')) |
