diff --git a/changelog/63025.fixed b/changelog/63025.fixed new file mode 100644 index 000000000000..11546d63bb17 --- /dev/null +++ b/changelog/63025.fixed @@ -0,0 +1 @@ +Fix btrfs.subvolume_snapshot command failing diff --git a/salt/modules/btrfs.py b/salt/modules/btrfs.py index 4a1d37fbfcb0..4b02eb21afaf 100644 --- a/salt/modules/btrfs.py +++ b/salt/modules/btrfs.py @@ -1222,6 +1222,9 @@ def subvolume_snapshot(source, dest=None, name=None, read_only=False): cmd = ["btrfs", "subvolume", "snapshot"] if read_only: cmd.append("-r") + + cmd.append(source) + if dest and not name: cmd.append(dest) if dest and name: diff --git a/tests/pytests/unit/modules/test_btrfs.py b/tests/pytests/unit/modules/test_btrfs.py new file mode 100644 index 000000000000..5b848f079bf6 --- /dev/null +++ b/tests/pytests/unit/modules/test_btrfs.py @@ -0,0 +1,781 @@ +""" + Test cases for salt.modules.btrfs + + :codeauthor: Jayesh Kariya +""" + +import os + +import pytest + +import salt.modules.btrfs as btrfs +import salt.utils.files +import salt.utils.fsutils +import salt.utils.platform +from salt.exceptions import CommandExecutionError +from tests.support.mock import MagicMock, mock_open, patch + + +@pytest.fixture +def configure_loader_modules(): + return {btrfs: {"__salt__": {}}} + + +# 'version' function tests: 1 +def test_version(): + """ + Test if it return BTRFS version. + """ + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + assert btrfs.version() == {"version": "Salt"} + + +# 'info' function tests: 1 + + +def test_info(): + """ + Test if it get BTRFS filesystem information. + """ + with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock(return_value={"Salt": "salt"}) + with patch.object(btrfs, "_parse_btrfs_info", mock): + assert btrfs.info("/dev/sda1") == {"Salt": "salt"} + + +# 'devices' function tests: 1 + + +def test_devices(): + """ + Test if it get known BTRFS formatted devices on the system. + """ + with patch("salt.utils.fsutils._blkid_output", MagicMock(return_value="Salt")): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + assert btrfs.devices() == "Salt" + + +# 'defragment' function tests: 2 + + +def test_defragment(): + """ + Test if it defragment mounted BTRFS filesystem. + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=False)): + with patch("os.path.exists", MagicMock(return_value=True)): + ret = [ + { + "range": "/dev/sda1", + "mount_point": False, + "log": False, + "passed": True, + } + ] + mock_run = MagicMock( + return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} + ) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock_run}): + mock_file = mock_open(read_data="/dev/sda1 / ext4 rw,data=ordered 0 0") + with patch.object(salt.utils.files, "fopen", mock_file): + assert btrfs.defragment("/dev/sda1") == ret + + +def test_defragment_error(): + """ + Test if it gives device not mount error + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): + mock_run = MagicMock( + return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} + ) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock_run}): + mock_file = mock_open(read_data="/dev/sda1 / ext4 rw,data=ordered 0 0") + with patch.object(salt.utils.files, "fopen", mock_file): + pytest.raises(CommandExecutionError, btrfs.defragment, "/dev/sda1") + + +# 'features' function tests: 1 + + +def test_features(): + """ + Test if it list currently available BTRFS features. + """ + with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + assert btrfs.features() == {} + + +# 'usage' function tests: 1 + + +def test_usage(): + """ + Test if it shows in which disk the chunks are allocated. + """ + with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock(return_value={"Salt": "salt"}) + with patch.object(btrfs, "_usage_specific", mock): + assert btrfs.usage("/dev/sda1") == {"Salt": "salt"} + + mock = MagicMock( + return_value={"retcode": 1, "stderr": "", "stdout": "Unallocated:\n"} + ) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock(return_value={"/dev/sda1": True}) + with patch.object(btrfs, "_usage_unallocated", mock): + assert btrfs.usage("/dev/sda1") == {"unallocated": {"/dev/sda1": True}} + + mock = MagicMock( + return_value={"retcode": 1, "stderr": "", "stdout": "Overall:\n"} + ) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock(return_value={"/dev/sda1": True}) + with patch.object(btrfs, "_usage_overall", mock): + assert btrfs.usage("/dev/sda1") == {"overall": {"/dev/sda1": True}} + + +# 'mkfs' function tests: 3 + + +def test_mkfs(): + """ + Test if it create a file system on the specified device. + """ + mock_cmd = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + mock_info = MagicMock(return_value=[]) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock_cmd, "btrfs.info": mock_info}): + mock_file = mock_open(read_data="/dev/sda1 / ext4 rw,data=ordered 0 0") + with patch.object(salt.utils.files, "fopen", mock_file): + assert btrfs.mkfs("/dev/sda1") == {"log": "Salt"} + + +def test_mkfs_error(): + """ + Test if it No devices specified error + """ + pytest.raises(CommandExecutionError, btrfs.mkfs) + + +def test_mkfs_mount_error(): + """ + Test if it device mount error + """ + mock = MagicMock(return_value={"/dev/sda1": True}) + with patch.object(salt.utils.fsutils, "_get_mounts", mock): + pytest.raises(CommandExecutionError, btrfs.mkfs, "/dev/sda1") + + +# 'resize' function tests: 4 + + +def test_resize(): + """ + Test if it resize filesystem. + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + mock_info = MagicMock(return_value=[]) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock, "btrfs.info": mock_info}): + mock = MagicMock(return_value={"/dev/sda1": True}) + with patch.object(salt.utils.fsutils, "_get_mounts", mock): + assert btrfs.resize("/dev/sda1", "max") == {"log": "Salt"} + + +def test_resize_valid_error(): + """ + Test if it gives device should be mounted error + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=False)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + pytest.raises(CommandExecutionError, btrfs.resize, "/dev/sda1", "max") + + +def test_resize_mount_error(): + """ + Test if it gives mount point error + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): + mock = MagicMock(return_value={"/dev/sda1": False}) + with patch.object(salt.utils.fsutils, "_get_mounts", mock): + pytest.raises(CommandExecutionError, btrfs.resize, "/dev/sda1", "max") + + +def test_resize_size_error(): + """ + Test if it gives unknown size error + """ + pytest.raises(CommandExecutionError, btrfs.resize, "/dev/sda1", "250m") + + +# 'convert' function tests: 5 + + +def test_convert(): + """ + Test if it convert ext2/3/4 to BTRFS + """ + with patch("os.path.exists", MagicMock(return_value=True)): + ret = { + "after": { + "balance_log": "Salt", + "ext4_image": "removed", + "ext4_image_info": "N/A", + "fsck_status": "N/A", + "mount_point": None, + "type": "ext4", + }, + "before": { + "fsck_status": "Filesystem errors corrected", + "mount_point": None, + "type": "ext4", + }, + } + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock(return_value={"/dev/sda3": {"type": "ext4"}}) + with patch.object(salt.utils.fsutils, "_blkid_output", mock): + mock = MagicMock(return_value={"/dev/sda3": [{"mount_point": None}]}) + with patch.object(salt.utils.fsutils, "_get_mounts", mock): + assert btrfs.convert("/dev/sda3", permanent=True) == ret + + +def test_convert_device_error(): + """ + Test if it gives device not found error + """ + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock(return_value={"/dev/sda1": False}) + with patch.object(salt.utils.fsutils, "_blkid_output", mock): + pytest.raises(CommandExecutionError, btrfs.convert, "/dev/sda1") + + +def test_convert_filesystem_error(): + """ + Test if it gives file system error + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock(return_value={"/dev/sda1": {"type": "ext"}}) + with patch.object(salt.utils.fsutils, "_blkid_output", mock): + pytest.raises(CommandExecutionError, btrfs.convert, "/dev/sda1") + + +def test_convert_error(): + """ + Test if it gives error cannot convert root + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + mock = MagicMock( + return_value={"/dev/sda1": {"type": "ext4", "mount_point": "/"}} + ) + with patch.object(salt.utils.fsutils, "_blkid_output", mock): + mock = MagicMock(return_value={"/dev/sda1": [{"mount_point": "/"}]}) + with patch.object(salt.utils.fsutils, "_get_mounts", mock): + pytest.raises(CommandExecutionError, btrfs.convert, "/dev/sda1") + + +def test_convert_migration_error(): + """ + Test if it gives migration error + """ + with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): + mock_run = MagicMock( + return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} + ) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock_run}): + mock_blk = MagicMock(return_value={"/dev/sda1": {"type": "ext4"}}) + with patch.object(salt.utils.fsutils, "_blkid_output", mock_blk): + mock_file = mock_open(read_data="/dev/sda1 / ext4 rw,data=ordered 0 0") + with patch.object(salt.utils.files, "fopen", mock_file): + pytest.raises(CommandExecutionError, btrfs.convert, "/dev/sda1") + + +# 'add' function tests: 1 + + +def test_add(): + """ + Test if it add a devices to a BTRFS filesystem. + """ + with patch("salt.modules.btrfs._restripe", MagicMock(return_value={})): + assert btrfs.add("/mountpoint", "/dev/sda1", "/dev/sda2") == {} + + +# 'delete' function tests: 1 + + +def test_delete(): + """ + Test if it delete a devices to a BTRFS filesystem. + """ + with patch("salt.modules.btrfs._restripe", MagicMock(return_value={})): + assert btrfs.delete("/mountpoint", "/dev/sda1", "/dev/sda2") == {} + + +# 'properties' function tests: 1 + + +def test_properties(): + """ + Test if list properties for given btrfs object + """ + with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): + mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) + with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): + assert btrfs.properties("/dev/sda1", "subvol") == {} + + +def test_properties_unknown_error(): + """ + Test if it gives unknown property error + """ + pytest.raises(CommandExecutionError, btrfs.properties, "/dev/sda1", "a") + + +def test_properties_error(): + """ + Test if it gives exception error + """ + pytest.raises(CommandExecutionError, btrfs.properties, "/dev/sda1", "subvol", True) + + +def test_subvolume_exists(): + """ + Test subvolume_exists + """ + salt_mock = { + "cmd.retcode": MagicMock(return_value=0), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_exists("/mnt/one") + + +def test_subvolume_not_exists(): + """ + Test subvolume_exists + """ + salt_mock = { + "cmd.retcode": MagicMock(return_value=1), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert not btrfs.subvolume_exists("/mnt/nowhere") + + +def test_subvolume_create_fails_parameters(): + """ + Test btrfs subvolume create + """ + # Fails when qgroupids is not a list + with pytest.raises(CommandExecutionError): + btrfs.subvolume_create("var", qgroupids="1") + + +@patch("salt.modules.btrfs.subvolume_exists") +def test_subvolume_create_already_exists(subvolume_exists): + """ + Test btrfs subvolume create + """ + subvolume_exists.return_value = True + assert not btrfs.subvolume_create("var", dest="/mnt") + + +@patch("salt.modules.btrfs.subvolume_exists") +def test_subvolume_create(subvolume_exists): + """ + Test btrfs subvolume create + """ + subvolume_exists.return_value = False + salt_mock = { + "cmd.run_all": MagicMock(return_value={"recode": 0}), + } + expected_path = os.path.join("/mnt", "var") + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_create("var", dest="/mnt") + subvolume_exists.assert_called_once() + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "create", expected_path] + ) + + +def test_subvolume_delete_fails_parameters(): + """ + Test btrfs subvolume delete + """ + # We need to provide name or names + with pytest.raises(CommandExecutionError): + btrfs.subvolume_delete() + + with pytest.raises(CommandExecutionError): + btrfs.subvolume_delete(names="var") + + +def test_subvolume_delete_fails_parameter_commit(): + """ + Test btrfs subvolume delete + """ + # Parameter commit can be 'after' or 'each' + with pytest.raises(CommandExecutionError): + btrfs.subvolume_delete(name="var", commit="maybe") + + +@patch("salt.modules.btrfs.subvolume_exists") +def test_subvolume_delete_already_missing(subvolume_exists): + """ + Test btrfs subvolume delete + """ + subvolume_exists.return_value = False + assert not btrfs.subvolume_delete(name="var", names=["tmp"]) + + +@patch("salt.modules.btrfs.subvolume_exists") +def test_subvolume_delete_already_missing_name(subvolume_exists): + """ + Test btrfs subvolume delete + """ + subvolume_exists.return_value = False + assert not btrfs.subvolume_delete(name="var") + + +@patch("salt.modules.btrfs.subvolume_exists") +def test_subvolume_delete_already_missing_names(subvolume_exists): + """ + Test btrfs subvolume delete + """ + subvolume_exists.return_value = False + assert not btrfs.subvolume_delete(names=["tmp"]) + + +@patch("salt.modules.btrfs.subvolume_exists") +def test_subvolume_delete(subvolume_exists): + """ + Test btrfs subvolume delete + """ + subvolume_exists.return_value = True + salt_mock = { + "cmd.run_all": MagicMock(return_value={"recode": 0}), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_delete("var", names=["tmp"]) + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "delete", "var", "tmp"] + ) + + +def test_subvolume_find_new_empty(): + """ + Test btrfs subvolume find-new + """ + salt_mock = { + "cmd.run_all": MagicMock( + return_value={"recode": 0, "stdout": "transid marker was 1024"} + ), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_find_new("var", "2000") == { + "files": [], + "transid": "1024", + } + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "find-new", "var", "2000"] + ) + + +def test_subvolume_find_new(): + """ + Test btrfs subvolume find-new + """ + salt_mock = { + "cmd.run_all": MagicMock( + return_value={ + "recode": 0, + "stdout": """inode 185148 ... gen 2108 flags NONE var/log/audit/audit.log +inode 187390 ... INLINE etc/openvpn/openvpn-status.log +transid marker was 1024""", + } + ), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_find_new("var", "1023") == { + "files": ["var/log/audit/audit.log", "etc/openvpn/openvpn-status.log"], + "transid": "1024", + } + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "find-new", "var", "1023"] + ) + + +def test_subvolume_get_default_free(): + """ + Test btrfs subvolume get-default + """ + salt_mock = { + "cmd.run_all": MagicMock( + return_value={"recode": 0, "stdout": "ID 5 (FS_TREE)"} + ), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_get_default("/mnt") == { + "id": "5", + "name": "(FS_TREE)", + } + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "get-default", "/mnt"] + ) + + +def test_subvolume_get_default(): + """ + Test btrfs subvolume get-default + """ + salt_mock = { + "cmd.run_all": MagicMock( + return_value={ + "recode": 0, + "stdout": "ID 257 gen 8 top level 5 path var", + } + ), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_get_default("/mnt") == { + "id": "257", + "name": "var", + } + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "get-default", "/mnt"] + ) + + +def test_subvolume_list_fails_parameters(): + """ + Test btrfs subvolume list + """ + # Fails when sort is not a list + with pytest.raises(CommandExecutionError): + btrfs.subvolume_list("/mnt", sort="-rootid") + + # Fails when sort is not recognized + with pytest.raises(CommandExecutionError): + btrfs.subvolume_list("/mnt", sort=["-root"]) + + +def test_subvolume_list_simple(): + """ + Test btrfs subvolume list + """ + salt_mock = { + "cmd.run_all": MagicMock( + return_value={ + "recode": 0, + "stdout": """ID 257 gen 8 top level 5 path one +ID 258 gen 10 top level 5 path another one +""", + } + ), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_list("/mnt") == [ + {"id": "257", "gen": "8", "top level": "5", "path": "one"}, + {"id": "258", "gen": "10", "top level": "5", "path": "another one"}, + ] + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "list", "/mnt"] + ) + + +def test_subvolume_list(): + """ + Test btrfs subvolume list + """ + salt_mock = { + "cmd.run_all": MagicMock( + return_value={ + "recode": 0, + "stdout": """\ +ID 257 gen 8 cgen 8 parent 5 top level 5 parent_uuid - received_uuid - \ + uuid 777...-..05 path one +ID 258 gen 10 cgen 10 parent 5 top level 5 parent_uuid - received_uuid - \ + uuid a90...-..01 path another one +""", + } + ), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_list( + "/mnt", + parent_id=True, + absolute=True, + ogeneration=True, + generation=True, + subvolumes=True, + uuid=True, + parent_uuid=True, + sent_subvolume_uuid=True, + generation_cmp="-100", + ogeneration_cmp="+5", + sort=["-rootid", "gen"], + ) == [ + { + "id": "257", + "gen": "8", + "cgen": "8", + "parent": "5", + "top level": "5", + "parent_uuid": "-", + "received_uuid": "-", + "uuid": "777...-..05", + "path": "one", + }, + { + "id": "258", + "gen": "10", + "cgen": "10", + "parent": "5", + "top level": "5", + "parent_uuid": "-", + "received_uuid": "-", + "uuid": "a90...-..01", + "path": "another one", + }, + ] + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + [ + "btrfs", + "subvolume", + "list", + "-p", + "-a", + "-c", + "-g", + "-o", + "-u", + "-q", + "-R", + "-G", + "-100", + "-C", + "+5", + "--sort=-rootid,gen", + "/mnt", + ] + ) + + +def test_subvolume_set_default(): + """ + Test btrfs subvolume set-default + """ + salt_mock = { + "cmd.run_all": MagicMock(return_value={"recode": 0}), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_set_default("257", "/mnt") + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "set-default", "257", "/mnt"] + ) + + +def test_subvolume_show(): + """ + Test btrfs subvolume show + """ + salt_mock = { + "cmd.run_all": MagicMock( + return_value={ + "recode": 0, + "stdout": """@/var + Name: var + UUID: 7a14...-...04 + Parent UUID: - + Received UUID: - + Creation time: 2018-10-01 14:33:12 +0200 + Subvolume ID: 258 + Generation: 82479 + Gen at creation: 10 + Parent ID: 256 + Top level ID: 256 + Flags: - + Snapshot(s): +""", + } + ), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_show("/var") == { + "@/var": { + "name": "var", + "uuid": "7a14...-...04", + "parent uuid": "-", + "received uuid": "-", + "creation time": "2018-10-01 14:33:12 +0200", + "subvolume id": "258", + "generation": "82479", + "gen at creation": "10", + "parent id": "256", + "top level id": "256", + "flags": "-", + "snapshot(s)": "", + }, + } + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "show", "/var"] + ) + + +def test_subvolume_sync_fail_parameters(): + """ + Test btrfs subvolume sync + """ + # Fails when subvolids is not a list + with pytest.raises(CommandExecutionError): + btrfs.subvolume_sync("/mnt", subvolids="257") + + +def test_subvolume_sync(): + """ + Test btrfs subvolume sync + """ + salt_mock = { + "cmd.run_all": MagicMock(return_value={"recode": 0}), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_sync("/mnt", subvolids=["257"], sleep="1") + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "sync", "-s", "1", "/mnt", "257"] + ) + + +def test_subvolume_snapshot(): + salt_mock = { + "cmd.run_all": MagicMock(return_value={"recode": 0}), + } + with patch.dict(btrfs.__salt__, salt_mock): + assert btrfs.subvolume_snapshot("/mnt", name="tmp_snap") + salt_mock["cmd.run_all"].assert_called_once() + salt_mock["cmd.run_all"].assert_called_with( + ["btrfs", "subvolume", "snapshot", "/mnt", "tmp_snap"] + ) diff --git a/tests/unit/modules/test_btrfs.py b/tests/unit/modules/test_btrfs.py deleted file mode 100644 index 40522d77ca88..000000000000 --- a/tests/unit/modules/test_btrfs.py +++ /dev/null @@ -1,770 +0,0 @@ -""" - :codeauthor: Jayesh Kariya -""" - -import os - -import pytest - -import salt.modules.btrfs as btrfs -import salt.utils.files -import salt.utils.fsutils -import salt.utils.platform -from salt.exceptions import CommandExecutionError -from tests.support.mixins import LoaderModuleMockMixin -from tests.support.mock import MagicMock, mock_open, patch -from tests.support.unit import TestCase - - -class BtrfsTestCase(TestCase, LoaderModuleMockMixin): - """ - Test cases for salt.modules.btrfs - """ - - def setup_loader_modules(self): - return {btrfs: {"__salt__": {}}} - - # 'version' function tests: 1 - def test_version(self): - """ - Test if it return BTRFS version. - """ - mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - self.assertDictEqual(btrfs.version(), {"version": "Salt"}) - - # 'info' function tests: 1 - - def test_info(self): - """ - Test if it get BTRFS filesystem information. - """ - with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock(return_value={"Salt": "salt"}) - with patch.object(btrfs, "_parse_btrfs_info", mock): - self.assertDictEqual(btrfs.info("/dev/sda1"), {"Salt": "salt"}) - - # 'devices' function tests: 1 - - def test_devices(self): - """ - Test if it get known BTRFS formatted devices on the system. - """ - with patch("salt.utils.fsutils._blkid_output", MagicMock(return_value="Salt")): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - self.assertEqual(btrfs.devices(), "Salt") - - # 'defragment' function tests: 2 - - def test_defragment(self): - """ - Test if it defragment mounted BTRFS filesystem. - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=False)): - with patch("os.path.exists", MagicMock(return_value=True)): - ret = [ - { - "range": "/dev/sda1", - "mount_point": False, - "log": False, - "passed": True, - } - ] - mock_run = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock_run}): - mock_file = mock_open( - read_data="/dev/sda1 / ext4 rw,data=ordered 0 0" - ) - with patch.object(salt.utils.files, "fopen", mock_file): - self.assertListEqual(btrfs.defragment("/dev/sda1"), ret) - - def test_defragment_error(self): - """ - Test if it gives device not mount error - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): - mock_run = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock_run}): - mock_file = mock_open(read_data="/dev/sda1 / ext4 rw,data=ordered 0 0") - with patch.object(salt.utils.files, "fopen", mock_file): - self.assertRaises( - CommandExecutionError, btrfs.defragment, "/dev/sda1" - ) - - # 'features' function tests: 1 - - def test_features(self): - """ - Test if it list currently available BTRFS features. - """ - with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - self.assertDictEqual(btrfs.features(), {}) - - # 'usage' function tests: 1 - - def test_usage(self): - """ - Test if it shows in which disk the chunks are allocated. - """ - with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock(return_value={"Salt": "salt"}) - with patch.object(btrfs, "_usage_specific", mock): - self.assertDictEqual(btrfs.usage("/dev/sda1"), {"Salt": "salt"}) - - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Unallocated:\n"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock(return_value={"/dev/sda1": True}) - with patch.object(btrfs, "_usage_unallocated", mock): - self.assertDictEqual( - btrfs.usage("/dev/sda1"), {"unallocated": {"/dev/sda1": True}} - ) - - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Overall:\n"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock(return_value={"/dev/sda1": True}) - with patch.object(btrfs, "_usage_overall", mock): - self.assertDictEqual( - btrfs.usage("/dev/sda1"), {"overall": {"/dev/sda1": True}} - ) - - # 'mkfs' function tests: 3 - - def test_mkfs(self): - """ - Test if it create a file system on the specified device. - """ - mock_cmd = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - mock_info = MagicMock(return_value=[]) - with patch.dict( - btrfs.__salt__, {"cmd.run_all": mock_cmd, "btrfs.info": mock_info} - ): - mock_file = mock_open(read_data="/dev/sda1 / ext4 rw,data=ordered 0 0") - with patch.object(salt.utils.files, "fopen", mock_file): - self.assertDictEqual(btrfs.mkfs("/dev/sda1"), {"log": "Salt"}) - - def test_mkfs_error(self): - """ - Test if it No devices specified error - """ - self.assertRaises(CommandExecutionError, btrfs.mkfs) - - def test_mkfs_mount_error(self): - """ - Test if it device mount error - """ - mock = MagicMock(return_value={"/dev/sda1": True}) - with patch.object(salt.utils.fsutils, "_get_mounts", mock): - self.assertRaises(CommandExecutionError, btrfs.mkfs, "/dev/sda1") - - # 'resize' function tests: 4 - - def test_resize(self): - """ - Test if it resize filesystem. - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - mock_info = MagicMock(return_value=[]) - with patch.dict( - btrfs.__salt__, {"cmd.run_all": mock, "btrfs.info": mock_info} - ): - mock = MagicMock(return_value={"/dev/sda1": True}) - with patch.object(salt.utils.fsutils, "_get_mounts", mock): - self.assertDictEqual( - btrfs.resize("/dev/sda1", "max"), {"log": "Salt"} - ) - - def test_resize_valid_error(self): - """ - Test if it gives device should be mounted error - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=False)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - self.assertRaises( - CommandExecutionError, btrfs.resize, "/dev/sda1", "max" - ) - - def test_resize_mount_error(self): - """ - Test if it gives mount point error - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): - mock = MagicMock(return_value={"/dev/sda1": False}) - with patch.object(salt.utils.fsutils, "_get_mounts", mock): - self.assertRaises( - CommandExecutionError, btrfs.resize, "/dev/sda1", "max" - ) - - def test_resize_size_error(self): - """ - Test if it gives unknown size error - """ - self.assertRaises(CommandExecutionError, btrfs.resize, "/dev/sda1", "250m") - - # 'convert' function tests: 5 - - def test_convert(self): - """ - Test if it convert ext2/3/4 to BTRFS - """ - with patch("os.path.exists", MagicMock(return_value=True)): - ret = { - "after": { - "balance_log": "Salt", - "ext4_image": "removed", - "ext4_image_info": "N/A", - "fsck_status": "N/A", - "mount_point": None, - "type": "ext4", - }, - "before": { - "fsck_status": "Filesystem errors corrected", - "mount_point": None, - "type": "ext4", - }, - } - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock(return_value={"/dev/sda3": {"type": "ext4"}}) - with patch.object(salt.utils.fsutils, "_blkid_output", mock): - mock = MagicMock( - return_value={"/dev/sda3": [{"mount_point": None}]} - ) - with patch.object(salt.utils.fsutils, "_get_mounts", mock): - self.assertDictEqual( - btrfs.convert("/dev/sda3", permanent=True), ret - ) - - def test_convert_device_error(self): - """ - Test if it gives device not found error - """ - mock = MagicMock(return_value={"retcode": 1, "stderr": "", "stdout": "Salt"}) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock(return_value={"/dev/sda1": False}) - with patch.object(salt.utils.fsutils, "_blkid_output", mock): - self.assertRaises(CommandExecutionError, btrfs.convert, "/dev/sda1") - - def test_convert_filesystem_error(self): - """ - Test if it gives file system error - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock(return_value={"/dev/sda1": {"type": "ext"}}) - with patch.object(salt.utils.fsutils, "_blkid_output", mock): - self.assertRaises(CommandExecutionError, btrfs.convert, "/dev/sda1") - - def test_convert_error(self): - """ - Test if it gives error cannot convert root - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - mock = MagicMock( - return_value={"/dev/sda1": {"type": "ext4", "mount_point": "/"}} - ) - with patch.object(salt.utils.fsutils, "_blkid_output", mock): - mock = MagicMock(return_value={"/dev/sda1": [{"mount_point": "/"}]}) - with patch.object(salt.utils.fsutils, "_get_mounts", mock): - self.assertRaises( - CommandExecutionError, btrfs.convert, "/dev/sda1" - ) - - def test_convert_migration_error(self): - """ - Test if it gives migration error - """ - with patch("salt.utils.fsutils._is_device", MagicMock(return_value=True)): - mock_run = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock_run}): - mock_blk = MagicMock(return_value={"/dev/sda1": {"type": "ext4"}}) - with patch.object(salt.utils.fsutils, "_blkid_output", mock_blk): - mock_file = mock_open( - read_data="/dev/sda1 / ext4 rw,data=ordered 0 0" - ) - with patch.object(salt.utils.files, "fopen", mock_file): - self.assertRaises( - CommandExecutionError, btrfs.convert, "/dev/sda1" - ) - - # 'add' function tests: 1 - - def test_add(self): - """ - Test if it add a devices to a BTRFS filesystem. - """ - with patch("salt.modules.btrfs._restripe", MagicMock(return_value={})): - self.assertDictEqual(btrfs.add("/mountpoint", "/dev/sda1", "/dev/sda2"), {}) - - # 'delete' function tests: 1 - - def test_delete(self): - """ - Test if it delete a devices to a BTRFS filesystem. - """ - with patch("salt.modules.btrfs._restripe", MagicMock(return_value={})): - self.assertDictEqual( - btrfs.delete("/mountpoint", "/dev/sda1", "/dev/sda2"), {} - ) - - # 'properties' function tests: 1 - - def test_properties(self): - """ - Test if list properties for given btrfs object - """ - with patch("salt.utils.fsutils._verify_run", MagicMock(return_value=True)): - mock = MagicMock( - return_value={"retcode": 1, "stderr": "", "stdout": "Salt"} - ) - with patch.dict(btrfs.__salt__, {"cmd.run_all": mock}): - self.assertDictEqual(btrfs.properties("/dev/sda1", "subvol"), {}) - - def test_properties_unknown_error(self): - """ - Test if it gives unknown property error - """ - self.assertRaises(CommandExecutionError, btrfs.properties, "/dev/sda1", "a") - - def test_properties_error(self): - """ - Test if it gives exception error - """ - self.assertRaises( - CommandExecutionError, btrfs.properties, "/dev/sda1", "subvol", True - ) - - def test_subvolume_exists(self): - """ - Test subvolume_exists - """ - salt_mock = { - "cmd.retcode": MagicMock(return_value=0), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_exists("/mnt/one") - - def test_subvolume_not_exists(self): - """ - Test subvolume_exists - """ - salt_mock = { - "cmd.retcode": MagicMock(return_value=1), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert not btrfs.subvolume_exists("/mnt/nowhere") - - def test_subvolume_create_fails_parameters(self): - """ - Test btrfs subvolume create - """ - # Fails when qgroupids is not a list - with pytest.raises(CommandExecutionError): - btrfs.subvolume_create("var", qgroupids="1") - - @patch("salt.modules.btrfs.subvolume_exists") - def test_subvolume_create_already_exists(self, subvolume_exists): - """ - Test btrfs subvolume create - """ - subvolume_exists.return_value = True - assert not btrfs.subvolume_create("var", dest="/mnt") - - @patch("salt.modules.btrfs.subvolume_exists") - def test_subvolume_create(self, subvolume_exists): - """ - Test btrfs subvolume create - """ - subvolume_exists.return_value = False - salt_mock = { - "cmd.run_all": MagicMock(return_value={"recode": 0}), - } - expected_path = os.path.join("/mnt", "var") - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_create("var", dest="/mnt") - subvolume_exists.assert_called_once() - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "create", expected_path] - ) - - def test_subvolume_delete_fails_parameters(self): - """ - Test btrfs subvolume delete - """ - # We need to provide name or names - with pytest.raises(CommandExecutionError): - btrfs.subvolume_delete() - - with pytest.raises(CommandExecutionError): - btrfs.subvolume_delete(names="var") - - def test_subvolume_delete_fails_parameter_commit(self): - """ - Test btrfs subvolume delete - """ - # Parameter commit can be 'after' or 'each' - with pytest.raises(CommandExecutionError): - btrfs.subvolume_delete(name="var", commit="maybe") - - @patch("salt.modules.btrfs.subvolume_exists") - def test_subvolume_delete_already_missing(self, subvolume_exists): - """ - Test btrfs subvolume delete - """ - subvolume_exists.return_value = False - assert not btrfs.subvolume_delete(name="var", names=["tmp"]) - - @patch("salt.modules.btrfs.subvolume_exists") - def test_subvolume_delete_already_missing_name(self, subvolume_exists): - """ - Test btrfs subvolume delete - """ - subvolume_exists.return_value = False - assert not btrfs.subvolume_delete(name="var") - - @patch("salt.modules.btrfs.subvolume_exists") - def test_subvolume_delete_already_missing_names(self, subvolume_exists): - """ - Test btrfs subvolume delete - """ - subvolume_exists.return_value = False - assert not btrfs.subvolume_delete(names=["tmp"]) - - @patch("salt.modules.btrfs.subvolume_exists") - def test_subvolume_delete(self, subvolume_exists): - """ - Test btrfs subvolume delete - """ - subvolume_exists.return_value = True - salt_mock = { - "cmd.run_all": MagicMock(return_value={"recode": 0}), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_delete("var", names=["tmp"]) - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "delete", "var", "tmp"] - ) - - def test_subvolume_find_new_empty(self): - """ - Test btrfs subvolume find-new - """ - salt_mock = { - "cmd.run_all": MagicMock( - return_value={"recode": 0, "stdout": "transid marker was 1024"} - ), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_find_new("var", "2000") == { - "files": [], - "transid": "1024", - } - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "find-new", "var", "2000"] - ) - - def test_subvolume_find_new(self): - """ - Test btrfs subvolume find-new - """ - salt_mock = { - "cmd.run_all": MagicMock( - return_value={ - "recode": 0, - "stdout": """inode 185148 ... gen 2108 flags NONE var/log/audit/audit.log -inode 187390 ... INLINE etc/openvpn/openvpn-status.log -transid marker was 1024""", - } - ), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_find_new("var", "1023") == { - "files": ["var/log/audit/audit.log", "etc/openvpn/openvpn-status.log"], - "transid": "1024", - } - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "find-new", "var", "1023"] - ) - - def test_subvolume_get_default_free(self): - """ - Test btrfs subvolume get-default - """ - salt_mock = { - "cmd.run_all": MagicMock( - return_value={"recode": 0, "stdout": "ID 5 (FS_TREE)"} - ), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_get_default("/mnt") == { - "id": "5", - "name": "(FS_TREE)", - } - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "get-default", "/mnt"] - ) - - def test_subvolume_get_default(self): - """ - Test btrfs subvolume get-default - """ - salt_mock = { - "cmd.run_all": MagicMock( - return_value={ - "recode": 0, - "stdout": "ID 257 gen 8 top level 5 path var", - } - ), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_get_default("/mnt") == { - "id": "257", - "name": "var", - } - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "get-default", "/mnt"] - ) - - def test_subvolume_list_fails_parameters(self): - """ - Test btrfs subvolume list - """ - # Fails when sort is not a list - with pytest.raises(CommandExecutionError): - btrfs.subvolume_list("/mnt", sort="-rootid") - - # Fails when sort is not recognized - with pytest.raises(CommandExecutionError): - btrfs.subvolume_list("/mnt", sort=["-root"]) - - def test_subvolume_list_simple(self): - """ - Test btrfs subvolume list - """ - salt_mock = { - "cmd.run_all": MagicMock( - return_value={ - "recode": 0, - "stdout": """ID 257 gen 8 top level 5 path one -ID 258 gen 10 top level 5 path another one -""", - } - ), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_list("/mnt") == [ - {"id": "257", "gen": "8", "top level": "5", "path": "one"}, - {"id": "258", "gen": "10", "top level": "5", "path": "another one"}, - ] - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "list", "/mnt"] - ) - - def test_subvolume_list(self): - """ - Test btrfs subvolume list - """ - salt_mock = { - "cmd.run_all": MagicMock( - return_value={ - "recode": 0, - "stdout": """\ -ID 257 gen 8 cgen 8 parent 5 top level 5 parent_uuid - received_uuid - \ - uuid 777...-..05 path one -ID 258 gen 10 cgen 10 parent 5 top level 5 parent_uuid - received_uuid - \ - uuid a90...-..01 path another one -""", - } - ), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_list( - "/mnt", - parent_id=True, - absolute=True, - ogeneration=True, - generation=True, - subvolumes=True, - uuid=True, - parent_uuid=True, - sent_subvolume_uuid=True, - generation_cmp="-100", - ogeneration_cmp="+5", - sort=["-rootid", "gen"], - ) == [ - { - "id": "257", - "gen": "8", - "cgen": "8", - "parent": "5", - "top level": "5", - "parent_uuid": "-", - "received_uuid": "-", - "uuid": "777...-..05", - "path": "one", - }, - { - "id": "258", - "gen": "10", - "cgen": "10", - "parent": "5", - "top level": "5", - "parent_uuid": "-", - "received_uuid": "-", - "uuid": "a90...-..01", - "path": "another one", - }, - ] - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - [ - "btrfs", - "subvolume", - "list", - "-p", - "-a", - "-c", - "-g", - "-o", - "-u", - "-q", - "-R", - "-G", - "-100", - "-C", - "+5", - "--sort=-rootid,gen", - "/mnt", - ] - ) - - def test_subvolume_set_default(self): - """ - Test btrfs subvolume set-default - """ - salt_mock = { - "cmd.run_all": MagicMock(return_value={"recode": 0}), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_set_default("257", "/mnt") - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "set-default", "257", "/mnt"] - ) - - def test_subvolume_show(self): - """ - Test btrfs subvolume show - """ - salt_mock = { - "cmd.run_all": MagicMock( - return_value={ - "recode": 0, - "stdout": """@/var - Name: var - UUID: 7a14...-...04 - Parent UUID: - - Received UUID: - - Creation time: 2018-10-01 14:33:12 +0200 - Subvolume ID: 258 - Generation: 82479 - Gen at creation: 10 - Parent ID: 256 - Top level ID: 256 - Flags: - - Snapshot(s): -""", - } - ), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_show("/var") == { - "@/var": { - "name": "var", - "uuid": "7a14...-...04", - "parent uuid": "-", - "received uuid": "-", - "creation time": "2018-10-01 14:33:12 +0200", - "subvolume id": "258", - "generation": "82479", - "gen at creation": "10", - "parent id": "256", - "top level id": "256", - "flags": "-", - "snapshot(s)": "", - }, - } - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "show", "/var"] - ) - - def test_subvolume_sync_fail_parameters(self): - """ - Test btrfs subvolume sync - """ - # Fails when subvolids is not a list - with pytest.raises(CommandExecutionError): - btrfs.subvolume_sync("/mnt", subvolids="257") - - def test_subvolume_sync(self): - """ - Test btrfs subvolume sync - """ - salt_mock = { - "cmd.run_all": MagicMock(return_value={"recode": 0}), - } - with patch.dict(btrfs.__salt__, salt_mock): - assert btrfs.subvolume_sync("/mnt", subvolids=["257"], sleep="1") - salt_mock["cmd.run_all"].assert_called_once() - salt_mock["cmd.run_all"].assert_called_with( - ["btrfs", "subvolume", "sync", "-s", "1", "/mnt", "257"] - )