mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
348 lines
12 KiB
Python
348 lines
12 KiB
Python
"""
|
|
:codeauthor: Gareth J. Greenaway <ggreenaway@vmware.com>
|
|
"""
|
|
|
|
|
|
import os
|
|
import textwrap
|
|
|
|
import pytest
|
|
|
|
import salt.modules.pkg_resource as pkg_resource
|
|
import salt.modules.zypperpkg as zypper
|
|
from salt.exceptions import CommandExecutionError
|
|
from tests.support.mock import MagicMock, patch
|
|
|
|
|
|
@pytest.fixture
|
|
def configure_loader_modules():
|
|
return {
|
|
zypper: {
|
|
"rpm": None,
|
|
"_systemd_scope": MagicMock(return_value=False),
|
|
"osrelease_info": [15, 3],
|
|
"__salt__": {"pkg_resource.parse_targets": pkg_resource.parse_targets},
|
|
},
|
|
pkg_resource: {"__grains__": {"os": "SUSE"}},
|
|
}
|
|
|
|
|
|
def test_list_pkgs_no_context():
|
|
"""
|
|
Test packages listing.
|
|
|
|
:return:
|
|
"""
|
|
|
|
def _add_data(data, key, value):
|
|
data.setdefault(key, []).append(value)
|
|
|
|
rpm_out = [
|
|
"protobuf-java_|-(none)_|-2.6.1_|-3.1.develHead_|-noarch_|-(none)_|-1499257756",
|
|
"yast2-ftp-server_|-(none)_|-3.1.8_|-8.1_|-x86_64_|-(none)_|-1499257798",
|
|
"jose4j_|-(none)_|-0.4.4_|-2.1.develHead_|-noarch_|-(none)_|-1499257756",
|
|
"apache-commons-cli_|-(none)_|-1.2_|-1.233_|-noarch_|-(none)_|-1498636510",
|
|
"jakarta-commons-discovery_|-(none)_|-0.4_|-129.686_|-noarch_|-(none)_|-1498636511",
|
|
"susemanager-build-keys-web_|-(none)_|-12.0_|-5.1.develHead_|-noarch_|-(none)_|-1498636510",
|
|
"gpg-pubkey_|-(none)_|-39db7c82_|-5847eb1f_|-(none)_|-(none)_|-1519203802",
|
|
"gpg-pubkey_|-(none)_|-8a7c64f9_|-5aaa93ca_|-(none)_|-(none)_|-1529925595",
|
|
"kernel-default_|-(none)_|-4.4.138_|-94.39.1_|-x86_64_|-(none)_|-1529936067",
|
|
"kernel-default_|-(none)_|-4.4.73_|-5.1_|-x86_64_|-(none)_|-1503572639",
|
|
"perseus-dummy_|-(none)_|-1.1_|-1.1_|-i586_|-(none)_|-1529936062",
|
|
]
|
|
with patch.dict(zypper.__grains__, {"osarch": "x86_64"}), patch.dict(
|
|
zypper.__salt__,
|
|
{"cmd.run": MagicMock(return_value=os.linesep.join(rpm_out))},
|
|
), patch.dict(zypper.__salt__, {"pkg_resource.add_pkg": _add_data}), patch.dict(
|
|
zypper.__salt__,
|
|
{"pkg_resource.format_pkg_list": pkg_resource.format_pkg_list},
|
|
), patch.dict(
|
|
zypper.__salt__, {"pkg_resource.stringify": MagicMock()}
|
|
), patch.object(
|
|
zypper, "_list_pkgs_from_context"
|
|
) as list_pkgs_context_mock:
|
|
pkgs = zypper.list_pkgs(versions_as_list=True, use_context=False)
|
|
list_pkgs_context_mock.assert_not_called()
|
|
list_pkgs_context_mock.reset_mock()
|
|
|
|
pkgs = zypper.list_pkgs(versions_as_list=True, use_context=False)
|
|
list_pkgs_context_mock.assert_not_called()
|
|
list_pkgs_context_mock.reset_mock()
|
|
|
|
|
|
def test_normalize_name():
|
|
"""
|
|
Test that package is normalized only when it should be
|
|
"""
|
|
with patch.dict(zypper.__grains__, {"osarch": "x86_64"}):
|
|
result = zypper.normalize_name("foo")
|
|
assert result == "foo", result
|
|
result = zypper.normalize_name("foo.x86_64")
|
|
assert result == "foo", result
|
|
result = zypper.normalize_name("foo.noarch")
|
|
assert result == "foo", result
|
|
|
|
with patch.dict(zypper.__grains__, {"osarch": "aarch64"}):
|
|
result = zypper.normalize_name("foo")
|
|
assert result == "foo", result
|
|
result = zypper.normalize_name("foo.aarch64")
|
|
assert result == "foo", result
|
|
result = zypper.normalize_name("foo.noarch")
|
|
assert result == "foo", result
|
|
|
|
|
|
def test_pkg_hold():
|
|
"""
|
|
Tests holding packages with Zypper
|
|
"""
|
|
|
|
# Test openSUSE 15.3
|
|
list_locks_mock = {
|
|
"bar": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
|
|
"minimal_base": {
|
|
"type": "pattern",
|
|
"match_type": "glob",
|
|
"case_sensitive": "on",
|
|
},
|
|
"baz": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
|
|
}
|
|
|
|
cmd = MagicMock(
|
|
return_value={
|
|
"pid": 1234,
|
|
"retcode": 0,
|
|
"stdout": "Specified lock has been successfully added.",
|
|
"stderr": "",
|
|
}
|
|
)
|
|
with patch.object(
|
|
zypper, "list_locks", MagicMock(return_value=list_locks_mock)
|
|
), patch.dict(zypper.__salt__, {"cmd.run_all": cmd}):
|
|
ret = zypper.hold("foo")
|
|
assert ret["foo"]["changes"]["old"] == ""
|
|
assert ret["foo"]["changes"]["new"] == "hold"
|
|
assert ret["foo"]["comment"] == "Package foo is now being held."
|
|
cmd.assert_called_once_with(
|
|
["zypper", "--non-interactive", "--no-refresh", "al", "foo"],
|
|
env={},
|
|
output_loglevel="trace",
|
|
python_shell=False,
|
|
)
|
|
cmd.reset_mock()
|
|
ret = zypper.hold(pkgs=["foo", "bar"])
|
|
assert ret["foo"]["changes"]["old"] == ""
|
|
assert ret["foo"]["changes"]["new"] == "hold"
|
|
assert ret["foo"]["comment"] == "Package foo is now being held."
|
|
assert ret["bar"]["changes"] == {}
|
|
assert ret["bar"]["comment"] == "Package bar is already set to be held."
|
|
cmd.assert_called_once_with(
|
|
["zypper", "--non-interactive", "--no-refresh", "al", "foo"],
|
|
env={},
|
|
output_loglevel="trace",
|
|
python_shell=False,
|
|
)
|
|
|
|
|
|
def test_pkg_unhold():
|
|
"""
|
|
Tests unholding packages with Zypper
|
|
"""
|
|
|
|
# Test openSUSE 15.3
|
|
list_locks_mock = {
|
|
"bar": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
|
|
"minimal_base": {
|
|
"type": "pattern",
|
|
"match_type": "glob",
|
|
"case_sensitive": "on",
|
|
},
|
|
"baz": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
|
|
}
|
|
|
|
cmd = MagicMock(
|
|
return_value={
|
|
"pid": 1234,
|
|
"retcode": 0,
|
|
"stdout": "1 lock has been successfully removed.",
|
|
"stderr": "",
|
|
}
|
|
)
|
|
with patch.object(
|
|
zypper, "list_locks", MagicMock(return_value=list_locks_mock)
|
|
), patch.dict(zypper.__salt__, {"cmd.run_all": cmd}):
|
|
ret = zypper.unhold("foo")
|
|
assert ret["foo"]["comment"] == "Package foo was already unheld."
|
|
cmd.assert_not_called()
|
|
cmd.reset_mock()
|
|
ret = zypper.unhold(pkgs=["foo", "bar"])
|
|
assert ret["foo"]["changes"] == {}
|
|
assert ret["foo"]["comment"] == "Package foo was already unheld."
|
|
assert ret["bar"]["changes"]["old"] == "hold"
|
|
assert ret["bar"]["changes"]["new"] == ""
|
|
assert ret["bar"]["comment"] == "Package bar is no longer held."
|
|
cmd.assert_called_once_with(
|
|
["zypper", "--non-interactive", "--no-refresh", "rl", "bar"],
|
|
env={},
|
|
output_loglevel="trace",
|
|
python_shell=False,
|
|
)
|
|
|
|
|
|
def test_pkg_list_holds():
|
|
"""
|
|
Tests listing of calculated held packages with Zypper
|
|
"""
|
|
|
|
# Test openSUSE 15.3
|
|
list_locks_mock = {
|
|
"bar": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
|
|
"minimal_base": {
|
|
"type": "pattern",
|
|
"match_type": "glob",
|
|
"case_sensitive": "on",
|
|
},
|
|
"baz": {"type": "package", "match_type": "glob", "case_sensitive": "on"},
|
|
}
|
|
installed_pkgs = {
|
|
"foo": [{"edition": "1.2.3-1.1"}],
|
|
"bar": [{"edition": "2.3.4-2.1", "epoch": "2"}],
|
|
}
|
|
|
|
def zypper_search_mock(name, *_args, **_kwargs):
|
|
if name in installed_pkgs:
|
|
return {name: installed_pkgs.get(name)}
|
|
|
|
with patch.object(
|
|
zypper, "list_locks", MagicMock(return_value=list_locks_mock)
|
|
), patch.object(
|
|
zypper, "search", MagicMock(side_effect=zypper_search_mock)
|
|
), patch.object(
|
|
zypper, "info_installed", MagicMock(side_effect=zypper_search_mock)
|
|
):
|
|
ret = zypper.list_holds()
|
|
assert len(ret) == 1
|
|
assert "bar-2:2.3.4-2.1.*" in ret
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"package,pre_version,post_version,fromrepo_param,name_param,pkgs_param",
|
|
[
|
|
("vim", "1.1", "1.2", [], "", []),
|
|
("kernel-default", "1.1", "1.1,1.2", ["dummy", "dummy2"], "", []),
|
|
("vim", "1.1", "1.2", [], "vim", []),
|
|
],
|
|
)
|
|
@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
|
|
def test_upgrade(
|
|
package, pre_version, post_version, fromrepo_param, name_param, pkgs_param
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call"
|
|
) as zypper_mock, patch.object(
|
|
zypper,
|
|
"list_pkgs",
|
|
MagicMock(side_effect=[{package: pre_version}, {package: post_version}]),
|
|
):
|
|
expected_call = ["update", "--auto-agree-with-licenses"]
|
|
for repo in fromrepo_param:
|
|
expected_call.extend(["--repo", repo])
|
|
|
|
if pkgs_param:
|
|
expected_call.extend(pkgs_param)
|
|
elif name_param:
|
|
expected_call.append(name_param)
|
|
|
|
result = zypper.upgrade(
|
|
name=name_param, pkgs=pkgs_param, fromrepo=fromrepo_param
|
|
)
|
|
zypper_mock.assert_any_call(*expected_call)
|
|
assert result == {package: {"old": pre_version, "new": post_version}}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"package,pre_version,post_version,fromrepo_param",
|
|
[
|
|
("vim", "1.1", "1.2", []),
|
|
("emacs", "1.1", "1.2", ["Dummy", "Dummy2"]),
|
|
],
|
|
)
|
|
@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
|
|
def test_dist_upgrade(package, pre_version, post_version, fromrepo_param):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call"
|
|
) as zypper_mock, patch.object(
|
|
zypper,
|
|
"list_pkgs",
|
|
MagicMock(side_effect=[{package: pre_version}, {package: post_version}]),
|
|
):
|
|
expected_call = ["dist-upgrade", "--auto-agree-with-licenses"]
|
|
|
|
for repo in fromrepo_param:
|
|
expected_call.extend(["--from", repo])
|
|
|
|
result = zypper.upgrade(dist_upgrade=True, fromrepo=fromrepo_param)
|
|
zypper_mock.assert_any_call(*expected_call)
|
|
assert result == {package: {"old": pre_version, "new": post_version}}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"package,pre_version,post_version,fromrepo_param",
|
|
[
|
|
("vim", "1.1", "1.1", []),
|
|
("emacs", "1.1", "1.1", ["Dummy", "Dummy2"]),
|
|
],
|
|
)
|
|
@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
|
|
def test_dist_upgrade_dry_run(package, pre_version, post_version, fromrepo_param):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call"
|
|
) as zypper_mock, patch.object(
|
|
zypper,
|
|
"list_pkgs",
|
|
MagicMock(side_effect=[{package: pre_version}, {package: post_version}]),
|
|
):
|
|
expected_call = ["dist-upgrade", "--auto-agree-with-licenses", "--dry-run"]
|
|
|
|
for repo in fromrepo_param:
|
|
expected_call.extend(["--from", repo])
|
|
|
|
zypper.upgrade(dist_upgrade=True, dryrun=True, fromrepo=fromrepo_param)
|
|
zypper_mock.assert_any_call(*expected_call)
|
|
# dryrun=True causes two calls, one with a trailing --debug-solver flag
|
|
expected_call.append("--debug-solver")
|
|
zypper_mock.assert_any_call(*expected_call)
|
|
|
|
|
|
@patch.object(zypper, "refresh_db", MagicMock(return_value=True))
|
|
def test_dist_upgrade_failure():
|
|
zypper_output = textwrap.dedent(
|
|
"""\
|
|
Loading repository data...
|
|
Reading installed packages...
|
|
Computing distribution upgrade...
|
|
Use 'zypper repos' to get the list of defined repositories.
|
|
Repository 'DUMMY' not found by its alias, number, or URI.
|
|
"""
|
|
)
|
|
call_spy = MagicMock()
|
|
zypper_mock = MagicMock()
|
|
zypper_mock.stdout = zypper_output
|
|
zypper_mock.stderr = ""
|
|
zypper_mock.exit_code = 3
|
|
zypper_mock.noraise.call = call_spy
|
|
with patch("salt.modules.zypperpkg.__zypper__", zypper_mock), patch.object(
|
|
zypper, "list_pkgs", MagicMock(side_effect=[{"vim": 1.1}, {"vim": 1.1}])
|
|
):
|
|
expected_call = [
|
|
"dist-upgrade",
|
|
"--auto-agree-with-licenses",
|
|
"--from",
|
|
"Dummy",
|
|
]
|
|
|
|
with pytest.raises(CommandExecutionError) as exc:
|
|
zypper.upgrade(dist_upgrade=True, fromrepo=["Dummy"])
|
|
call_spy.assert_called_with(*expected_call)
|
|
|
|
assert exc.exception.info["changes"] == {}
|
|
assert exc.exception.info["result"]["stdout"] == zypper_output
|