File set-default-target-for-pip-from-venv_pip_target-envi.patch of Package salt
From 003266fc86c1364a41ac4bd35207290c036151a0 Mon Sep 17 00:00:00 2001
From: Victor Zhestkov <vzhestkov@suse.com>
Date: Mon, 27 Jun 2022 18:02:31 +0300
Subject: [PATCH] Set default target for pip from VENV_PIP_TARGET
environment variable
* Use VENV_PIP_TARGET as a target for pkg.install
if set and no target specified on the call
* Add test for VENV_PIP_TARGET environment variable
* Changelog entry
---
changelog/62089.changed | 1 +
salt/modules/pip.py | 6 +
tests/pytests/unit/modules/test_pip.py | 1806 ++++++++++++++++++++++++
3 files changed, 1813 insertions(+)
create mode 100644 changelog/62089.changed
create mode 100644 tests/pytests/unit/modules/test_pip.py
diff --git a/changelog/62089.changed b/changelog/62089.changed
new file mode 100644
index 0000000000..09feb2e922
--- /dev/null
+++ b/changelog/62089.changed
@@ -0,0 +1 @@
+Use VENV_PIP_TARGET environment variable as a default target for pip if present.
diff --git a/salt/modules/pip.py b/salt/modules/pip.py
index da26416662..9410024fd5 100644
--- a/salt/modules/pip.py
+++ b/salt/modules/pip.py
@@ -858,6 +858,12 @@ def install(
if build:
cmd.extend(["--build", build])
+ # Use VENV_PIP_TARGET environment variable value as target
+ # if set and no target specified on the function call
+ target_env = os.environ.get("VENV_PIP_TARGET", None)
+ if target is None and target_env is not None:
+ target = target_env
+
if target:
cmd.extend(["--target", target])
diff --git a/tests/pytests/unit/modules/test_pip.py b/tests/pytests/unit/modules/test_pip.py
new file mode 100644
index 0000000000..ae9005d806
--- /dev/null
+++ b/tests/pytests/unit/modules/test_pip.py
@@ -0,0 +1,1806 @@
+import os
+import sys
+
+import pytest
+import salt.modules.pip as pip
+import salt.utils.files
+import salt.utils.platform
+from salt.exceptions import CommandExecutionError
+from tests.support.mock import MagicMock, patch
+
+
+class FakeFopen:
+ def __init__(self, filename):
+ d = {
+ "requirements-0.txt": (
+ b"--index-url http://fake.com/simple\n\n"
+ b"one # -r wrong.txt, other\n"
+ b"two # --requirement wrong.exe;some\n"
+ b"three\n"
+ b"-r requirements-1.txt\n"
+ b"# nothing\n"
+ ),
+ "requirements-1.txt": (
+ "four\n"
+ "five\n"
+ "--requirement=requirements-2.txt\t# --requirements-2.txt\n\n"
+ ),
+ "requirements-2.txt": b"""six""",
+ "requirements-3.txt": (
+ b"# some comment\n"
+ b"-e git+ssh://git.example.com/MyProject#egg=MyProject # the project\n"
+ b"seven\n"
+ b"-e git+ssh://git.example.com/Example#egg=example\n"
+ b"eight # -e something#or other\n"
+ b"--requirement requirements-4.txt\n\n"
+ ),
+ "requirements-4.txt": "",
+ }
+ self.val = d[filename]
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args, **kwargs):
+ pass
+
+ def read(self):
+ return self.val
+
+
+@pytest.fixture
+def expected_user():
+ return "fnord"
+
+
+@pytest.fixture
+def configure_loader_modules():
+ return {pip: {"__salt__": {"cmd.which_bin": lambda _: "pip"}}}
+
+
+def test__pip_bin_env():
+ ret = pip._pip_bin_env(None, "C:/Users/ch44d/Documents/salt/tests/pip.exe")
+ if salt.utils.platform.is_windows():
+ assert ret == "C:/Users/ch44d/Documents/salt/tests"
+ else:
+ assert ret is None
+
+
+def test__pip_bin_env_no_change():
+ cwd = "C:/Users/ch44d/Desktop"
+ ret = pip._pip_bin_env(cwd, "C:/Users/ch44d/Documents/salt/tests/pip.exe")
+ assert ret == cwd
+
+
+def test__pip_bin_env_no_bin_env():
+ ret = pip._pip_bin_env(None, None)
+ assert ret is None
+
+
+def test_install_frozen_app():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch("sys.frozen", True, create=True):
+ with patch("sys._MEIPASS", True, create=True):
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg)
+ expected = [
+ sys.executable,
+ "pip",
+ "install",
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ python_shell=False,
+ saltenv="base",
+ use_vt=False,
+ runas=None,
+ )
+
+
+def test_install_source_app():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch("sys.frozen", False, create=True):
+ with patch("sys._MEIPASS", False, create=True):
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ python_shell=False,
+ saltenv="base",
+ use_vt=False,
+ runas=None,
+ )
+
+
+def test_fix4361():
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(requirements="requirements.txt")
+ expected_cmd = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--requirement",
+ "requirements.txt",
+ ]
+ mock.assert_called_with(
+ expected_cmd,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_editable_without_egg_fails():
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(
+ CommandExecutionError,
+ pip.install,
+ editable="git+https://github.com/saltstack/salt-testing.git",
+ )
+
+
+def test_install_multiple_editable():
+ editables = [
+ "git+https://github.com/jek/blinker.git#egg=Blinker",
+ "git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting",
+ ]
+
+ expected = [sys.executable, "-m", "pip", "install"]
+ for item in editables:
+ expected.extend(["--editable", item])
+
+ # Passing editables as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(editable=editables)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing editables as a comma separated list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(editable=",".join(editables))
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_multiple_pkgs_and_editables():
+ pkgs = ["pep8", "salt"]
+ editables = [
+ "git+https://github.com/jek/blinker.git#egg=Blinker",
+ "git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting",
+ ]
+
+ expected = [sys.executable, "-m", "pip", "install"]
+ expected.extend(pkgs)
+ for item in editables:
+ expected.extend(["--editable", item])
+
+ # Passing editables as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkgs=pkgs, editable=editables)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing editables as a comma separated list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkgs=",".join(pkgs), editable=",".join(editables))
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # As single string (just use the first element from pkgs and editables)
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkgs=pkgs[0], editable=editables[0])
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ pkgs[0],
+ "--editable",
+ editables[0],
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_issue5940_install_multiple_pip_mirrors():
+ """
+ test multiple pip mirrors. This test only works with pip < 7.0.0
+ """
+ with patch.object(pip, "version", MagicMock(return_value="1.4")):
+ mirrors = [
+ "http://g.pypi.python.org",
+ "http://c.pypi.python.org",
+ "http://pypi.crate.io",
+ ]
+
+ expected = [sys.executable, "-m", "pip", "install", "--use-mirrors"]
+ for item in mirrors:
+ expected.extend(["--mirrors", item])
+ expected.append("pep8")
+
+ # Passing mirrors as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkgs=["pep8"], mirrors=mirrors)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing mirrors as a comma separated list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkgs=["pep8"], mirrors=",".join(mirrors))
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--use-mirrors",
+ "--mirrors",
+ mirrors[0],
+ "pep8",
+ ]
+
+ # As single string (just use the first element from mirrors)
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkgs=["pep8"], mirrors=mirrors[0])
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_with_multiple_find_links():
+ find_links = [
+ "http://g.pypi.python.org",
+ "http://c.pypi.python.org",
+ "http://pypi.crate.io",
+ ]
+ pkg = "pep8"
+
+ expected = [sys.executable, "-m", "pip", "install"]
+ for item in find_links:
+ expected.extend(["--find-links", item])
+ expected.append(pkg)
+
+ # Passing mirrors as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, find_links=find_links)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing mirrors as a comma separated list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, find_links=",".join(find_links))
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Valid protos work?
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, find_links=find_links)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--find-links",
+ find_links[0],
+ pkg,
+ ]
+
+ # As single string (just use the first element from find_links)
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, find_links=find_links[0])
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Invalid proto raises exception
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(
+ CommandExecutionError,
+ pip.install,
+ "'" + pkg + "'",
+ find_links="sftp://pypi.crate.io",
+ )
+
+
+def test_install_no_index_with_index_url_or_extra_index_url_raises():
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(
+ CommandExecutionError,
+ pip.install,
+ no_index=True,
+ index_url="http://foo.tld",
+ )
+
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(
+ CommandExecutionError,
+ pip.install,
+ no_index=True,
+ extra_index_url="http://foo.tld",
+ )
+
+
+def test_install_failed_cached_requirements():
+ with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements:
+ get_cached_requirements.return_value = False
+ ret = pip.install(requirements="salt://my_test_reqs")
+ assert False is ret["result"]
+ assert "my_test_reqs" in ret["comment"]
+
+
+def test_install_cached_requirements_used():
+ with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements:
+ get_cached_requirements.return_value = "my_cached_reqs"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(requirements="salt://requirements.txt")
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--requirement",
+ "my_cached_reqs",
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_venv():
+ with patch("os.path") as mock_path:
+
+ def join(*args):
+ return os.path.normpath(os.sep.join(args))
+
+ mock_path.is_file.return_value = True
+ mock_path.isdir.return_value = True
+ mock_path.join = join
+
+ if salt.utils.platform.is_windows():
+ venv_path = "C:\\test_env"
+ bin_path = os.path.join(venv_path, "python.exe")
+ else:
+ venv_path = "/test_env"
+ bin_path = os.path.join(venv_path, "python")
+
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ pip_bin = MagicMock(return_value=[bin_path, "-m", "pip"])
+
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}), patch.object(
+ pip, "_get_pip_bin", pip_bin
+ ):
+ pip.install("mock", bin_env=venv_path)
+ mock.assert_called_with(
+ [bin_path, "-m", "pip", "install", "mock"],
+ env={"VIRTUAL_ENV": venv_path},
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_log_argument_in_resulting_command():
+ with patch("os.access") as mock_path:
+ pkg = "pep8"
+ log_path = "/tmp/pip-install.log"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, log=log_path)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--log",
+ log_path,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_non_writeable_log():
+ with patch("os.path") as mock_path:
+ # Let's fake a non-writable log file
+ pkg = "pep8"
+ log_path = "/tmp/pip-install.log"
+ mock_path.exists.side_effect = IOError("Fooo!")
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(IOError, pip.install, pkg, log=log_path)
+
+
+def test_install_timeout_argument_in_resulting_command():
+ # Passing an int
+ pkg = "pep8"
+ expected = [sys.executable, "-m", "pip", "install", "--timeout"]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, timeout=10)
+ mock.assert_called_with(
+ expected + [10, pkg],
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing an int as a string
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, timeout="10")
+ mock.assert_called_with(
+ expected + ["10", pkg],
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing a non-int to timeout
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(ValueError, pip.install, pkg, timeout="a")
+
+
+def test_install_index_url_argument_in_resulting_command():
+ pkg = "pep8"
+ index_url = "http://foo.tld"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, index_url=index_url)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--index-url",
+ index_url,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_extra_index_url_argument_in_resulting_command():
+ pkg = "pep8"
+ extra_index_url = "http://foo.tld"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, extra_index_url=extra_index_url)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--extra-index-url",
+ extra_index_url,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_no_index_argument_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, no_index=True)
+ expected = [sys.executable, "-m", "pip", "install", "--no-index", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_build_argument_in_resulting_command():
+ pkg = "pep8"
+ build = "/tmp/foo"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, build=build)
+ expected = [sys.executable, "-m", "pip", "install", "--build", build, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_target_argument_in_resulting_command():
+ pkg = "pep8"
+ target = "/tmp/foo"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, target=target)
+ expected = [sys.executable, "-m", "pip", "install", "--target", target, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_download_argument_in_resulting_command():
+ pkg = "pep8"
+ download = "/tmp/foo"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, download=download)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--download",
+ download,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_no_download_argument_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, no_download=True)
+ expected = [sys.executable, "-m", "pip", "install", "--no-download", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_download_cache_dir_arguments_in_resulting_command():
+ pkg = "pep8"
+ cache_dir_arg_mapping = {
+ "1.5.6": "--download-cache",
+ "6.0": "--cache-dir",
+ }
+ download_cache = "/tmp/foo"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ for pip_version, cmd_arg in cache_dir_arg_mapping.items():
+ with patch("salt.modules.pip.version", MagicMock(return_value=pip_version)):
+ # test `download_cache` kwarg
+ pip.install(pkg, download_cache="/tmp/foo")
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ cmd_arg,
+ download_cache,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # test `cache_dir` kwarg
+ pip.install(pkg, cache_dir="/tmp/foo")
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_source_argument_in_resulting_command():
+ pkg = "pep8"
+ source = "/tmp/foo"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, source=source)
+ expected = [sys.executable, "-m", "pip", "install", "--source", source, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_exists_action_argument_in_resulting_command():
+ pkg = "pep8"
+ for action in ("s", "i", "w", "b"):
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, exists_action=action)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--exists-action",
+ action,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Test for invalid action
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(CommandExecutionError, pip.install, pkg, exists_action="d")
+
+
+def test_install_install_options_argument_in_resulting_command():
+ install_options = ["--exec-prefix=/foo/bar", "--install-scripts=/foo/bar/bin"]
+ pkg = "pep8"
+
+ expected = [sys.executable, "-m", "pip", "install"]
+ for item in install_options:
+ expected.extend(["--install-option", item])
+ expected.append(pkg)
+
+ # Passing options as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, install_options=install_options)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing mirrors as a comma separated list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, install_options=",".join(install_options))
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing mirrors as a single string entry
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, install_options=install_options[0])
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--install-option",
+ install_options[0],
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_global_options_argument_in_resulting_command():
+ global_options = ["--quiet", "--no-user-cfg"]
+ pkg = "pep8"
+
+ expected = [sys.executable, "-m", "pip", "install"]
+ for item in global_options:
+ expected.extend(["--global-option", item])
+ expected.append(pkg)
+
+ # Passing options as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, global_options=global_options)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing mirrors as a comma separated list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, global_options=",".join(global_options))
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing mirrors as a single string entry
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, global_options=global_options[0])
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--global-option",
+ global_options[0],
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_upgrade_argument_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, upgrade=True)
+ expected = [sys.executable, "-m", "pip", "install", "--upgrade", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_force_reinstall_argument_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, force_reinstall=True)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--force-reinstall",
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_ignore_installed_argument_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, ignore_installed=True)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--ignore-installed",
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_no_deps_argument_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, no_deps=True)
+ expected = [sys.executable, "-m", "pip", "install", "--no-deps", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_no_install_argument_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, no_install=True)
+ expected = [sys.executable, "-m", "pip", "install", "--no-install", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_proxy_argument_in_resulting_command():
+ pkg = "pep8"
+ proxy = "salt-user:salt-passwd@salt-proxy:3128"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(pkg, proxy=proxy)
+ expected = [sys.executable, "-m", "pip", "install", "--proxy", proxy, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_proxy_false_argument_in_resulting_command():
+ """
+ Checking that there is no proxy set if proxy arg is set to False
+ even if the global proxy is set.
+ """
+ pkg = "pep8"
+ proxy = False
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ config_mock = {
+ "proxy_host": "salt-proxy",
+ "proxy_port": "3128",
+ "proxy_username": "salt-user",
+ "proxy_password": "salt-passwd",
+ }
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch.dict(pip.__opts__, config_mock):
+ pip.install(pkg, proxy=proxy)
+ expected = [sys.executable, "-m", "pip", "install", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_global_proxy_in_resulting_command():
+ """
+ Checking that there is proxy set if global proxy is set.
+ """
+ pkg = "pep8"
+ proxy = "http://salt-user:salt-passwd@salt-proxy:3128"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ config_mock = {
+ "proxy_host": "salt-proxy",
+ "proxy_port": "3128",
+ "proxy_username": "salt-user",
+ "proxy_password": "salt-passwd",
+ }
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch.dict(pip.__opts__, config_mock):
+ pip.install(pkg)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--proxy",
+ proxy,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_multiple_requirements_arguments_in_resulting_command():
+ with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements:
+ cached_reqs = ["my_cached_reqs-1", "my_cached_reqs-2"]
+ get_cached_requirements.side_effect = cached_reqs
+ requirements = ["salt://requirements-1.txt", "salt://requirements-2.txt"]
+
+ expected = [sys.executable, "-m", "pip", "install"]
+ for item in cached_reqs:
+ expected.extend(["--requirement", item])
+
+ # Passing option as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(requirements=requirements)
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing option as a comma separated list
+ get_cached_requirements.side_effect = cached_reqs
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(requirements=",".join(requirements))
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing option as a single string entry
+ get_cached_requirements.side_effect = [cached_reqs[0]]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(requirements=requirements[0])
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ "--requirement",
+ cached_reqs[0],
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_extra_args_arguments_in_resulting_command():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.install(
+ pkg, extra_args=[{"--latest-pip-kwarg": "param"}, "--latest-pip-arg"]
+ )
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "install",
+ pkg,
+ "--latest-pip-kwarg",
+ "param",
+ "--latest-pip-arg",
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_install_extra_args_arguments_recursion_error():
+ pkg = "pep8"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+
+ pytest.raises(
+ TypeError,
+ lambda: pip.install(
+ pkg, extra_args=[{"--latest-pip-kwarg": ["param1", "param2"]}]
+ ),
+ )
+
+ pytest.raises(
+ TypeError,
+ lambda: pip.install(
+ pkg, extra_args=[{"--latest-pip-kwarg": [{"--too-deep": dict()}]}]
+ ),
+ )
+
+
+def test_uninstall_multiple_requirements_arguments_in_resulting_command():
+ with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements:
+ cached_reqs = ["my_cached_reqs-1", "my_cached_reqs-2"]
+ get_cached_requirements.side_effect = cached_reqs
+ requirements = ["salt://requirements-1.txt", "salt://requirements-2.txt"]
+
+ expected = [sys.executable, "-m", "pip", "uninstall", "-y"]
+ for item in cached_reqs:
+ expected.extend(["--requirement", item])
+
+ # Passing option as a list
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.uninstall(requirements=requirements)
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing option as a comma separated list
+ get_cached_requirements.side_effect = cached_reqs
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.uninstall(requirements=",".join(requirements))
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing option as a single string entry
+ get_cached_requirements.side_effect = [cached_reqs[0]]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.uninstall(requirements=requirements[0])
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "uninstall",
+ "-y",
+ "--requirement",
+ cached_reqs[0],
+ ]
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_uninstall_global_proxy_in_resulting_command():
+ """
+ Checking that there is proxy set if global proxy is set.
+ """
+ pkg = "pep8"
+ proxy = "http://salt-user:salt-passwd@salt-proxy:3128"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ config_mock = {
+ "proxy_host": "salt-proxy",
+ "proxy_port": "3128",
+ "proxy_username": "salt-user",
+ "proxy_password": "salt-passwd",
+ }
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch.dict(pip.__opts__, config_mock):
+ pip.uninstall(pkg)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "uninstall",
+ "-y",
+ "--proxy",
+ proxy,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ cwd=None,
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_uninstall_proxy_false_argument_in_resulting_command():
+ """
+ Checking that there is no proxy set if proxy arg is set to False
+ even if the global proxy is set.
+ """
+ pkg = "pep8"
+ proxy = False
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ config_mock = {
+ "proxy_host": "salt-proxy",
+ "proxy_port": "3128",
+ "proxy_username": "salt-user",
+ "proxy_password": "salt-passwd",
+ }
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch.dict(pip.__opts__, config_mock):
+ pip.uninstall(pkg, proxy=proxy)
+ expected = [sys.executable, "-m", "pip", "uninstall", "-y", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ cwd=None,
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_uninstall_log_argument_in_resulting_command():
+ pkg = "pep8"
+ log_path = "/tmp/pip-install.log"
+
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.uninstall(pkg, log=log_path)
+ expected = [
+ sys.executable,
+ "-m",
+ "pip",
+ "uninstall",
+ "-y",
+ "--log",
+ log_path,
+ pkg,
+ ]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ cwd=None,
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Let's fake a non-writable log file
+ with patch("os.path") as mock_path:
+ mock_path.exists.side_effect = IOError("Fooo!")
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(IOError, pip.uninstall, pkg, log=log_path)
+
+
+def test_uninstall_timeout_argument_in_resulting_command():
+ pkg = "pep8"
+ expected = [sys.executable, "-m", "pip", "uninstall", "-y", "--timeout"]
+ # Passing an int
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.uninstall(pkg, timeout=10)
+ mock.assert_called_with(
+ expected + [10, pkg],
+ cwd=None,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing an int as a string
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pip.uninstall(pkg, timeout="10")
+ mock.assert_called_with(
+ expected + ["10", pkg],
+ cwd=None,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ # Passing a non-int to timeout
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ pytest.raises(ValueError, pip.uninstall, pkg, timeout="a")
+
+
+def test_freeze_command():
+ expected = [sys.executable, "-m", "pip", "freeze"]
+ eggs = [
+ "M2Crypto==0.21.1",
+ "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev",
+ "bbfreeze==1.1.0",
+ "bbfreeze-loader==1.1.0",
+ "pycrypto==2.6",
+ ]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ ret = pip.freeze()
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+ assert ret == eggs
+
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ # Passing env_vars passes them to underlying command?
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ ret = pip.freeze(env_vars={"foo": "bar"})
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ env={"foo": "bar"},
+ )
+ assert ret == eggs
+
+ # Non zero returncode raises exception?
+ mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ pytest.raises(
+ CommandExecutionError,
+ pip.freeze,
+ )
+
+
+def test_freeze_command_with_all():
+ eggs = [
+ "M2Crypto==0.21.1",
+ "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev",
+ "bbfreeze==1.1.0",
+ "bbfreeze-loader==1.1.0",
+ "pip==0.9.1",
+ "pycrypto==2.6",
+ "setuptools==20.10.1",
+ ]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="9.0.1")):
+ ret = pip.freeze()
+ expected = [sys.executable, "-m", "pip", "freeze", "--all"]
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+ assert ret == eggs
+
+ # Non zero returncode raises exception?
+ mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="9.0.1")):
+ pytest.raises(
+ CommandExecutionError,
+ pip.freeze,
+ )
+
+
+def test_list_command():
+ eggs = [
+ "M2Crypto==0.21.1",
+ "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev",
+ "bbfreeze==1.1.0",
+ "bbfreeze-loader==1.1.0",
+ "pycrypto==2.6",
+ ]
+ mock_version = "6.1.1"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value=mock_version)):
+ ret = pip.list_()
+ expected = [sys.executable, "-m", "pip", "freeze"]
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ runas=None,
+ python_shell=False,
+ use_vt=False,
+ )
+ assert ret == {
+ "SaltTesting-dev": "git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8",
+ "M2Crypto": "0.21.1",
+ "bbfreeze-loader": "1.1.0",
+ "bbfreeze": "1.1.0",
+ "pip": mock_version,
+ "pycrypto": "2.6",
+ }
+
+ # Non zero returncode raises exception?
+ mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ pytest.raises(
+ CommandExecutionError,
+ pip.list_,
+ )
+
+
+def test_list_command_with_all():
+ eggs = [
+ "M2Crypto==0.21.1",
+ "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev",
+ "bbfreeze==1.1.0",
+ "bbfreeze-loader==1.1.0",
+ "pip==9.0.1",
+ "pycrypto==2.6",
+ "setuptools==20.10.1",
+ ]
+ # N.B.: this is deliberately different from the "output" of pip freeze.
+ # This is to demonstrate that the version reported comes from freeze
+ # instead of from the pip.version function.
+ mock_version = "9.0.0"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value=mock_version)):
+ ret = pip.list_()
+ expected = [sys.executable, "-m", "pip", "freeze", "--all"]
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ runas=None,
+ python_shell=False,
+ use_vt=False,
+ )
+ assert ret == {
+ "SaltTesting-dev": "git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8",
+ "M2Crypto": "0.21.1",
+ "bbfreeze-loader": "1.1.0",
+ "bbfreeze": "1.1.0",
+ "pip": "9.0.1",
+ "pycrypto": "2.6",
+ "setuptools": "20.10.1",
+ }
+
+ # Non zero returncode raises exception?
+ mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ pytest.raises(
+ CommandExecutionError,
+ pip.list_,
+ )
+
+
+def test_list_command_with_prefix():
+ eggs = [
+ "M2Crypto==0.21.1",
+ "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev",
+ "bbfreeze==1.1.0",
+ "bbfreeze-loader==1.1.0",
+ "pycrypto==2.6",
+ ]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ ret = pip.list_(prefix="bb")
+ expected = [sys.executable, "-m", "pip", "freeze"]
+ mock.assert_called_with(
+ expected,
+ cwd=None,
+ runas=None,
+ python_shell=False,
+ use_vt=False,
+ )
+ assert ret == {"bbfreeze-loader": "1.1.0", "bbfreeze": "1.1.0"}
+
+
+def test_list_upgrades_legacy():
+ eggs = [
+ "apache-libcloud (Current: 1.1.0 Latest: 2.2.1 [wheel])",
+ "appdirs (Current: 1.4.1 Latest: 1.4.3 [wheel])",
+ "awscli (Current: 1.11.63 Latest: 1.12.1 [sdist])",
+ ]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ ret = pip.list_upgrades()
+ mock.assert_called_with(
+ [sys.executable, "-m", "pip", "list", "--outdated"],
+ cwd=None,
+ runas=None,
+ )
+ assert ret == {
+ "apache-libcloud": "2.2.1 [wheel]",
+ "appdirs": "1.4.3 [wheel]",
+ "awscli": "1.12.1 [sdist]",
+ }
+
+
+def test_list_upgrades_gt9():
+ eggs = """[{"latest_filetype": "wheel", "version": "1.1.0", "name": "apache-libcloud", "latest_version": "2.2.1"},
+ {"latest_filetype": "wheel", "version": "1.4.1", "name": "appdirs", "latest_version": "1.4.3"},
+ {"latest_filetype": "sdist", "version": "1.11.63", "name": "awscli", "latest_version": "1.12.1"}
+ ]"""
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "{}".format(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="9.1.1")):
+ ret = pip.list_upgrades()
+ mock.assert_called_with(
+ [
+ sys.executable,
+ "-m",
+ "pip",
+ "list",
+ "--outdated",
+ "--format=json",
+ ],
+ cwd=None,
+ runas=None,
+ )
+ assert ret == {
+ "apache-libcloud": "2.2.1 [wheel]",
+ "appdirs": "1.4.3 [wheel]",
+ "awscli": "1.12.1 [sdist]",
+ }
+
+
+def test_is_installed_true():
+ eggs = [
+ "M2Crypto==0.21.1",
+ "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev",
+ "bbfreeze==1.1.0",
+ "bbfreeze-loader==1.1.0",
+ "pycrypto==2.6",
+ ]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ ret = pip.is_installed(pkgname="bbfreeze")
+ mock.assert_called_with(
+ [sys.executable, "-m", "pip", "freeze"],
+ cwd=None,
+ runas=None,
+ python_shell=False,
+ use_vt=False,
+ )
+ assert ret
+
+
+def test_is_installed_false():
+ eggs = [
+ "M2Crypto==0.21.1",
+ "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev",
+ "bbfreeze==1.1.0",
+ "bbfreeze-loader==1.1.0",
+ "pycrypto==2.6",
+ ]
+ mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)})
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")):
+ ret = pip.is_installed(pkgname="notexist")
+ mock.assert_called_with(
+ [sys.executable, "-m", "pip", "freeze"],
+ cwd=None,
+ runas=None,
+ python_shell=False,
+ use_vt=False,
+ )
+ assert not ret
+
+
+def test_install_pre_argument_in_resulting_command():
+ pkg = "pep8"
+ # Lower than 1.4 versions don't end up with `--pre` in the resulting output
+ mock = MagicMock(
+ side_effect=[
+ {"retcode": 0, "stdout": "pip 1.2.0 /path/to/site-packages/pip"},
+ {"retcode": 0, "stdout": ""},
+ ]
+ )
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}):
+ with patch("salt.modules.pip.version", MagicMock(return_value="1.3")):
+ pip.install(pkg, pre_releases=True)
+ expected = [sys.executable, "-m", "pip", "install", pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+ mock_run = MagicMock(return_value="pip 1.4.1 /path/to/site-packages/pip")
+ mock_run_all = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ with patch.dict(
+ pip.__salt__, {"cmd.run_stdout": mock_run, "cmd.run_all": mock_run_all}
+ ):
+ with patch("salt.modules.pip._get_pip_bin", MagicMock(return_value=["pip"])):
+ pip.install(pkg, pre_releases=True)
+ expected = ["pip", "install", "--pre", pkg]
+ mock_run_all.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+
+
+def test_resolve_requirements_chain_function():
+ with patch("salt.utils.files.fopen", FakeFopen):
+ chain = pip._resolve_requirements_chain(
+ ["requirements-0.txt", "requirements-3.txt"]
+ )
+ assert chain == [
+ "requirements-0.txt",
+ "requirements-1.txt",
+ "requirements-2.txt",
+ "requirements-3.txt",
+ "requirements-4.txt",
+ ]
+
+
+def test_when_upgrade_is_called_and_there_are_available_upgrades_it_should_call_correct_command(
+ expected_user,
+):
+ fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ pip_user = expected_user
+ with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch(
+ "salt.modules.pip.list_upgrades", autospec=True, return_value=[pip_user]
+ ), patch(
+ "salt.modules.pip._get_pip_bin",
+ autospec=True,
+ return_value=["some-other-pip"],
+ ):
+ pip.upgrade(user=pip_user)
+
+ fake_run_all.assert_any_call(
+ ["some-other-pip", "install", "-U", "freeze", "--all", pip_user],
+ runas=pip_user,
+ cwd=None,
+ use_vt=False,
+ )
+
+
+def test_when_list_upgrades_is_provided_a_user_it_should_be_passed_to_the_version_command(
+ expected_user,
+):
+ fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": "{}"})
+ pip_user = expected_user
+
+ def all_new_commands(*args, **kwargs):
+ """
+ Without this, mutating the return value mutates the return value
+ for EVERYTHING.
+ """
+ return ["some-other-pip"]
+
+ with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch(
+ "salt.modules.pip._get_pip_bin",
+ autospec=True,
+ side_effect=all_new_commands,
+ ):
+ pip._clear_context()
+ pip.list_upgrades(user=pip_user)
+ fake_run_all.assert_any_call(
+ ["some-other-pip", "--version"],
+ runas=expected_user,
+ cwd=None,
+ python_shell=False,
+ )
+
+
+def test_when_install_is_provided_a_user_it_should_be_passed_to_the_version_command(
+ expected_user,
+):
+ fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": "{}"})
+ pip_user = expected_user
+
+ def all_new_commands(*args, **kwargs):
+ """
+ Without this, mutating the return value mutates the return value
+ for EVERYTHING.
+ """
+ return ["some-other-pip"]
+
+ with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch(
+ "salt.modules.pip._get_pip_bin",
+ autospec=True,
+ side_effect=all_new_commands,
+ ):
+ pip._clear_context()
+ pip.install(user=pip_user)
+ fake_run_all.assert_any_call(
+ ["some-other-pip", "--version"],
+ runas=pip_user,
+ cwd=None,
+ python_shell=False,
+ )
+
+
+def test_when_version_is_called_with_a_user_it_should_be_passed_to_undelying_runas(
+ expected_user,
+):
+ fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ pip_user = expected_user
+ with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch(
+ "salt.modules.pip.list_upgrades", autospec=True, return_value=[pip_user]
+ ), patch(
+ "salt.modules.pip._get_pip_bin",
+ autospec=True,
+ return_value=["some-new-pip"],
+ ):
+ pip.version(user=pip_user)
+ fake_run_all.assert_called_with(
+ ["some-new-pip", "--version"],
+ runas=pip_user,
+ cwd=None,
+ python_shell=False,
+ )
+
+
+def test_install_target_from_VENV_PIP_TARGET_in_resulting_command():
+ pkg = "pep8"
+ target = "/tmp/foo"
+ target_env = "/tmp/bar"
+ mock = MagicMock(return_value={"retcode": 0, "stdout": ""})
+ environment = os.environ.copy()
+ environment["VENV_PIP_TARGET"] = target_env
+ with patch.dict(pip.__salt__, {"cmd.run_all": mock}), patch.object(
+ os, "environ", environment
+ ):
+ pip.install(pkg)
+ expected = [sys.executable, "-m", "pip", "install", "--target", target_env, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
+ mock.reset_mock()
+ pip.install(pkg, target=target)
+ expected = [sys.executable, "-m", "pip", "install", "--target", target, pkg]
+ mock.assert_called_with(
+ expected,
+ saltenv="base",
+ runas=None,
+ use_vt=False,
+ python_shell=False,
+ )
--
2.36.1