mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
1962 lines
77 KiB
Python
1962 lines
77 KiB
Python
"""
|
|
:codeauthor: Bo Maryniuk <bo@suse.de>
|
|
"""
|
|
|
|
|
|
import configparser
|
|
import errno
|
|
import io
|
|
import os
|
|
from xml.dom import minidom
|
|
|
|
import salt.modules.pkg_resource as pkg_resource
|
|
import salt.modules.zypperpkg as zypper
|
|
import salt.utils.files
|
|
import salt.utils.pkg
|
|
from salt.exceptions import CommandExecutionError
|
|
from tests.support.mixins import LoaderModuleMockMixin
|
|
from tests.support.mock import MagicMock, Mock, call, mock_open, patch
|
|
from tests.support.unit import TestCase
|
|
|
|
|
|
class ZyppCallMock:
|
|
def __init__(self, return_value=None):
|
|
self.__return_value = return_value
|
|
|
|
def __getattr__(self, item):
|
|
return self
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
# If the call is for a configuration modifier, we return self
|
|
if any(i in kwargs for i in ("no_repo_failure", "systemd_scope", "root")):
|
|
return self
|
|
return MagicMock(return_value=self.__return_value)()
|
|
|
|
|
|
def get_test_data(filename):
|
|
"""
|
|
Return static test data
|
|
"""
|
|
with salt.utils.files.fopen(
|
|
os.path.join(
|
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "zypp"), filename
|
|
)
|
|
) as rfh:
|
|
return rfh.read()
|
|
|
|
|
|
class ZypperTestCase(TestCase, LoaderModuleMockMixin):
|
|
"""
|
|
Test cases for salt.modules.zypper
|
|
"""
|
|
|
|
def setup_loader_modules(self):
|
|
return {zypper: {"rpm": None}, pkg_resource: {}}
|
|
|
|
def setUp(self):
|
|
self.new_repo_config = dict(
|
|
name="mock-repo-name", url="http://repo.url/some/path"
|
|
)
|
|
side_effect = [
|
|
Mock(**{"sections.return_value": []}),
|
|
Mock(**{"sections.return_value": [self.new_repo_config["name"]]}),
|
|
]
|
|
self.zypper_patcher_config = {
|
|
"_get_configured_repos": Mock(side_effect=side_effect),
|
|
"__zypper__": Mock(),
|
|
"_get_repo_info": Mock(
|
|
return_value={
|
|
"keeppackages": False,
|
|
"autorefresh": True,
|
|
"enabled": False,
|
|
"baseurl": self.new_repo_config["url"],
|
|
"alias": self.new_repo_config["name"],
|
|
"name": self.new_repo_config["name"],
|
|
"priority": 1,
|
|
"type": "rpm-md",
|
|
}
|
|
),
|
|
"del_repo": Mock(),
|
|
"mod_repo": Mock(wraps=zypper.mod_repo),
|
|
}
|
|
|
|
def tearDown(self):
|
|
del self.new_repo_config
|
|
del self.zypper_patcher_config
|
|
|
|
def test_list_upgrades(self):
|
|
"""
|
|
List package upgrades
|
|
:return:
|
|
"""
|
|
ref_out = {
|
|
"stdout": get_test_data("zypper-updates.xml"),
|
|
"stderr": None,
|
|
"retcode": 0,
|
|
}
|
|
with patch.dict(
|
|
zypper.__salt__, {"cmd.run_all": MagicMock(return_value=ref_out)}
|
|
), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
|
|
upgrades = zypper.list_upgrades(refresh=False)
|
|
self.assertEqual(len(upgrades), 3)
|
|
for pkg, version in {
|
|
"SUSEConnect": "0.2.33-7.1",
|
|
"bind-utils": "9.9.6P1-35.1",
|
|
"bind-libs": "9.9.6P1-35.1",
|
|
}.items():
|
|
self.assertIn(pkg, upgrades)
|
|
self.assertEqual(upgrades[pkg], version)
|
|
|
|
@patch(
|
|
"salt.utils.environment.get_module_environment",
|
|
MagicMock(return_value={"SALT_RUNNING": "1"}),
|
|
)
|
|
def test_zypper_caller(self):
|
|
"""
|
|
Test Zypper caller.
|
|
:return:
|
|
"""
|
|
|
|
class RunSniffer:
|
|
def __init__(self, stdout=None, stderr=None, retcode=None):
|
|
self.calls = list()
|
|
self._stdout = stdout or ""
|
|
self._stderr = stderr or ""
|
|
self._retcode = retcode or 0
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
self.calls.append({"args": args, "kwargs": kwargs})
|
|
return {
|
|
"stdout": self._stdout,
|
|
"stderr": self._stderr,
|
|
"retcode": self._retcode,
|
|
}
|
|
|
|
stdout_xml_snippet = '<?xml version="1.0"?><test foo="bar"/>'
|
|
sniffer = RunSniffer(stdout=stdout_xml_snippet)
|
|
with patch.dict("salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}):
|
|
self.assertEqual(zypper.__zypper__.call("foo"), stdout_xml_snippet)
|
|
self.assertEqual(len(sniffer.calls), 1)
|
|
|
|
zypper.__zypper__.call("--no-refresh", "bar")
|
|
self.assertEqual(len(sniffer.calls), 2)
|
|
self.assertEqual(
|
|
sniffer.calls[0]["args"][0],
|
|
["zypper", "--non-interactive", "--no-refresh", "foo"],
|
|
)
|
|
self.assertEqual(
|
|
sniffer.calls[1]["args"][0],
|
|
["zypper", "--non-interactive", "--no-refresh", "bar"],
|
|
)
|
|
|
|
dom = zypper.__zypper__.xml.call("xml-test")
|
|
self.assertEqual(
|
|
sniffer.calls[2]["args"][0],
|
|
["zypper", "--non-interactive", "--xmlout", "--no-refresh", "xml-test"],
|
|
)
|
|
self.assertEqual(
|
|
dom.getElementsByTagName("test")[0].getAttribute("foo"), "bar"
|
|
)
|
|
|
|
zypper.__zypper__.refreshable.call("refresh-test")
|
|
self.assertEqual(
|
|
sniffer.calls[3]["args"][0],
|
|
["zypper", "--non-interactive", "refresh-test"],
|
|
)
|
|
|
|
zypper.__zypper__.nolock.call("no-locking-test")
|
|
self.assertEqual(
|
|
sniffer.calls[4]
|
|
.get("kwargs", {})
|
|
.get("env", {})
|
|
.get("ZYPP_READONLY_HACK"),
|
|
"1",
|
|
)
|
|
self.assertEqual(
|
|
sniffer.calls[4].get("kwargs", {}).get("env", {}).get("SALT_RUNNING"),
|
|
"1",
|
|
)
|
|
|
|
zypper.__zypper__.call("locking-test")
|
|
self.assertEqual(
|
|
sniffer.calls[5]
|
|
.get("kwargs", {})
|
|
.get("env", {})
|
|
.get("ZYPP_READONLY_HACK"),
|
|
None,
|
|
)
|
|
self.assertEqual(
|
|
sniffer.calls[5].get("kwargs", {}).get("env", {}).get("SALT_RUNNING"),
|
|
"1",
|
|
)
|
|
|
|
# Test exceptions
|
|
stdout_xml_snippet = (
|
|
'<?xml version="1.0"?><stream><message'
|
|
' type="error">Booya!</message></stream>'
|
|
)
|
|
sniffer = RunSniffer(stdout=stdout_xml_snippet, retcode=1)
|
|
with patch.dict(
|
|
"salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}
|
|
), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
|
|
with self.assertRaisesRegex(
|
|
CommandExecutionError, "^Zypper command failure: Booya!$"
|
|
):
|
|
zypper.__zypper__.xml.call("crashme")
|
|
|
|
output_to_user_stdout = "Output to user to stdout"
|
|
output_to_user_stderr = "Output to user to stderr"
|
|
sniffer = RunSniffer(
|
|
stdout=output_to_user_stdout, stderr=output_to_user_stderr, retcode=1
|
|
)
|
|
with patch.dict(
|
|
"salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}
|
|
), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
|
|
with self.assertRaisesRegex(
|
|
CommandExecutionError,
|
|
"^Zypper command failure: {}$".format(
|
|
output_to_user_stderr + output_to_user_stdout
|
|
),
|
|
):
|
|
zypper.__zypper__.call("crashme again")
|
|
|
|
sniffer = RunSniffer(retcode=1)
|
|
with patch.dict(
|
|
"salt.modules.zypperpkg.__salt__", {"cmd.run_all": sniffer}
|
|
), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
|
|
zypper.__zypper__.noraise.call("stay quiet")
|
|
self.assertEqual(zypper.__zypper__.error_msg, "Check Zypper's logs.")
|
|
|
|
def test_list_upgrades_error_handling(self):
|
|
"""
|
|
Test error handling in the list package upgrades.
|
|
:return:
|
|
"""
|
|
# Test handled errors
|
|
ref_out = {
|
|
"stdout": """<?xml version='1.0'?>
|
|
<stream>
|
|
<message type="info">Refreshing service 'container-suseconnect'.</message>
|
|
<message type="error">Some handled zypper internal error</message>
|
|
<message type="error">Another zypper internal error</message>
|
|
</stream>
|
|
""",
|
|
"stderr": "",
|
|
"retcode": 1,
|
|
}
|
|
with patch.dict(
|
|
"salt.modules.zypperpkg.__salt__",
|
|
{"cmd.run_all": MagicMock(return_value=ref_out)},
|
|
), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
|
|
with self.assertRaisesRegex(
|
|
CommandExecutionError,
|
|
"^Zypper command failure: Some handled zypper internal error{}Another"
|
|
" zypper internal error$".format(os.linesep),
|
|
):
|
|
zypper.list_upgrades(refresh=False)
|
|
|
|
# Test unhandled error
|
|
ref_out = {"retcode": 1, "stdout": "", "stderr": ""}
|
|
with patch.dict(
|
|
"salt.modules.zypperpkg.__salt__",
|
|
{"cmd.run_all": MagicMock(return_value=ref_out)},
|
|
), patch.object(zypper.__zypper__, "_is_rpm_lock", return_value=False):
|
|
with self.assertRaisesRegex(
|
|
CommandExecutionError, "^Zypper command failure: Check Zypper's logs.$"
|
|
):
|
|
zypper.list_upgrades(refresh=False)
|
|
|
|
def test_list_products(self):
|
|
"""
|
|
List products test.
|
|
"""
|
|
for filename, test_data in {
|
|
"zypper-products-sle12sp1.xml": {
|
|
"name": [
|
|
"SLES",
|
|
"SLES",
|
|
"SUSE-Manager-Proxy",
|
|
"SUSE-Manager-Server",
|
|
"sle-manager-tools-beta",
|
|
"sle-manager-tools-beta-broken-eol",
|
|
"sle-manager-tools-beta-no-eol",
|
|
],
|
|
"vendor": "SUSE LLC <https://www.suse.com/>",
|
|
"release": ["0", "0", "0", "0", "0", "0", "0"],
|
|
"productline": [None, None, None, None, None, None, "sles"],
|
|
"eol_t": [
|
|
None,
|
|
0,
|
|
1509408000,
|
|
1522454400,
|
|
1522454400,
|
|
1730332800,
|
|
1730332800,
|
|
],
|
|
"isbase": [False, False, False, False, False, False, True],
|
|
"installed": [False, False, False, False, False, False, True],
|
|
"registerrelease": [None, None, None, None, None, None, "123"],
|
|
},
|
|
"zypper-products-sle11sp3.xml": {
|
|
"name": [
|
|
"SUSE-Manager-Server",
|
|
"SUSE-Manager-Server",
|
|
"SUSE-Manager-Server-Broken-EOL",
|
|
"SUSE_SLES",
|
|
"SUSE_SLES",
|
|
"SUSE_SLES",
|
|
"SUSE_SLES-SP4-migration",
|
|
],
|
|
"vendor": "SUSE LINUX Products GmbH, Nuernberg, Germany",
|
|
"release": ["1.138", "1.2", "1.2", "1.2", "1.201", "1.201", "1.4"],
|
|
"productline": [None, None, None, None, None, "manager", "manager"],
|
|
"eol_t": [None, 0, 0, 0, 0, 0, 0],
|
|
"isbase": [False, False, False, False, False, True, True],
|
|
"installed": [False, False, False, False, False, True, True],
|
|
"registerrelease": [None, None, None, None, None, None, "42"],
|
|
},
|
|
}.items():
|
|
|
|
ref_out = {"retcode": 0, "stdout": get_test_data(filename)}
|
|
|
|
cmd_run_all = MagicMock(return_value=ref_out)
|
|
mock_call = call(
|
|
[
|
|
"zypper",
|
|
"--non-interactive",
|
|
"--xmlout",
|
|
"--no-refresh",
|
|
"--disable-repositories",
|
|
"products",
|
|
"-i",
|
|
],
|
|
env={"ZYPP_READONLY_HACK": "1"},
|
|
output_loglevel="trace",
|
|
python_shell=False,
|
|
)
|
|
|
|
with patch.dict(zypper.__salt__, {"cmd.run_all": cmd_run_all}):
|
|
products = zypper.list_products()
|
|
self.assertEqual(len(products), 7)
|
|
self.assertIn(
|
|
test_data["vendor"], [product["vendor"] for product in products]
|
|
)
|
|
for kwd in [
|
|
"name",
|
|
"isbase",
|
|
"installed",
|
|
"release",
|
|
"productline",
|
|
"eol_t",
|
|
"registerrelease",
|
|
]:
|
|
self.assertCountEqual(
|
|
test_data[kwd], [prod.get(kwd) for prod in products]
|
|
)
|
|
cmd_run_all.assert_has_calls([mock_call])
|
|
|
|
def test_refresh_db(self):
|
|
"""
|
|
Test if refresh DB handled correctly
|
|
"""
|
|
ref_out = [
|
|
"Repository 'openSUSE-Leap-42.1-LATEST' is up to date.",
|
|
"Repository 'openSUSE-Leap-42.1-Update' is up to date.",
|
|
"Retrieving repository 'openSUSE-Leap-42.1-Update-Non-Oss' metadata",
|
|
"Forcing building of repository cache",
|
|
"Building repository 'openSUSE-Leap-42.1-Update-Non-Oss' cache"
|
|
" ..........[done]",
|
|
"Building repository 'salt-dev' cache",
|
|
"All repositories have been refreshed.",
|
|
]
|
|
|
|
run_out = {"stderr": "", "stdout": "\n".join(ref_out), "retcode": 0}
|
|
|
|
zypper_mock = MagicMock(return_value=run_out)
|
|
call_kwargs = {"output_loglevel": "trace", "python_shell": False, "env": {}}
|
|
with patch.dict(zypper.__salt__, {"cmd.run_all": zypper_mock}):
|
|
with patch.object(salt.utils.pkg, "clear_rtag", Mock()):
|
|
result = zypper.refresh_db()
|
|
self.assertEqual(result.get("openSUSE-Leap-42.1-LATEST"), False)
|
|
self.assertEqual(result.get("openSUSE-Leap-42.1-Update"), False)
|
|
self.assertEqual(result.get("openSUSE-Leap-42.1-Update-Non-Oss"), True)
|
|
zypper_mock.assert_called_with(
|
|
["zypper", "--non-interactive", "refresh", "--force"], **call_kwargs
|
|
)
|
|
zypper.refresh_db(force=False)
|
|
zypper_mock.assert_called_with(
|
|
["zypper", "--non-interactive", "refresh"], **call_kwargs
|
|
)
|
|
zypper.refresh_db(force=True)
|
|
zypper_mock.assert_called_with(
|
|
["zypper", "--non-interactive", "refresh", "--force"], **call_kwargs
|
|
)
|
|
|
|
def test_info_installed(self):
|
|
"""
|
|
Test the return information of the named package(s), installed on the system.
|
|
|
|
:return:
|
|
"""
|
|
run_out = {
|
|
"virgo-dummy": {
|
|
"build_date": "2015-07-09T10:55:19Z",
|
|
"vendor": "openSUSE Build Service",
|
|
"description": (
|
|
"This is the Virgo dummy package used for testing SUSE Manager"
|
|
),
|
|
"license": "GPL-2.0",
|
|
"build_host": "sheep05",
|
|
"url": "http://www.suse.com",
|
|
"build_date_time_t": 1436432119,
|
|
"relocations": "(not relocatable)",
|
|
"source_rpm": "virgo-dummy-1.0-1.1.src.rpm",
|
|
"install_date": "2016-02-23T16:31:57Z",
|
|
"install_date_time_t": 1456241517,
|
|
"summary": "Virgo dummy package",
|
|
"version": "1.0",
|
|
"signature": (
|
|
"DSA/SHA1, Thu Jul 9 08:55:33 2015, Key ID 27fa41bd8a7c64f9"
|
|
),
|
|
"release": "1.1",
|
|
"group": "Applications/System",
|
|
"arch": "noarch",
|
|
"size": "17992",
|
|
},
|
|
"libopenssl1_0_0": {
|
|
"build_date": "2015-11-04T23:20:34Z",
|
|
"vendor": "SUSE LLC <https://www.suse.com/>",
|
|
"description": "The OpenSSL Project is a collaborative effort.",
|
|
"license": "OpenSSL",
|
|
"build_host": "sheep11",
|
|
"url": "https://www.openssl.org/",
|
|
"build_date_time_t": 1446675634,
|
|
"relocations": "(not relocatable)",
|
|
"source_rpm": "openssl-1.0.1i-34.1.src.rpm",
|
|
"install_date": "2016-02-23T16:31:35Z",
|
|
"install_date_time_t": 1456241495,
|
|
"summary": "Secure Sockets and Transport Layer Security",
|
|
"version": "1.0.1i",
|
|
"signature": (
|
|
"RSA/SHA256, Wed Nov 4 22:21:34 2015, Key ID 70af9e8139db7c82"
|
|
),
|
|
"release": "34.1",
|
|
"group": "Productivity/Networking/Security",
|
|
"packager": "https://www.suse.com/",
|
|
"arch": "x86_64",
|
|
"size": "2576912",
|
|
},
|
|
}
|
|
with patch.dict(
|
|
zypper.__salt__, {"lowpkg.info": MagicMock(return_value=run_out)}
|
|
):
|
|
installed = zypper.info_installed()
|
|
# Test overall products length
|
|
self.assertEqual(len(installed), 2)
|
|
|
|
# Test translated fields
|
|
for pkg_name, pkg_info in installed.items():
|
|
self.assertEqual(
|
|
installed[pkg_name].get("source"), run_out[pkg_name]["source_rpm"]
|
|
)
|
|
|
|
# Test keys transition from the lowpkg.info
|
|
for pn_key, pn_val in run_out["virgo-dummy"].items():
|
|
if pn_key == "source_rpm":
|
|
continue
|
|
self.assertEqual(installed["virgo-dummy"][pn_key], pn_val)
|
|
|
|
def test_info_installed_with_non_ascii_char(self):
|
|
"""
|
|
Test the return information of the named package(s), installed on the system whith non-ascii chars
|
|
|
|
:return:
|
|
"""
|
|
run_out = {"vīrgô": {"description": "vīrgô d€šçripţiǫñ"}}
|
|
with patch.dict(
|
|
zypper.__salt__, {"lowpkg.info": MagicMock(return_value=run_out)}
|
|
):
|
|
installed = zypper.info_installed()
|
|
self.assertEqual(installed["vīrgô"]["description"], "vīrgô d€šçripţiǫñ")
|
|
|
|
def test_info_installed_with_all_versions(self):
|
|
"""
|
|
Test the return information of all versions for the named package(s), installed on the system.
|
|
|
|
:return:
|
|
"""
|
|
run_out = {
|
|
"virgo-dummy": [
|
|
{
|
|
"build_date": "2015-07-09T10:55:19Z",
|
|
"vendor": "openSUSE Build Service",
|
|
"description": (
|
|
"This is the Virgo dummy package used for testing SUSE Manager"
|
|
),
|
|
"license": "GPL-2.0",
|
|
"build_host": "sheep05",
|
|
"url": "http://www.suse.com",
|
|
"build_date_time_t": 1436432119,
|
|
"relocations": "(not relocatable)",
|
|
"source_rpm": "virgo-dummy-1.0-1.1.src.rpm",
|
|
"install_date": "2016-02-23T16:31:57Z",
|
|
"install_date_time_t": 1456241517,
|
|
"summary": "Virgo dummy package",
|
|
"version": "1.0",
|
|
"signature": (
|
|
"DSA/SHA1, Thu Jul 9 08:55:33 2015, Key ID 27fa41bd8a7c64f9"
|
|
),
|
|
"release": "1.1",
|
|
"group": "Applications/System",
|
|
"arch": "i686",
|
|
"size": "17992",
|
|
},
|
|
{
|
|
"build_date": "2015-07-09T10:15:19Z",
|
|
"vendor": "openSUSE Build Service",
|
|
"description": (
|
|
"This is the Virgo dummy package used for testing SUSE Manager"
|
|
),
|
|
"license": "GPL-2.0",
|
|
"build_host": "sheep05",
|
|
"url": "http://www.suse.com",
|
|
"build_date_time_t": 1436432119,
|
|
"relocations": "(not relocatable)",
|
|
"source_rpm": "virgo-dummy-1.0-1.1.src.rpm",
|
|
"install_date": "2016-02-23T16:31:57Z",
|
|
"install_date_time_t": 14562415127,
|
|
"summary": "Virgo dummy package",
|
|
"version": "1.0",
|
|
"signature": (
|
|
"DSA/SHA1, Thu Jul 9 08:55:33 2015, Key ID 27fa41bd8a7c64f9"
|
|
),
|
|
"release": "1.1",
|
|
"group": "Applications/System",
|
|
"arch": "x86_64",
|
|
"size": "13124",
|
|
},
|
|
],
|
|
"libopenssl1_0_0": [
|
|
{
|
|
"build_date": "2015-11-04T23:20:34Z",
|
|
"vendor": "SUSE LLC <https://www.suse.com/>",
|
|
"description": "The OpenSSL Project is a collaborative effort.",
|
|
"license": "OpenSSL",
|
|
"build_host": "sheep11",
|
|
"url": "https://www.openssl.org/",
|
|
"build_date_time_t": 1446675634,
|
|
"relocations": "(not relocatable)",
|
|
"source_rpm": "openssl-1.0.1i-34.1.src.rpm",
|
|
"install_date": "2016-02-23T16:31:35Z",
|
|
"install_date_time_t": 1456241495,
|
|
"summary": "Secure Sockets and Transport Layer Security",
|
|
"version": "1.0.1i",
|
|
"signature": (
|
|
"RSA/SHA256, Wed Nov 4 22:21:34 2015, Key ID 70af9e8139db7c82"
|
|
),
|
|
"release": "34.1",
|
|
"group": "Productivity/Networking/Security",
|
|
"packager": "https://www.suse.com/",
|
|
"arch": "x86_64",
|
|
"size": "2576912",
|
|
}
|
|
],
|
|
}
|
|
with patch.dict(
|
|
zypper.__salt__, {"lowpkg.info": MagicMock(return_value=run_out)}
|
|
):
|
|
installed = zypper.info_installed(all_versions=True)
|
|
# Test overall products length
|
|
self.assertEqual(len(installed), 2)
|
|
|
|
# Test multiple versions for the same package
|
|
for pkg_name, pkg_info_list in installed.items():
|
|
self.assertEqual(
|
|
len(pkg_info_list), 2 if pkg_name == "virgo-dummy" else 1
|
|
)
|
|
for info in pkg_info_list:
|
|
self.assertTrue(info["arch"] in ("x86_64", "i686"))
|
|
|
|
def test_info_available(self):
|
|
"""
|
|
Test return the information of the named package available for the system.
|
|
|
|
:return:
|
|
"""
|
|
test_pkgs = ["vim", "emacs", "python"]
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__",
|
|
ZyppCallMock(return_value=get_test_data("zypper-available.txt")),
|
|
):
|
|
available = zypper.info_available(*test_pkgs, refresh=False)
|
|
self.assertEqual(len(available), 3)
|
|
for pkg_name, pkg_info in available.items():
|
|
self.assertIn(pkg_name, test_pkgs)
|
|
|
|
self.assertEqual(available["emacs"]["status"], "up-to-date")
|
|
self.assertTrue(available["emacs"]["installed"])
|
|
self.assertEqual(available["emacs"]["support level"], "Level 3")
|
|
self.assertEqual(
|
|
available["emacs"]["vendor"], "SUSE LLC <https://www.suse.com/>"
|
|
)
|
|
self.assertEqual(available["emacs"]["summary"], "GNU Emacs Base Package")
|
|
|
|
self.assertEqual(available["vim"]["status"], "not installed")
|
|
self.assertFalse(available["vim"]["installed"])
|
|
self.assertEqual(available["vim"]["support level"], "Level 3")
|
|
self.assertEqual(
|
|
available["vim"]["vendor"], "SUSE LLC <https://www.suse.com/>"
|
|
)
|
|
self.assertEqual(available["vim"]["summary"], "Vi IMproved")
|
|
|
|
def test_latest_version(self):
|
|
"""
|
|
Test the latest version of the named package available for upgrade or installation.
|
|
|
|
:return:
|
|
"""
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__",
|
|
ZyppCallMock(return_value=get_test_data("zypper-available.txt")),
|
|
), patch("salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)):
|
|
self.assertEqual(zypper.latest_version("vim"), "7.4.326-2.62")
|
|
self.assertDictEqual(
|
|
zypper.latest_version("vim", "fakepkg"),
|
|
{"vim": "7.4.326-2.62", "fakepkg": ""},
|
|
)
|
|
|
|
def test_upgrade_kernel(self):
|
|
"""
|
|
Test kernel package upgrade success.
|
|
|
|
:return:
|
|
"""
|
|
with patch.dict(zypper.__grains__, {"osrelease_info": [12, 1]}), patch(
|
|
"salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)
|
|
), patch(
|
|
"salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False)
|
|
):
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"pkg_resource.parse_targets": MagicMock(
|
|
return_value=(["kernel-default"], None)
|
|
)
|
|
},
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call", MagicMock()
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.list_pkgs",
|
|
MagicMock(
|
|
side_effect=[
|
|
{"kernel-default": "3.12.49-11.1"},
|
|
{"kernel-default": "3.12.49-11.1,3.12.51-60.20.2"},
|
|
]
|
|
),
|
|
):
|
|
ret = zypper.install(
|
|
"kernel-default", "--auto-agree-with-licenses"
|
|
)
|
|
self.assertDictEqual(
|
|
ret,
|
|
{
|
|
"kernel-default": {
|
|
"old": "3.12.49-11.1",
|
|
"new": "3.12.49-11.1,3.12.51-60.20.2",
|
|
}
|
|
},
|
|
)
|
|
|
|
def test_upgrade_available(self):
|
|
"""
|
|
Test whether or not an upgrade is available for a given package.
|
|
|
|
:return:
|
|
"""
|
|
ref_out = get_test_data("zypper-available.txt")
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__",
|
|
ZyppCallMock(return_value=get_test_data("zypper-available.txt")),
|
|
), patch("salt.modules.zypperpkg.refresh_db", MagicMock(return_value=True)):
|
|
for pkg_name in ["emacs", "python"]:
|
|
self.assertFalse(zypper.upgrade_available(pkg_name))
|
|
self.assertTrue(zypper.upgrade_available("vim"))
|
|
|
|
def test_list_pkgs(self):
|
|
"""
|
|
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()}
|
|
):
|
|
pkgs = zypper.list_pkgs(versions_as_list=True)
|
|
self.assertFalse(pkgs.get("gpg-pubkey", False))
|
|
self.assertTrue("pkg.list_pkgs_None_[]" in zypper.__context__)
|
|
for pkg_name, pkg_version in {
|
|
"jakarta-commons-discovery": ["0.4-129.686"],
|
|
"yast2-ftp-server": ["3.1.8-8.1"],
|
|
"protobuf-java": ["2.6.1-3.1.develHead"],
|
|
"susemanager-build-keys-web": ["12.0-5.1.develHead"],
|
|
"apache-commons-cli": ["1.2-1.233"],
|
|
"kernel-default": ["4.4.138-94.39.1", "4.4.73-5.1"],
|
|
"perseus-dummy.i586": ["1.1-1.1"],
|
|
"jose4j": ["0.4.4-2.1.develHead"],
|
|
}.items():
|
|
self.assertTrue(pkgs.get(pkg_name))
|
|
self.assertEqual(pkgs[pkg_name], pkg_version)
|
|
|
|
def test_list_pkgs_no_context(self):
|
|
"""
|
|
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_list_pkgs_with_attr(self):
|
|
"""
|
|
Test packages listing with the attr parameter
|
|
|
|
: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.__salt__,
|
|
{"cmd.run": MagicMock(return_value=os.linesep.join(rpm_out))},
|
|
), patch.dict(zypper.__grains__, {"osarch": "x86_64"}), 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.dict(
|
|
pkg_resource.__salt__, {"pkg.parse_arch": zypper.parse_arch}
|
|
):
|
|
pkgs = zypper.list_pkgs(
|
|
attr=["epoch", "release", "arch", "install_date_time_t"]
|
|
)
|
|
self.assertFalse(pkgs.get("gpg-pubkey", False))
|
|
self.assertTrue("pkg.list_pkgs_None_[]" in zypper.__context__)
|
|
for pkg_name, pkg_attr in {
|
|
"jakarta-commons-discovery": [
|
|
{
|
|
"version": "0.4",
|
|
"release": "129.686",
|
|
"arch": "noarch",
|
|
"install_date_time_t": 1498636511,
|
|
"epoch": None,
|
|
}
|
|
],
|
|
"yast2-ftp-server": [
|
|
{
|
|
"version": "3.1.8",
|
|
"release": "8.1",
|
|
"arch": "x86_64",
|
|
"install_date_time_t": 1499257798,
|
|
"epoch": None,
|
|
}
|
|
],
|
|
"protobuf-java": [
|
|
{
|
|
"version": "2.6.1",
|
|
"release": "3.1.develHead",
|
|
"install_date_time_t": 1499257756,
|
|
"arch": "noarch",
|
|
"epoch": None,
|
|
}
|
|
],
|
|
"susemanager-build-keys-web": [
|
|
{
|
|
"version": "12.0",
|
|
"release": "5.1.develHead",
|
|
"arch": "noarch",
|
|
"install_date_time_t": 1498636510,
|
|
"epoch": None,
|
|
}
|
|
],
|
|
"apache-commons-cli": [
|
|
{
|
|
"version": "1.2",
|
|
"release": "1.233",
|
|
"arch": "noarch",
|
|
"install_date_time_t": 1498636510,
|
|
"epoch": None,
|
|
}
|
|
],
|
|
"kernel-default": [
|
|
{
|
|
"version": "4.4.138",
|
|
"release": "94.39.1",
|
|
"arch": "x86_64",
|
|
"install_date_time_t": 1529936067,
|
|
"epoch": None,
|
|
},
|
|
{
|
|
"version": "4.4.73",
|
|
"release": "5.1",
|
|
"arch": "x86_64",
|
|
"install_date_time_t": 1503572639,
|
|
"epoch": None,
|
|
},
|
|
],
|
|
"perseus-dummy": [
|
|
{
|
|
"version": "1.1",
|
|
"release": "1.1",
|
|
"arch": "i586",
|
|
"install_date_time_t": 1529936062,
|
|
"epoch": None,
|
|
}
|
|
],
|
|
"jose4j": [
|
|
{
|
|
"arch": "noarch",
|
|
"version": "0.4.4",
|
|
"release": "2.1.develHead",
|
|
"install_date_time_t": 1499257756,
|
|
"epoch": None,
|
|
}
|
|
],
|
|
}.items():
|
|
self.assertTrue(pkgs.get(pkg_name))
|
|
self.assertEqual(pkgs[pkg_name], pkg_attr)
|
|
|
|
def test_list_pkgs_with_attr_multiple_versions(self):
|
|
"""
|
|
Test packages listing with the attr parameter reporting multiple version installed
|
|
|
|
:return:
|
|
"""
|
|
|
|
def _add_data(data, key, value):
|
|
data.setdefault(key, []).append(value)
|
|
|
|
rpm_out = [
|
|
"glibc_|-2.12_|-1.212.el6_|-i686_|-_|-1542394210",
|
|
"glibc_|-2.12_|-1.212.el6_|-x86_64_|-_|-1542394204",
|
|
"virt-what_|-1.13_|-8.el7_|-x86_64_|-_|-1487838486",
|
|
"virt-what_|-1.10_|-2.el7_|-x86_64_|-_|-1387838486",
|
|
]
|
|
|
|
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.dict(
|
|
pkg_resource.__salt__, {"pkg.parse_arch": zypper.parse_arch}
|
|
):
|
|
pkgs = zypper.list_pkgs(
|
|
attr=["epoch", "release", "arch", "install_date_time_t"]
|
|
)
|
|
expected_pkg_list = {
|
|
"glibc": [
|
|
{
|
|
"version": "2.12",
|
|
"release": "1.212.el6",
|
|
"install_date_time_t": 1542394210,
|
|
"arch": "i686",
|
|
"epoch": None,
|
|
},
|
|
{
|
|
"version": "2.12",
|
|
"release": "1.212.el6",
|
|
"install_date_time_t": 1542394204,
|
|
"arch": "x86_64",
|
|
"epoch": None,
|
|
},
|
|
],
|
|
"virt-what": [
|
|
{
|
|
"version": "1.10",
|
|
"release": "2.el7",
|
|
"install_date_time_t": 1387838486,
|
|
"arch": "x86_64",
|
|
"epoch": None,
|
|
},
|
|
{
|
|
"version": "1.13",
|
|
"release": "8.el7",
|
|
"install_date_time_t": 1487838486,
|
|
"arch": "x86_64",
|
|
"epoch": None,
|
|
},
|
|
],
|
|
}
|
|
for pkgname, pkginfo in pkgs.items():
|
|
self.assertCountEqual(pkginfo, expected_pkg_list[pkgname])
|
|
|
|
def test_list_patches(self):
|
|
"""
|
|
Test advisory patches listing.
|
|
|
|
:return:
|
|
"""
|
|
|
|
ref_out = {
|
|
"stdout": get_test_data("zypper-patches.xml"),
|
|
"stderr": None,
|
|
"retcode": 0,
|
|
}
|
|
|
|
PATCHES_RET = {
|
|
"SUSE-SLE-SERVER-12-SP2-2017-97": {
|
|
"installed": False,
|
|
"summary": "Recommended update for ovmf",
|
|
},
|
|
"SUSE-SLE-SERVER-12-SP2-2017-98": {
|
|
"installed": True,
|
|
"summary": "Recommended update for kmod",
|
|
},
|
|
"SUSE-SLE-SERVER-12-SP2-2017-99": {
|
|
"installed": False,
|
|
"summary": "Security update for apache2",
|
|
},
|
|
}
|
|
|
|
with patch.dict(
|
|
zypper.__salt__, {"cmd.run_all": MagicMock(return_value=ref_out)}
|
|
):
|
|
list_patches = zypper.list_patches(refresh=False)
|
|
self.assertEqual(len(list_patches), 3)
|
|
self.assertDictEqual(list_patches, PATCHES_RET)
|
|
|
|
@patch(
|
|
"salt.utils.path.os_walk", MagicMock(return_value=[("test", "test", "test")])
|
|
)
|
|
@patch("os.path.getsize", MagicMock(return_value=123456))
|
|
@patch("os.path.getctime", MagicMock(return_value=1234567890.123456))
|
|
@patch(
|
|
"fnmatch.filter",
|
|
MagicMock(return_value=["/var/cache/zypper/packages/foo/bar/test_package.rpm"]),
|
|
)
|
|
def test_list_downloaded_with_kwargs(self):
|
|
"""
|
|
Test downloaded packages listing.
|
|
|
|
:return:
|
|
"""
|
|
DOWNLOADED_RET = {
|
|
"test-package": {
|
|
"1.0": {
|
|
"path": "/var/cache/zypper/packages/foo/bar/test_package.rpm",
|
|
"size": 123456,
|
|
"creation_date_time_t": 1234567890,
|
|
"creation_date_time": "2009-02-13T23:31:30",
|
|
}
|
|
}
|
|
}
|
|
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"lowpkg.bin_pkg_info": MagicMock(
|
|
return_value={"name": "test-package", "version": "1.0"}
|
|
)
|
|
},
|
|
):
|
|
list_downloaded = zypper.list_downloaded(kw1=True, kw2=False)
|
|
self.assertEqual(len(list_downloaded), 1)
|
|
self.assertDictEqual(list_downloaded, DOWNLOADED_RET)
|
|
|
|
@patch(
|
|
"salt.utils.path.os_walk", MagicMock(return_value=[("test", "test", "test")])
|
|
)
|
|
@patch("os.path.getsize", MagicMock(return_value=123456))
|
|
@patch("os.path.getctime", MagicMock(return_value=1234567890.123456))
|
|
@patch(
|
|
"fnmatch.filter",
|
|
MagicMock(return_value=["/var/cache/zypper/packages/foo/bar/test_package.rpm"]),
|
|
)
|
|
def test_list_downloaded(self):
|
|
"""
|
|
Test downloaded packages listing.
|
|
|
|
:return:
|
|
"""
|
|
DOWNLOADED_RET = {
|
|
"test-package": {
|
|
"1.0": {
|
|
"path": "/var/cache/zypper/packages/foo/bar/test_package.rpm",
|
|
"size": 123456,
|
|
"creation_date_time_t": 1234567890,
|
|
"creation_date_time": "2009-02-13T23:31:30",
|
|
}
|
|
}
|
|
}
|
|
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"lowpkg.bin_pkg_info": MagicMock(
|
|
return_value={"name": "test-package", "version": "1.0"}
|
|
)
|
|
},
|
|
):
|
|
list_downloaded = zypper.list_downloaded()
|
|
self.assertEqual(len(list_downloaded), 1)
|
|
self.assertDictEqual(list_downloaded, DOWNLOADED_RET)
|
|
|
|
def test_download(self):
|
|
"""
|
|
Test package download
|
|
:return:
|
|
"""
|
|
download_out = {
|
|
"stdout": get_test_data("zypper-download.xml"),
|
|
"stderr": None,
|
|
"retcode": 0,
|
|
}
|
|
|
|
test_out = {
|
|
"nmap": {
|
|
"path": "/var/cache/zypp/packages/SLE-12-x86_64-Pool/x86_64/nmap-6.46-1.72.x86_64.rpm",
|
|
"repository-alias": "SLE-12-x86_64-Pool",
|
|
"repository-name": "SLE-12-x86_64-Pool",
|
|
}
|
|
}
|
|
|
|
with patch.dict(
|
|
zypper.__salt__, {"cmd.run_all": MagicMock(return_value=download_out)}
|
|
):
|
|
with patch.dict(
|
|
zypper.__salt__, {"lowpkg.checksum": MagicMock(return_value=True)}
|
|
):
|
|
self.assertEqual(zypper.download("nmap"), test_out)
|
|
test_out["_error"] = "The following package(s) failed to download: foo"
|
|
self.assertEqual(zypper.download("nmap", "foo"), test_out)
|
|
|
|
@patch("salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False))
|
|
@patch(
|
|
"salt.modules.zypperpkg.list_downloaded",
|
|
MagicMock(
|
|
side_effect=[
|
|
{},
|
|
{
|
|
"vim": {
|
|
"1.1": {
|
|
"path": "/foo/bar/test.rpm",
|
|
"size": 1234,
|
|
"creation_date_time_t": 1234567890,
|
|
"creation_date_time": "2009-02-13T23:31:30",
|
|
}
|
|
}
|
|
},
|
|
]
|
|
),
|
|
)
|
|
def test_install_with_downloadonly(self):
|
|
"""
|
|
Test a package installation with downloadonly=True.
|
|
|
|
:return:
|
|
"""
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"pkg_resource.parse_targets": MagicMock(
|
|
return_value=({"vim": None}, "repository")
|
|
)
|
|
},
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call", MagicMock()
|
|
) as zypper_mock:
|
|
ret = zypper.install(pkgs=["vim"], downloadonly=True)
|
|
zypper_mock.assert_called_once_with(
|
|
"--no-refresh",
|
|
"install",
|
|
"--auto-agree-with-licenses",
|
|
"--name",
|
|
"--download-only",
|
|
"vim",
|
|
)
|
|
self.assertDictEqual(
|
|
ret,
|
|
{
|
|
"vim": {
|
|
"new": {
|
|
"1.1": {
|
|
"path": "/foo/bar/test.rpm",
|
|
"size": 1234,
|
|
"creation_date_time_t": 1234567890,
|
|
"creation_date_time": "2009-02-13T23:31:30",
|
|
}
|
|
},
|
|
"old": "",
|
|
}
|
|
},
|
|
)
|
|
|
|
@patch("salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False))
|
|
@patch(
|
|
"salt.modules.zypperpkg.list_downloaded",
|
|
MagicMock(
|
|
return_value={
|
|
"vim": {
|
|
"1.1": {
|
|
"path": "/foo/bar/test.rpm",
|
|
"size": 1234,
|
|
"creation_date_time_t": 1234567890,
|
|
"creation_date_time": "2017-01-01T11:00:00",
|
|
}
|
|
}
|
|
}
|
|
),
|
|
)
|
|
def test_install_with_downloadonly_already_downloaded(self):
|
|
"""
|
|
Test a package installation with downloadonly=True when package is already downloaded.
|
|
|
|
:return:
|
|
"""
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"pkg_resource.parse_targets": MagicMock(
|
|
return_value=({"vim": None}, "repository")
|
|
)
|
|
},
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call", MagicMock()
|
|
) as zypper_mock:
|
|
ret = zypper.install(pkgs=["vim"], downloadonly=True)
|
|
zypper_mock.assert_called_once_with(
|
|
"--no-refresh",
|
|
"install",
|
|
"--auto-agree-with-licenses",
|
|
"--name",
|
|
"--download-only",
|
|
"vim",
|
|
)
|
|
self.assertDictEqual(ret, {})
|
|
|
|
@patch("salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False))
|
|
@patch(
|
|
"salt.modules.zypperpkg._get_patches",
|
|
MagicMock(
|
|
return_value={"SUSE-PATCH-1234": {"installed": False, "summary": "test"}}
|
|
),
|
|
)
|
|
@patch(
|
|
"salt.modules.zypperpkg.list_pkgs",
|
|
MagicMock(side_effect=[{"vim": "1.1"}, {"vim": "1.2"}]),
|
|
)
|
|
def test_install_advisory_patch_ok(self):
|
|
"""
|
|
Test successfully advisory patch installation.
|
|
|
|
:return:
|
|
"""
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"pkg_resource.parse_targets": MagicMock(
|
|
return_value=({"SUSE-PATCH-1234": None}, "advisory")
|
|
)
|
|
},
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call", MagicMock()
|
|
) as zypper_mock:
|
|
ret = zypper.install(advisory_ids=["SUSE-PATCH-1234"])
|
|
zypper_mock.assert_called_once_with(
|
|
"--no-refresh",
|
|
"install",
|
|
"--auto-agree-with-licenses",
|
|
"--name",
|
|
"patch:SUSE-PATCH-1234",
|
|
)
|
|
self.assertDictEqual(ret, {"vim": {"old": "1.1", "new": "1.2"}})
|
|
|
|
@patch("salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False))
|
|
@patch(
|
|
"salt.modules.zypperpkg._get_patches",
|
|
MagicMock(
|
|
return_value={"SUSE-PATCH-1234": {"installed": False, "summary": "test"}}
|
|
),
|
|
)
|
|
@patch("salt.modules.zypperpkg.list_pkgs", MagicMock(return_value={"vim": "1.1"}))
|
|
def test_install_advisory_patch_failure(self):
|
|
"""
|
|
Test failing advisory patch installation because patch does not exist.
|
|
|
|
:return:
|
|
"""
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"pkg_resource.parse_targets": MagicMock(
|
|
return_value=({"SUSE-PATCH-XXX": None}, "advisory")
|
|
)
|
|
},
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call", MagicMock()
|
|
) as zypper_mock:
|
|
with self.assertRaisesRegex(
|
|
CommandExecutionError, '^Advisory id "SUSE-PATCH-XXX" not found$'
|
|
):
|
|
zypper.install(advisory_ids=["SUSE-PATCH-XXX"])
|
|
|
|
@patch("salt.modules.zypperpkg._systemd_scope", MagicMock(return_value=False))
|
|
@patch(
|
|
"salt.modules.zypperpkg.list_products",
|
|
MagicMock(return_value={"openSUSE": {"installed": False, "summary": "test"}}),
|
|
)
|
|
@patch(
|
|
"salt.modules.zypperpkg.list_pkgs",
|
|
MagicMock(
|
|
side_effect=[{"product:openSUSE": "15.2"}, {"product:openSUSE": "15.3"}]
|
|
),
|
|
)
|
|
def test_install_product_ok(self):
|
|
"""
|
|
Test successfully product installation.
|
|
"""
|
|
with patch.dict(
|
|
zypper.__salt__,
|
|
{
|
|
"pkg_resource.parse_targets": MagicMock(
|
|
return_value=(["product:openSUSE"], None)
|
|
)
|
|
},
|
|
):
|
|
with patch(
|
|
"salt.modules.zypperpkg.__zypper__.noraise.call", MagicMock()
|
|
) as zypper_mock:
|
|
ret = zypper.install("product:openSUSE", includes=["product"])
|
|
zypper_mock.assert_called_once_with(
|
|
"--no-refresh",
|
|
"install",
|
|
"--auto-agree-with-licenses",
|
|
"--name",
|
|
"product:openSUSE",
|
|
)
|
|
self.assertDictEqual(
|
|
ret, {"product:openSUSE": {"old": "15.2", "new": "15.3"}}
|
|
)
|
|
|
|
def test_remove_purge(self):
|
|
"""
|
|
Test package removal
|
|
:return:
|
|
"""
|
|
|
|
class ListPackages:
|
|
def __init__(self):
|
|
self._packages = ["vim", "pico"]
|
|
self._pkgs = {
|
|
"vim": "0.18.0",
|
|
"emacs": "24.0.1",
|
|
"pico": "0.1.1",
|
|
}
|
|
|
|
def __call__(self, root=None, includes=None):
|
|
pkgs = self._pkgs.copy()
|
|
for target in self._packages:
|
|
if self._pkgs.get(target):
|
|
del self._pkgs[target]
|
|
|
|
return pkgs
|
|
|
|
parsed_targets = [{"vim": None, "pico": None}, None]
|
|
cmd_out = {"retcode": 0, "stdout": "", "stderr": ""}
|
|
|
|
# If config.get starts being used elsewhere, we'll need to write a
|
|
# side_effect function.
|
|
patches = {
|
|
"cmd.run_all": MagicMock(return_value=cmd_out),
|
|
"pkg_resource.parse_targets": MagicMock(return_value=parsed_targets),
|
|
"pkg_resource.stringify": MagicMock(),
|
|
"config.get": MagicMock(return_value=True),
|
|
}
|
|
|
|
with patch.dict(zypper.__salt__, patches):
|
|
with patch("salt.modules.zypperpkg.list_pkgs", ListPackages()):
|
|
diff = zypper.remove(name="vim,pico")
|
|
for pkg_name in ["vim", "pico"]:
|
|
self.assertTrue(diff.get(pkg_name))
|
|
self.assertTrue(diff[pkg_name]["old"])
|
|
self.assertFalse(diff[pkg_name]["new"])
|
|
|
|
def test_repo_value_info(self):
|
|
"""
|
|
Tests if repo info is properly parsed.
|
|
|
|
:return:
|
|
"""
|
|
repos_cfg = configparser.ConfigParser()
|
|
for cfg in ["zypper-repo-1.cfg", "zypper-repo-2.cfg"]:
|
|
repos_cfg.readfp(io.StringIO(get_test_data(cfg)))
|
|
|
|
for alias in repos_cfg.sections():
|
|
r_info = zypper._get_repo_info(alias, repos_cfg=repos_cfg)
|
|
self.assertEqual(type(r_info["type"]), type(None))
|
|
self.assertEqual(type(r_info["enabled"]), bool)
|
|
self.assertEqual(type(r_info["autorefresh"]), bool)
|
|
self.assertEqual(type(r_info["baseurl"]), str)
|
|
self.assertEqual(type(r_info["name"]), str)
|
|
self.assertEqual(r_info["type"], None)
|
|
self.assertEqual(r_info["enabled"], alias == "SLE12-SP1-x86_64-Update")
|
|
self.assertEqual(r_info["autorefresh"], alias == "SLE12-SP1-x86_64-Update")
|
|
|
|
def test_repo_add_mod_name(self):
|
|
"""
|
|
Test mod_repo adds the new repo and call modify to update descriptive
|
|
name.
|
|
|
|
:return:
|
|
"""
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
desc_name = "Update Repository"
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
with zypper_patcher:
|
|
zypper.mod_repo(
|
|
name, **{"url": url, "name": desc_name}
|
|
)
|
|
self.assertEqual(
|
|
zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call("ar", url, name)],
|
|
)
|
|
zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
"mr", "--name", desc_name, name
|
|
)
|
|
|
|
def test_repo_add_nomod_noref(self):
|
|
"""
|
|
Test mod_repo adds the new repo and nothing else
|
|
|
|
:return:
|
|
"""
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{"url": url})
|
|
self.assertEqual(
|
|
zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call("ar", url, name)],
|
|
)
|
|
self.assertTrue(
|
|
zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0
|
|
)
|
|
|
|
def test_repo_noadd_nomod_noref(self):
|
|
"""
|
|
Test mod_repo detects the repo already exists,
|
|
no modification was requested and no refresh requested either
|
|
|
|
:return:
|
|
"""
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
self.zypper_patcher_config["_get_configured_repos"] = Mock(
|
|
**{"return_value.sections.return_value": [name]}
|
|
)
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
with zypper_patcher:
|
|
out = zypper.mod_repo(name, alias="new-alias")
|
|
self.assertEqual(
|
|
out["comment"],
|
|
"Specified arguments did not result in modification of repo",
|
|
)
|
|
self.assertTrue(zypper.__zypper__(root=None).xml.call.call_count == 0)
|
|
self.assertTrue(
|
|
zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0
|
|
)
|
|
|
|
def test_repo_noadd_modbaseurl_ref(self):
|
|
"""
|
|
Test mod_repo detects the repo already exists,
|
|
no modification was requested and no refresh requested either
|
|
|
|
:return:
|
|
"""
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
self.zypper_patcher_config["_get_configured_repos"] = Mock(
|
|
**{"return_value.sections.side_effect": [[name], [], [], [name]]}
|
|
)
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
with zypper_patcher:
|
|
params = {"baseurl": url + "-changed", "enabled": False}
|
|
zypper.mod_repo(name, **params)
|
|
expected_params = {
|
|
"alias": "mock-repo-name",
|
|
"name": "mock-repo-name",
|
|
"autorefresh": True,
|
|
"baseurl": "http://repo.url/some/path-changed",
|
|
"enabled": False,
|
|
"priority": 1,
|
|
"cache": False,
|
|
"keeppackages": False,
|
|
"type": "rpm-md",
|
|
"root": None,
|
|
}
|
|
self.assertEqual(zypper.mod_repo.call_count, 2)
|
|
self.assertEqual(
|
|
zypper.mod_repo.mock_calls[1], call(name, **expected_params)
|
|
)
|
|
|
|
def test_repo_add_mod_noref(self):
|
|
"""
|
|
Test mod_repo adds the new repo and call modify to update autorefresh
|
|
|
|
:return:
|
|
"""
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{"url": url, "refresh": True})
|
|
self.assertEqual(
|
|
zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call("ar", url, name)],
|
|
)
|
|
zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
"mr", "--refresh", name
|
|
)
|
|
|
|
def test_repo_noadd_mod_noref(self):
|
|
"""
|
|
Test mod_repo detects the repository exists,
|
|
calls modify to update 'autorefresh' but does not call refresh
|
|
|
|
:return:
|
|
"""
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
self.zypper_patcher_config["_get_configured_repos"] = Mock(
|
|
**{"return_value.sections.return_value": [name]}
|
|
)
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{"url": url, "refresh": True})
|
|
self.assertTrue(zypper.__zypper__(root=None).xml.call.call_count == 0)
|
|
zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
"mr", "--refresh", name
|
|
)
|
|
|
|
def test_repo_add_nomod_ref(self):
|
|
"""
|
|
Test mod_repo adds the new repo and refreshes the repo with
|
|
`zypper --gpg-auto-import-keys refresh <repo-name>`
|
|
|
|
:return:
|
|
"""
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{"url": url, "gpgautoimport": True})
|
|
self.assertEqual(
|
|
zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[
|
|
call("ar", url, name),
|
|
call("--gpg-auto-import-keys", "refresh", name),
|
|
],
|
|
)
|
|
self.assertTrue(
|
|
zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0
|
|
)
|
|
|
|
def test_repo_noadd_nomod_ref(self):
|
|
"""
|
|
Test mod_repo detects the repo already exists,
|
|
has nothing to modify and refreshes the repo with
|
|
`zypper --gpg-auto-import-keys refresh <repo-name>`
|
|
|
|
:return:
|
|
"""
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
self.zypper_patcher_config["_get_configured_repos"] = Mock(
|
|
**{"return_value.sections.return_value": [name]}
|
|
)
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
with zypper_patcher:
|
|
zypper.mod_repo(name, **{"url": url, "gpgautoimport": True})
|
|
self.assertEqual(
|
|
zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call("--gpg-auto-import-keys", "refresh", name)],
|
|
)
|
|
self.assertTrue(
|
|
zypper.__zypper__(root=None).refreshable.xml.call.call_count == 0
|
|
)
|
|
|
|
def test_repo_add_mod_ref(self):
|
|
"""
|
|
Test mod_repo adds the new repo,
|
|
calls modify to update 'autorefresh' and refreshes the repo with
|
|
`zypper --gpg-auto-import-keys refresh <repo-name>`
|
|
|
|
:return:
|
|
"""
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
with zypper_patcher:
|
|
zypper.mod_repo(
|
|
name, **{"url": url, "refresh": True, "gpgautoimport": True}
|
|
)
|
|
self.assertEqual(
|
|
zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[
|
|
call("ar", url, name),
|
|
call("--gpg-auto-import-keys", "refresh", name),
|
|
],
|
|
)
|
|
zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
"--gpg-auto-import-keys", "mr", "--refresh", name
|
|
)
|
|
|
|
def test_repo_noadd_mod_ref(self):
|
|
"""
|
|
Test mod_repo detects the repo already exists,
|
|
calls modify to update 'autorefresh' and refreshes the repo with
|
|
`zypper --gpg-auto-import-keys refresh <repo-name>`
|
|
|
|
:return:
|
|
"""
|
|
url = self.new_repo_config["url"]
|
|
name = self.new_repo_config["name"]
|
|
self.zypper_patcher_config["_get_configured_repos"] = Mock(
|
|
**{"return_value.sections.return_value": [name]}
|
|
)
|
|
zypper_patcher = patch.multiple(
|
|
"salt.modules.zypperpkg", **self.zypper_patcher_config
|
|
)
|
|
|
|
with zypper_patcher:
|
|
zypper.mod_repo(
|
|
name, **{"url": url, "refresh": True, "gpgautoimport": True}
|
|
)
|
|
self.assertEqual(
|
|
zypper.__zypper__(root=None).xml.call.call_args_list,
|
|
[call("--gpg-auto-import-keys", "refresh", name)],
|
|
)
|
|
zypper.__zypper__(root=None).refreshable.xml.call.assert_called_once_with(
|
|
"--gpg-auto-import-keys", "mr", "--refresh", name
|
|
)
|
|
|
|
def test_wildcard_to_query_match_all(self):
|
|
"""
|
|
Test wildcard to query match all pattern
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="SLE-12-SP2-x86_64-Pool"/>
|
|
<solvable status="not-installed" name="libzypp" kind="srcpackage" edition="16.3.2-25.1" arch="noarch" repository="SLE-12-SP2-x86_64-Update"/>
|
|
<solvable status="not-installed" name="libzypp" kind="srcpackage" edition="16.5.2-27.9.1" arch="noarch" repository="SLE-12-SP2-x86_64-Update"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.3.2-25.1" arch="x86_64" repository="SLE-12-SP2-x86_64-Update"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.5.2-27.9.1" arch="x86_64" repository="SLE-12-SP2-x86_64-Update"/>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="(System Packages)"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "*"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
"16.2.4-19.5",
|
|
"16.3.2-25.1",
|
|
"16.5.2-27.9.1",
|
|
]
|
|
|
|
def test_wildcard_to_query_multiple_asterisk(self):
|
|
"""
|
|
Test wildcard to query match multiple asterisk
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "16.2.*-2*"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
"16.2.5-25.1",
|
|
"16.2.6-27.9.1",
|
|
]
|
|
|
|
def test_wildcard_to_query_exact_match_at_end(self):
|
|
"""
|
|
Test wildcard to query match exact pattern at the end
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "16.2.5*"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
"16.2.5-25.1"
|
|
]
|
|
|
|
def test_wildcard_to_query_exact_match_at_beginning(self):
|
|
"""
|
|
Test wildcard to query match exact pattern at the beginning
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
wcard = zypper.Wildcard(_zpr)
|
|
wcard.name, wcard.version = "libzypp", "*.1"
|
|
assert wcard._get_scope_versions(wcard._get_available_versions()) == [
|
|
"16.2.5-25.1",
|
|
"17.2.6-27.9.1",
|
|
]
|
|
|
|
def test_wildcard_to_query_usage(self):
|
|
"""
|
|
Test wildcard to query usage.
|
|
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
assert zypper.Wildcard(_zpr)("libzypp", "16.2.4*") == "16.2.4-19.5"
|
|
assert zypper.Wildcard(_zpr)("libzypp", "16.2*") == "16.2.5-25.1"
|
|
assert zypper.Wildcard(_zpr)("libzypp", "*6-*") == "17.2.6-27.9.1"
|
|
assert zypper.Wildcard(_zpr)("libzypp", "*.1") == "17.2.6-27.9.1"
|
|
|
|
def test_wildcard_to_query_noversion(self):
|
|
"""
|
|
Test wildcard to query when no version has been passed on.
|
|
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
assert zypper.Wildcard(_zpr)("libzypp", None) is None
|
|
|
|
def test_wildcard_to_query_typecheck(self):
|
|
"""
|
|
Test wildcard to query typecheck.
|
|
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
assert isinstance(zypper.Wildcard(_zpr)("libzypp", "*.1"), str)
|
|
|
|
def test_wildcard_to_query_condition_preservation(self):
|
|
"""
|
|
Test wildcard to query Zypper condition preservation.
|
|
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
|
|
for op in zypper.Wildcard.Z_OP:
|
|
assert zypper.Wildcard(_zpr)(
|
|
"libzypp", "{}*.1".format(op)
|
|
) == "{}17.2.6-27.9.1".format(op)
|
|
|
|
# Auto-fix feature: moves operator from end to front
|
|
for op in zypper.Wildcard.Z_OP:
|
|
assert zypper.Wildcard(_zpr)(
|
|
"libzypp", "16*{}".format(op)
|
|
) == "{}16.2.5-25.1".format(op)
|
|
|
|
def test_wildcard_to_query_unsupported_operators(self):
|
|
"""
|
|
Test wildcard to query unsupported operators.
|
|
|
|
:return:
|
|
"""
|
|
xmldoc = """<?xml version='1.0'?><stream>
|
|
<search-result version="0.0"><solvable-list>
|
|
<solvable status="installed" name="libzypp" kind="package" edition="16.2.4-19.5" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="16.2.5-25.1" arch="x86_64" repository="foo"/>
|
|
<solvable status="other-version" name="libzypp" kind="package" edition="17.2.6-27.9.1" arch="x86_64" repository="foo"/>
|
|
</solvable-list></search-result></stream>
|
|
"""
|
|
_zpr = MagicMock()
|
|
_zpr.nolock.xml.call = MagicMock(return_value=minidom.parseString(xmldoc))
|
|
with self.assertRaises(CommandExecutionError):
|
|
for op in [">>", "==", "<<", "+"]:
|
|
zypper.Wildcard(_zpr)("libzypp", "{}*.1".format(op))
|
|
|
|
@patch("salt.modules.zypperpkg._get_visible_patterns")
|
|
def test__get_installed_patterns(self, get_visible_patterns):
|
|
"""Test installed patterns in the system"""
|
|
get_visible_patterns.return_value = {
|
|
"package-a": {"installed": True, "summary": "description a"},
|
|
"package-b": {"installed": False, "summary": "description b"},
|
|
}
|
|
|
|
salt_mock = {
|
|
"cmd.run": MagicMock(
|
|
return_value="""pattern() = package-a
|
|
pattern-visible()
|
|
pattern() = package-c"""
|
|
),
|
|
}
|
|
with patch.dict("salt.modules.zypperpkg.__salt__", salt_mock):
|
|
assert zypper._get_installed_patterns() == {
|
|
"package-a": {"installed": True, "summary": "description a"},
|
|
"package-c": {"installed": True, "summary": "Non-visible pattern"},
|
|
}
|
|
|
|
@patch("salt.modules.zypperpkg._get_visible_patterns")
|
|
def test__get_installed_patterns_with_alias(self, get_visible_patterns):
|
|
"""Test installed patterns in the system if they have alias"""
|
|
get_visible_patterns.return_value = {
|
|
"package-a": {"installed": True, "summary": "description a"},
|
|
"package-b": {"installed": False, "summary": "description b"},
|
|
}
|
|
|
|
salt_mock = {
|
|
"cmd.run": MagicMock(
|
|
return_value="""pattern() = .package-a-alias
|
|
pattern() = package-a
|
|
pattern-visible()
|
|
pattern() = package-c"""
|
|
),
|
|
}
|
|
with patch.dict("salt.modules.zypperpkg.__salt__", salt_mock):
|
|
assert zypper._get_installed_patterns() == {
|
|
"package-a": {"installed": True, "summary": "description a"},
|
|
"package-c": {"installed": True, "summary": "Non-visible pattern"},
|
|
}
|
|
|
|
@patch("salt.modules.zypperpkg._get_visible_patterns")
|
|
def test_list_patterns(self, get_visible_patterns):
|
|
"""Test available patterns in the repo"""
|
|
get_visible_patterns.return_value = {
|
|
"package-a": {"installed": True, "summary": "description a"},
|
|
"package-b": {"installed": False, "summary": "description b"},
|
|
}
|
|
assert zypper.list_patterns() == {
|
|
"package-a": {"installed": True, "summary": "description a"},
|
|
"package-b": {"installed": False, "summary": "description b"},
|
|
}
|
|
|
|
def test__clean_cache_empty(self):
|
|
"""Test that an empty cached can be cleaned"""
|
|
context = {}
|
|
with patch.dict(zypper.__context__, context):
|
|
zypper._clean_cache()
|
|
assert context == {}
|
|
|
|
def test__clean_cache_filled(self):
|
|
"""Test that a filled cached can be cleaned"""
|
|
context = {
|
|
"pkg.list_pkgs_/mnt_[]": None,
|
|
"pkg.list_pkgs_/mnt_[patterns]": None,
|
|
"pkg.list_provides": None,
|
|
"pkg.other_data": None,
|
|
}
|
|
with patch.dict(zypper.__context__, context):
|
|
zypper._clean_cache()
|
|
self.assertEqual(zypper.__context__, {"pkg.other_data": None})
|
|
|
|
def test_services_need_restart(self):
|
|
"""
|
|
Test that zypper ps is used correctly to list services that need to
|
|
be restarted.
|
|
"""
|
|
expected = ["salt-minion", "firewalld"]
|
|
zypper_output = "salt-minion\nfirewalld"
|
|
zypper_mock = Mock()
|
|
zypper_mock(root=None).nolock.call = Mock(return_value=zypper_output)
|
|
|
|
with patch("salt.modules.zypperpkg.__zypper__", zypper_mock):
|
|
assert zypper.services_need_restart() == expected
|
|
zypper_mock(root=None).nolock.call.assert_called_with("ps", "-sss")
|
|
|
|
def test_is_rpm_lock_no_error(self):
|
|
with patch.object(os.path, "exists", return_value=True):
|
|
self.assertFalse(zypper.__zypper__._is_rpm_lock())
|
|
|
|
def test_rpm_lock_does_not_exist(self):
|
|
if salt.utils.files.is_fcntl_available():
|
|
zypper.__zypper__.exit_code = 1
|
|
with patch.object(
|
|
os.path, "exists", return_value=False
|
|
) as mock_path_exists:
|
|
self.assertFalse(zypper.__zypper__._is_rpm_lock())
|
|
mock_path_exists.assert_called_with(zypper.__zypper__.RPM_LOCK)
|
|
zypper.__zypper__._reset()
|
|
|
|
def test_rpm_lock_acquirable(self):
|
|
if salt.utils.files.is_fcntl_available():
|
|
zypper.__zypper__.exit_code = 1
|
|
with patch.object(os.path, "exists", return_value=True), patch(
|
|
"fcntl.lockf", side_effect=OSError(errno.EAGAIN, "")
|
|
) as lockf_mock, patch("salt.utils.files.fopen", mock_open()):
|
|
self.assertTrue(zypper.__zypper__._is_rpm_lock())
|
|
lockf_mock.assert_called()
|
|
zypper.__zypper__._reset()
|
|
|
|
def test_rpm_lock_not_acquirable(self):
|
|
if salt.utils.files.is_fcntl_available():
|
|
zypper.__zypper__.exit_code = 1
|
|
with patch.object(os.path, "exists", return_value=True), patch(
|
|
"fcntl.lockf"
|
|
) as lockf_mock, patch("salt.utils.files.fopen", mock_open()):
|
|
self.assertFalse(zypper.__zypper__._is_rpm_lock())
|
|
self.assertEqual(lockf_mock.call_count, 2)
|
|
zypper.__zypper__._reset()
|