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

add install of networkx fix aggregate to properly work with requisites fix requisite checking to not be exponential fix pkg aggregate to work when multiple states specify the same package add some type hints to state.py to make the code easier to follow fix case of pkg aggregate duplicate package.
1294 lines
40 KiB
Python
1294 lines
40 KiB
Python
import logging
|
|
import textwrap
|
|
|
|
import pytest
|
|
|
|
import salt.modules.beacons as beaconmod
|
|
import salt.modules.cp as cp
|
|
import salt.modules.pacmanpkg as pacmanpkg
|
|
import salt.modules.pkg_resource as pkg_resource
|
|
import salt.modules.yumpkg as yumpkg
|
|
import salt.states.beacon as beaconstate
|
|
import salt.states.pkg as pkg
|
|
import salt.utils.state as state_utils
|
|
from salt.utils.event import SaltEvent
|
|
from tests.support.mock import MagicMock, patch
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
@pytest.fixture
|
|
def configure_loader_modules(minion_opts):
|
|
return {
|
|
cp: {
|
|
"__opts__": minion_opts,
|
|
},
|
|
pkg: {
|
|
"__env__": "base",
|
|
"__salt__": {},
|
|
"__grains__": {"os": "CentOS", "os_family": "RedHat"},
|
|
"__opts__": minion_opts,
|
|
"__instance_id__": "",
|
|
"__low__": {},
|
|
"__utils__": {"state.gen_tag": state_utils.gen_tag},
|
|
},
|
|
beaconstate: {
|
|
"__salt__": {},
|
|
"__opts__": minion_opts,
|
|
},
|
|
beaconmod: {
|
|
"__salt__": {},
|
|
"__opts__": minion_opts,
|
|
},
|
|
pacmanpkg: {
|
|
"__salt__": {},
|
|
"__opts__": minion_opts,
|
|
},
|
|
pkg_resource: {
|
|
"__salt__": {},
|
|
"__grains__": {"os": "CentOS", "os_family": "RedHat"},
|
|
},
|
|
yumpkg: {
|
|
"__salt__": {},
|
|
"__grains__": {"osarch": "x86_64", "osmajorrelease": 7},
|
|
"__opts__": minion_opts,
|
|
},
|
|
}
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def pkgs():
|
|
return {
|
|
"pkga": {"old": "1.0.1", "new": "2.0.1"},
|
|
"pkgb": {"old": "1.0.2", "new": "2.0.2"},
|
|
"pkgc": {"old": "1.0.3", "new": "2.0.3"},
|
|
}
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def list_pkgs():
|
|
return {
|
|
"pkga": "1.0.1",
|
|
"pkgb": "1.0.2",
|
|
"pkgc": "1.0.3",
|
|
}
|
|
|
|
|
|
def test_uptodate_with_changes(pkgs):
|
|
"""
|
|
Test pkg.uptodate with simulated changes
|
|
"""
|
|
|
|
list_upgrades = MagicMock(
|
|
return_value={pkgname: pkgver["new"] for pkgname, pkgver in pkgs.items()}
|
|
)
|
|
upgrade = MagicMock(return_value=pkgs)
|
|
version = MagicMock(side_effect=lambda pkgname, **_: pkgs[pkgname]["old"])
|
|
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"pkg.list_upgrades": list_upgrades,
|
|
"pkg.upgrade": upgrade,
|
|
"pkg.version": version,
|
|
},
|
|
):
|
|
# Run state with test=false
|
|
with patch.dict(pkg.__opts__, {"test": False}):
|
|
ret = pkg.uptodate("dummy")
|
|
assert ret["result"]
|
|
assert ret["changes"] == pkgs
|
|
|
|
# Run state with test=true
|
|
with patch.dict(pkg.__opts__, {"test": True}):
|
|
ret = pkg.uptodate("dummy")
|
|
assert ret["result"] is None
|
|
assert ret["changes"] == pkgs
|
|
|
|
|
|
def test_uptodate_with_pkgs_with_changes(pkgs):
|
|
"""
|
|
Test pkg.uptodate with simulated changes
|
|
"""
|
|
|
|
list_upgrades = MagicMock(
|
|
return_value={pkgname: pkgver["new"] for pkgname, pkgver in pkgs.items()}
|
|
)
|
|
upgrade = MagicMock(return_value=pkgs)
|
|
version = MagicMock(side_effect=lambda pkgname, **_: pkgs[pkgname]["old"])
|
|
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"pkg.list_upgrades": list_upgrades,
|
|
"pkg.upgrade": upgrade,
|
|
"pkg.version": version,
|
|
},
|
|
):
|
|
# Run state with test=false
|
|
with patch.dict(pkg.__opts__, {"test": False}):
|
|
ret = pkg.uptodate(
|
|
"dummy",
|
|
test=True,
|
|
pkgs=[pkgname for pkgname in pkgs],
|
|
)
|
|
assert ret["result"]
|
|
assert ret["changes"] == pkgs
|
|
|
|
# Run state with test=true
|
|
with patch.dict(pkg.__opts__, {"test": True}):
|
|
ret = pkg.uptodate(
|
|
"dummy",
|
|
test=True,
|
|
pkgs=[pkgname for pkgname in pkgs],
|
|
)
|
|
assert ret["result"] is None
|
|
assert ret["changes"] == pkgs
|
|
|
|
|
|
def test_uptodate_no_changes():
|
|
"""
|
|
Test pkg.uptodate with no changes
|
|
"""
|
|
list_upgrades = MagicMock(return_value={})
|
|
upgrade = MagicMock(return_value={})
|
|
|
|
with patch.dict(
|
|
pkg.__salt__, {"pkg.list_upgrades": list_upgrades, "pkg.upgrade": upgrade}
|
|
):
|
|
# Run state with test=false
|
|
with patch.dict(pkg.__opts__, {"test": False}):
|
|
ret = pkg.uptodate("dummy")
|
|
assert ret["result"]
|
|
assert ret["changes"] == {}
|
|
|
|
# Run state with test=true
|
|
with patch.dict(pkg.__opts__, {"test": True}):
|
|
ret = pkg.uptodate("dummy")
|
|
assert ret["result"]
|
|
assert ret["changes"] == {}
|
|
|
|
|
|
def test_uptodate_with_pkgs_no_changes(pkgs):
|
|
"""
|
|
Test pkg.uptodate with no changes
|
|
"""
|
|
|
|
list_upgrades = MagicMock(return_value={})
|
|
upgrade = MagicMock(return_value={})
|
|
|
|
with patch.dict(
|
|
pkg.__salt__, {"pkg.list_upgrades": list_upgrades, "pkg.upgrade": upgrade}
|
|
):
|
|
# Run state with test=false
|
|
with patch.dict(pkg.__opts__, {"test": False}):
|
|
ret = pkg.uptodate(
|
|
"dummy",
|
|
test=True,
|
|
pkgs=[pkgname for pkgname in pkgs],
|
|
)
|
|
assert ret["result"]
|
|
assert ret["changes"] == {}
|
|
|
|
# Run state with test=true
|
|
with patch.dict(pkg.__opts__, {"test": True}):
|
|
ret = pkg.uptodate(
|
|
"dummy",
|
|
test=True,
|
|
pkgs=[pkgname for pkgname in pkgs],
|
|
)
|
|
assert ret["result"]
|
|
assert ret["changes"] == {}
|
|
|
|
|
|
def test_uptodate_with_failed_changes(pkgs):
|
|
"""
|
|
Test pkg.uptodate with simulated failed changes
|
|
"""
|
|
|
|
list_upgrades = MagicMock(
|
|
return_value={pkgname: pkgver["new"] for pkgname, pkgver in pkgs.items()}
|
|
)
|
|
upgrade = MagicMock(return_value={})
|
|
version = MagicMock(side_effect=lambda pkgname, **_: pkgs[pkgname]["old"])
|
|
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"pkg.list_upgrades": list_upgrades,
|
|
"pkg.upgrade": upgrade,
|
|
"pkg.version": version,
|
|
},
|
|
):
|
|
# Run state with test=false
|
|
with patch.dict(pkg.__opts__, {"test": False}):
|
|
ret = pkg.uptodate(
|
|
"dummy",
|
|
test=True,
|
|
pkgs=[pkgname for pkgname in pkgs],
|
|
)
|
|
assert not ret["result"]
|
|
assert ret["changes"] == {}
|
|
|
|
# Run state with test=true
|
|
with patch.dict(pkg.__opts__, {"test": True}):
|
|
ret = pkg.uptodate(
|
|
"dummy",
|
|
test=True,
|
|
pkgs=[pkgname for pkgname in pkgs],
|
|
)
|
|
assert ret["result"] is None
|
|
assert ret["changes"] == pkgs
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"version_string, expected_version_conditions",
|
|
[
|
|
(
|
|
"> 1.0.0, < 15.0.0, != 14.0.1",
|
|
[(">", "1.0.0"), ("<", "15.0.0"), ("!=", "14.0.1")],
|
|
),
|
|
(
|
|
"> 1.0.0,< 15.0.0,!= 14.0.1",
|
|
[(">", "1.0.0"), ("<", "15.0.0"), ("!=", "14.0.1")],
|
|
),
|
|
(">= 1.0.0, < 15.0.0", [(">=", "1.0.0"), ("<", "15.0.0")]),
|
|
(">=1.0.0,< 15.0.0", [(">=", "1.0.0"), ("<", "15.0.0")]),
|
|
("< 15.0.0", [("<", "15.0.0")]),
|
|
("<15.0.0", [("<", "15.0.0")]),
|
|
("15.0.0", [("==", "15.0.0")]),
|
|
("", []),
|
|
],
|
|
)
|
|
def test_parse_version_string(version_string, expected_version_conditions):
|
|
version_conditions = pkg._parse_version_string(version_string)
|
|
assert len(expected_version_conditions) == len(version_conditions)
|
|
for expected_version_condition, version_condition in zip(
|
|
expected_version_conditions, version_conditions
|
|
):
|
|
assert expected_version_condition[0] == version_condition[0]
|
|
assert expected_version_condition[1] == version_condition[1]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"version_string, installed_versions, expected_result",
|
|
[
|
|
("> 1.0.0, < 15.0.0, != 14.0.1", [], False),
|
|
("> 1.0.0, < 15.0.0, != 14.0.1", ["1.0.0"], False),
|
|
("> 1.0.0, < 15.0.0, != 14.0.1", ["14.0.1"], False),
|
|
("> 1.0.0, < 15.0.0, != 14.0.1", ["16.0.0"], False),
|
|
("> 1.0.0, < 15.0.0, != 14.0.1", ["2.0.0"], True),
|
|
(
|
|
"> 1.0.0, < 15.0.0, != 14.0.1",
|
|
["1.0.0", "14.0.1", "16.0.0", "2.0.0"],
|
|
True,
|
|
),
|
|
("> 15.0.0", [], False),
|
|
("> 15.0.0", ["1.0.0"], False),
|
|
("> 15.0.0", ["16.0.0"], True),
|
|
("15.0.0", [], False),
|
|
("15.0.0", ["15.0.0"], True),
|
|
# No version specified, whatever version installed. This is threated like ANY version installed fulfills.
|
|
("", ["15.0.0"], True),
|
|
# No version specified, no version installed.
|
|
("", [], False),
|
|
],
|
|
)
|
|
def test_fulfills_version_string(version_string, installed_versions, expected_result):
|
|
msg = "version_string: {}, installed_versions: {}, expected_result: {}".format(
|
|
version_string, installed_versions, expected_result
|
|
)
|
|
assert expected_result == pkg._fulfills_version_string(
|
|
installed_versions, version_string
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"installed_versions, operator, version, expected_result",
|
|
[
|
|
(["1.0.0", "14.0.1", "16.0.0", "2.0.0"], "==", "1.0.0", True),
|
|
(["1.0.0", "14.0.1", "16.0.0", "2.0.0"], ">=", "1.0.0", True),
|
|
(["1.0.0", "14.0.1", "16.0.0", "2.0.0"], ">", "1.0.0", True),
|
|
(["1.0.0", "14.0.1", "16.0.0", "2.0.0"], "<", "2.0.0", True),
|
|
(["1.0.0", "14.0.1", "16.0.0", "2.0.0"], "<=", "2.0.0", True),
|
|
(["1.0.0", "14.0.1", "16.0.0", "2.0.0"], "!=", "1.0.0", True),
|
|
(["1.0.0", "14.0.1", "16.0.0", "2.0.0"], "==", "17.0.0", False),
|
|
(["1.0.0"], "!=", "1.0.0", False),
|
|
([], "==", "17.0.0", False),
|
|
],
|
|
)
|
|
def test_fulfills_version_spec(installed_versions, operator, version, expected_result):
|
|
msg = (
|
|
"installed_versions: {}, operator: {}, version: {}, expected_result: {}".format(
|
|
installed_versions, operator, version, expected_result
|
|
)
|
|
)
|
|
assert expected_result == pkg._fulfills_version_spec(
|
|
installed_versions, operator, version
|
|
)
|
|
|
|
|
|
@pytest.mark.usefixtures("mocked_tcp_pub_client")
|
|
def test_mod_beacon(tmp_path):
|
|
"""
|
|
Test to create a beacon based on a pkg
|
|
"""
|
|
name = "vim"
|
|
|
|
with patch.dict(pkg.__salt__, {"beacons.list": MagicMock(return_value={})}):
|
|
with patch.dict(pkg.__states__, {"beacon.present": beaconstate.present}):
|
|
ret = pkg.mod_beacon(name, sfun="latest")
|
|
expected = {
|
|
"name": name,
|
|
"changes": {},
|
|
"result": False,
|
|
"comment": (
|
|
"pkg.latest does not work with the mod_beacon state function"
|
|
),
|
|
}
|
|
|
|
assert ret == expected
|
|
|
|
ret = pkg.mod_beacon(name, sfun="installed")
|
|
expected = {
|
|
"name": name,
|
|
"changes": {},
|
|
"result": True,
|
|
"comment": "Not adding beacon.",
|
|
}
|
|
|
|
assert ret == expected
|
|
|
|
event_returns = [
|
|
{
|
|
"complete": True,
|
|
"tag": "/salt/minion/minion_beacons_list_complete",
|
|
"beacons": {},
|
|
},
|
|
{
|
|
"complete": True,
|
|
"tag": "/salt/minion/minion_beacons_list_complete",
|
|
"beacons": {},
|
|
},
|
|
{
|
|
"complete": True,
|
|
"tag": "/salt/minion/minion_beacons_list_available_complete",
|
|
"beacons": ["pkg"],
|
|
},
|
|
{
|
|
"valid": True,
|
|
"tag": "/salt/minion/minion_beacon_validation_complete",
|
|
"vcomment": "Valid beacon configuration",
|
|
},
|
|
{
|
|
"complete": True,
|
|
"tag": "/salt/minion/minion_beacon_add_complete",
|
|
"beacons": {
|
|
"beacon_pkg_vim": [
|
|
{"pkgs": [name]},
|
|
{"interval": 60},
|
|
{"beacon_module": "pkg"},
|
|
]
|
|
},
|
|
},
|
|
]
|
|
mock = MagicMock(return_value=True)
|
|
beacon_state_mocks = {
|
|
"beacons.list": beaconmod.list_,
|
|
"beacons.add": beaconmod.add,
|
|
"beacons.list_available": beaconmod.list_available,
|
|
"event.fire": mock,
|
|
}
|
|
|
|
beacon_mod_mocks = {"event.fire": mock}
|
|
|
|
sock_dir = str(tmp_path / "test-socks")
|
|
with patch.dict(pkg.__states__, {"beacon.present": beaconstate.present}):
|
|
with patch.dict(beaconstate.__salt__, beacon_state_mocks):
|
|
with patch.dict(beaconmod.__salt__, beacon_mod_mocks):
|
|
with patch.dict(
|
|
beaconmod.__opts__, {"beacons": {}, "sock_dir": sock_dir}
|
|
):
|
|
with patch.object(
|
|
SaltEvent, "get_event", side_effect=event_returns
|
|
):
|
|
ret = pkg.mod_beacon(name, sfun="installed", beacon=True)
|
|
expected = {
|
|
"name": "beacon_pkg_vim",
|
|
"changes": {},
|
|
"result": True,
|
|
"comment": "Adding beacon_pkg_vim to beacons",
|
|
}
|
|
|
|
assert ret == expected
|
|
|
|
|
|
def test_mod_aggregate():
|
|
"""
|
|
Test to mod_aggregate function
|
|
"""
|
|
low = {
|
|
"state": "pkg",
|
|
"name": "other_pkgs",
|
|
"pkgs": ["byobu"],
|
|
"aggregate": True,
|
|
"fun": "installed",
|
|
}
|
|
|
|
chunks = [
|
|
{
|
|
"state": "file",
|
|
"name": "/tmp/install-vim",
|
|
"__sls__": "47628",
|
|
"__env__": "base",
|
|
"__id__": "/tmp/install-vim",
|
|
"order": 10000,
|
|
"fun": "managed",
|
|
},
|
|
{
|
|
"state": "file",
|
|
"name": "/tmp/install-tmux",
|
|
"__sls__": "47628",
|
|
"__env__": "base",
|
|
"__id__": "/tmp/install-tmux",
|
|
"order": 10001,
|
|
"fun": "managed",
|
|
},
|
|
{
|
|
"state": "pkg",
|
|
"name": "other_pkgs",
|
|
"__sls__": "47628",
|
|
"__env __": "base",
|
|
"__id__": "other_pkgs",
|
|
"pkgs": ["byobu"],
|
|
"aggregate": True,
|
|
"order": 10002,
|
|
"fun": "installed",
|
|
},
|
|
{
|
|
"state": "pkg",
|
|
"name": "bc",
|
|
"__sls__": "47628",
|
|
"__env__": "base",
|
|
"__id__": "bc",
|
|
"hold": True,
|
|
"order": 10003,
|
|
"fun": "installed",
|
|
},
|
|
{
|
|
"state": "pkg",
|
|
"name": "vim",
|
|
"__sls__": "47628",
|
|
"__env__": "base",
|
|
"__id__": "vim",
|
|
"require": ["/tmp/install-vim"],
|
|
"order": 10004,
|
|
"fun": "installed",
|
|
},
|
|
{
|
|
"state": "pkg",
|
|
"name": "tmux",
|
|
"__sls__": "47628",
|
|
"__env__": "base",
|
|
"__id__": "tmux",
|
|
"require": ["/tmp/install-tmux"],
|
|
"order": 10005,
|
|
"fun": "installed",
|
|
},
|
|
{
|
|
"state": "pkgrepo",
|
|
"name": "deb https://packages.cloud.google.com/apt cloud-sdk main",
|
|
"__sls__": "47628",
|
|
"__env__": "base",
|
|
"__id__": "google-cloud-repo",
|
|
"humanname": "Google Cloud SDK",
|
|
"file": "/etc/apt/sources.list.d/google-cloud-sdk.list",
|
|
"key_url": "https://packages.cloud.google.com/apt/doc/apt-key.gpg",
|
|
"order": 10006,
|
|
"fun": "managed",
|
|
},
|
|
{
|
|
"state": "pkg",
|
|
"name": "google-cloud-sdk",
|
|
"__sls__": "47628",
|
|
"__env__": "base",
|
|
"__id__": "google-cloud-sdk",
|
|
"require": ["google-cloud-repo"],
|
|
"order": 10007,
|
|
"fun": "installed",
|
|
},
|
|
]
|
|
|
|
running = {
|
|
"file_|-/tmp/install-vim_| -/tmp/install-vim_|-managed": {
|
|
"changes": {},
|
|
"comment": "File /tmp/install-vim exists with proper permissions. No changes made.",
|
|
"name": "/tmp/install-vim",
|
|
"result": True,
|
|
"__sls__": "47628",
|
|
"__run_num__": 0,
|
|
"start_time": "18:41:20.987275",
|
|
"duration": 5.833,
|
|
"__id__": "/tmp/install-vim",
|
|
},
|
|
"file_|-/tmp/install-tmux_|-/tmp/install-tmux_|-managed": {
|
|
"changes": {},
|
|
"comment": "File /tmp/install-tmux exists with proper permissions. No changes made.",
|
|
"name": "/tmp/install-tmux",
|
|
"result": True,
|
|
"__sls__": "47628",
|
|
"__run_num__": 1,
|
|
"start_time": "18:41:20.993258",
|
|
"duration": 1.263,
|
|
"__id__": "/tmp/install-tmux",
|
|
},
|
|
}
|
|
|
|
expected = {
|
|
"pkgs": ["byobu", "vim", "tmux", "google-cloud-sdk"],
|
|
"name": "other_pkgs",
|
|
"fun": "installed",
|
|
"aggregate": True,
|
|
"state": "pkg",
|
|
}
|
|
res = pkg.mod_aggregate(low, chunks, running)
|
|
assert res == expected
|
|
|
|
|
|
def test_installed_with_changes_test_true(list_pkgs):
|
|
"""
|
|
Test pkg.installed with simulated changes
|
|
"""
|
|
|
|
latest_pkgs = MagicMock(return_value="some version here")
|
|
list_pkgs = MagicMock(return_value=list_pkgs)
|
|
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"pkg.latest_version": latest_pkgs,
|
|
"pkg.list_pkgs": list_pkgs,
|
|
},
|
|
):
|
|
|
|
expected = {"dummy": {"new": "some version here", "old": ""}}
|
|
# Run state with test=true
|
|
with patch.dict(pkg.__opts__, {"test": True}):
|
|
ret = pkg.installed("dummy")
|
|
assert ret["result"] is None
|
|
assert ret["changes"] == expected
|
|
|
|
|
|
def test_installed_with_sources(list_pkgs, tmp_path):
|
|
"""
|
|
Test pkg.installed with passing `sources`
|
|
"""
|
|
|
|
list_pkgs = MagicMock(return_value=list_pkgs)
|
|
pkg_source = tmp_path / "pkga-package-0.3.0.deb"
|
|
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"cp.cache_file": cp.cache_file,
|
|
"pkg.list_pkgs": list_pkgs,
|
|
"pkg_resource.pack_sources": pkg_resource.pack_sources,
|
|
"lowpkg.bin_pkg_info": MagicMock(),
|
|
},
|
|
), patch("salt.fileclient.get_file_client", return_value=MagicMock()):
|
|
try:
|
|
ret = pkg.installed("install-pkgd", sources=[{"pkga": str(pkg_source)}])
|
|
assert ret["result"] is False
|
|
except TypeError as exc:
|
|
if "got multiple values for keyword argument 'saltenv'" in str(exc):
|
|
pytest.fail(f"TypeError should have not been raised: {exc}")
|
|
raise exc from None
|
|
|
|
|
|
@pytest.mark.parametrize("action", ["removed", "purged"])
|
|
def test_removed_purged_with_changes_test_true(list_pkgs, action):
|
|
"""
|
|
Test pkg.removed with simulated changes
|
|
"""
|
|
|
|
list_pkgs = MagicMock(return_value=list_pkgs)
|
|
|
|
mock_parse_targets = MagicMock(return_value=[{"pkga": None}, "repository"])
|
|
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"pkg.list_pkgs": list_pkgs,
|
|
"pkg_resource.parse_targets": mock_parse_targets,
|
|
"pkg_resource.version_clean": MagicMock(return_value=None),
|
|
},
|
|
):
|
|
expected = {"pkga": {"new": f"{action}", "old": ""}}
|
|
pkg_actions = {"removed": pkg.removed, "purged": pkg.purged}
|
|
|
|
# Run state with test=true
|
|
with patch.dict(pkg.__opts__, {"test": True}):
|
|
ret = pkg_actions[action]("pkga")
|
|
assert ret["result"] is None
|
|
assert ret["changes"] == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"package_manager",
|
|
[("Zypper"), ("YUM/DNF"), ("APT")],
|
|
)
|
|
def test_held_unheld(package_manager):
|
|
"""
|
|
Test pkg.held and pkg.unheld with Zypper, YUM/DNF and APT
|
|
"""
|
|
|
|
if package_manager == "Zypper":
|
|
list_holds_func = "pkg.list_locks"
|
|
list_holds_mock = MagicMock(
|
|
return_value={
|
|
"bar": {
|
|
"type": "package",
|
|
"match_type": "glob",
|
|
"case_sensitive": "on",
|
|
},
|
|
"minimal_base": {
|
|
"type": "pattern",
|
|
"match_type": "glob",
|
|
"case_sensitive": "on",
|
|
},
|
|
"baz": {
|
|
"type": "package",
|
|
"match_type": "glob",
|
|
"case_sensitive": "on",
|
|
},
|
|
}
|
|
)
|
|
elif package_manager == "YUM/DNF":
|
|
list_holds_func = "pkg.list_holds"
|
|
list_holds_mock = MagicMock(
|
|
return_value=[
|
|
"bar-0:1.2.3-1.1.*",
|
|
"baz-0:2.3.4-2.1.*",
|
|
]
|
|
)
|
|
elif package_manager == "APT":
|
|
list_holds_func = "pkg.get_selections"
|
|
list_holds_mock = MagicMock(
|
|
return_value={
|
|
"hold": [
|
|
"bar",
|
|
"baz",
|
|
]
|
|
}
|
|
)
|
|
|
|
def pkg_hold(name, pkgs=None, *_args, **__kwargs):
|
|
if name and pkgs is None:
|
|
pkgs = [name]
|
|
ret = {}
|
|
for pkg in pkgs:
|
|
ret.update(
|
|
{
|
|
pkg: {
|
|
"name": pkg,
|
|
"changes": {"new": "hold", "old": ""},
|
|
"result": True,
|
|
"comment": f"Package {pkg} is now being held.",
|
|
}
|
|
}
|
|
)
|
|
return ret
|
|
|
|
def pkg_unhold(name, pkgs=None, *_args, **__kwargs):
|
|
if name and pkgs is None:
|
|
pkgs = [name]
|
|
ret = {}
|
|
for pkg in pkgs:
|
|
ret.update(
|
|
{
|
|
pkg: {
|
|
"name": pkg,
|
|
"changes": {"new": "", "old": "hold"},
|
|
"result": True,
|
|
"comment": f"Package {pkg} is no longer held.",
|
|
}
|
|
}
|
|
)
|
|
return ret
|
|
|
|
hold_mock = MagicMock(side_effect=pkg_hold)
|
|
unhold_mock = MagicMock(side_effect=pkg_unhold)
|
|
|
|
# Testing with Zypper
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
list_holds_func: list_holds_mock,
|
|
"pkg.hold": hold_mock,
|
|
"pkg.unhold": unhold_mock,
|
|
},
|
|
):
|
|
# Holding one of two packages
|
|
ret = pkg.held("held-test", pkgs=["foo", "bar"])
|
|
assert "foo" in ret["changes"]
|
|
assert len(ret["changes"]) == 1
|
|
hold_mock.assert_called_once_with(name="held-test", pkgs=["foo"])
|
|
unhold_mock.assert_not_called()
|
|
|
|
hold_mock.reset_mock()
|
|
unhold_mock.reset_mock()
|
|
|
|
# Holding one of two packages and replacing all the rest held packages
|
|
ret = pkg.held("held-test", pkgs=["foo", "bar"], replace=True)
|
|
assert "foo" in ret["changes"]
|
|
assert "baz" in ret["changes"]
|
|
assert len(ret["changes"]) == 2
|
|
hold_mock.assert_called_once_with(name="held-test", pkgs=["foo"])
|
|
unhold_mock.assert_called_once_with(name="held-test", pkgs=["baz"])
|
|
|
|
hold_mock.reset_mock()
|
|
unhold_mock.reset_mock()
|
|
|
|
# Remove all holds
|
|
ret = pkg.held("held-test", pkgs=[], replace=True)
|
|
assert "bar" in ret["changes"]
|
|
assert "baz" in ret["changes"]
|
|
assert len(ret["changes"]) == 2
|
|
hold_mock.assert_not_called()
|
|
unhold_mock.assert_any_call(name="held-test", pkgs=["baz"])
|
|
unhold_mock.assert_any_call(name="held-test", pkgs=["bar"])
|
|
|
|
hold_mock.reset_mock()
|
|
unhold_mock.reset_mock()
|
|
|
|
# Unolding one of two packages
|
|
ret = pkg.unheld("held-test", pkgs=["foo", "bar"])
|
|
assert "bar" in ret["changes"]
|
|
assert len(ret["changes"]) == 1
|
|
unhold_mock.assert_called_once_with(name="held-test", pkgs=["bar"])
|
|
hold_mock.assert_not_called()
|
|
|
|
hold_mock.reset_mock()
|
|
unhold_mock.reset_mock()
|
|
|
|
# Remove all holds
|
|
ret = pkg.unheld("held-test", all=True)
|
|
assert "bar" in ret["changes"]
|
|
assert "baz" in ret["changes"]
|
|
assert len(ret["changes"]) == 2
|
|
hold_mock.assert_not_called()
|
|
unhold_mock.assert_any_call(name="held-test", pkgs=["baz"])
|
|
unhold_mock.assert_any_call(name="held-test", pkgs=["bar"])
|
|
|
|
|
|
def test_installed_with_single_normalize():
|
|
"""
|
|
Test pkg.installed with preventing multiple package name normalisation
|
|
"""
|
|
|
|
list_no_weird_installed = {
|
|
"pkga": "1.0.1",
|
|
"pkgb": "1.0.2",
|
|
"pkgc": "1.0.3",
|
|
}
|
|
list_no_weird_installed_ver_list = {
|
|
"pkga": ["1.0.1"],
|
|
"pkgb": ["1.0.2"],
|
|
"pkgc": ["1.0.3"],
|
|
}
|
|
list_with_weird_installed = {
|
|
"pkga": "1.0.1",
|
|
"pkgb": "1.0.2",
|
|
"pkgc": "1.0.3",
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": "20220214-2.1",
|
|
}
|
|
list_with_weird_installed_ver_list = {
|
|
"pkga": ["1.0.1"],
|
|
"pkgb": ["1.0.2"],
|
|
"pkgc": ["1.0.3"],
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": ["20220214-2.1"],
|
|
}
|
|
list_pkgs = MagicMock(
|
|
side_effect=[
|
|
# For the package with version specified
|
|
list_no_weird_installed_ver_list,
|
|
{},
|
|
list_no_weird_installed,
|
|
list_no_weird_installed_ver_list,
|
|
list_with_weird_installed,
|
|
list_with_weird_installed_ver_list,
|
|
# For the package with no version specified
|
|
list_no_weird_installed_ver_list,
|
|
{},
|
|
list_no_weird_installed,
|
|
list_no_weird_installed_ver_list,
|
|
list_with_weird_installed,
|
|
list_with_weird_installed_ver_list,
|
|
]
|
|
)
|
|
|
|
salt_dict = {
|
|
"pkg.install": yumpkg.install,
|
|
"pkg.list_pkgs": list_pkgs,
|
|
"pkg.normalize_name": yumpkg.normalize_name,
|
|
"pkg_resource.version_clean": pkg_resource.version_clean,
|
|
"pkg_resource.parse_targets": pkg_resource.parse_targets,
|
|
}
|
|
|
|
with patch("salt.modules.yumpkg.list_pkgs", list_pkgs), patch(
|
|
"salt.modules.yumpkg.version_cmp", MagicMock(return_value=0)
|
|
), patch(
|
|
"salt.modules.yumpkg._call_yum", MagicMock(return_value={"retcode": 0})
|
|
) as call_yum_mock, patch.dict(
|
|
pkg.__salt__, salt_dict
|
|
), patch.dict(
|
|
pkg_resource.__salt__, salt_dict
|
|
), patch.dict(
|
|
yumpkg.__salt__, salt_dict
|
|
), patch.dict(
|
|
yumpkg.__grains__, {"os": "CentOS", "osarch": "x86_64", "osmajorrelease": 7}
|
|
), patch.object(
|
|
yumpkg, "list_holds", MagicMock()
|
|
):
|
|
expected = {
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": {
|
|
"old": "",
|
|
"new": "20220214-2.1",
|
|
}
|
|
}
|
|
ret = pkg.installed(
|
|
"test_install",
|
|
pkgs=[{"weird-name-1.2.3-1234.5.6.test7tst.x86_64.noarch": "20220214-2.1"}],
|
|
)
|
|
call_yum_mock.assert_called_once()
|
|
assert (
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64-20220214-2.1"
|
|
in call_yum_mock.mock_calls[0].args[0]
|
|
)
|
|
assert ret["result"]
|
|
assert ret["changes"] == expected
|
|
|
|
call_yum_mock.reset_mock()
|
|
|
|
ret = pkg.installed(
|
|
"test_install",
|
|
pkgs=["weird-name-1.2.3-1234.5.6.test7tst.x86_64.noarch"],
|
|
)
|
|
call_yum_mock.assert_called_once()
|
|
assert (
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64"
|
|
in call_yum_mock.mock_calls[0].args[0]
|
|
)
|
|
assert ret["result"]
|
|
assert ret["changes"] == expected
|
|
|
|
|
|
def test_removed_with_single_normalize():
|
|
"""
|
|
Test pkg.removed with preventing multiple package name normalisation
|
|
"""
|
|
|
|
list_no_weird_installed = {
|
|
"pkga": "1.0.1",
|
|
"pkgb": "1.0.2",
|
|
"pkgc": "1.0.3",
|
|
}
|
|
list_no_weird_installed_ver_list = {
|
|
"pkga": ["1.0.1"],
|
|
"pkgb": ["1.0.2"],
|
|
"pkgc": ["1.0.3"],
|
|
}
|
|
list_with_weird_installed = {
|
|
"pkga": "1.0.1",
|
|
"pkgb": "1.0.2",
|
|
"pkgc": "1.0.3",
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": "20220214-2.1",
|
|
}
|
|
list_with_weird_installed_ver_list = {
|
|
"pkga": ["1.0.1"],
|
|
"pkgb": ["1.0.2"],
|
|
"pkgc": ["1.0.3"],
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": ["20220214-2.1"],
|
|
}
|
|
list_pkgs = MagicMock(
|
|
side_effect=[
|
|
# For the package with version specified
|
|
list_with_weird_installed_ver_list,
|
|
list_with_weird_installed,
|
|
list_no_weird_installed,
|
|
list_no_weird_installed_ver_list,
|
|
# For the package with no version specified
|
|
list_with_weird_installed_ver_list,
|
|
list_with_weird_installed,
|
|
list_no_weird_installed,
|
|
list_no_weird_installed_ver_list,
|
|
]
|
|
)
|
|
|
|
salt_dict = {
|
|
"pkg.remove": yumpkg.remove,
|
|
"pkg.list_pkgs": list_pkgs,
|
|
"pkg.normalize_name": yumpkg.normalize_name,
|
|
"pkg_resource.parse_targets": pkg_resource.parse_targets,
|
|
"pkg_resource.version_clean": pkg_resource.version_clean,
|
|
}
|
|
|
|
with patch("salt.modules.yumpkg.list_pkgs", list_pkgs), patch(
|
|
"salt.modules.yumpkg.version_cmp", MagicMock(return_value=0)
|
|
), patch(
|
|
"salt.modules.yumpkg._call_yum", MagicMock(return_value={"retcode": 0})
|
|
) as call_yum_mock, patch.dict(
|
|
pkg.__salt__, salt_dict
|
|
), patch.dict(
|
|
pkg_resource.__salt__, salt_dict
|
|
), patch.dict(
|
|
yumpkg.__salt__, salt_dict
|
|
):
|
|
expected = {
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64": {
|
|
"old": "20220214-2.1",
|
|
"new": "",
|
|
}
|
|
}
|
|
ret = pkg.removed(
|
|
"test_remove",
|
|
pkgs=[{"weird-name-1.2.3-1234.5.6.test7tst.x86_64.noarch": "20220214-2.1"}],
|
|
)
|
|
call_yum_mock.assert_called_once()
|
|
assert (
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64-20220214-2.1"
|
|
in call_yum_mock.mock_calls[0].args[0]
|
|
)
|
|
assert ret["result"]
|
|
assert ret["changes"] == expected
|
|
|
|
call_yum_mock.reset_mock()
|
|
|
|
ret = pkg.removed(
|
|
"test_remove",
|
|
pkgs=["weird-name-1.2.3-1234.5.6.test7tst.x86_64.noarch"],
|
|
)
|
|
call_yum_mock.assert_called_once()
|
|
assert (
|
|
"weird-name-1.2.3-1234.5.6.test7tst.x86_64"
|
|
in call_yum_mock.mock_calls[0].args[0]
|
|
)
|
|
assert ret["result"]
|
|
assert ret["changes"] == expected
|
|
|
|
|
|
def test_installed_with_single_normalize_32bit():
|
|
"""
|
|
Test pkg.installed of 32bit package with preventing multiple package name normalisation
|
|
"""
|
|
|
|
list_no_weird_installed = {
|
|
"pkga": "1.0.1",
|
|
"pkgb": "1.0.2",
|
|
"pkgc": "1.0.3",
|
|
}
|
|
list_no_weird_installed_ver_list = {
|
|
"pkga": ["1.0.1"],
|
|
"pkgb": ["1.0.2"],
|
|
"pkgc": ["1.0.3"],
|
|
}
|
|
list_with_weird_installed = {
|
|
"pkga": "1.0.1",
|
|
"pkgb": "1.0.2",
|
|
"pkgc": "1.0.3",
|
|
"xz-devel.i686": "1.2.3",
|
|
}
|
|
list_with_weird_installed_ver_list = {
|
|
"pkga": ["1.0.1"],
|
|
"pkgb": ["1.0.2"],
|
|
"pkgc": ["1.0.3"],
|
|
"xz-devel.i686": ["1.2.3"],
|
|
}
|
|
list_pkgs = MagicMock(
|
|
side_effect=[
|
|
list_no_weird_installed_ver_list,
|
|
{},
|
|
list_no_weird_installed,
|
|
list_no_weird_installed_ver_list,
|
|
list_with_weird_installed,
|
|
list_with_weird_installed,
|
|
list_with_weird_installed_ver_list,
|
|
]
|
|
)
|
|
|
|
salt_dict = {
|
|
"pkg.install": yumpkg.install,
|
|
"pkg.list_pkgs": list_pkgs,
|
|
"pkg.normalize_name": yumpkg.normalize_name,
|
|
"pkg_resource.version_clean": pkg_resource.version_clean,
|
|
"pkg_resource.parse_targets": pkg_resource.parse_targets,
|
|
}
|
|
|
|
with patch("salt.modules.yumpkg.list_pkgs", list_pkgs), patch(
|
|
"salt.modules.yumpkg.version_cmp", MagicMock(return_value=0)
|
|
), patch(
|
|
"salt.modules.yumpkg._call_yum", MagicMock(return_value={"retcode": 0})
|
|
) as call_yum_mock, patch.dict(
|
|
pkg.__salt__, salt_dict
|
|
), patch.dict(
|
|
pkg_resource.__salt__, salt_dict
|
|
), patch.dict(
|
|
yumpkg.__salt__, salt_dict
|
|
), patch.dict(
|
|
yumpkg.__grains__, {"os": "CentOS", "osarch": "x86_64", "osmajorrelease": 7}
|
|
):
|
|
expected = {
|
|
"xz-devel.i686": {
|
|
"old": "",
|
|
"new": "1.2.3",
|
|
}
|
|
}
|
|
ret = pkg.installed(
|
|
"test_install",
|
|
pkgs=["xz-devel.i686"],
|
|
)
|
|
call_yum_mock.assert_called_once()
|
|
assert "xz-devel.i686" in call_yum_mock.mock_calls[0].args[0]
|
|
assert ret["result"]
|
|
assert ret["changes"] == expected
|
|
|
|
|
|
def test__get_installable_versions_no_version_found():
|
|
mock_latest_versions = MagicMock(return_value={})
|
|
mock_list_repo_pkgs = MagicMock(return_value={})
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"pkg.latest_version": mock_latest_versions,
|
|
"pkg.list_pkgs": mock_list_repo_pkgs,
|
|
},
|
|
), patch.dict(pkg.__opts__, {"test": True}):
|
|
expected = {"dummy": {"new": "installed", "old": ""}}
|
|
ret = pkg._get_installable_versions({"dummy": None}, current=None)
|
|
assert ret == expected
|
|
|
|
|
|
def test__get_installable_versions_version_found():
|
|
mock_latest_versions = MagicMock(return_value={"dummy": "1.0.1"})
|
|
mock_list_repo_pkgs = MagicMock(return_value={})
|
|
with patch.dict(
|
|
pkg.__salt__,
|
|
{
|
|
"pkg.latest_version": mock_latest_versions,
|
|
"pkg.list_pkgs": mock_list_repo_pkgs,
|
|
},
|
|
), patch.dict(pkg.__opts__, {"test": True}):
|
|
expected = {"dummy": {"new": "1.0.1", "old": ""}}
|
|
ret = pkg._get_installable_versions({"dummy": None}, current=None)
|
|
assert ret == expected
|
|
|
|
|
|
def test_installed_salt_minion_windows():
|
|
mock_list_pkgs = MagicMock(
|
|
return_value={
|
|
"git": "1.34.1",
|
|
"salt-minion-py3": "3006.0",
|
|
"vim": "1.6",
|
|
}
|
|
)
|
|
mock_install = MagicMock(
|
|
return_value={
|
|
"salt-minion-py3": {"install status": "task started"},
|
|
}
|
|
)
|
|
mock_find_install_targets = MagicMock(
|
|
return_value=(
|
|
{"salt-minion-py3": "3006.1"},
|
|
{"salt-minion-py3": "3006.1"},
|
|
[],
|
|
{},
|
|
{},
|
|
[],
|
|
True,
|
|
)
|
|
)
|
|
salt_dict = {
|
|
"pkg.install": mock_install,
|
|
"pkg.list_pkgs": mock_list_pkgs,
|
|
"pkg_resource.check_extra_requirements": pkg_resource.check_extra_requirements,
|
|
"pkg_resource.version_clean": pkg_resource.version_clean,
|
|
}
|
|
with patch.dict(pkg.__salt__, salt_dict), patch.object(
|
|
pkg, "_find_install_targets", mock_find_install_targets
|
|
):
|
|
expected = {
|
|
"salt-minion-py3": {"install status": "task started"},
|
|
}
|
|
ret = pkg.installed(name="salt-minion-py3", version="3006.1")
|
|
assert ret["result"]
|
|
assert ret["changes"] == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"kwargs, expected_cli_options",
|
|
(
|
|
(
|
|
(
|
|
"fromrepo=foo,bar",
|
|
"someotherkwarg=test",
|
|
"disablerepo=ignored",
|
|
"enablerepo=otherignored",
|
|
"disableexcludes=this_argument_is_also_ignored",
|
|
),
|
|
("--disablerepo=*", "--enablerepo=foo,bar"),
|
|
),
|
|
(
|
|
("enablerepo=foo", "disablerepo=bar"),
|
|
("--disablerepo=bar", "--enablerepo=foo"),
|
|
),
|
|
(
|
|
("disablerepo=foo",),
|
|
("--disablerepo=foo",),
|
|
),
|
|
(
|
|
("enablerepo=bar",),
|
|
("--enablerepo=bar",),
|
|
),
|
|
),
|
|
)
|
|
def test_yumpkg_group_installed_with_repo_options(
|
|
list_pkgs, kwargs, expected_cli_options
|
|
):
|
|
"""
|
|
Test that running a pkg.group_installed with repo options on RPM-based
|
|
systems results in the correct yum/dnf groupinfo command being run by
|
|
pkg.group_info.
|
|
"""
|
|
kwargs = dict(item.split("=", 1) for item in kwargs)
|
|
run_stdout = MagicMock(
|
|
return_value=textwrap.dedent(
|
|
"""\
|
|
Group: MyGroup
|
|
Group-Id: my-group
|
|
Description: A test group
|
|
Mandatory Packages:
|
|
pkga
|
|
pkgb
|
|
"""
|
|
)
|
|
)
|
|
|
|
salt_dict = {
|
|
"cmd.run_stdout": run_stdout,
|
|
"pkg.group_diff": yumpkg.group_diff,
|
|
"pkg.group_info": yumpkg.group_info,
|
|
}
|
|
|
|
name = "MyGroup"
|
|
with patch.dict(pkg.__salt__, salt_dict), patch.dict(
|
|
yumpkg.__salt__, salt_dict
|
|
), patch.object(
|
|
yumpkg,
|
|
"list_pkgs",
|
|
MagicMock(return_value=list_pkgs),
|
|
):
|
|
ret = pkg.group_installed(name, **kwargs)
|
|
assert ret["result"]
|
|
assert not ret["changes"]
|
|
expected = [yumpkg._yum(), "--quiet"]
|
|
expected.extend(expected_cli_options)
|
|
expected.extend(("groupinfo", name))
|
|
run_stdout.assert_called_once_with(
|
|
expected,
|
|
output_loglevel="trace",
|
|
python_shell=False,
|
|
)
|
|
|
|
|
|
def test_pacmanpkg_group_installed_with_repo_options(list_pkgs):
|
|
"""
|
|
Test that running a pkg.group_installed with additional arguments on
|
|
platforms which use pacman does not result in a traceback, but is instead
|
|
cleanly handled and a useful comment included in the state return.
|
|
"""
|
|
salt_dict = {
|
|
"pkg.group_diff": pacmanpkg.group_diff,
|
|
}
|
|
|
|
with patch.dict(pkg.__salt__, salt_dict), patch.dict(pacmanpkg.__salt__, salt_dict):
|
|
ret = pkg.group_installed("foo", fromrepo="bar")
|
|
assert not ret["result"]
|
|
assert not ret["changes"]
|
|
assert ret["comment"] == "Repo options are not supported on this platform"
|
|
|
|
|
|
def test_latest():
|
|
"""
|
|
Test pkg.latest
|
|
"""
|
|
pkg_name = "fake_pkg"
|
|
old_version = "1.2.2"
|
|
new_version = "1.2.3"
|
|
latest_version_mock = MagicMock(return_value={pkg_name: new_version})
|
|
current_version_mock = MagicMock(return_value={pkg_name: old_version})
|
|
install_mock = MagicMock(
|
|
return_value={
|
|
pkg_name: {
|
|
"new": new_version,
|
|
"old": old_version,
|
|
},
|
|
}
|
|
)
|
|
salt_dict = {
|
|
"pkg.latest_version": latest_version_mock,
|
|
"pkg.version": current_version_mock,
|
|
"pkg.install": install_mock,
|
|
}
|
|
with patch.dict(pkg.__salt__, salt_dict):
|
|
ret = pkg.latest(pkg_name)
|
|
assert ret.get("result", False) is True
|
|
|
|
|
|
def test_latest_multiple_versions():
|
|
"""
|
|
This case arises most often when updating the kernel, where multiple versions are now installed.
|
|
|
|
See: https://github.com/saltstack/salt/issues/60931
|
|
"""
|
|
pkg_name = "fake_pkg"
|
|
old_version = "1.2.2"
|
|
new_version = "1.2.3"
|
|
latest_version_mock = MagicMock(return_value={pkg_name: new_version})
|
|
current_version_mock = MagicMock(return_value={pkg_name: old_version})
|
|
install_mock = MagicMock(
|
|
return_value={
|
|
pkg_name: {
|
|
"new": f"{old_version},{new_version}",
|
|
"old": old_version,
|
|
},
|
|
}
|
|
)
|
|
salt_dict = {
|
|
"pkg.latest_version": latest_version_mock,
|
|
"pkg.version": current_version_mock,
|
|
"pkg.install": install_mock,
|
|
}
|
|
with patch.dict(pkg.__salt__, salt_dict):
|
|
ret = pkg.latest(pkg_name)
|
|
assert ret.get("result", False) is True
|
|
|
|
|
|
def test_latest_no_change_windows():
|
|
"""
|
|
Test pkg.latest with no change to the package version for winrepo packages
|
|
|
|
See: https://github.com/saltstack/salt/issues/65165
|
|
"""
|
|
pkg_name = "fake_pkg"
|
|
version = "1.2.2"
|
|
latest_version_mock = MagicMock(return_value={pkg_name: version})
|
|
current_version_mock = MagicMock(return_value={pkg_name: version})
|
|
install_mock = MagicMock(return_value={pkg_name: {"install status": "success"}})
|
|
salt_dict = {
|
|
"pkg.latest_version": latest_version_mock,
|
|
"pkg.version": current_version_mock,
|
|
"pkg.install": install_mock,
|
|
}
|
|
with patch.dict(pkg.__salt__, salt_dict):
|
|
ret = pkg.latest(pkg_name)
|
|
assert ret.get("result", False) is True
|