mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00

Some checks failed
CI / Prepare Workflow Run (push) Has been cancelled
CI / Pre-Commit (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / NSIS Tests (push) Has been cancelled
CI / Prepare Release: (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / Build Source Tarball (push) Has been cancelled
CI / Build Salt Onedir (push) Has been cancelled
CI / Build Packages (push) Has been cancelled
CI / CI Deps (push) Has been cancelled
CI / Test Package (push) Has been cancelled
CI / Test Salt (push) Has been cancelled
CI / Combine Code Coverage (push) Has been cancelled
CI / Set the Pipeline Exit Status (push) Has been cancelled
Fixes: #66980
311 lines
9 KiB
Python
311 lines
9 KiB
Python
import logging
|
|
import os
|
|
import shutil
|
|
|
|
import pytest
|
|
|
|
import salt.config
|
|
import salt.loader
|
|
import salt.modules.cmdmod as cmdmod
|
|
import salt.modules.config as configmod
|
|
import salt.modules.file as filemod
|
|
import salt.utils.data
|
|
import salt.utils.files
|
|
import salt.utils.platform
|
|
import salt.utils.stringutils
|
|
from tests.support.mock import MagicMock, call, patch
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
@pytest.fixture
|
|
def configure_loader_modules():
|
|
return {
|
|
filemod: {
|
|
"__salt__": {
|
|
"config.manage_mode": configmod.manage_mode,
|
|
"cmd.run": cmdmod.run,
|
|
"cmd.run_all": cmdmod.run_all,
|
|
},
|
|
"__opts__": {
|
|
"test": False,
|
|
"file_roots": {"base": "tmp"},
|
|
"pillar_roots": {"base": "tmp"},
|
|
"cachedir": "tmp",
|
|
"grains": {},
|
|
},
|
|
"__grains__": {"kernel": "Linux"},
|
|
}
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_sub_dir(tmp_path):
|
|
directory = tmp_path / "file-basics-test-dir"
|
|
directory.mkdir()
|
|
|
|
yield directory
|
|
|
|
shutil.rmtree(str(directory))
|
|
|
|
|
|
@pytest.fixture
|
|
def tfile(tmp_sub_dir):
|
|
filename = str(tmp_sub_dir / "file-basics-test-file")
|
|
|
|
with salt.utils.files.fopen(filename, "w+") as fp:
|
|
fp.write("Hi hello! I am a file.")
|
|
|
|
yield filename
|
|
|
|
os.remove(filename)
|
|
|
|
|
|
@pytest.fixture
|
|
def myfile(tmp_sub_dir):
|
|
filename = str(tmp_sub_dir / "myfile")
|
|
|
|
with salt.utils.files.fopen(filename, "w+") as fp:
|
|
fp.write(salt.utils.stringutils.to_str("Hello\n"))
|
|
|
|
yield filename
|
|
|
|
os.remove(filename)
|
|
|
|
|
|
@pytest.fixture
|
|
def a_link(tmp_sub_dir):
|
|
path = tmp_sub_dir / "a_link"
|
|
linkname = str(path)
|
|
|
|
yield linkname
|
|
|
|
if path.exists():
|
|
os.remove(linkname)
|
|
|
|
|
|
@pytest.fixture
|
|
def a_hardlink(tmp_sub_dir):
|
|
path = tmp_sub_dir / "a_hardlink"
|
|
linkname = str(path)
|
|
|
|
yield linkname
|
|
|
|
if path.exists():
|
|
os.remove(linkname)
|
|
|
|
|
|
@pytest.mark.skip_on_windows(reason="os.symlink is not available on Windows")
|
|
def test_symlink_already_in_desired_state(tfile, a_link):
|
|
os.symlink(tfile, a_link)
|
|
result = filemod.symlink(tfile, a_link)
|
|
assert result
|
|
|
|
|
|
@pytest.mark.skip_on_windows(reason="os.link is not available on Windows")
|
|
def test_hardlink_sanity(tfile, a_hardlink):
|
|
target = a_hardlink
|
|
result = filemod.link(tfile, target)
|
|
assert result
|
|
|
|
|
|
@pytest.mark.skip_on_windows(reason="os.link is not available on Windows")
|
|
def test_hardlink_numlinks(tfile, a_hardlink):
|
|
target = a_hardlink
|
|
result = filemod.link(tfile, target)
|
|
name_i = os.stat(tfile).st_nlink
|
|
assert name_i > 1
|
|
|
|
|
|
@pytest.mark.skip_on_windows(reason="os.link is not available on Windows")
|
|
def test_hardlink_working(tfile, a_hardlink):
|
|
target = a_hardlink
|
|
result = filemod.link(tfile, target)
|
|
name_i = os.stat(tfile).st_ino
|
|
target_i = os.stat(target).st_ino
|
|
assert name_i == target_i
|
|
|
|
|
|
def test_source_list_for_list_returns_file_from_dict_via_http():
|
|
with patch("salt.modules.file.os.remove") as remove:
|
|
remove.return_value = None
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=[]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
"cp.cache_file": MagicMock(return_value="/tmp/http.conf"),
|
|
},
|
|
):
|
|
with patch("salt.utils.http.query") as http_query:
|
|
http_query.return_value = {}
|
|
ret = filemod.source_list(
|
|
[{"http://t.est.com/http/httpd.conf": "filehash"}], "", "base"
|
|
)
|
|
assert list(ret) == ["http://t.est.com/http/httpd.conf", "filehash"]
|
|
|
|
|
|
def test_source_list_use_requests():
|
|
with patch("salt.modules.file.os.remove") as remove:
|
|
remove.return_value = None
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=[]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
"cp.cache_file": MagicMock(return_value="/tmp/http.conf"),
|
|
},
|
|
):
|
|
expected_call = call(
|
|
"http://t.est.com/http/file1",
|
|
decode_body=False,
|
|
method="HEAD",
|
|
)
|
|
with patch(
|
|
"salt.utils.http.query", MagicMock(return_value={})
|
|
) as http_query:
|
|
ret = filemod.source_list(
|
|
[{"http://t.est.com/http/file1": "filehash"}], "", "base"
|
|
)
|
|
assert list(ret) == ["http://t.est.com/http/file1", "filehash"]
|
|
assert expected_call in http_query.mock_calls
|
|
|
|
|
|
def test_source_list_for_list_returns_existing_file():
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=["http/httpd.conf.fallback"]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
},
|
|
):
|
|
ret = filemod.source_list(
|
|
["salt://http/httpd.conf", "salt://http/httpd.conf.fallback"],
|
|
"filehash",
|
|
"base",
|
|
)
|
|
assert list(ret) == ["salt://http/httpd.conf.fallback", "filehash"]
|
|
|
|
|
|
def test_source_list_for_list_returns_file_from_other_env():
|
|
def list_master(env):
|
|
dct = {"base": [], "dev": ["http/httpd.conf"]}
|
|
return dct[env]
|
|
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(side_effect=list_master),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
},
|
|
):
|
|
ret = filemod.source_list(
|
|
[
|
|
"salt://http/httpd.conf?saltenv=dev",
|
|
"salt://http/httpd.conf.fallback",
|
|
],
|
|
"filehash",
|
|
"base",
|
|
)
|
|
assert list(ret) == ["salt://http/httpd.conf?saltenv=dev", "filehash"]
|
|
|
|
|
|
def test_source_list_for_list_returns_file_from_dict():
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=["http/httpd.conf"]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
},
|
|
):
|
|
ret = filemod.source_list([{"salt://http/httpd.conf": ""}], "filehash", "base")
|
|
assert list(ret) == ["salt://http/httpd.conf", "filehash"]
|
|
|
|
|
|
def test_source_list_for_list_returns_existing_local_file_slash(myfile):
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=[]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
},
|
|
):
|
|
ret = filemod.source_list([myfile + "-foo", myfile], "filehash", "base")
|
|
assert list(ret) == [myfile, "filehash"]
|
|
|
|
|
|
def test_source_list_for_list_returns_existing_local_file_proto(myfile):
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=[]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
},
|
|
):
|
|
ret = filemod.source_list(
|
|
["file://" + myfile + "-foo", "file://" + myfile],
|
|
"filehash",
|
|
"base",
|
|
)
|
|
assert list(ret) == ["file://" + myfile, "filehash"]
|
|
|
|
|
|
def test_source_list_for_list_returns_local_file_slash_from_dict(myfile):
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=[]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
},
|
|
):
|
|
ret = filemod.source_list([{myfile: ""}], "filehash", "base")
|
|
assert list(ret) == [myfile, "filehash"]
|
|
|
|
|
|
def test_source_list_for_list_returns_local_file_proto_from_dict(myfile):
|
|
with patch.dict(
|
|
filemod.__salt__,
|
|
{
|
|
"cp.list_master": MagicMock(return_value=[]),
|
|
"cp.list_master_dirs": MagicMock(return_value=[]),
|
|
},
|
|
):
|
|
ret = filemod.source_list([{"file://" + myfile: ""}], "filehash", "base")
|
|
assert list(ret) == ["file://" + myfile, "filehash"]
|
|
|
|
|
|
def test_symlink_lexists_called_follow_symlinks_false():
|
|
tfile = "/tmp/file-basics-test-file"
|
|
a_link = "/tmp/a_link"
|
|
|
|
exists = MagicMock(return_value=False)
|
|
lexists = MagicMock(return_value=False)
|
|
|
|
with patch("os.path.exists", exists), patch("os.path.lexists", lexists), patch(
|
|
"os.symlink", MagicMock(return_value=True)
|
|
):
|
|
filemod.symlink(tfile, a_link)
|
|
lexists.assert_not_called()
|
|
exists.assert_called()
|
|
|
|
lexists.reset_mock()
|
|
exists.reset_mock()
|
|
|
|
filemod.symlink(tfile, a_link, follow_symlinks=False)
|
|
lexists.assert_called()
|
|
exists.assert_not_called()
|
|
|
|
|
|
def test_symlink_lexists_called_follow_symlinks_true():
|
|
tfile = "/tmp/file-basics-test-file"
|
|
a_link = "/tmp/a_link"
|
|
|
|
exists = MagicMock(return_value=False)
|
|
lexists = MagicMock(return_value=False)
|
|
|
|
with patch("os.path.exists", exists), patch("os.path.lexists", lexists), patch(
|
|
"os.symlink", MagicMock(return_value=True)
|
|
):
|
|
filemod.symlink(tfile, a_link, follow_symlinks=True)
|
|
lexists.assert_not_called()
|
|
exists.assert_called()
|