1import logging
2import os
3
4import salt.modules.cmdmod as cmdmod
5import salt.modules.pkg_resource as pkg_resource
6import salt.modules.rpm_lowpkg as rpm
7import salt.modules.yumpkg as yumpkg
8import salt.utils.platform
9from salt.exceptions import CommandExecutionError, SaltInvocationError
10from tests.support.mock import MagicMock, Mock, call, patch
11
12try:
13    import pytest
14except ImportError:
15    pytest = None
16
17log = logging.getLogger(__name__)
18
19
20@pytest.fixture(scope="module")
21def list_repos_var():
22
23    return {
24        "base": {
25            "file": "/etc/yum.repos.d/CentOS-Base.repo",
26            "gpgcheck": "1",
27            "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
28            "mirrorlist": "http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra",
29            "name": "CentOS-$releasever - Base",
30        },
31        "base-source": {
32            "baseurl": "http://vault.centos.org/centos/$releasever/os/Source/",
33            "enabled": "0",
34            "file": "/etc/yum.repos.d/CentOS-Sources.repo",
35            "gpgcheck": "1",
36            "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
37            "name": "CentOS-$releasever - Base Sources",
38        },
39        "updates": {
40            "file": "/etc/yum.repos.d/CentOS-Base.repo",
41            "gpgcheck": "1",
42            "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
43            "mirrorlist": "http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra",
44            "name": "CentOS-$releasever - Updates",
45        },
46        "updates-source": {
47            "baseurl": "http://vault.centos.org/centos/$releasever/updates/Source/",
48            "enabled": "0",
49            "file": "/etc/yum.repos.d/CentOS-Sources.repo",
50            "gpgcheck": "1",
51            "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
52            "name": "CentOS-$releasever - Updates Sources",
53        },
54    }
55
56
57@pytest.fixture
58def configure_loader_modules():
59
60    return {
61        yumpkg: {
62            "__context__": {"yum_bin": "yum"},
63            "__grains__": {
64                "osarch": "x86_64",
65                "os": "CentOS",
66                "os_family": "RedHat",
67                "osmajorrelease": 7,
68            },
69        },
70        pkg_resource: {},
71    }
72
73
74def test_list_pkgs():
75    """
76    Test packages listing.
77
78    :return:
79    """
80
81    def _add_data(data, key, value):
82        data.setdefault(key, []).append(value)
83
84    rpm_out = [
85        "python-urlgrabber_|-(none)_|-3.10_|-8.el7_|-noarch_|-(none)_|-1487838471",
86        "alsa-lib_|-(none)_|-1.1.1_|-1.el7_|-x86_64_|-(none)_|-1487838475",
87        "gnupg2_|-(none)_|-2.0.22_|-4.el7_|-x86_64_|-(none)_|-1487838477",
88        "rpm-python_|-(none)_|-4.11.3_|-21.el7_|-x86_64_|-(none)_|-1487838477",
89        "pygpgme_|-(none)_|-0.3_|-9.el7_|-x86_64_|-(none)_|-1487838478",
90        "yum_|-(none)_|-3.4.3_|-150.el7.centos_|-noarch_|-(none)_|-1487838479",
91        "lzo_|-(none)_|-2.06_|-8.el7_|-x86_64_|-(none)_|-1487838479",
92        "qrencode-libs_|-(none)_|-3.4.1_|-3.el7_|-x86_64_|-(none)_|-1487838480",
93        "ustr_|-(none)_|-1.0.4_|-16.el7_|-x86_64_|-(none)_|-1487838480",
94        "shadow-utils_|-2_|-4.1.5.1_|-24.el7_|-x86_64_|-(none)_|-1487838481",
95        "util-linux_|-(none)_|-2.23.2_|-33.el7_|-x86_64_|-(none)_|-1487838484",
96        "openssh_|-(none)_|-6.6.1p1_|-33.el7_3_|-x86_64_|-(none)_|-1487838485",
97        "virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486",
98    ]
99    with patch.dict(yumpkg.__grains__, {"osarch": "x86_64"}), patch.dict(
100        yumpkg.__salt__,
101        {"cmd.run": MagicMock(return_value=os.linesep.join(rpm_out))},
102    ), patch.dict(yumpkg.__salt__, {"pkg_resource.add_pkg": _add_data}), patch.dict(
103        yumpkg.__salt__,
104        {"pkg_resource.format_pkg_list": pkg_resource.format_pkg_list},
105    ), patch.dict(
106        yumpkg.__salt__, {"pkg_resource.stringify": MagicMock()}
107    ), patch.dict(
108        pkg_resource.__salt__, {"pkg.parse_arch": yumpkg.parse_arch}
109    ):
110        pkgs = yumpkg.list_pkgs(versions_as_list=True)
111        for pkg_name, pkg_version in {
112            "python-urlgrabber": "3.10-8.el7",
113            "alsa-lib": "1.1.1-1.el7",
114            "gnupg2": "2.0.22-4.el7",
115            "rpm-python": "4.11.3-21.el7",
116            "pygpgme": "0.3-9.el7",
117            "yum": "3.4.3-150.el7.centos",
118            "lzo": "2.06-8.el7",
119            "qrencode-libs": "3.4.1-3.el7",
120            "ustr": "1.0.4-16.el7",
121            "shadow-utils": "2:4.1.5.1-24.el7",
122            "util-linux": "2.23.2-33.el7",
123            "openssh": "6.6.1p1-33.el7_3",
124            "virt-what": "1.13-8.el7",
125        }.items():
126            assert pkgs.get(pkg_name) is not None
127            assert pkgs[pkg_name] == [pkg_version]
128
129
130def test_list_pkgs_no_context():
131    """
132    Test packages listing.
133
134    :return:
135    """
136
137    def _add_data(data, key, value):
138        data.setdefault(key, []).append(value)
139
140    rpm_out = [
141        "python-urlgrabber_|-(none)_|-3.10_|-8.el7_|-noarch_|-(none)_|-1487838471",
142        "alsa-lib_|-(none)_|-1.1.1_|-1.el7_|-x86_64_|-(none)_|-1487838475",
143        "gnupg2_|-(none)_|-2.0.22_|-4.el7_|-x86_64_|-(none)_|-1487838477",
144        "rpm-python_|-(none)_|-4.11.3_|-21.el7_|-x86_64_|-(none)_|-1487838477",
145        "pygpgme_|-(none)_|-0.3_|-9.el7_|-x86_64_|-(none)_|-1487838478",
146        "yum_|-(none)_|-3.4.3_|-150.el7.centos_|-noarch_|-(none)_|-1487838479",
147        "lzo_|-(none)_|-2.06_|-8.el7_|-x86_64_|-(none)_|-1487838479",
148        "qrencode-libs_|-(none)_|-3.4.1_|-3.el7_|-x86_64_|-(none)_|-1487838480",
149        "ustr_|-(none)_|-1.0.4_|-16.el7_|-x86_64_|-(none)_|-1487838480",
150        "shadow-utils_|-2_|-4.1.5.1_|-24.el7_|-x86_64_|-(none)_|-1487838481",
151        "util-linux_|-(none)_|-2.23.2_|-33.el7_|-x86_64_|-(none)_|-1487838484",
152        "openssh_|-(none)_|-6.6.1p1_|-33.el7_3_|-x86_64_|-(none)_|-1487838485",
153        "virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486",
154    ]
155    with patch.dict(yumpkg.__grains__, {"osarch": "x86_64"}), patch.dict(
156        yumpkg.__salt__,
157        {"cmd.run": MagicMock(return_value=os.linesep.join(rpm_out))},
158    ), patch.dict(yumpkg.__salt__, {"pkg_resource.add_pkg": _add_data}), patch.dict(
159        yumpkg.__salt__,
160        {"pkg_resource.format_pkg_list": pkg_resource.format_pkg_list},
161    ), patch.dict(
162        yumpkg.__salt__, {"pkg_resource.stringify": MagicMock()}
163    ), patch.dict(
164        pkg_resource.__salt__, {"pkg.parse_arch": yumpkg.parse_arch}
165    ), patch.object(
166        yumpkg, "_list_pkgs_from_context"
167    ) as list_pkgs_context_mock:
168        pkgs = yumpkg.list_pkgs(versions_as_list=True, use_context=False)
169        list_pkgs_context_mock.assert_not_called()
170        list_pkgs_context_mock.reset_mock()
171
172        pkgs = yumpkg.list_pkgs(versions_as_list=True, use_context=False)
173        list_pkgs_context_mock.assert_not_called()
174        list_pkgs_context_mock.reset_mock()
175
176
177def test_list_pkgs_with_attr():
178    """
179    Test packages listing with the attr parameter
180
181    :return:
182    """
183
184    def _add_data(data, key, value):
185        data.setdefault(key, []).append(value)
186
187    rpm_out = [
188        "python-urlgrabber_|-(none)_|-3.10_|-8.el7_|-noarch_|-(none)_|-1487838471",
189        "alsa-lib_|-(none)_|-1.1.1_|-1.el7_|-x86_64_|-(none)_|-1487838475",
190        "gnupg2_|-(none)_|-2.0.22_|-4.el7_|-x86_64_|-(none)_|-1487838477",
191        "rpm-python_|-(none)_|-4.11.3_|-21.el7_|-x86_64_|-(none)_|-1487838477",
192        "pygpgme_|-(none)_|-0.3_|-9.el7_|-x86_64_|-(none)_|-1487838478",
193        "yum_|-(none)_|-3.4.3_|-150.el7.centos_|-noarch_|-(none)_|-1487838479",
194        "lzo_|-(none)_|-2.06_|-8.el7_|-x86_64_|-(none)_|-1487838479",
195        "qrencode-libs_|-(none)_|-3.4.1_|-3.el7_|-x86_64_|-(none)_|-1487838480",
196        "ustr_|-(none)_|-1.0.4_|-16.el7_|-x86_64_|-(none)_|-1487838480",
197        "shadow-utils_|-2_|-4.1.5.1_|-24.el7_|-x86_64_|-(none)_|-1487838481",
198        "util-linux_|-(none)_|-2.23.2_|-33.el7_|-x86_64_|-(none)_|-1487838484",
199        "openssh_|-(none)_|-6.6.1p1_|-33.el7_3_|-x86_64_|-(none)_|-1487838485",
200        "virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486",
201    ]
202    with patch.dict(yumpkg.__grains__, {"osarch": "x86_64"}), patch.dict(
203        yumpkg.__salt__,
204        {"cmd.run": MagicMock(return_value=os.linesep.join(rpm_out))},
205    ), patch.dict(yumpkg.__salt__, {"pkg_resource.add_pkg": _add_data}), patch.dict(
206        yumpkg.__salt__,
207        {"pkg_resource.format_pkg_list": pkg_resource.format_pkg_list},
208    ), patch.dict(
209        yumpkg.__salt__, {"pkg_resource.stringify": MagicMock()}
210    ), patch.dict(
211        pkg_resource.__salt__, {"pkg.parse_arch": yumpkg.parse_arch}
212    ):
213        pkgs = yumpkg.list_pkgs(
214            attr=["epoch", "release", "arch", "install_date_time_t"]
215        )
216        for pkg_name, pkg_attr in {
217            "python-urlgrabber": {
218                "version": "3.10",
219                "release": "8.el7",
220                "arch": "noarch",
221                "install_date_time_t": 1487838471,
222                "epoch": None,
223            },
224            "alsa-lib": {
225                "version": "1.1.1",
226                "release": "1.el7",
227                "arch": "x86_64",
228                "install_date_time_t": 1487838475,
229                "epoch": None,
230            },
231            "gnupg2": {
232                "version": "2.0.22",
233                "release": "4.el7",
234                "arch": "x86_64",
235                "install_date_time_t": 1487838477,
236                "epoch": None,
237            },
238            "rpm-python": {
239                "version": "4.11.3",
240                "release": "21.el7",
241                "arch": "x86_64",
242                "install_date_time_t": 1487838477,
243                "epoch": None,
244            },
245            "pygpgme": {
246                "version": "0.3",
247                "release": "9.el7",
248                "arch": "x86_64",
249                "install_date_time_t": 1487838478,
250                "epoch": None,
251            },
252            "yum": {
253                "version": "3.4.3",
254                "release": "150.el7.centos",
255                "arch": "noarch",
256                "install_date_time_t": 1487838479,
257                "epoch": None,
258            },
259            "lzo": {
260                "version": "2.06",
261                "release": "8.el7",
262                "arch": "x86_64",
263                "install_date_time_t": 1487838479,
264                "epoch": None,
265            },
266            "qrencode-libs": {
267                "version": "3.4.1",
268                "release": "3.el7",
269                "arch": "x86_64",
270                "install_date_time_t": 1487838480,
271                "epoch": None,
272            },
273            "ustr": {
274                "version": "1.0.4",
275                "release": "16.el7",
276                "arch": "x86_64",
277                "install_date_time_t": 1487838480,
278                "epoch": None,
279            },
280            "shadow-utils": {
281                "epoch": "2",
282                "version": "4.1.5.1",
283                "release": "24.el7",
284                "arch": "x86_64",
285                "install_date_time_t": 1487838481,
286            },
287            "util-linux": {
288                "version": "2.23.2",
289                "release": "33.el7",
290                "arch": "x86_64",
291                "install_date_time_t": 1487838484,
292                "epoch": None,
293            },
294            "openssh": {
295                "version": "6.6.1p1",
296                "release": "33.el7_3",
297                "arch": "x86_64",
298                "install_date_time_t": 1487838485,
299                "epoch": None,
300            },
301            "virt-what": {
302                "version": "1.13",
303                "release": "8.el7",
304                "install_date_time_t": 1487838486,
305                "arch": "x86_64",
306                "epoch": None,
307            },
308        }.items():
309
310            assert pkgs.get(pkg_name) is not None
311            assert pkgs[pkg_name] == [pkg_attr]
312
313
314def test_list_pkgs_with_attr_multiple_versions():
315    """
316    Test packages listing with the attr parameter reporting multiple version installed
317
318    :return:
319    """
320
321    def _add_data(data, key, value):
322        data.setdefault(key, []).append(value)
323
324    rpm_out = [
325        "glibc_|-(none)_|-2.12_|-1.212.el6_|-i686_|-(none)_|-1542394210"
326        "glibc_|-(none)_|-2.12_|-1.212.el6_|-x86_64_|-(none)_|-1542394204",
327        "virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486",
328        "virt-what_|-(none)_|-1.10_|-2.el7_|-x86_64_|-(none)_|-1387838486",
329    ]
330    with patch.dict(yumpkg.__grains__, {"osarch": "x86_64"}), patch.dict(
331        yumpkg.__salt__,
332        {"cmd.run": MagicMock(return_value=os.linesep.join(rpm_out))},
333    ), patch.dict(yumpkg.__salt__, {"pkg_resource.add_pkg": _add_data}), patch.dict(
334        yumpkg.__salt__,
335        {"pkg_resource.format_pkg_list": pkg_resource.format_pkg_list},
336    ), patch.dict(
337        yumpkg.__salt__, {"pkg_resource.stringify": MagicMock()}
338    ), patch.dict(
339        pkg_resource.__salt__, {"pkg.parse_arch": yumpkg.parse_arch}
340    ):
341        pkgs = yumpkg.list_pkgs(
342            attr=["epoch", "release", "arch", "install_date_time_t"]
343        )
344        expected_pkg_list = {
345            "glibc": [
346                {
347                    "version": "2.12",
348                    "release": "1.212.el6",
349                    "install_date_time_t": 1542394210,
350                    "arch": "i686",
351                    "epoch": None,
352                },
353                {
354                    "version": "2.12",
355                    "release": "1.212.el6",
356                    "install_date_time_t": 1542394204,
357                    "arch": "x86_64",
358                    "epoch": None,
359                },
360            ],
361            "virt-what": [
362                {
363                    "version": "1.10",
364                    "release": "2.el7",
365                    "install_date_time_t": 1387838486,
366                    "arch": "x86_64",
367                    "epoch": None,
368                },
369                {
370                    "version": "1.13",
371                    "release": "8.el7",
372                    "install_date_time_t": 1487838486,
373                    "arch": "x86_64",
374                    "epoch": None,
375                },
376            ],
377        }
378        for pkgname, pkginfo in pkgs.items():
379            assert pkginfo == expected_pkg_list[pkgname]
380            assert len(pkginfo) == len(expected_pkg_list[pkgname])
381
382
383def test_list_patches():
384    """
385    Test patches listing.
386
387    :return:
388    """
389    yum_out = [
390        "i my-fake-patch-not-installed-1234 recommended   "
391        " spacewalk-usix-2.7.5.2-2.2.noarch",
392        "  my-fake-patch-not-installed-1234 recommended   "
393        " spacewalksd-5.0.26.2-21.2.x86_64",
394        "i my-fake-patch-not-installed-1234 recommended   "
395        " suseRegisterInfo-3.1.1-18.2.x86_64",
396        "i my-fake-patch-installed-1234 recommended       "
397        " my-package-one-1.1-0.1.x86_64",
398        "i my-fake-patch-installed-1234 recommended       "
399        " my-package-two-1.1-0.1.x86_64",
400    ]
401
402    expected_patches = {
403        "my-fake-patch-not-installed-1234": {
404            "installed": False,
405            "summary": [
406                "spacewalk-usix-2.7.5.2-2.2.noarch",
407                "spacewalksd-5.0.26.2-21.2.x86_64",
408                "suseRegisterInfo-3.1.1-18.2.x86_64",
409            ],
410        },
411        "my-fake-patch-installed-1234": {
412            "installed": True,
413            "summary": [
414                "my-package-one-1.1-0.1.x86_64",
415                "my-package-two-1.1-0.1.x86_64",
416            ],
417        },
418    }
419
420    with patch.dict(yumpkg.__grains__, {"osarch": "x86_64"}), patch.dict(
421        yumpkg.__salt__,
422        {"cmd.run_stdout": MagicMock(return_value=os.linesep.join(yum_out))},
423    ):
424        patches = yumpkg.list_patches()
425        assert patches["my-fake-patch-not-installed-1234"]["installed"] is False
426        assert len(patches["my-fake-patch-not-installed-1234"]["summary"]) == 3
427        for _patch in expected_patches["my-fake-patch-not-installed-1234"]["summary"]:
428            assert _patch in patches["my-fake-patch-not-installed-1234"]["summary"]
429
430        assert patches["my-fake-patch-installed-1234"]["installed"] is True
431        assert len(patches["my-fake-patch-installed-1234"]["summary"]) == 2
432        for _patch in expected_patches["my-fake-patch-installed-1234"]["summary"]:
433            assert _patch in patches["my-fake-patch-installed-1234"]["summary"]
434
435
436def test_latest_version_with_options():
437    with patch.object(yumpkg, "list_pkgs", MagicMock(return_value={})):
438
439        # with fromrepo
440        cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
441        with patch.dict(
442            yumpkg.__salt__,
443            {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
444        ):
445            yumpkg.latest_version("foo", refresh=False, fromrepo="good", branch="foo")
446            cmd.assert_called_once_with(
447                [
448                    "yum",
449                    "--quiet",
450                    "--disablerepo=*",
451                    "--enablerepo=good",
452                    "--branch=foo",
453                    "list",
454                    "available",
455                    "foo",
456                ],
457                env={},
458                ignore_retcode=True,
459                output_loglevel="trace",
460                python_shell=False,
461            )
462
463        # without fromrepo
464        cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
465        with patch.dict(
466            yumpkg.__salt__,
467            {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
468        ):
469            yumpkg.latest_version(
470                "foo",
471                refresh=False,
472                enablerepo="good",
473                disablerepo="bad",
474                branch="foo",
475            )
476            cmd.assert_called_once_with(
477                [
478                    "yum",
479                    "--quiet",
480                    "--disablerepo=bad",
481                    "--enablerepo=good",
482                    "--branch=foo",
483                    "list",
484                    "available",
485                    "foo",
486                ],
487                env={},
488                ignore_retcode=True,
489                output_loglevel="trace",
490                python_shell=False,
491            )
492
493        # without fromrepo, but within the scope
494        cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
495        with patch("salt.utils.systemd.has_scope", MagicMock(return_value=True)):
496            with patch.dict(
497                yumpkg.__salt__,
498                {"cmd.run_all": cmd, "config.get": MagicMock(return_value=True)},
499            ):
500                yumpkg.latest_version(
501                    "foo",
502                    refresh=False,
503                    enablerepo="good",
504                    disablerepo="bad",
505                    branch="foo",
506                )
507                cmd.assert_called_once_with(
508                    [
509                        "systemd-run",
510                        "--scope",
511                        "yum",
512                        "--quiet",
513                        "--disablerepo=bad",
514                        "--enablerepo=good",
515                        "--branch=foo",
516                        "list",
517                        "available",
518                        "foo",
519                    ],
520                    env={},
521                    ignore_retcode=True,
522                    output_loglevel="trace",
523                    python_shell=False,
524                )
525
526
527def test_list_repo_pkgs_with_options(list_repos_var):
528    """
529    Test list_repo_pkgs with and without fromrepo
530
531    NOTE: mock_calls is a stack. The most recent call is indexed
532    with 0, while the first call would have the highest index.
533    """
534    really_old_yum = MagicMock(return_value="3.2.0")
535    older_yum = MagicMock(return_value="3.4.0")
536    newer_yum = MagicMock(return_value="3.4.5")
537    list_repos_mock = MagicMock(return_value=list_repos_var)
538    kwargs = {
539        "output_loglevel": "trace",
540        "ignore_retcode": True,
541        "python_shell": False,
542        "env": {},
543    }
544
545    with patch.object(yumpkg, "list_repos", list_repos_mock):
546
547        # Test with really old yum. The fromrepo argument has no effect on
548        # the yum commands we'd run.
549        with patch.dict(yumpkg.__salt__, {"cmd.run": really_old_yum}):
550
551            cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
552            with patch.dict(
553                yumpkg.__salt__,
554                {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
555            ):
556                yumpkg.list_repo_pkgs("foo")
557                # We should have called cmd.run_all twice
558                assert len(cmd.mock_calls) == 2
559
560                # Check args from first call
561                assert cmd.mock_calls[1][1] == (
562                    ["yum", "--quiet", "list", "available"],
563                )
564
565                # Check kwargs from first call
566                assert cmd.mock_calls[1][2] == kwargs
567
568                # Check args from second call
569                assert cmd.mock_calls[0][1] == (
570                    ["yum", "--quiet", "list", "installed"],
571                )
572
573                # Check kwargs from second call
574                assert cmd.mock_calls[0][2] == kwargs
575
576        # Test with really old yum. The fromrepo argument has no effect on
577        # the yum commands we'd run.
578        with patch.dict(yumpkg.__salt__, {"cmd.run": older_yum}):
579
580            cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
581            with patch.dict(
582                yumpkg.__salt__,
583                {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
584            ):
585                yumpkg.list_repo_pkgs("foo")
586                # We should have called cmd.run_all twice
587                assert len(cmd.mock_calls) == 2
588
589                # Check args from first call
590                assert cmd.mock_calls[1][1] == (
591                    ["yum", "--quiet", "--showduplicates", "list", "available"],
592                )
593
594                # Check kwargs from first call
595                assert cmd.mock_calls[1][2] == kwargs
596
597                # Check args from second call
598                assert cmd.mock_calls[0][1] == (
599                    ["yum", "--quiet", "--showduplicates", "list", "installed"],
600                )
601
602                # Check kwargs from second call
603                assert cmd.mock_calls[0][2] == kwargs
604
605        # Test with newer yum. We should run one yum command per repo, so
606        # fromrepo would limit how many calls we make.
607        with patch.dict(yumpkg.__salt__, {"cmd.run": newer_yum}):
608
609            # When fromrepo is used, we would only run one yum command, for
610            # that specific repo.
611            cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
612            with patch.dict(
613                yumpkg.__salt__,
614                {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
615            ):
616                yumpkg.list_repo_pkgs("foo", fromrepo="base")
617                # We should have called cmd.run_all once
618                assert len(cmd.mock_calls) == 1
619
620                # Check args
621                assert cmd.mock_calls[0][1] == (
622                    [
623                        "yum",
624                        "--quiet",
625                        "--showduplicates",
626                        "repository-packages",
627                        "base",
628                        "list",
629                        "foo",
630                    ],
631                )
632                # Check kwargs
633                assert cmd.mock_calls[0][2] == kwargs
634
635            # Test enabling base-source and disabling updates. We should
636            # get two calls, one for each enabled repo. Because dict
637            # iteration order will vary, different Python versions will be
638            # do them in different orders, which is OK, but it will just
639            # mean that we will have to check both the first and second
640            # mock call both times.
641            cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
642            with patch.dict(
643                yumpkg.__salt__,
644                {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
645            ):
646                yumpkg.list_repo_pkgs(
647                    "foo", enablerepo="base-source", disablerepo="updates"
648                )
649                # We should have called cmd.run_all twice
650                assert len(cmd.mock_calls) == 2
651
652                for repo in ("base", "base-source"):
653                    for index in (0, 1):
654                        try:
655                            # Check args
656                            assert cmd.mock_calls[index][1] == (
657                                [
658                                    "yum",
659                                    "--quiet",
660                                    "--showduplicates",
661                                    "repository-packages",
662                                    repo,
663                                    "list",
664                                    "foo",
665                                ],
666                            )
667                            # Check kwargs
668                            assert cmd.mock_calls[index][2] == kwargs
669                            break
670                        except AssertionError:
671                            continue
672                    else:
673                        pytest.fail("repo '{}' not checked".format(repo))
674
675
676def test_list_upgrades_dnf():
677    """
678    The subcommand should be "upgrades" with dnf
679    """
680    with patch.dict(yumpkg.__context__, {"yum_bin": "dnf"}):
681        # with fromrepo
682        cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
683        with patch.dict(
684            yumpkg.__salt__,
685            {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
686        ):
687            yumpkg.list_upgrades(refresh=False, fromrepo="good", branch="foo")
688            cmd.assert_called_once_with(
689                [
690                    "dnf",
691                    "--quiet",
692                    "--disablerepo=*",
693                    "--enablerepo=good",
694                    "--branch=foo",
695                    "list",
696                    "upgrades",
697                ],
698                env={},
699                output_loglevel="trace",
700                ignore_retcode=True,
701                python_shell=False,
702            )
703
704        # without fromrepo
705        cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
706        with patch.dict(
707            yumpkg.__salt__,
708            {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
709        ):
710            yumpkg.list_upgrades(
711                refresh=False, enablerepo="good", disablerepo="bad", branch="foo"
712            )
713            cmd.assert_called_once_with(
714                [
715                    "dnf",
716                    "--quiet",
717                    "--disablerepo=bad",
718                    "--enablerepo=good",
719                    "--branch=foo",
720                    "list",
721                    "upgrades",
722                ],
723                env={},
724                output_loglevel="trace",
725                ignore_retcode=True,
726                python_shell=False,
727            )
728
729
730def test_list_upgrades_yum():
731    """
732    The subcommand should be "updates" with yum
733    """
734    # with fromrepo
735    cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
736    with patch.dict(
737        yumpkg.__salt__,
738        {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
739    ):
740        yumpkg.list_upgrades(refresh=False, fromrepo="good", branch="foo")
741        cmd.assert_called_once_with(
742            [
743                "yum",
744                "--quiet",
745                "--disablerepo=*",
746                "--enablerepo=good",
747                "--branch=foo",
748                "list",
749                "updates",
750            ],
751            env={},
752            output_loglevel="trace",
753            ignore_retcode=True,
754            python_shell=False,
755        )
756
757    # without fromrepo
758    cmd = MagicMock(return_value={"retcode": 0, "stdout": ""})
759    with patch.dict(
760        yumpkg.__salt__,
761        {"cmd.run_all": cmd, "config.get": MagicMock(return_value=False)},
762    ):
763        yumpkg.list_upgrades(
764            refresh=False, enablerepo="good", disablerepo="bad", branch="foo"
765        )
766        cmd.assert_called_once_with(
767            [
768                "yum",
769                "--quiet",
770                "--disablerepo=bad",
771                "--enablerepo=good",
772                "--branch=foo",
773                "list",
774                "updates",
775            ],
776            env={},
777            output_loglevel="trace",
778            ignore_retcode=True,
779            python_shell=False,
780        )
781
782
783def test_refresh_db_with_options():
784
785    with patch("salt.utils.pkg.clear_rtag", Mock()):
786
787        # With check_update=True we will do a cmd.run to run the clean_cmd, and
788        # then a separate cmd.retcode to check for updates.
789
790        # with fromrepo
791        yum_call = MagicMock()
792        with patch.dict(
793            yumpkg.__salt__,
794            {"cmd.run_all": yum_call, "config.get": MagicMock(return_value=False)},
795        ):
796            yumpkg.refresh_db(check_update=True, fromrepo="good", branch="foo")
797
798            assert yum_call.call_count == 2
799            yum_call.assert_any_call(
800                [
801                    "yum",
802                    "--quiet",
803                    "--assumeyes",
804                    "clean",
805                    "expire-cache",
806                    "--disablerepo=*",
807                    "--enablerepo=good",
808                    "--branch=foo",
809                ],
810                env={},
811                ignore_retcode=True,
812                output_loglevel="trace",
813                python_shell=False,
814            )
815            yum_call.assert_any_call(
816                [
817                    "yum",
818                    "--quiet",
819                    "--assumeyes",
820                    "check-update",
821                    "--setopt=autocheck_running_kernel=false",
822                    "--disablerepo=*",
823                    "--enablerepo=good",
824                    "--branch=foo",
825                ],
826                output_loglevel="trace",
827                env={},
828                ignore_retcode=True,
829                python_shell=False,
830            )
831
832        # without fromrepo
833        yum_call = MagicMock()
834        with patch.dict(
835            yumpkg.__salt__,
836            {"cmd.run_all": yum_call, "config.get": MagicMock(return_value=False)},
837        ):
838            yumpkg.refresh_db(
839                check_update=True,
840                enablerepo="good",
841                disablerepo="bad",
842                branch="foo",
843            )
844            assert yum_call.call_count == 2
845            yum_call.assert_any_call(
846                [
847                    "yum",
848                    "--quiet",
849                    "--assumeyes",
850                    "clean",
851                    "expire-cache",
852                    "--disablerepo=bad",
853                    "--enablerepo=good",
854                    "--branch=foo",
855                ],
856                env={},
857                ignore_retcode=True,
858                output_loglevel="trace",
859                python_shell=False,
860            )
861            yum_call.assert_any_call(
862                [
863                    "yum",
864                    "--quiet",
865                    "--assumeyes",
866                    "check-update",
867                    "--setopt=autocheck_running_kernel=false",
868                    "--disablerepo=bad",
869                    "--enablerepo=good",
870                    "--branch=foo",
871                ],
872                output_loglevel="trace",
873                env={},
874                ignore_retcode=True,
875                python_shell=False,
876            )
877
878        # With check_update=False we will just do a cmd.run for the clean_cmd
879
880        # with fromrepo
881        yum_call = MagicMock()
882        with patch.dict(
883            yumpkg.__salt__,
884            {"cmd.run_all": yum_call, "config.get": MagicMock(return_value=False)},
885        ):
886            yumpkg.refresh_db(check_update=False, fromrepo="good", branch="foo")
887            assert yum_call.call_count == 1
888            yum_call.assert_called_once_with(
889                [
890                    "yum",
891                    "--quiet",
892                    "--assumeyes",
893                    "clean",
894                    "expire-cache",
895                    "--disablerepo=*",
896                    "--enablerepo=good",
897                    "--branch=foo",
898                ],
899                env={},
900                output_loglevel="trace",
901                ignore_retcode=True,
902                python_shell=False,
903            )
904
905        # without fromrepo
906        yum_call = MagicMock()
907        with patch.dict(
908            yumpkg.__salt__,
909            {"cmd.run_all": yum_call, "config.get": MagicMock(return_value=False)},
910        ):
911            yumpkg.refresh_db(
912                check_update=False,
913                enablerepo="good",
914                disablerepo="bad",
915                branch="foo",
916            )
917            assert yum_call.call_count == 1
918            yum_call.assert_called_once_with(
919                [
920                    "yum",
921                    "--quiet",
922                    "--assumeyes",
923                    "clean",
924                    "expire-cache",
925                    "--disablerepo=bad",
926                    "--enablerepo=good",
927                    "--branch=foo",
928                ],
929                env={},
930                output_loglevel="trace",
931                ignore_retcode=True,
932                python_shell=False,
933            )
934
935
936def test_install_with_options():
937    parse_targets = MagicMock(return_value=({"foo": None}, "repository"))
938    with patch.object(yumpkg, "list_pkgs", MagicMock(return_value={})), patch.object(
939        yumpkg, "list_holds", MagicMock(return_value=[])
940    ), patch.dict(
941        yumpkg.__salt__, {"pkg_resource.parse_targets": parse_targets}
942    ), patch(
943        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
944    ):
945
946        # with fromrepo
947        cmd = MagicMock(return_value={"retcode": 0})
948        with patch.dict(yumpkg.__salt__, {"cmd.run_all": cmd}):
949            yumpkg.install(
950                refresh=False,
951                fromrepo="good",
952                branch="foo",
953                setopt="obsoletes=0,plugins=0",
954            )
955            cmd.assert_called_once_with(
956                [
957                    "yum",
958                    "-y",
959                    "--disablerepo=*",
960                    "--enablerepo=good",
961                    "--branch=foo",
962                    "--setopt",
963                    "obsoletes=0",
964                    "--setopt",
965                    "plugins=0",
966                    "install",
967                    "foo",
968                ],
969                env={},
970                output_loglevel="trace",
971                python_shell=False,
972                ignore_retcode=False,
973                redirect_stderr=True,
974            )
975
976        # without fromrepo
977        cmd = MagicMock(return_value={"retcode": 0})
978        with patch.dict(yumpkg.__salt__, {"cmd.run_all": cmd}):
979            yumpkg.install(
980                refresh=False,
981                enablerepo="good",
982                disablerepo="bad",
983                branch="foo",
984                setopt="obsoletes=0,plugins=0",
985            )
986            cmd.assert_called_once_with(
987                [
988                    "yum",
989                    "-y",
990                    "--disablerepo=bad",
991                    "--enablerepo=good",
992                    "--branch=foo",
993                    "--setopt",
994                    "obsoletes=0",
995                    "--setopt",
996                    "plugins=0",
997                    "install",
998                    "foo",
999                ],
1000                env={},
1001                output_loglevel="trace",
1002                python_shell=False,
1003                ignore_retcode=False,
1004                redirect_stderr=True,
1005            )
1006
1007
1008def test_remove_with_epoch():
1009    """
1010    Tests that we properly identify a version containing an epoch for
1011    deinstallation.
1012
1013    You can deinstall pkgs only without the epoch if no arch is provided:
1014
1015    .. code-block:: bash
1016
1017        yum remove PackageKit-yum-1.1.10-2.el7.centos
1018    """
1019    name = "foo"
1020    installed = "8:3.8.12-4.n.el7"
1021    list_pkgs_mock = MagicMock(
1022        side_effect=lambda **kwargs: {
1023            name: [installed] if kwargs.get("versions_as_list", False) else installed
1024        }
1025    )
1026    cmd_mock = MagicMock(
1027        return_value={"pid": 12345, "retcode": 0, "stdout": "", "stderr": ""}
1028    )
1029    salt_mock = {
1030        "cmd.run_all": cmd_mock,
1031        "lowpkg.version_cmp": rpm.version_cmp,
1032        "pkg_resource.parse_targets": MagicMock(
1033            return_value=({name: installed}, "repository")
1034        ),
1035    }
1036    full_pkg_string = "-".join((name, installed[2:]))
1037    with patch.object(yumpkg, "list_pkgs", list_pkgs_mock), patch(
1038        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1039    ), patch.dict(yumpkg.__salt__, salt_mock):
1040
1041        with patch.dict(yumpkg.__grains__, {"os": "CentOS", "osrelease": 7}):
1042            expected = ["yum", "-y", "remove", full_pkg_string]
1043            yumpkg.remove(name)
1044            call = cmd_mock.mock_calls[0][1][0]
1045            assert call == expected, call
1046
1047
1048def test_remove_with_epoch_and_arch_info():
1049    """
1050    Tests that we properly identify a version containing an epoch and arch
1051    deinstallation.
1052
1053    You can deinstall pkgs with or without epoch in combination with the arch.
1054    Here we test for the absence of the epoch, but the presence for the arch:
1055
1056    .. code-block:: bash
1057
1058        yum remove PackageKit-yum-1.1.10-2.el7.centos.x86_64
1059    """
1060    arch = "x86_64"
1061    name = "foo"
1062    name_and_arch = name + "." + arch
1063    installed = "8:3.8.12-4.n.el7"
1064    list_pkgs_mock = MagicMock(
1065        side_effect=lambda **kwargs: {
1066            name_and_arch: [installed]
1067            if kwargs.get("versions_as_list", False)
1068            else installed
1069        }
1070    )
1071    cmd_mock = MagicMock(
1072        return_value={"pid": 12345, "retcode": 0, "stdout": "", "stderr": ""}
1073    )
1074    salt_mock = {
1075        "cmd.run_all": cmd_mock,
1076        "lowpkg.version_cmp": rpm.version_cmp,
1077        "pkg_resource.parse_targets": MagicMock(
1078            return_value=({name_and_arch: installed}, "repository")
1079        ),
1080    }
1081    full_pkg_string = "-".join((name, installed[2:]))
1082    with patch.object(yumpkg, "list_pkgs", list_pkgs_mock), patch(
1083        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1084    ), patch.dict(yumpkg.__salt__, salt_mock):
1085
1086        with patch.dict(yumpkg.__grains__, {"os": "CentOS", "osrelease": 7}):
1087            expected = ["yum", "-y", "remove", full_pkg_string + "." + arch]
1088            yumpkg.remove(name)
1089            call = cmd_mock.mock_calls[0][1][0]
1090            assert call == expected, call
1091
1092
1093def test_remove_with_wildcard():
1094    """
1095    Tests that we properly identify a version containing an epoch for
1096    deinstallation.
1097
1098    You can deinstall pkgs only without the epoch if no arch is provided:
1099
1100    .. code-block:: bash
1101
1102        yum remove foo*
1103
1104        yum remove pkgs='[{"foo*": "8:3.8.12-4.n.el7"}]'
1105    """
1106    name = "foobarpkg"
1107    installed = "8:3.8.12-4.n.el7"
1108    list_pkgs_mock = MagicMock(
1109        side_effect=lambda **kwargs: {
1110            name: [installed] if kwargs.get("versions_as_list", False) else installed
1111        }
1112    )
1113    cmd_mock = MagicMock(
1114        return_value={"pid": 12345, "retcode": 0, "stdout": "", "stderr": ""}
1115    )
1116    salt_mock = {
1117        "cmd.run_all": cmd_mock,
1118        "lowpkg.version_cmp": rpm.version_cmp,
1119        "pkg_resource.parse_targets": MagicMock(
1120            return_value=({name: installed}, "repository")
1121        ),
1122    }
1123    full_pkg_string = "-".join((name, installed[2:]))
1124    with patch.object(yumpkg, "list_pkgs", list_pkgs_mock), patch(
1125        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1126    ), patch.dict(yumpkg.__salt__, salt_mock):
1127
1128        with patch.dict(yumpkg.__grains__, {"os": "CentOS", "osrelease": 7}):
1129            expected = ["yum", "-y", "remove", full_pkg_string]
1130            yumpkg.remove("foo*")
1131            call = cmd_mock.mock_calls[0][1][0]
1132            assert call == expected, call
1133
1134            expected = ["yum", "-y", "remove", full_pkg_string]
1135            yumpkg.remove(pkgs=[{"foo*": "8:3.8.12-4.n.el7"}])
1136            call = cmd_mock.mock_calls[0][1][0]
1137            assert call == expected, call
1138
1139
1140def test_install_with_epoch():
1141    """
1142    Tests that we properly identify a version containing an epoch as an
1143    upgrade instead of a downgrade.
1144    """
1145    name = "foo"
1146    old = "8:3.8.12-6.n.el7"
1147    new = "9:3.8.12-4.n.el7"
1148    list_pkgs_mock = MagicMock(
1149        side_effect=lambda **kwargs: {
1150            name: [old] if kwargs.get("versions_as_list", False) else old
1151        }
1152    )
1153    cmd_mock = MagicMock(
1154        return_value={"pid": 12345, "retcode": 0, "stdout": "", "stderr": ""}
1155    )
1156    salt_mock = {
1157        "cmd.run_all": cmd_mock,
1158        "lowpkg.version_cmp": rpm.version_cmp,
1159        "pkg_resource.parse_targets": MagicMock(
1160            return_value=({name: new}, "repository")
1161        ),
1162    }
1163    full_pkg_string = "-".join((name, new[2:]))
1164    with patch.object(yumpkg, "list_pkgs", list_pkgs_mock), patch(
1165        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1166    ), patch.dict(yumpkg.__salt__, salt_mock):
1167
1168        # Test yum
1169        expected = ["yum", "-y", "install", full_pkg_string]
1170        with patch.dict(yumpkg.__context__, {"yum_bin": "yum"}), patch.dict(
1171            yumpkg.__grains__, {"os": "CentOS", "osrelease": 7}
1172        ):
1173            yumpkg.install("foo", version=new)
1174            call = cmd_mock.mock_calls[0][1][0]
1175            assert call == expected, call
1176
1177        # Test dnf
1178        expected = [
1179            "dnf",
1180            "-y",
1181            "--best",
1182            "--allowerasing",
1183            "install",
1184            full_pkg_string,
1185        ]
1186        yumpkg.__context__.pop("yum_bin")
1187        cmd_mock.reset_mock()
1188        with patch.dict(yumpkg.__context__, {"yum_bin": "dnf"}), patch.dict(
1189            yumpkg.__grains__, {"os": "Fedora", "osrelease": 27}
1190        ):
1191            yumpkg.install("foo", version=new)
1192            call = cmd_mock.mock_calls[0][1][0]
1193            assert call == expected, call
1194
1195
1196@pytest.mark.skipif(not salt.utils.platform.is_linux(), reason="Only run on Linux")
1197def test_install_error_reporting():
1198    """
1199    Tests that we properly report yum/dnf errors.
1200    """
1201    name = "foo"
1202    old = "8:3.8.12-6.n.el7"
1203    new = "9:3.8.12-4.n.el7"
1204    list_pkgs_mock = MagicMock(
1205        side_effect=lambda **kwargs: {
1206            name: [old] if kwargs.get("versions_as_list", False) else old
1207        }
1208    )
1209    salt_mock = {
1210        "cmd.run_all": cmdmod.run_all,
1211        "lowpkg.version_cmp": rpm.version_cmp,
1212        "pkg_resource.parse_targets": MagicMock(
1213            return_value=({name: new}, "repository")
1214        ),
1215    }
1216    full_pkg_string = "-".join((name, new[2:]))
1217    with patch.object(yumpkg, "list_pkgs", list_pkgs_mock), patch(
1218        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1219    ), patch.dict(yumpkg.__salt__, salt_mock), patch.object(
1220        yumpkg, "_yum", MagicMock(return_value="cat")
1221    ):
1222
1223        expected = {
1224            "changes": {},
1225            "errors": [
1226                "cat: invalid option -- 'y'\nTry 'cat --help' for more information."
1227            ],
1228        }
1229        with pytest.raises(CommandExecutionError) as exc_info:
1230            yumpkg.install("foo", version=new)
1231        assert exc_info.value.info == expected, exc_info.value.info
1232
1233
1234def test_upgrade_with_options():
1235    with patch.object(yumpkg, "list_pkgs", MagicMock(return_value={})), patch(
1236        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1237    ):
1238
1239        # with fromrepo
1240        cmd = MagicMock(return_value={"retcode": 0})
1241        with patch.dict(yumpkg.__salt__, {"cmd.run_all": cmd}):
1242            yumpkg.upgrade(
1243                refresh=False,
1244                fromrepo="good",
1245                exclude="kernel*",
1246                branch="foo",
1247                setopt="obsoletes=0,plugins=0",
1248            )
1249            cmd.assert_called_once_with(
1250                [
1251                    "yum",
1252                    "--quiet",
1253                    "-y",
1254                    "--disablerepo=*",
1255                    "--enablerepo=good",
1256                    "--branch=foo",
1257                    "--setopt",
1258                    "obsoletes=0",
1259                    "--setopt",
1260                    "plugins=0",
1261                    "--exclude=kernel*",
1262                    "upgrade",
1263                ],
1264                env={},
1265                output_loglevel="trace",
1266                python_shell=False,
1267            )
1268
1269        # without fromrepo
1270        cmd = MagicMock(return_value={"retcode": 0})
1271        with patch.dict(yumpkg.__salt__, {"cmd.run_all": cmd}):
1272            yumpkg.upgrade(
1273                refresh=False,
1274                enablerepo="good",
1275                disablerepo="bad",
1276                exclude="kernel*",
1277                branch="foo",
1278                setopt="obsoletes=0,plugins=0",
1279            )
1280            cmd.assert_called_once_with(
1281                [
1282                    "yum",
1283                    "--quiet",
1284                    "-y",
1285                    "--disablerepo=bad",
1286                    "--enablerepo=good",
1287                    "--branch=foo",
1288                    "--setopt",
1289                    "obsoletes=0",
1290                    "--setopt",
1291                    "plugins=0",
1292                    "--exclude=kernel*",
1293                    "upgrade",
1294                ],
1295                env={},
1296                output_loglevel="trace",
1297                python_shell=False,
1298            )
1299
1300
1301def test_info_installed_with_all_versions():
1302    """
1303    Test the return information of all versions for the named package(s), installed on the system.
1304
1305    :return:
1306    """
1307    run_out = {
1308        "virgo-dummy": [
1309            {
1310                "build_date": "2015-07-09T10:55:19Z",
1311                "vendor": "openSUSE Build Service",
1312                "description": (
1313                    "This is the Virgo dummy package used for testing SUSE Manager"
1314                ),
1315                "license": "GPL-2.0",
1316                "build_host": "sheep05",
1317                "url": "http://www.suse.com",
1318                "build_date_time_t": 1436432119,
1319                "relocations": "(not relocatable)",
1320                "source_rpm": "virgo-dummy-1.0-1.1.src.rpm",
1321                "install_date": "2016-02-23T16:31:57Z",
1322                "install_date_time_t": 1456241517,
1323                "summary": "Virgo dummy package",
1324                "version": "1.0",
1325                "signature": (
1326                    "DSA/SHA1, Thu Jul  9 08:55:33 2015, Key ID 27fa41bd8a7c64f9"
1327                ),
1328                "release": "1.1",
1329                "group": "Applications/System",
1330                "arch": "i686",
1331                "size": "17992",
1332            },
1333            {
1334                "build_date": "2015-07-09T10:15:19Z",
1335                "vendor": "openSUSE Build Service",
1336                "description": (
1337                    "This is the Virgo dummy package used for testing SUSE Manager"
1338                ),
1339                "license": "GPL-2.0",
1340                "build_host": "sheep05",
1341                "url": "http://www.suse.com",
1342                "build_date_time_t": 1436432119,
1343                "relocations": "(not relocatable)",
1344                "source_rpm": "virgo-dummy-1.0-1.1.src.rpm",
1345                "install_date": "2016-02-23T16:31:57Z",
1346                "install_date_time_t": 14562415127,
1347                "summary": "Virgo dummy package",
1348                "version": "1.0",
1349                "signature": (
1350                    "DSA/SHA1, Thu Jul  9 08:55:33 2015, Key ID 27fa41bd8a7c64f9"
1351                ),
1352                "release": "1.1",
1353                "group": "Applications/System",
1354                "arch": "x86_64",
1355                "size": "13124",
1356            },
1357        ],
1358        "libopenssl1_0_0": [
1359            {
1360                "build_date": "2015-11-04T23:20:34Z",
1361                "vendor": "SUSE LLC <https://www.suse.com/>",
1362                "description": "The OpenSSL Project is a collaborative effort.",
1363                "license": "OpenSSL",
1364                "build_host": "sheep11",
1365                "url": "https://www.openssl.org/",
1366                "build_date_time_t": 1446675634,
1367                "relocations": "(not relocatable)",
1368                "source_rpm": "openssl-1.0.1i-34.1.src.rpm",
1369                "install_date": "2016-02-23T16:31:35Z",
1370                "install_date_time_t": 1456241495,
1371                "summary": "Secure Sockets and Transport Layer Security",
1372                "version": "1.0.1i",
1373                "signature": (
1374                    "RSA/SHA256, Wed Nov  4 22:21:34 2015, Key ID 70af9e8139db7c82"
1375                ),
1376                "release": "34.1",
1377                "group": "Productivity/Networking/Security",
1378                "packager": "https://www.suse.com/",
1379                "arch": "x86_64",
1380                "size": "2576912",
1381            }
1382        ],
1383    }
1384    with patch.dict(yumpkg.__salt__, {"lowpkg.info": MagicMock(return_value=run_out)}):
1385        installed = yumpkg.info_installed(all_versions=True)
1386        # Test overall products length
1387        assert len(installed) == 2
1388
1389        # Test multiple versions for the same package
1390        for pkg_name, pkg_info_list in installed.items():
1391            assert len(pkg_info_list) == 2 if pkg_name == "virgo-dummy" else 1
1392            for info in pkg_info_list:
1393                assert info["arch"] in ("x86_64", "i686")
1394
1395
1396def test_pkg_hold_yum():
1397    """
1398    Tests that we properly identify versionlock plugin when using yum
1399    for RHEL/CentOS 7 and Fedora < 22
1400    """
1401
1402    # Test RHEL/CentOS 7
1403    list_pkgs_mock = {
1404        "yum-plugin-versionlock": "0:1.0.0-0.n.el7",
1405        "yum-versionlock": "0:1.0.0-0.n.el7",
1406    }
1407
1408    cmd = MagicMock(return_value={"retcode": 0})
1409    with patch.object(
1410        yumpkg, "list_pkgs", MagicMock(return_value=list_pkgs_mock)
1411    ), patch.object(yumpkg, "list_holds", MagicMock(return_value=[])), patch.dict(
1412        yumpkg.__salt__, {"cmd.run_all": cmd}
1413    ), patch(
1414        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1415    ):
1416        yumpkg.hold("foo")
1417        cmd.assert_called_once_with(
1418            ["yum", "versionlock", "foo"],
1419            env={},
1420            output_loglevel="trace",
1421            python_shell=False,
1422        )
1423
1424    # Test Fedora 20
1425    cmd = MagicMock(return_value={"retcode": 0})
1426    with patch.dict(yumpkg.__context__, {"yum_bin": "yum"}), patch.dict(
1427        yumpkg.__grains__, {"os": "Fedora", "osrelease": 20}
1428    ), patch.object(
1429        yumpkg, "list_pkgs", MagicMock(return_value=list_pkgs_mock)
1430    ), patch.object(
1431        yumpkg, "list_holds", MagicMock(return_value=[])
1432    ), patch.dict(
1433        yumpkg.__salt__, {"cmd.run_all": cmd}
1434    ), patch(
1435        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1436    ):
1437        yumpkg.hold("foo")
1438        cmd.assert_called_once_with(
1439            ["yum", "versionlock", "foo"],
1440            env={},
1441            output_loglevel="trace",
1442            python_shell=False,
1443        )
1444
1445
1446def test_pkg_hold_tdnf():
1447    """
1448    Tests that we raise a SaltInvocationError if we try to use
1449    hold-related functions on Photon OS.
1450    """
1451    with patch.dict(yumpkg.__context__, {"yum_bin": "tdnf"}):
1452        with pytest.raises(SaltInvocationError) as exc_info:
1453            yumpkg.hold("foo")
1454
1455
1456def test_pkg_hold_dnf():
1457    """
1458    Tests that we properly identify versionlock plugin when using dnf
1459    for RHEL/CentOS 8 and Fedora >= 22
1460    """
1461
1462    # Test RHEL/CentOS 8
1463    list_pkgs_mock = {
1464        "python2-dnf-plugin-versionlock": "0:1.0.0-0.n.el8",
1465        "python3-dnf-plugin-versionlock": "0:1.0.0-0.n.el8",
1466    }
1467
1468    yumpkg.__context__.pop("yum_bin")
1469    cmd = MagicMock(return_value={"retcode": 0})
1470    with patch.dict(yumpkg.__context__, {"yum_bin": "dnf"}), patch.dict(
1471        yumpkg.__grains__, {"osmajorrelease": 8}
1472    ), patch.object(
1473        yumpkg, "list_pkgs", MagicMock(return_value=list_pkgs_mock)
1474    ), patch.object(
1475        yumpkg, "list_holds", MagicMock(return_value=[])
1476    ), patch.dict(
1477        yumpkg.__salt__, {"cmd.run_all": cmd}
1478    ), patch(
1479        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1480    ):
1481        yumpkg.hold("foo")
1482        cmd.assert_called_once_with(
1483            ["dnf", "versionlock", "foo"],
1484            env={},
1485            output_loglevel="trace",
1486            python_shell=False,
1487        )
1488
1489    # Test Fedora 26+
1490    cmd = MagicMock(return_value={"retcode": 0})
1491    with patch.dict(yumpkg.__context__, {"yum_bin": "dnf"}), patch.dict(
1492        yumpkg.__grains__, {"os": "Fedora", "osrelease": 26}
1493    ), patch.object(
1494        yumpkg, "list_pkgs", MagicMock(return_value=list_pkgs_mock)
1495    ), patch.object(
1496        yumpkg, "list_holds", MagicMock(return_value=[])
1497    ), patch.dict(
1498        yumpkg.__salt__, {"cmd.run_all": cmd}
1499    ), patch(
1500        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1501    ):
1502        yumpkg.hold("foo")
1503        cmd.assert_called_once_with(
1504            ["dnf", "versionlock", "foo"],
1505            env={},
1506            output_loglevel="trace",
1507            python_shell=False,
1508        )
1509
1510    # Test Fedora 22-25
1511    list_pkgs_mock = {
1512        "python-dnf-plugins-extras-versionlock": "0:1.0.0-0.n.el8",
1513        "python3-dnf-plugins-extras-versionlock": "0:1.0.0-0.n.el8",
1514    }
1515
1516    cmd = MagicMock(return_value={"retcode": 0})
1517    with patch.dict(yumpkg.__context__, {"yum_bin": "dnf"}), patch.dict(
1518        yumpkg.__grains__, {"os": "Fedora", "osrelease": 25}
1519    ), patch.object(
1520        yumpkg, "list_pkgs", MagicMock(return_value=list_pkgs_mock)
1521    ), patch.object(
1522        yumpkg, "list_holds", MagicMock(return_value=[])
1523    ), patch.dict(
1524        yumpkg.__salt__, {"cmd.run_all": cmd}
1525    ), patch(
1526        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1527    ):
1528        yumpkg.hold("foo")
1529        cmd.assert_called_once_with(
1530            ["dnf", "versionlock", "foo"],
1531            env={},
1532            output_loglevel="trace",
1533            python_shell=False,
1534        )
1535
1536
1537@pytest.mark.skipif(not yumpkg.HAS_YUM, reason="Could not import yum")
1538def test_yum_base_error():
1539    with patch("yum.YumBase") as mock_yum_yumbase:
1540        mock_yum_yumbase.side_effect = CommandExecutionError
1541        with pytest.raises(CommandExecutionError):
1542            yumpkg._get_yum_config()
1543
1544
1545def test_group_info():
1546    """
1547    Test yumpkg.group_info parsing
1548    """
1549    expected = {
1550        "conditional": [],
1551        "default": ["qgnomeplatform", "xdg-desktop-portal-gtk"],
1552        "description": (
1553            "GNOME is a highly intuitive and user friendly desktop environment."
1554        ),
1555        "group": "GNOME",
1556        "id": "gnome-desktop",
1557        "mandatory": [
1558            "NetworkManager-libreswan-gnome",
1559            "PackageKit-command-not-found",
1560            "PackageKit-gtk3-module",
1561            "abrt-desktop",
1562            "at-spi2-atk",
1563            "at-spi2-core",
1564            "avahi",
1565            "baobab",
1566            "caribou",
1567            "caribou-gtk2-module",
1568            "caribou-gtk3-module",
1569            "cheese",
1570            "chrome-gnome-shell",
1571            "compat-cheese314",
1572            "control-center",
1573            "dconf",
1574            "empathy",
1575            "eog",
1576            "evince",
1577            "evince-nautilus",
1578            "file-roller",
1579            "file-roller-nautilus",
1580            "firewall-config",
1581            "firstboot",
1582            "fprintd-pam",
1583            "gdm",
1584            "gedit",
1585            "glib-networking",
1586            "gnome-bluetooth",
1587            "gnome-boxes",
1588            "gnome-calculator",
1589            "gnome-classic-session",
1590            "gnome-clocks",
1591            "gnome-color-manager",
1592            "gnome-contacts",
1593            "gnome-dictionary",
1594            "gnome-disk-utility",
1595            "gnome-font-viewer",
1596            "gnome-getting-started-docs",
1597            "gnome-icon-theme",
1598            "gnome-icon-theme-extras",
1599            "gnome-icon-theme-symbolic",
1600            "gnome-initial-setup",
1601            "gnome-packagekit",
1602            "gnome-packagekit-updater",
1603            "gnome-screenshot",
1604            "gnome-session",
1605            "gnome-session-xsession",
1606            "gnome-settings-daemon",
1607            "gnome-shell",
1608            "gnome-software",
1609            "gnome-system-log",
1610            "gnome-system-monitor",
1611            "gnome-terminal",
1612            "gnome-terminal-nautilus",
1613            "gnome-themes-standard",
1614            "gnome-tweak-tool",
1615            "gnome-user-docs",
1616            "gnome-weather",
1617            "gucharmap",
1618            "gvfs-afc",
1619            "gvfs-afp",
1620            "gvfs-archive",
1621            "gvfs-fuse",
1622            "gvfs-goa",
1623            "gvfs-gphoto2",
1624            "gvfs-mtp",
1625            "gvfs-smb",
1626            "initial-setup-gui",
1627            "libcanberra-gtk2",
1628            "libcanberra-gtk3",
1629            "libproxy-mozjs",
1630            "librsvg2",
1631            "libsane-hpaio",
1632            "metacity",
1633            "mousetweaks",
1634            "nautilus",
1635            "nautilus-sendto",
1636            "nm-connection-editor",
1637            "orca",
1638            "redhat-access-gui",
1639            "sane-backends-drivers-scanners",
1640            "seahorse",
1641            "setroubleshoot",
1642            "sushi",
1643            "totem",
1644            "totem-nautilus",
1645            "vinagre",
1646            "vino",
1647            "xdg-user-dirs-gtk",
1648            "yelp",
1649        ],
1650        "optional": [
1651            "",
1652            "alacarte",
1653            "dconf-editor",
1654            "dvgrab",
1655            "fonts-tweak-tool",
1656            "gconf-editor",
1657            "gedit-plugins",
1658            "gnote",
1659            "libappindicator-gtk3",
1660            "seahorse-nautilus",
1661            "seahorse-sharing",
1662            "vim-X11",
1663            "xguest",
1664        ],
1665        "type": "package group",
1666    }
1667    cmd_out = """Group: GNOME
1668     Group-Id: gnome-desktop
1669     Description: GNOME is a highly intuitive and user friendly desktop environment.
1670     Mandatory Packages:
1671       =NetworkManager-libreswan-gnome
1672       =PackageKit-command-not-found
1673       =PackageKit-gtk3-module
1674        abrt-desktop
1675       =at-spi2-atk
1676       =at-spi2-core
1677       =avahi
1678       =baobab
1679       -caribou
1680       -caribou-gtk2-module
1681       -caribou-gtk3-module
1682       =cheese
1683       =chrome-gnome-shell
1684       =compat-cheese314
1685       =control-center
1686       =dconf
1687       =empathy
1688       =eog
1689       =evince
1690       =evince-nautilus
1691       =file-roller
1692       =file-roller-nautilus
1693       =firewall-config
1694       =firstboot
1695        fprintd-pam
1696       =gdm
1697       =gedit
1698       =glib-networking
1699       =gnome-bluetooth
1700       =gnome-boxes
1701       =gnome-calculator
1702       =gnome-classic-session
1703       =gnome-clocks
1704       =gnome-color-manager
1705       =gnome-contacts
1706       =gnome-dictionary
1707       =gnome-disk-utility
1708       =gnome-font-viewer
1709       =gnome-getting-started-docs
1710       =gnome-icon-theme
1711       =gnome-icon-theme-extras
1712       =gnome-icon-theme-symbolic
1713       =gnome-initial-setup
1714       =gnome-packagekit
1715       =gnome-packagekit-updater
1716       =gnome-screenshot
1717       =gnome-session
1718       =gnome-session-xsession
1719       =gnome-settings-daemon
1720       =gnome-shell
1721       =gnome-software
1722       =gnome-system-log
1723       =gnome-system-monitor
1724       =gnome-terminal
1725       =gnome-terminal-nautilus
1726       =gnome-themes-standard
1727       =gnome-tweak-tool
1728       =gnome-user-docs
1729       =gnome-weather
1730       =gucharmap
1731       =gvfs-afc
1732       =gvfs-afp
1733       =gvfs-archive
1734       =gvfs-fuse
1735       =gvfs-goa
1736       =gvfs-gphoto2
1737       =gvfs-mtp
1738       =gvfs-smb
1739        initial-setup-gui
1740       =libcanberra-gtk2
1741       =libcanberra-gtk3
1742       =libproxy-mozjs
1743       =librsvg2
1744       =libsane-hpaio
1745       =metacity
1746       =mousetweaks
1747       =nautilus
1748       =nautilus-sendto
1749       =nm-connection-editor
1750       =orca
1751       -redhat-access-gui
1752       =sane-backends-drivers-scanners
1753       =seahorse
1754       =setroubleshoot
1755       =sushi
1756       =totem
1757       =totem-nautilus
1758       =vinagre
1759       =vino
1760       =xdg-user-dirs-gtk
1761       =yelp
1762     Default Packages:
1763       =qgnomeplatform
1764       =xdg-desktop-portal-gtk
1765     Optional Packages:
1766       alacarte
1767       dconf-editor
1768       dvgrab
1769       fonts-tweak-tool
1770       gconf-editor
1771       gedit-plugins
1772       gnote
1773       libappindicator-gtk3
1774       seahorse-nautilus
1775       seahorse-sharing
1776       vim-X11
1777       xguest
1778    """
1779    with patch.dict(
1780        yumpkg.__salt__, {"cmd.run_stdout": MagicMock(return_value=cmd_out)}
1781    ):
1782        info = yumpkg.group_info("@gnome-desktop")
1783        assert info == expected
1784
1785
1786def test_get_repo_with_existent_repo(list_repos_var):
1787    """
1788    Test get_repo with an existent repository
1789    Expected return is a populated dictionary
1790    """
1791    repo = "base-source"
1792    kwargs = {
1793        "baseurl": "http://vault.centos.org/centos/$releasever/os/Source/",
1794        "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
1795        "name": "CentOS-$releasever - Base Sources",
1796        "enabled": True,
1797    }
1798    parse_repo_file_return = (
1799        "",
1800        {
1801            "base-source": {
1802                "baseurl": "http://vault.centos.org/centos/$releasever/os/Source/",
1803                "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
1804                "name": "CentOS-$releasever - Base Sources",
1805                "enabled": "1",
1806            }
1807        },
1808    )
1809    expected = {
1810        "baseurl": "http://vault.centos.org/centos/$releasever/os/Source/",
1811        "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
1812        "name": "CentOS-$releasever - Base Sources",
1813        "enabled": "1",
1814    }
1815    patch_list_repos = patch.object(
1816        yumpkg, "list_repos", autospec=True, return_value=list_repos_var
1817    )
1818    patch_parse_repo_file = patch.object(
1819        yumpkg,
1820        "_parse_repo_file",
1821        autospec=True,
1822        return_value=parse_repo_file_return,
1823    )
1824
1825    with patch_list_repos, patch_parse_repo_file:
1826        ret = yumpkg.get_repo(repo, **kwargs)
1827    assert ret == expected, ret
1828
1829
1830def test_get_repo_with_non_existent_repo(list_repos_var):
1831    """
1832    Test get_repo with an non existent repository
1833    Expected return is an empty dictionary
1834    """
1835    repo = "non-existent-repository"
1836    kwargs = {
1837        "baseurl": "http://fake.centos.org/centos/$releasever/os/Non-Existent/",
1838        "gpgkey": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7",
1839        "name": "CentOS-$releasever - Non-Existent Repository",
1840        "enabled": True,
1841    }
1842    expected = {}
1843    patch_list_repos = patch.object(
1844        yumpkg, "list_repos", autospec=True, return_value=list_repos_var
1845    )
1846
1847    with patch_list_repos:
1848        ret = yumpkg.get_repo(repo, **kwargs)
1849    assert ret == expected, ret
1850
1851
1852def test_pkg_update_dnf():
1853    """
1854    Tests that the proper CLI options are added when obsoletes=False
1855    """
1856    name = "foo"
1857    old = "1.2.2-1.fc31"
1858    new = "1.2.3-1.fc31"
1859    cmd_mock = MagicMock(return_value={"retcode": 0})
1860    list_pkgs_mock = MagicMock(side_effect=[{name: old}, {name: new}])
1861    parse_targets_mock = MagicMock(return_value=({"foo": None}, "repository"))
1862    with patch.dict(
1863        yumpkg.__salt__,
1864        {"cmd.run_all": cmd_mock, "pkg_resource.parse_targets": parse_targets_mock},
1865    ), patch.object(yumpkg, "refresh_db", MagicMock()), patch.object(
1866        yumpkg, "list_pkgs", list_pkgs_mock
1867    ), patch.object(
1868        yumpkg, "_yum", MagicMock(return_value="dnf")
1869    ), patch(
1870        "salt.utils.systemd.has_scope", MagicMock(return_value=False)
1871    ):
1872        ret = yumpkg.update(name, setopt="obsoletes=0,plugins=0")
1873        expected = {name: {"old": old, "new": new}}
1874        assert ret == expected, ret
1875
1876        cmd_mock.assert_called_once_with(
1877            [
1878                "dnf",
1879                "--quiet",
1880                "-y",
1881                "--setopt",
1882                "plugins=0",
1883                "--setopt",
1884                "obsoletes=False",
1885                "upgrade",
1886                "foo",
1887            ],
1888            env={},
1889            output_loglevel="trace",
1890            python_shell=False,
1891        )
1892
1893
1894def test_call_yum_default():
1895    """
1896    Call default Yum/Dnf.
1897    :return:
1898    """
1899    with patch.dict(yumpkg.__context__, {"yum_bin": "fake-yum"}):
1900        with patch.dict(
1901            yumpkg.__salt__,
1902            {"cmd.run_all": MagicMock(), "config.get": MagicMock(return_value=False)},
1903        ):
1904            yumpkg._call_yum(["-y", "--do-something"])  # pylint: disable=W0106
1905            yumpkg.__salt__["cmd.run_all"].assert_called_once_with(
1906                ["fake-yum", "-y", "--do-something"],
1907                env={},
1908                output_loglevel="trace",
1909                python_shell=False,
1910            )
1911
1912
1913@patch("salt.utils.systemd.has_scope", MagicMock(return_value=True))
1914def test_call_yum_in_scope():
1915    """
1916    Call Yum/Dnf within the scope.
1917    :return:
1918    """
1919    with patch.dict(yumpkg.__context__, {"yum_bin": "fake-yum"}):
1920        with patch.dict(
1921            yumpkg.__salt__,
1922            {"cmd.run_all": MagicMock(), "config.get": MagicMock(return_value=True)},
1923        ):
1924            yumpkg._call_yum(["-y", "--do-something"])  # pylint: disable=W0106
1925            yumpkg.__salt__["cmd.run_all"].assert_called_once_with(
1926                ["systemd-run", "--scope", "fake-yum", "-y", "--do-something"],
1927                env={},
1928                output_loglevel="trace",
1929                python_shell=False,
1930            )
1931
1932
1933def test_call_yum_with_kwargs():
1934    """
1935    Call Yum/Dnf with the optinal keyword arguments.
1936    :return:
1937    """
1938    with patch.dict(yumpkg.__context__, {"yum_bin": "fake-yum"}):
1939        with patch.dict(
1940            yumpkg.__salt__,
1941            {"cmd.run_all": MagicMock(), "config.get": MagicMock(return_value=False)},
1942        ):
1943            yumpkg._call_yum(
1944                ["-y", "--do-something"],
1945                python_shell=True,
1946                output_loglevel="quiet",
1947                ignore_retcode=False,
1948                username="Darth Vader",
1949            )  # pylint: disable=W0106
1950            yumpkg.__salt__["cmd.run_all"].assert_called_once_with(
1951                ["fake-yum", "-y", "--do-something"],
1952                env={},
1953                ignore_retcode=False,
1954                output_loglevel="quiet",
1955                python_shell=True,
1956                username="Darth Vader",
1957            )
1958
1959
1960@pytest.mark.skipif(not salt.utils.systemd.booted(), reason="Requires systemd")
1961def test_services_need_restart():
1962    """
1963    Test that dnf needs-restarting output is parsed and
1964    salt.utils.systemd.pid_to_service is called as expected.
1965    """
1966    expected = ["firewalld", "salt-minion"]
1967
1968    dnf_mock = Mock(
1969        return_value="123 : /usr/bin/firewalld\n456 : /usr/bin/salt-minion\n"
1970    )
1971    systemd_mock = Mock(side_effect=["firewalld", "salt-minion"])
1972    with patch("salt.modules.yumpkg._yum", Mock(return_value="dnf")):
1973        with patch.dict(yumpkg.__salt__, {"cmd.run_stdout": dnf_mock}), patch(
1974            "salt.utils.systemd.pid_to_service", systemd_mock
1975        ):
1976            assert sorted(yumpkg.services_need_restart()) == expected
1977            systemd_mock.assert_has_calls([call("123"), call("456")])
1978
1979
1980def test_services_need_restart_requires_systemd():
1981    """Test that yumpkg.services_need_restart raises an error if systemd is unavailable."""
1982    with patch("salt.modules.yumpkg._yum", Mock(return_value="dnf")):
1983        with patch("salt.utils.systemd.booted", Mock(return_value=False)):
1984            pytest.raises(CommandExecutionError, yumpkg.services_need_restart)
1985
1986
1987def test_services_need_restart_requires_dnf():
1988    """Test that yumpkg.services_need_restart raises an error if DNF is unavailable."""
1989    with patch("salt.modules.yumpkg._yum", Mock(return_value="yum")):
1990        pytest.raises(CommandExecutionError, yumpkg.services_need_restart)
1991
1992
1993def test_61003_pkg_should_not_fail_when_target_not_in_old_pkgs():
1994    patch_list_pkgs = patch(
1995        "salt.modules.yumpkg.list_pkgs", return_value={}, autospec=True
1996    )
1997    patch_salt = patch.dict(
1998        yumpkg.__salt__,
1999        {
2000            "pkg_resource.parse_targets": Mock(
2001                return_value=[
2002                    {
2003                        "fnord-this-is-not-actually-a-package": "fnord-this-is-not-actually-a-package-1.2.3"
2004                    }
2005                ]
2006            )
2007        },
2008    )
2009    with patch_list_pkgs, patch_salt:
2010        # During the 3004rc1 we discoverd that if list_pkgs was missing
2011        # packages that were returned by parse_targets that yumpkg.remove would
2012        # catch on fire.  This ensures that won't go undetected again.
2013        yumpkg.remove()
2014