1import logging
2import os
3import shutil
4
5import pytest
6import salt.serializers.json as jsonserializer
7import salt.serializers.msgpack as msgpackserializer
8import salt.serializers.plist as plistserializer
9import salt.serializers.python as pythonserializer
10import salt.serializers.yaml as yamlserializer
11import salt.states.file as filestate
12from tests.support.mock import MagicMock, patch
13
14log = logging.getLogger(__name__)
15
16
17@pytest.fixture
18def configure_loader_modules():
19    return {
20        filestate: {
21            "__env__": "base",
22            "__salt__": {"file.manage_file": False},
23            "__serializers__": {
24                "yaml.serialize": yamlserializer.serialize,
25                "yaml.seserialize": yamlserializer.serialize,
26                "python.serialize": pythonserializer.serialize,
27                "json.serialize": jsonserializer.serialize,
28                "plist.serialize": plistserializer.serialize,
29                "msgpack.serialize": msgpackserializer.serialize,
30            },
31            "__opts__": {"test": False, "cachedir": ""},
32            "__instance_id__": "",
33            "__low__": {},
34            "__utils__": {},
35        }
36    }
37
38
39# 'rename' function tests: 1
40def test_rename(tmp_path):
41    """
42    Test if the source file exists on the system,
43    rename it to the named file.
44    """
45    name = str(tmp_path / "salt")
46    source = str(tmp_path / "salt" / "salt")
47
48    ret = {"name": name, "result": False, "comment": "", "changes": {}}
49
50    comt = "Must provide name to file.rename"
51    ret.update({"comment": comt, "name": ""})
52    assert filestate.rename("", source) == ret
53
54    mock_t = MagicMock(return_value=True)
55    mock_f = MagicMock(return_value=False)
56
57    mock_lex = MagicMock(side_effect=[False, True, True])
58    with patch.object(os.path, "isabs", mock_f):
59        comt = "Specified file {} is not an absolute path".format(name)
60        ret.update({"comment": comt, "name": name})
61        assert filestate.rename(name, source) == ret
62
63    mock_lex = MagicMock(return_value=False)
64    with patch.object(os.path, "isabs", mock_t):
65        with patch.object(os.path, "lexists", mock_lex):
66            comt = 'Source file "{}" has already been moved out of place'.format(source)
67            ret.update({"comment": comt, "result": True})
68            assert filestate.rename(name, source) == ret
69
70    mock_lex = MagicMock(side_effect=[True, True, True])
71    with patch.object(os.path, "isabs", mock_t):
72        with patch.object(os.path, "lexists", mock_lex):
73            comt = 'The target file "{}" exists and will not be overwritten'.format(
74                name
75            )
76            ret.update({"comment": comt, "result": True})
77            assert filestate.rename(name, source) == ret
78
79    mock_lex = MagicMock(side_effect=[True, True, True])
80    mock_rem = MagicMock(side_effect=IOError)
81    with patch.object(os.path, "isabs", mock_t):
82        with patch.object(os.path, "lexists", mock_lex):
83            with patch.dict(filestate.__opts__, {"test": False}):
84                comt = 'Failed to delete "{}" in preparation for forced move'.format(
85                    name
86                )
87                with patch.dict(filestate.__salt__, {"file.remove": mock_rem}):
88                    ret.update({"name": name, "comment": comt, "result": False})
89                    assert filestate.rename(name, source, force=True) == ret
90
91    mock_lex = MagicMock(side_effect=[True, False, False])
92    with patch.object(os.path, "isabs", mock_t):
93        with patch.object(os.path, "lexists", mock_lex):
94            with patch.dict(filestate.__opts__, {"test": True}):
95                comt = 'File "{}" is set to be moved to "{}"'.format(source, name)
96                ret.update({"name": name, "comment": comt, "result": None})
97                assert filestate.rename(name, source) == ret
98
99    mock_lex = MagicMock(side_effect=[True, False, False])
100    with patch.object(os.path, "isabs", mock_t):
101        with patch.object(os.path, "lexists", mock_lex):
102            with patch.object(os.path, "isdir", mock_f):
103                with patch.dict(filestate.__opts__, {"test": False}):
104                    comt = "The target directory {} is not present".format(tmp_path)
105                    ret.update({"name": name, "comment": comt, "result": False})
106                    assert filestate.rename(name, source) == ret
107
108    mock_lex = MagicMock(side_effect=[True, False, False])
109    with patch.object(os.path, "isabs", mock_t):
110        with patch.object(os.path, "lexists", mock_lex):
111            with patch.object(os.path, "isdir", mock_t):
112                with patch.object(os.path, "islink", mock_f):
113                    with patch.dict(filestate.__opts__, {"test": False}):
114                        with patch.object(
115                            shutil, "move", MagicMock(side_effect=IOError)
116                        ):
117                            comt = 'Failed to move "{}" to "{}"'.format(source, name)
118                            ret.update({"name": name, "comment": comt, "result": False})
119                            assert filestate.rename(name, source) == ret
120
121    mock_lex = MagicMock(side_effect=[True, False, False])
122    with patch.object(os.path, "isabs", mock_t):
123        with patch.object(os.path, "lexists", mock_lex):
124            with patch.object(os.path, "isdir", mock_t):
125                with patch.object(os.path, "islink", mock_f):
126                    with patch.dict(filestate.__opts__, {"test": False}):
127                        with patch.object(shutil, "move", MagicMock()):
128                            comt = 'Moved "{}" to "{}"'.format(source, name)
129                            ret.update(
130                                {
131                                    "name": name,
132                                    "comment": comt,
133                                    "result": True,
134                                    "changes": {name: source},
135                                }
136                            )
137                            assert filestate.rename(name, source) == ret
138