/
githubmirror
/
salt
Обзор
Документация
Войти
/
githubmirror
/
salt
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/pytests/functional/states/test_pkg.py
1 169 строк
40 KB
Daniel A. Wozniak
Fix package CI downgrades and Windows pkg state tests
27 апр 2026, 22:58
27 апр 2026, 22:58
8bb12a6
Код
Авторство
О чём код?
""" tests for pkg state """ import logging import os import subprocess import time import pytest import salt.utils.files import salt.utils.path import salt.utils.pkg.rpm import salt.utils.platform log = logging.getLogger(__name__) pytestmark = [ pytest.mark.slow_test, pytest.mark.skip_if_not_root, pytest.mark.destructive_test, pytest.mark.windows_whitelisted, pytest.mark.timeout_unless_on_windows(240), pytest.mark.skipif( bool(salt.utils.path.which("transactional-update")), reason="Skipping on transactional systems", ), ] @pytest.fixture(scope="module", autouse=True) def refresh_db(grains, modules): if salt.utils.platform.is_windows(): modules.winrepo.update_git_repos() modules.pkg.refresh_db() # If this is Arch Linux, check if pacman is in use by another process if grains["os_family"] == "Arch": for _ in range(12): if not os.path.isfile("/var/lib/pacman/db.lck"): break else: time.sleep(5) else: pytest.fail("Package database locked after 60 seconds, bailing out") @pytest.fixture(scope="module", autouse=True) def refresh_keys(grains, modules): if grains["os_family"] == "Arch": # We should be running this periodically when building new test runner # images, otherwise this could take several minutes to complete. proc = subprocess.run(["pacman-key", "--refresh-keys"], check=False) if proc.returncode != 0: pytest.fail("pacman-key --refresh-keys command failed.") @pytest.fixture def PKG_TARGETS(grains): _PKG_TARGETS = ["figlet", "sl"] if grains["os"] == "Windows": _PKG_TARGETS = ["npp_x64", "putty"] elif grains["os"] == "Amazon": if grains["osfinger"] == "Amazon Linux-2023": _PKG_TARGETS = ["lynx", "gnuplot-minimal"] else: _PKG_TARGETS = ["lynx", "gnuplot"] elif grains["os_family"] == "RedHat": if grains["os"] == "VMware Photon OS": _PKG_TARGETS = ["zsh", "pciutils"] elif ( grains["os"] in ("CentOS Stream", "Rocky", "AlmaLinux") and grains["osmajorrelease"] >= 9 ): _PKG_TARGETS = ["units", "zsh"] else: _PKG_TARGETS = ["units", "zsh-html"] elif grains["os_family"] == "Suse": _PKG_TARGETS = ["iotop", "screen"] return _PKG_TARGETS @pytest.fixture def PKG_CAP_TARGETS(grains): _PKG_CAP_TARGETS = [] if grains["os_family"] == "Suse": if grains["os"] == "SUSE": _PKG_CAP_TARGETS = [("perl(YAML)", "perl-YAML")] # sudo zypper install 'perl(YAML)' # Loading repository data... # Reading installed packages... # 'perl(YAML)' not found in package names. Trying capabilities. # Resolving package dependencies... # # The following NEW package is going to be installed: # perl-YAML # # 1 new package to install. # Overall download size: 85.3 KiB. Already cached: 0 B. After the operation, additional 183.3 KiB will be used. # Continue? [y/n/v/...? shows all options] (y): # So, it just doesn't work here? skip it for now _PKG_CAP_TARGETS.clear() if not _PKG_CAP_TARGETS: pytest.skip("Capability not provided") return _PKG_CAP_TARGETS @pytest.fixture def PKG_32_TARGETS(grains): _PKG_32_TARGETS = [] if grains["os_family"] == "RedHat" and grains["oscodename"] != "Photon": if grains["os"] == "CentOS": if grains["osmajorrelease"] == 5: _PKG_32_TARGETS = ["xz-devel.i386"] else: _PKG_32_TARGETS.append("xz-devel.i686") elif grains["os"] == "Windows": # Prefer putty first: 32-bit ``npp`` winrepo metadata and uninstall # registry cleanup have been flaky on Windows Server 2022/2025 CI, # causing pkg.removed / latest_version to disagree with reality. _PKG_32_TARGETS = ["putty", "npp"] if not _PKG_32_TARGETS: pytest.skip("No 32 bit packages have been specified for testing") return _PKG_32_TARGETS @pytest.fixture def PKG_DOT_TARGETS(grains): _PKG_DOT_TARGETS = [] if grains["os_family"] == "RedHat" and grains["oscodename"] != "Photon": if grains["osmajorrelease"] == 7: _PKG_DOT_TARGETS = ["tomcat-el-2.2-api"] elif grains["osmajorrelease"] == 8: _PKG_DOT_TARGETS = ["aspnetcore-runtime-6.0"] if not _PKG_DOT_TARGETS: pytest.skip( 'No packages with "." in their name have been specified', ) return _PKG_DOT_TARGETS @pytest.fixture def PKG_EPOCH_TARGETS(grains): _PKG_EPOCH_TARGETS = [] if grains["os_family"] == "RedHat" and grains["oscodename"] != "Photon": if grains["osmajorrelease"] == 7: _PKG_EPOCH_TARGETS = ["comps-extras"] elif grains["osmajorrelease"] == 8: _PKG_EPOCH_TARGETS = ["traceroute"] if not _PKG_EPOCH_TARGETS: pytest.skip('No targets have been configured with "epoch" in the version') return _PKG_EPOCH_TARGETS @pytest.fixture def VERSION_SPEC_SUPPORTED(grains): _VERSION_SPEC_SUPPORTED = True if grains["os"] == "FreeBSD": _VERSION_SPEC_SUPPORTED = False if not _VERSION_SPEC_SUPPORTED: pytest.skip("Version specification not supported") return _VERSION_SPEC_SUPPORTED @pytest.fixture def WILDCARDS_SUPPORTED(grains): _WILDCARDS_SUPPORTED = False if grains["os_family"] in ("Arch", "Debian"): _WILDCARDS_SUPPORTED = True if not _WILDCARDS_SUPPORTED: pytest.skip("Wildcards in pkg.install are not supported") return _WILDCARDS_SUPPORTED @pytest.fixture def ctx(): return {} @pytest.fixture def latest_version(ctx, modules): """ Helper function which ensures that we don't make any unnecessary calls to pkg.latest_version to figure out what version we need to install. This won't stop pkg.latest_version from being run in a pkg.latest state, but it will reduce the amount of times we check the latest version here in the test suite. """ def run_command(*names): key = "latest_version" if key not in ctx: ctx[key] = dict() targets = [x for x in names if x not in ctx[key]] if targets: result = modules.pkg.latest_version(*targets, refresh=False) try: ctx[key].update(result) except ValueError: # Only a single target, pkg.latest_version returned a string ctx[key][targets[0]] = result ret = {x: ctx[key].get(x, "") for x in names} if len(names) == 1: return ret[names[0]] return ret return run_command @pytest.fixture(scope="function") def install_7zip(modules): try: modules.pkg.install(name="7zip", version="22.01.00.0") modules.pkg.install(name="7zip", version="19.00.00.0") versions = modules.pkg.version("7zip") assert "19.00.00.0" in versions assert "22.01.00.0" in versions yield finally: modules.pkg.remove(name="7zip", version="19.00.00.0") modules.pkg.remove(name="7zip", version="22.01.00.0") versions = modules.pkg.version("7zip") assert "19.00.00.0" not in versions assert "22.01.00.0" not in versions @pytest.fixture(scope="module") def pkg_def_contents(state_tree): return r""" my-software: '1.0.1': full_name: 'My Software' installer: 'C:\files\mysoftware101.msi' install_flags: '/qn /norestart' uninstaller: 'C:\files\mysoftware101.msi' uninstall_flags: '/qn /norestart' msiexec: True reboot: False '1.0.2': full_name: 'My Software' installer: 'C:\files\mysoftware102.msi' install_flags: '/qn /norestart' uninstaller: 'C:\files\mysoftware102.msi' uninstall_flags: '/qn /norestart' msiexec: True reboot: False """ @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_001_installed(modules, states, PKG_TARGETS): """ This is a destructive test as it installs and then removes a package """ target = PKG_TARGETS[0] version = modules.pkg.version(target) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so this package # needs to not be installed before we run the states below assert not version ret = states.pkg.installed(name=target, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.usefixtures("VERSION_SPEC_SUPPORTED") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_002_installed_with_version(PKG_TARGETS, states, latest_version): """ This is a destructive test as it installs and then removes a package """ target = PKG_TARGETS[0] version = latest_version(target) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so this package # needs to not be installed before we run the states below assert version ret = states.pkg.installed(name=target, version=version, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_003_installed_multipkg(caplog, PKG_TARGETS, modules, states, grains): """ This is a destructive test as it installs and then removes two packages """ if grains["os_family"] == "Arch": pytest.skip("Arch needs refresh_db logic added to golden image") version = modules.pkg.version(*PKG_TARGETS) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so these # packages need to not be installed before we run the states below assert not any(version.values()) ret = states.pkg.removed(name=None, pkgs=PKG_TARGETS) assert ret.result is True try: ret = states.pkg.installed(name=None, pkgs=PKG_TARGETS, refresh=False) assert ret.result is True if not salt.utils.platform.is_windows(): assert "WARNING" not in caplog.text finally: ret = states.pkg.removed(name=None, pkgs=PKG_TARGETS) assert ret.result is True @pytest.mark.usefixtures("VERSION_SPEC_SUPPORTED") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_004_installed_multipkg_with_version( PKG_TARGETS, latest_version, states, grains ): """ This is a destructive test as it installs and then removes two packages """ if grains["os_family"] == "Arch": pytest.skip("Arch needs refresh_db logic added to golden image") version = latest_version(PKG_TARGETS[0]) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so these # packages need to not be installed before we run the states below assert bool(version) pkgs = [{PKG_TARGETS[0]: version}, PKG_TARGETS[1]] try: ret = states.pkg.installed(name=None, pkgs=pkgs, refresh=False) assert ret.result is True finally: ret = states.pkg.removed(name=None, pkgs=PKG_TARGETS) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_005_installed_32bit(PKG_32_TARGETS, modules, states): """ This is a destructive test as it installs and then removes a package """ target = PKG_32_TARGETS[0] # _PKG_TARGETS_32 is only populated for platforms for which Salt has to # munge package names for 32-bit-on-x86_64 (Currently only Ubuntu and # RHEL-based). Don't actually perform this test on other platforms. version = modules.pkg.version(target) # If this assert fails, we need to find a new target. This test # needs to be able to test successful installation of packages, so # the target needs to not be installed before we run the states # below assert not version ret = states.pkg.installed(name=target, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_006_installed_32bit_with_version(PKG_32_TARGETS, latest_version, states): """ This is a destructive test as it installs and then removes a package """ target = PKG_32_TARGETS[0] # _PKG_TARGETS_32 is only populated for platforms for which Salt has to # munge package names for 32-bit-on-x86_64 (Currently only Ubuntu and # RHEL-based). Don't actually perform this test on other platforms. version = latest_version(target) # If this assert fails, we need to find a new target. This test # needs to be able to test successful installation of the package, so # the target needs to not be installed before we run the states # below assert version ret = states.pkg.installed(name=target, version=version, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_007_with_dot_in_pkgname(PKG_DOT_TARGETS, latest_version, states): """ This tests for the regression found in the following issue: https://github.com/saltstack/salt/issues/8614 This is a destructive test as it installs a package """ target = PKG_DOT_TARGETS[0] version = latest_version(target) # If this assert fails, we need to find a new target. This test # needs to be able to test successful installation of the package, so # the target needs to not be installed before we run the # pkg.installed state below assert bool(version) ret = states.pkg.installed(name=target, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_008_epoch_in_version(PKG_EPOCH_TARGETS, latest_version, states): """ This tests for the regression found in the following issue: https://github.com/saltstack/salt/issues/8614 This is a destructive test as it installs a package """ target = PKG_EPOCH_TARGETS[0] version = latest_version(target) # If this assert fails, we need to find a new target. This test # needs to be able to test successful installation of the package, so # the target needs to not be installed before we run the # pkg.installed state below assert version ret = states.pkg.installed(name=target, version=version, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version", "pkg.info_installed") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_009_latest_with_epoch(grains, modules, states): """ This tests for the following issue: https://github.com/saltstack/salt/issues/31014 This is a destructive test as it installs a package """ if grains["kernel"] != "linux": pytest.skip("Only runs on Linux.") if grains["os"] != "Amazon": pytest.skip("Does not runs on Amazon Linux.") package = "bash-completion" pkgquery = "version" ret = states.pkg.installed(name=package, refresh=False) assert ret.result is True ret = modules.pkg.info_installed(package) assert pkgquery in str(ret) @pytest.mark.requires_salt_states("pkg.latest", "pkg.removed") @pytest.mark.slow_test def test_pkg_010_latest(PKG_TARGETS, latest_version, states): """ This tests pkg.latest with a package that has no epoch (or a zero epoch). """ target = PKG_TARGETS[0] version = latest_version(target) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so this package # needs to not be installed before we run the states below assert version ret = states.pkg.latest(name=target, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.list_pkgs", "pkg.list_upgrades", "pkg.version") @pytest.mark.requires_salt_states("pkg.latest") @pytest.mark.slow_test def test_pkg_011_latest_only_upgrade( grains, PKG_TARGETS, latest_version, states, modules ): """ WARNING: This test will pick a package with an available upgrade (if there is one) and upgrade it to the latest version. """ if grains["os_family"] != "Debian": pytest.skip("Only runs on Debian based operating systems.") target = PKG_TARGETS[0] # If this assert fails, we need to find new targets, this test needs to # be able to test that the state fails when you try to run the state # with only_upgrade=True on a package which is not already installed, # so the targeted package needs to not be installed before we run the # state below. version = latest_version(target) assert version ret = states.pkg.latest(name=target, refresh=False, only_upgrade=True) assert ret.result is False # Now look for updates and try to run the state on a package which is already up-to-date. installed_pkgs = modules.pkg.list_pkgs() updates = modules.pkg.list_upgrades(refresh=False) for pkgname in updates: if pkgname in installed_pkgs: target = pkgname break else: target = "" log.warning( "No available upgrades to installed packages, skipping " "only_upgrade=True test with already-installed package. For " "best results run this test on a machine with upgrades " "available." ) if target: ret = states.pkg.latest(name=target, refresh=False, only_upgrade=True) assert ret.result is True new_version = modules.pkg.version(target, use_context=False) assert new_version == updates[target] ret = states.pkg.latest(name=target, refresh=False, only_upgrade=True) assert ( ret.raw["pkg_|-{0}_|-{0}_|-latest".format(target)]["comment"] == f"Package {target} is already up-to-date" ) @pytest.mark.usefixtures("WILDCARDS_SUPPORTED") @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_012_installed_with_wildcard_version(PKG_TARGETS, states, modules): """ This is a destructive test as it installs and then removes a package """ target = PKG_TARGETS[0] version = modules.pkg.version(target) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so this package # needs to not be installed before we run the states below assert not version ret = states.pkg.installed( name=target, version="*", refresh=False, ) assert ret.result is True # Repeat state, should pass ret = states.pkg.installed( name=target, version="*", refresh=False, ) expected_comment = ( "All specified packages are already installed and are at the desired version" ) assert ret.result is True assert ret.raw[next(iter(ret.raw))]["comment"] == expected_comment # Repeat one more time with unavailable version, test should fail ret = states.pkg.installed( name=target, version="93413*", refresh=False, ) assert ret.result is False # Clean up ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version", "pkg.latest_version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_013_installed_with_comparison_operator( grains, PKG_TARGETS, states, modules ): """ This is a destructive test as it installs and then removes a package """ if grains["os_family"] != "RedHat" or grains["os_family"] != "Debian": pytest.skip("Only runs on Debian or RedHat.") target = PKG_TARGETS[0] version = modules.pkg.version(target) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so this package # needs to not be installed before we run the states below assert not version latest_version = modules.pkg.latest_version(target, refresh=False) try: ret = states.pkg.installed( name=target, version="<9999999", refresh=False, ) assert ret.result is True # The version that was installed should be the latest available version = modules.pkg.version(target) assert version, latest_version finally: # Clean up ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_014_installed_missing_release(grains, PKG_TARGETS, states, modules): """ Tests that a version number missing the release portion still resolves as correctly installed. For example, version 2.0.2 instead of 2.0.2-1.el7 """ if grains["os_family"] != "RedHat": pytest.skip("Only runs on RedHat based operating systems.") target = PKG_TARGETS[0] version = modules.pkg.version(target) # If this assert fails, we need to find new targets, this test needs to # be able to test successful installation of packages, so this package # needs to not be installed before we run the states below assert not version ret = states.pkg.installed( name=target, version=salt.utils.pkg.rpm.version_to_evr(version)[1], refresh=False, ) assert ret.result is True # Clean up ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.skip_on_photonos( reason="package hold/unhold unsupported on Photon OS", ) @pytest.mark.requires_salt_modules( "pkg.hold", "pkg.unhold", "pkg.version", "pkg.list_pkgs" ) @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_015_installed_held(grains, modules, states, PKG_TARGETS): """ Tests that a package can be held even when the package is already installed. """ versionlock_pkg = None if grains["os_family"] == "RedHat": pkgs = { p for p in modules.pkg.list_repo_pkgs() if "yum-plugin-versionlock" in p } if not pkgs: pytest.skip("No versionlock package found in repositories") for versionlock_pkg in pkgs: ret = states.pkg.installed(name=versionlock_pkg, refresh=False) # Exit loop if a versionlock package installed correctly try: assert ret.result is True log.debug("Installed versionlock package: %s", versionlock_pkg) break except AssertionError as exc: log.debug("Versionlock package not found:\n%s", exc) else: pytest.fail(f"Could not install versionlock package from {pkgs}") target = PKG_TARGETS[0] # First we ensure that the package is installed ret = states.pkg.installed( name=target, refresh=False, ) assert ret.result is True # Then we check that the package is now held ret = states.pkg.installed( name=target, hold=True, refresh=False, ) if versionlock_pkg and "-versionlock is not installed" in str(ret): pytest.skip(f"{ret} `{versionlock_pkg}` is installed") # changes from pkg.hold for Red Hat family are different target_changes = {} if ( grains["os_family"] == "RedHat" or grains["os"] == "FreeBSD" or grains["os_family"] == "Suse" ): target_changes = {"new": "hold", "old": ""} elif grains["os_family"] == "Debian": target_changes = {"new": "hold", "old": "install"} try: tag = "pkg_|-{0}_|-{0}_|-installed".format(target) assert ret.result is True assert tag in ret.raw assert "changes" in ret.raw[tag] assert target in ret.raw[tag]["changes"] if not target_changes: pytest.skip( "Test needs to be configured for {}: {}".format( grains["os"], ret.raw[tag]["changes"][target] ) ) assert ret.raw[tag]["changes"][target] == target_changes finally: # Clean up, unhold package and remove modules.pkg.unhold(name=target) ret = states.pkg.removed(name=target) assert ret.result is True if versionlock_pkg: ret = states.pkg.removed(name=versionlock_pkg) assert ret.result is True @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_016_conditionally_ignore_epoch(PKG_EPOCH_TARGETS, latest_version, states): """ See https://github.com/saltstack/salt/issues/56654#issuecomment-615034952 This is a destructive test as it installs a package """ target = PKG_EPOCH_TARGETS[0] # Strip the epoch from the latest available version version = latest_version(target).split(":", 1)[-1] # If this assert fails, we need to find a new target. This test # needs to be able to test successful installation of the package, so # the target needs to not be installed before we run the # pkg.installed state below assert version # CASE 1: package name passed in "name" param ret = states.pkg.installed(name=target, version=version, refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True # CASE 2: same as case 1 but with "pkgs" ret = states.pkg.installed(name="foo", pkgs=[{target: version}], refresh=False) assert ret.result is True ret = states.pkg.removed(name=target) assert ret.result is True @pytest.mark.skip_on_photonos( reason="package hold/unhold unsupported on Photon OS", ) @pytest.mark.requires_salt_modules( "pkg.hold", "pkg.unhold", "pkg.version", "pkg.list_pkgs" ) @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") def test_pkg_017_installed_held_equals_false(grains, modules, states, PKG_TARGETS): """ Tests that a package is installed when hold is explicitly False. See https://github.com/saltstack/salt/issues/58801. """ versionlock_pkg = None if grains["os_family"] == "RedHat": from salt.modules.yumpkg import _versionlock_pkg pkgs = { p for p in modules.pkg.list_repo_pkgs() if _versionlock_pkg(grains) in p } if not pkgs: pytest.skip("No versionlock package found in repositories") for versionlock_pkg in pkgs: ret = states.pkg.installed(name=versionlock_pkg, refresh=False) # Exit loop if a versionlock package installed correctly try: assert ret.result is True log.debug("Installed versionlock package: %s", versionlock_pkg) break except AssertionError as exc: log.debug("Versionlock package not found:\n%s", exc) else: pytest.fail(f"Could not install versionlock package from {pkgs}") target = PKG_TARGETS[0] # First we ensure that the package is installed target_ret = states.pkg.installed( name=target, hold=False, refresh=False, ) assert target_ret.result is True if versionlock_pkg and "-versionlock is not installed" in str(target_ret): pytest.skip(f"{target_ret} `{versionlock_pkg}` is installed") try: tag = "pkg_|-{0}_|-{0}_|-installed".format(target) assert target_ret.result is True assert tag in target_ret.raw assert "changes" in target_ret.raw[tag] # On Centos 7 package is already installed, no change happened if target_ret.raw[tag].get("changes"): assert target in target_ret.raw[tag]["changes"] if grains["os_family"] == "Suse": assert "packages were installed" in target_ret.raw[tag]["comment"] else: # The "held" string is part of a longer comment that may look # like: # # Package units is not being held. assert "held" in target_ret.raw[tag]["comment"] finally: # Clean up, unhold package and remove ret = states.pkg.removed(name=target) assert ret.result is True if versionlock_pkg: ret = states.pkg.removed(name=versionlock_pkg) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_cap_001_installed(PKG_CAP_TARGETS, modules, states): """ This is a destructive test as it installs and then removes a package """ target, realpkg = PKG_CAP_TARGETS[0] version = modules.pkg.version(target) realver = modules.pkg.version(realpkg) # If this condition is False, we need to find new targets. # This needs to be able to test successful installation of packages. # These packages need to not be installed before we run the states below if not (version and realver): pytest.skip("TODO: New pkg cap targets required") try: ret = states.pkg.installed( name=target, refresh=False, resolve_capabilities=True, test=True, ) assert ( f"The following packages would be installed/updated: {realpkg}" in ret.comment ) ret = states.pkg.installed( name=target, refresh=False, resolve_capabilities=True ) assert ret.result is True finally: ret = states.pkg.removed(name=realpkg) assert ret.result is True @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_cap_002_already_installed(PKG_CAP_TARGETS, modules, states): """ This is a destructive test as it installs and then removes a package """ target, realpkg = PKG_CAP_TARGETS[0] version = modules.pkg.version(target) realver = modules.pkg.version(realpkg) # If this condition is False, we need to find new targets. # This needs to be able to test successful installation of packages. # These packages need to not be installed before we run the states below if not (version and realver): pytest.skip("TODO: New pkg cap targets required") try: # install the package ret = states.pkg.installed(name=realpkg, refresh=False) assert ret.result is True # Try to install again. Nothing should be installed this time. ret = states.pkg.installed( name=target, refresh=False, resolve_capabilities=True, test=True, ) assert "All specified packages are already installed" in ret.comment ret = states.pkg.installed( name=target, refresh=False, resolve_capabilities=True ) assert ret.result is True assert "packages are already installed" in ret.comment finally: ret = states.pkg.removed(name=realpkg) assert ret.result is True @pytest.mark.usefixtures("VERSION_SPEC_SUPPORTED") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed") @pytest.mark.slow_test def test_pkg_cap_003_installed_multipkg_with_version( PKG_CAP_TARGETS, PKG_TARGETS, latest_version, modules, states, grains, ): """ This is a destructive test as it installs and then removes two packages """ target, realpkg = PKG_CAP_TARGETS[0] version = modules.pkg.version(target) realver = modules.pkg.version(realpkg) # If this condition is False, we need to find new targets. # This needs to be able to test successful installation of packages. # These packages need to not be installed before we run the states below if not (version and realver): pytest.skip("TODO: New pkg cap targets required") cleanup_pkgs = PKG_TARGETS try: pkgs = [ {PKG_TARGETS[0]: version}, PKG_TARGETS[1], {target: realver}, ] ret = states.pkg.installed( name="test_pkg_cap_003_installed_multipkg_with_version-install", pkgs=pkgs, refresh=False, ) assert ret.result is False ret = states.pkg.installed( name="test_pkg_cap_003_installed_multipkg_with_version-install-capability", pkgs=pkgs, refresh=False, resolve_capabilities=True, test=True, ) assert "packages would be installed/updated" in ret.comment assert f"{realpkg}={realver}" in ret.comment ret = states.pkg.installed( name="test_pkg_cap_003_installed_multipkg_with_version-install-capability", pkgs=pkgs, refresh=False, resolve_capabilities=True, ) assert ret.result is True cleanup_pkgs.append(realpkg) finally: ret = states.pkg.removed( name="test_pkg_cap_003_installed_multipkg_with_version-remove", pkgs=cleanup_pkgs, ) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.latest", "pkg.removed") @pytest.mark.slow_test def test_pkg_cap_004_latest(PKG_CAP_TARGETS, modules, states): """ This tests pkg.latest with a package that has no epoch (or a zero epoch). """ target, realpkg = PKG_CAP_TARGETS[0] version = modules.pkg.version(target) realver = modules.pkg.version(realpkg) # If this condition is False, we need to find new targets. # This needs to be able to test successful installation of packages. # These packages need to not be installed before we run the states below if not (version and realver): pytest.skip("TODO: New pkg cap targets required") try: ret = states.pkg.latest( name=target, refresh=False, resolve_capabilities=True, test=True, ) assert ( f"The following packages would be installed/upgraded: {realpkg}" in ret.comment ) ret = states.pkg.latest(name=target, refresh=False, resolve_capabilities=True) assert ret.result is True ret = states.pkg.latest(name=target, refresh=False, resolve_capabilities=True) assert ret.result is True assert "is already up-to-date" in ret.comment finally: ret = states.pkg.removed(name=realpkg) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed", "pkg.downloaded") @pytest.mark.slow_test def test_pkg_cap_005_downloaded(PKG_CAP_TARGETS, modules, states): """ This is a destructive test as it installs and then removes a package """ target, realpkg = PKG_CAP_TARGETS[0] version = modules.pkg.version(target) realver = modules.pkg.version(realpkg) # If this condition is False, we need to find new targets. # This needs to be able to test successful installation of packages. # These packages need to not be installed before we run the states below if not (version and realver): pytest.skip("TODO: New pkg cap targets required") ret = states.pkg.downloaded(name=target, refresh=False) assert ret.result is False ret = states.pkg.downloaded( name=target, refresh=False, resolve_capabilities=True, test=True, ) assert f"The following packages would be downloaded: {realpkg}" in ret.comment ret = states.pkg.downloaded(name=target, refresh=False, resolve_capabilities=True) assert ret.result is True @pytest.mark.requires_salt_modules("pkg.version") @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed", "pkg.uptodate") @pytest.mark.slow_test def test_pkg_cap_006_uptodate(PKG_CAP_TARGETS, modules, states): """ This is a destructive test as it installs and then removes a package """ target, realpkg = PKG_CAP_TARGETS[0] version = modules.pkg.version(target) realver = modules.pkg.version(realpkg) # If this condition is False, we need to find new targets. # This needs to be able to test successful installation of packages. # These packages need to not be installed before we run the states below if not (version and realver): pytest.skip("TODO: New pkg cap targets required") try: ret = states.pkg.installed( name=target, refresh=False, resolve_capabilities=True ) assert ret.result is True ret = states.pkg.uptodate( name="test_pkg_cap_006_uptodate", pkgs=[target], refresh=False, resolve_capabilities=True, ) assert ret.result is True assert "System is already up-to-date" in ret.comment finally: ret = states.pkg.removed(name=realpkg) assert ret.result is True @pytest.mark.requires_salt_modules( "pkg.version", "pkg.latest_version", "pkg.remove", "pkg.purge", "pkg.list_pkgs" ) @pytest.mark.requires_salt_states("pkg.installed", "pkg.removed", "pkg.purged") def test_pkg_purged_with_removed_pkg(grains, PKG_TARGETS, states, modules): """ This is a destructive test as it installs and then removes a package, then purges a removed package """ if grains["os_family"] != "Debian": pytest.skip("Only runs on Debian.") target = PKG_TARGETS[0] ret = states.pkg.installed( name=target, version="<9999999", refresh=False, ) assert ret.result is True # The version that was installed should be the latest available version = modules.pkg.version(target) assert version # Clean up ret = states.pkg.removed(name=target) assert ret.result is True ret = states.pkg.purged(name=target) assert ret.result is True assert ret.name == target assert ret.comment == "All targeted packages were purged." assert ret.changes == { "installed": {}, "removed": {target: {"new": "", "old": version}}, } @pytest.mark.skip_unless_on_windows() def test_pkg_removed_with_version_multiple(install_7zip, modules, states): """ This tests removing a specific version of a package when multiple versions are installed. This is specific to Windows. The only version I could find that allowed multiple installs of differing versions was 7zip, so we'll use that. """ ret = states.pkg.removed(name="7zip", version="19.00.00.0") assert ret.result is True current = modules.pkg.version("7zip") assert "22.01.00.0" in current @pytest.mark.skip_unless_on_windows() def test_pkg_latest_test_true(states, modules, state_tree, pkg_def_contents): repo_dir = state_tree / "winrepo_ng" with pytest.helpers.temp_file("my-software.sls", pkg_def_contents, repo_dir): modules.pkg.refresh_db() assert len(modules.pkg.get_package_info("my-software")) == 2 result = states.pkg.latest("my-software", test=True) expected = {"my-software": {"new": "1.0.2", "old": ""}} assert result.changes == expected