SHA256
1
0
forked from pool/salt

osc copypac from project:systemsmanagement:saltstack:testing package:salt revision:341

OBS-URL: https://build.opensuse.org/package/show/systemsmanagement:saltstack/salt?expand=0&rev=169
This commit is contained in:
Jochen Breuer 2020-05-26 08:05:14 +00:00 committed by Git OBS Bridge
parent 2cabfb9e66
commit a3c40ef813
8 changed files with 612 additions and 1 deletions

View File

@ -1 +1 @@
4b7e8cbf000c33224e9cd7a7eb581954ca3dbbec
1a82ea698915484eb266be064a7ddaf207b4b1e9

179
add-docker-logout-237.patch Normal file
View File

@ -0,0 +1,179 @@
From 9e6bd24b07cd2424c3805777b07b9ea84adff416 Mon Sep 17 00:00:00 2001
From: Alexander Graul <agraul@suse.com>
Date: Mon, 18 May 2020 16:39:27 +0200
Subject: [PATCH] Add docker logout (#237)
Docker logout works analog to login. It takes none, one or more registries as
arguments. If there are no arguments, all known (specified in pillar)
docker registries are logged out of. If arguments are present, they are
interpreted as a list of docker registries to log out of.
---
salt/modules/dockermod.py | 80 ++++++++++++++++++++++++++++
tests/unit/modules/test_dockermod.py | 59 ++++++++++++++++++++
2 files changed, 139 insertions(+)
diff --git a/salt/modules/dockermod.py b/salt/modules/dockermod.py
index 28a2107cec..119e9eb170 100644
--- a/salt/modules/dockermod.py
+++ b/salt/modules/dockermod.py
@@ -1481,6 +1481,86 @@ def login(*registries):
return ret
+def logout(*registries):
+ """
+ .. versionadded:: 3001
+
+ Performs a ``docker logout`` to remove the saved authentication details for
+ one or more configured repositories.
+
+ Multiple registry URLs (matching those configured in Pillar) can be passed,
+ and Salt will attempt to logout of *just* those registries. If no registry
+ URLs are provided, Salt will attempt to logout of *all* configured
+ registries.
+
+ **RETURN DATA**
+
+ A dictionary containing the following keys:
+
+ - ``Results`` - A dictionary mapping registry URLs to the authentication
+ result. ``True`` means a successful logout, ``False`` means a failed
+ logout.
+ - ``Errors`` - A list of errors encountered during the course of this
+ function.
+
+ CLI Example:
+
+ .. code-block:: bash
+
+ salt myminion docker.logout
+ salt myminion docker.logout hub
+ salt myminion docker.logout hub https://mydomain.tld/registry/
+ """
+ # NOTE: This function uses the "docker logout" CLI command to remove
+ # authentication information from config.json. docker-py does not support
+ # this usecase (see https://github.com/docker/docker-py/issues/1091)
+
+ # To logout of all known (to Salt) docker registries, they have to be collected first
+ registry_auth = __salt__["config.get"]("docker-registries", {})
+ ret = {"retcode": 0}
+ errors = ret.setdefault("Errors", [])
+ if not isinstance(registry_auth, dict):
+ errors.append("'docker-registries' Pillar value must be a dictionary")
+ registry_auth = {}
+ for reg_name, reg_conf in six.iteritems(
+ __salt__["config.option"]("*-docker-registries", wildcard=True)
+ ):
+ try:
+ registry_auth.update(reg_conf)
+ except TypeError:
+ errors.append(
+ "Docker registry '{0}' was not specified as a "
+ "dictionary".format(reg_name)
+ )
+
+ # If no registries passed, we will logout of all known registries
+ if not registries:
+ registries = list(registry_auth)
+
+ results = ret.setdefault("Results", {})
+ for registry in registries:
+ if registry not in registry_auth:
+ errors.append("No match found for registry '{0}'".format(registry))
+ continue
+ else:
+ cmd = ["docker", "logout"]
+ if registry.lower() != "hub":
+ cmd.append(registry)
+ log.debug("Attempting to logout of docker registry '%s'", registry)
+ logout_cmd = __salt__["cmd.run_all"](
+ cmd, python_shell=False, output_loglevel="quiet",
+ )
+ results[registry] = logout_cmd["retcode"] == 0
+ if not results[registry]:
+ if logout_cmd["stderr"]:
+ errors.append(logout_cmd["stderr"])
+ elif logout_cmd["stdout"]:
+ errors.append(logout_cmd["stdout"])
+ if errors:
+ ret["retcode"] = 1
+ return ret
+
+
# Functions for information gathering
def depends(name):
'''
diff --git a/tests/unit/modules/test_dockermod.py b/tests/unit/modules/test_dockermod.py
index 191bfc123f..8f4ead2867 100644
--- a/tests/unit/modules/test_dockermod.py
+++ b/tests/unit/modules/test_dockermod.py
@@ -164,6 +164,65 @@ class DockerTestCase(TestCase, LoaderModuleMockMixin):
self.assertIn('retcode', ret)
self.assertNotEqual(ret['retcode'], 0)
+ def test_logout_calls_docker_cli_logout_single(self):
+ client = Mock()
+ get_client_mock = MagicMock(return_value=client)
+ ref_out = {"stdout": "", "stderr": "", "retcode": 0}
+ registry_auth_data = {
+ "portus.example.com:5000": {
+ "username": "admin",
+ "password": "linux12345",
+ "email": "tux@example.com",
+ }
+ }
+ docker_mock = MagicMock(return_value=ref_out)
+ with patch.object(docker_mod, "_get_client", get_client_mock):
+ dunder_salt = {
+ "config.get": MagicMock(return_value=registry_auth_data),
+ "cmd.run_all": docker_mock,
+ "config.option": MagicMock(return_value={}),
+ }
+ with patch.dict(docker_mod.__salt__, dunder_salt):
+ ret = docker_mod.logout("portus.example.com:5000")
+ assert "retcode" in ret
+ assert ret["retcode"] == 0
+ docker_mock.assert_called_with(
+ ["docker", "logout", "portus.example.com:5000"],
+ python_shell=False,
+ output_loglevel="quiet",
+ )
+
+
+ def test_logout_calls_docker_cli_logout_all(self):
+ client = Mock()
+ get_client_mock = MagicMock(return_value=client)
+ ref_out = {"stdout": "", "stderr": "", "retcode": 0}
+ registry_auth_data = {
+ "portus.example.com:5000": {
+ "username": "admin",
+ "password": "linux12345",
+ "email": "tux@example.com",
+ },
+ "portus2.example.com:5000": {
+ "username": "admin",
+ "password": "linux12345",
+ "email": "tux@example.com",
+ },
+ }
+
+ docker_mock = MagicMock(return_value=ref_out)
+ with patch.object(docker_mod, "_get_client", get_client_mock):
+ dunder_salt = {
+ "config.get": MagicMock(return_value=registry_auth_data),
+ "cmd.run_all": docker_mock,
+ "config.option": MagicMock(return_value={}),
+ }
+ with patch.dict(docker_mod.__salt__, dunder_salt):
+ ret = docker_mod.logout()
+ assert "retcode" in ret
+ assert ret["retcode"] == 0
+ assert docker_mock.call_count == 2
+
def test_ps_with_host_true(self):
'''
Check that docker.ps called with host is ``True``,
--
2.26.2

View File

@ -0,0 +1,66 @@
From c1e66b9953c753dc9eff3652aef316e19c22deb4 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Tue, 12 May 2020 14:16:23 +0200
Subject: [PATCH] Fix a test and some variable names (#229)
* loop: fix variable names for until_no_eval
* Fix test_core tests for fqdns errors
---
salt/modules/network.py | 2 +-
tests/unit/grains/test_core.py | 24 +++++++++++++-----------
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/salt/modules/network.py b/salt/modules/network.py
index 880f4f8d5f..9e11eb816e 100644
--- a/salt/modules/network.py
+++ b/salt/modules/network.py
@@ -1946,4 +1946,4 @@ def fqdns():
elapsed = time.time() - start
log.debug('Elapsed time getting FQDNs: {} seconds'.format(elapsed))
- return {"fqdns": sorted(list(fqdns))}
\ No newline at end of file
+ return {"fqdns": sorted(list(fqdns))}
diff --git a/tests/unit/grains/test_core.py b/tests/unit/grains/test_core.py
index 94e4199814..36aa49f232 100644
--- a/tests/unit/grains/test_core.py
+++ b/tests/unit/grains/test_core.py
@@ -1122,20 +1122,22 @@ class CoreGrainsTestCase(TestCase, LoaderModuleMockMixin):
for errno in (0, core.HOST_NOT_FOUND, core.NO_DATA):
mock_log = MagicMock()
+ with patch.dict(core.__salt__, {'network.fqdns': salt.modules.network.fqdns}):
+ with patch.object(socket, 'gethostbyaddr',
+ side_effect=_gen_gethostbyaddr(errno)):
+ with patch('salt.modules.network.log', mock_log):
+ self.assertEqual(core.fqdns(), {'fqdns': []})
+ mock_log.debug.assert_called()
+ mock_log.error.assert_not_called()
+
+ mock_log = MagicMock()
+ with patch.dict(core.__salt__, {'network.fqdns': salt.modules.network.fqdns}):
with patch.object(socket, 'gethostbyaddr',
- side_effect=_gen_gethostbyaddr(errno)):
- with patch('salt.grains.core.log', mock_log):
+ side_effect=_gen_gethostbyaddr(-1)):
+ with patch('salt.modules.network.log', mock_log):
self.assertEqual(core.fqdns(), {'fqdns': []})
mock_log.debug.assert_called_once()
- mock_log.error.assert_not_called()
-
- mock_log = MagicMock()
- with patch.object(socket, 'gethostbyaddr',
- side_effect=_gen_gethostbyaddr(-1)):
- with patch('salt.grains.core.log', mock_log):
- self.assertEqual(core.fqdns(), {'fqdns': []})
- mock_log.debug.assert_not_called()
- mock_log.error.assert_called_once()
+ mock_log.error.assert_called_once()
@patch.object(salt.utils.platform, 'is_windows', MagicMock(return_value=False))
@patch('salt.utils.network.ip_addrs', MagicMock(return_value=['1.2.3.4', '5.6.7.8']))
--
2.26.2

View File

@ -0,0 +1,113 @@
From 0c988e1db59a255b2f707c4e626cec21ff06d7a3 Mon Sep 17 00:00:00 2001
From: Jochen Breuer <jbreuer@suse.de>
Date: Thu, 9 Apr 2020 17:12:54 +0200
Subject: [PATCH] Fix for return value ret vs return in batch mode
The least intrusive fix for ret vs return in batch mode.
---
salt/cli/batch.py | 16 ++++++----
tests/unit/cli/test_batch.py | 62 ++++++++++++++++++++++++++++++++++++
2 files changed, 71 insertions(+), 7 deletions(-)
diff --git a/salt/cli/batch.py b/salt/cli/batch.py
index 10fc81a5f4..d5b8754ad7 100644
--- a/salt/cli/batch.py
+++ b/salt/cli/batch.py
@@ -234,14 +234,16 @@ class Batch(object):
if not self.quiet:
salt.utils.stringutils.print_cli('\nExecuting run on {0}\n'.format(sorted(next_)))
# create a new iterator for this batch of minions
+ return_value = self.opts.get("return", self.opts.get("ret", ""))
new_iter = self.local.cmd_iter_no_block(
- *args,
- raw=self.opts.get('raw', False),
- ret=self.opts.get('return', ''),
- show_jid=show_jid,
- verbose=show_verbose,
- gather_job_timeout=self.opts['gather_job_timeout'],
- **self.eauth)
+ *args,
+ raw=self.opts.get("raw", False),
+ ret=return_value,
+ show_jid=show_jid,
+ verbose=show_verbose,
+ gather_job_timeout=self.opts["gather_job_timeout"],
+ **self.eauth
+ )
# add it to our iterators and to the minion_tracker
iters.append(new_iter)
minion_tracker[new_iter] = {}
diff --git a/tests/unit/cli/test_batch.py b/tests/unit/cli/test_batch.py
index acabbe51f5..d7411e8039 100644
--- a/tests/unit/cli/test_batch.py
+++ b/tests/unit/cli/test_batch.py
@@ -72,3 +72,65 @@ class BatchTestCase(TestCase):
'''
ret = Batch.get_bnum(self.batch)
self.assertEqual(ret, None)
+
+ def test_return_value_in_run_for_ret(self):
+ """
+ cmd_iter_no_block should have been called with a return no matter if
+ the return value was in ret or return.
+ """
+ self.batch.opts = {
+ "batch": "100%",
+ "timeout": 5,
+ "fun": "test",
+ "arg": "foo",
+ "gather_job_timeout": 5,
+ "ret": "my_return",
+ }
+ self.batch.minions = ["foo", "bar", "baz"]
+ self.batch.local.cmd_iter_no_block = MagicMock(return_value=iter([]))
+ ret = Batch.run(self.batch)
+ # We need to fetch at least one object to trigger the relevant code path.
+ x = next(ret)
+ self.batch.local.cmd_iter_no_block.assert_called_with(
+ ["baz", "bar", "foo"],
+ "test",
+ "foo",
+ 5,
+ "list",
+ raw=False,
+ ret="my_return",
+ show_jid=False,
+ verbose=False,
+ gather_job_timeout=5,
+ )
+
+ def test_return_value_in_run_for_return(self):
+ """
+ cmd_iter_no_block should have been called with a return no matter if
+ the return value was in ret or return.
+ """
+ self.batch.opts = {
+ "batch": "100%",
+ "timeout": 5,
+ "fun": "test",
+ "arg": "foo",
+ "gather_job_timeout": 5,
+ "return": "my_return",
+ }
+ self.batch.minions = ["foo", "bar", "baz"]
+ self.batch.local.cmd_iter_no_block = MagicMock(return_value=iter([]))
+ ret = Batch.run(self.batch)
+ # We need to fetch at least one object to trigger the relevant code path.
+ x = next(ret)
+ self.batch.local.cmd_iter_no_block.assert_called_with(
+ ["baz", "bar", "foo"],
+ "test",
+ "foo",
+ 5,
+ "list",
+ raw=False,
+ ret="my_return",
+ show_jid=False,
+ verbose=False,
+ gather_job_timeout=5,
+ )
--
2.26.1

View File

@ -0,0 +1,124 @@
From bb870d08a0268cb2be5309ee1a1b8facd2c885df Mon Sep 17 00:00:00 2001
From: darix <darix@users.noreply.github.com>
Date: Tue, 12 May 2020 13:58:15 +0200
Subject: [PATCH] Option to en-/disable force refresh in zypper (#215)
The default will still be force refresh to keep existing setups working.
1. Pillar option to turn off force refresh
```
zypper:
refreshdb_force: false
```
2. Cmdline option to force refresh.
```
salt '*' pkg.refresh_db [force=true|false]
```
The cmdline option will override the pillar as well.
Co-authored-by: Alexander Graul <agraul@suse.com>
---
salt/modules/zypperpkg.py | 32 ++++++++++++++++++++--------
tests/unit/modules/test_zypperpkg.py | 24 +++++++++++++++++++--
2 files changed, 45 insertions(+), 11 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index e3f802a911..ed8420f398 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -1279,25 +1279,39 @@ def mod_repo(repo, **kwargs):
return repo
-def refresh_db(root=None):
- '''
- Force a repository refresh by calling ``zypper refresh --force``, return a dict::
+def refresh_db(root=None, force=None):
+ """
+ Trigger a repository refresh by calling ``zypper refresh``. Refresh will run
+ with ``--force`` if the "force=True" flag is passed on the CLI or
+ ``refreshdb_force`` is set to ``true`` in the pillar. The CLI option
+ overrides the pillar setting.
- {'<database name>': Bool}
+ It will return a dict::
- root
- operate on a different root directory.
+ {'<database name>': Bool}
CLI Example:
.. code-block:: bash
- salt '*' pkg.refresh_db
- '''
+ salt '*' pkg.refresh_db [force=true|false]
+
+ Pillar Example:
+
+ .. code-block:: yaml
+
+ zypper:
+ refreshdb_force: false
+ """
# Remove rtag file to keep multiple refreshes from happening in pkg states
salt.utils.pkg.clear_rtag(__opts__)
ret = {}
- out = __zypper__(root=root).refreshable.call('refresh', '--force')
+ refresh_opts = ['refresh']
+ if force is None:
+ force = __pillar__.get('zypper', {}).get('refreshdb_force', True)
+ if force:
+ refresh_opts.append('--force')
+ out = __zypper__(root=root).refreshable.call(*refresh_opts)
for line in out.splitlines():
if not line:
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index 2a8e753b9d..9a5c59a857 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -278,12 +278,32 @@ class ZypperTestCase(TestCase, LoaderModuleMockMixin):
'stderr': '', 'stdout': '\n'.join(ref_out), 'retcode': 0
}
- with patch.dict(zypper.__salt__, {'cmd.run_all': MagicMock(return_value=run_out)}):
- with patch.object(salt.utils.pkg, 'clear_rtag', Mock()):
+ 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):
'''
--
2.26.2

View File

@ -1,3 +1,37 @@
-------------------------------------------------------------------
Thu May 21 08:35:30 UTC 2020 - Pablo Suárez Hernández <pablo.suarezhernandez@suse.com>
- zypperpkg: filter patterns that start with dot (bsc#1171906)
- Added:
* zypperpkg-filter-patterns-that-start-with-dot-244.patch
-------------------------------------------------------------------
Wed May 20 13:27:23 UTC 2020 - Jochen Breuer <jbreuer@suse.de>
- Batch mode now also correctly provides return value (bsc#1168340)
- Added:
* fix-for-return-value-ret-vs-return-in-batch-mode.patch
-------------------------------------------------------------------
Mon May 18 15:22:58 UTC 2020 - Alexander Graul <alexander.graul@suse.com>
- Add docker.logout to docker execution module (bsc#1165572)
- Added:
* add-docker-logout-237.patch
-------------------------------------------------------------------
Tue May 12 15:07:12 UTC 2020 - Jochen Breuer <jbreuer@suse.de>
- Testsuite fix
- Add option to enable/disable force refresh for zypper
- Added:
* option-to-en-disable-force-refresh-in-zypper-215.patch
* fix-a-test-and-some-variable-names-229.patch
-------------------------------------------------------------------
Fri May 8 14:24:19 UTC 2020 - Jochen Breuer <jbreuer@suse.de>

View File

@ -308,6 +308,16 @@ Patch111: prevent-logging-deadlock-on-salt-api-subprocesses-bs.patch
Patch112: msgpack-support-versions-1.0.0.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/235
Patch113: python3.8-compatibility-pr-s-235.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56419
Patch114: option-to-en-disable-force-refresh-in-zypper-215.patch
# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/229
Patch115: fix-a-test-and-some-variable-names-229.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56439
Patch116: add-docker-logout-237.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/56595
Patch117: fix-for-return-value-ret-vs-return-in-batch-mode.patch
# PATCH-FIX_UPSTREAM: https://github.com/saltstack/salt/pull/57392
Patch118: zypperpkg-filter-patterns-that-start-with-dot-244.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildRequires: logrotate
@ -928,6 +938,11 @@ cp %{S:5} ./.travis.yml
%patch111 -p1
%patch112 -p1
%patch113 -p1
%patch114 -p1
%patch115 -p1
%patch116 -p1
%patch117 -p1
%patch118 -p1
%build
%if 0%{?build_py2}

View File

@ -0,0 +1,80 @@
From 31bccc548b6f9d894b7c87ade035b1b178c18841 Mon Sep 17 00:00:00 2001
From: Alberto Planas <aplanas@suse.com>
Date: Thu, 21 May 2020 10:19:15 +0200
Subject: [PATCH] zypperpkg: filter patterns that start with dot (#244)
For versions <=SLE12SP4 some patterns can contain alias, and can appear
duplicated. The alias start with ".", so they can be filtered.
If the module try to search by the alias name (pattern:.basename, for
example), zypper will not be able to find it and the operation will
fail.
This patch detect and filter the alias, and remove duplicates.
Fix bsc#1171906
(cherry picked from commit d043db63000df2892b2e7259f580ede81e33724d)
---
salt/modules/zypperpkg.py | 10 ++++++++--
tests/unit/modules/test_zypperpkg.py | 22 ++++++++++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/salt/modules/zypperpkg.py b/salt/modules/zypperpkg.py
index ed8420f398b91b3ef76417d2f11ec59c4051d120..96c3eed851b819ec800e733628e2ae255481bb92 100644
--- a/salt/modules/zypperpkg.py
+++ b/salt/modules/zypperpkg.py
@@ -2302,8 +2302,14 @@ def _get_installed_patterns(root=None):
# a real error.
output = __salt__['cmd.run'](cmd, ignore_retcode=True)
- installed_patterns = [_pattern_name(line) for line in output.splitlines()
- if line.startswith('pattern() = ')]
+ # On <= SLE12SP4 we have patterns that have multiple names (alias)
+ # and that are duplicated. The alias start with ".", so we filter
+ # them.
+ installed_patterns = {
+ _pattern_name(line)
+ for line in output.splitlines()
+ if line.startswith("pattern() = ") and not _pattern_name(line).startswith(".")
+ }
patterns = {k: v for k, v in _get_visible_patterns(root=root).items() if v['installed']}
diff --git a/tests/unit/modules/test_zypperpkg.py b/tests/unit/modules/test_zypperpkg.py
index 9a5c59a8572cb47c947645ed7c0b5c645c48a909..1fce3352c6aa0b5f19c802831bf8583012feb6bf 100644
--- a/tests/unit/modules/test_zypperpkg.py
+++ b/tests/unit/modules/test_zypperpkg.py
@@ -1493,6 +1493,28 @@ pattern() = package-c'''),
},
}
+ @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'''
--
2.23.0