mirror of https://github.com/mamba-org/mamba.git
305 lines
11 KiB
Python
305 lines
11 KiB
Python
import os
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
# Need to import everything to get fixtures
|
|
from .helpers import * # noqa: F403
|
|
from . import helpers
|
|
|
|
__this_dir__ = Path(__file__).parent.resolve()
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
helpers.dry_run_tests == helpers.DryRun.ULTRA_DRY, reason="Running ultra dry tests"
|
|
)
|
|
class TestRemove:
|
|
current_root_prefix = os.environ["MAMBA_ROOT_PREFIX"]
|
|
current_prefix = os.environ["CONDA_PREFIX"]
|
|
cache = os.path.join(current_root_prefix, "pkgs")
|
|
|
|
env_name = helpers.random_string()
|
|
root_prefix = os.path.expanduser(os.path.join("~", "tmproot" + helpers.random_string()))
|
|
prefix = os.path.join(root_prefix, "envs", env_name)
|
|
|
|
@staticmethod
|
|
@pytest.fixture(scope="class")
|
|
def root(existing_cache):
|
|
os.environ["MAMBA_ROOT_PREFIX"] = TestRemove.root_prefix
|
|
os.environ["CONDA_PREFIX"] = TestRemove.prefix
|
|
helpers.create("-n", "base", no_dry_run=True)
|
|
helpers.create("xtensor", "-n", TestRemove.env_name, no_dry_run=True)
|
|
|
|
yield
|
|
|
|
os.environ["MAMBA_ROOT_PREFIX"] = TestRemove.current_root_prefix
|
|
os.environ["CONDA_PREFIX"] = TestRemove.current_prefix
|
|
shutil.rmtree(TestRemove.root_prefix)
|
|
|
|
@staticmethod
|
|
@pytest.fixture
|
|
def env_created(root):
|
|
if helpers.dry_run_tests == helpers.DryRun.OFF:
|
|
helpers.install("xtensor", "-n", TestRemove.env_name)
|
|
|
|
@pytest.mark.parametrize("env_selector", ["", "name", "prefix"])
|
|
def test_remove(self, env_selector, env_created):
|
|
env_pkgs = [p["name"] for p in helpers.umamba_list("-p", TestRemove.prefix, "--json")]
|
|
|
|
if env_selector == "prefix":
|
|
res = helpers.remove("xtensor", "-p", TestRemove.prefix, "--json")
|
|
elif env_selector == "name":
|
|
res = helpers.remove("xtensor", "-n", TestRemove.env_name, "--json")
|
|
else:
|
|
res = helpers.remove("xtensor", "--dry-run", "--json")
|
|
|
|
keys = {"dry_run", "success", "prefix", "actions"}
|
|
assert keys.issubset(set(res.keys()))
|
|
assert res["success"]
|
|
assert len(res["actions"]["UNLINK"]) == len(env_pkgs)
|
|
for p in res["actions"]["UNLINK"]:
|
|
assert p["name"] in env_pkgs
|
|
assert res["actions"]["PREFIX"] == TestRemove.prefix
|
|
|
|
def test_remove_orphaned(self, env_created):
|
|
env_pkgs = [p["name"] for p in helpers.umamba_list("-p", TestRemove.prefix, "--json")]
|
|
helpers.install("xframe", "-n", TestRemove.env_name, no_dry_run=True)
|
|
|
|
res = helpers.remove("xframe", "-p", TestRemove.prefix, "--json")
|
|
|
|
keys = {"dry_run", "success", "prefix", "actions"}
|
|
assert keys.issubset(set(res.keys()))
|
|
assert res["success"]
|
|
assert len(res["actions"]["UNLINK"]) == 1
|
|
assert res["actions"]["UNLINK"][0]["name"] == "xframe"
|
|
assert res["actions"]["PREFIX"] == TestRemove.prefix
|
|
|
|
res = helpers.remove("xtensor", "-p", TestRemove.prefix, "--json")
|
|
|
|
keys = {"dry_run", "success", "prefix", "actions"}
|
|
assert keys.issubset(set(res.keys()))
|
|
assert res["success"]
|
|
assert len(res["actions"]["UNLINK"]) == len(env_pkgs) + (
|
|
1 if helpers.dry_run_tests == helpers.DryRun.DRY else 0
|
|
)
|
|
for p in res["actions"]["UNLINK"]:
|
|
assert p["name"] in env_pkgs
|
|
assert res["actions"]["PREFIX"] == TestRemove.prefix
|
|
|
|
def test_remove_force(self, env_created):
|
|
# check that we can remove a package without solving the environment (putting
|
|
# it in a bad state, actually)
|
|
helpers.install("xframe", "-n", TestRemove.env_name, no_dry_run=True)
|
|
|
|
res = helpers.remove("xtl", "-p", TestRemove.prefix, "--json", "--force")
|
|
|
|
keys = {"dry_run", "success", "prefix", "actions"}
|
|
assert keys.issubset(set(res.keys()))
|
|
assert res["success"]
|
|
assert len(res["actions"]["UNLINK"]) == 1
|
|
assert res["actions"]["UNLINK"][0]["name"] == "xtl"
|
|
assert res["actions"]["PREFIX"] == TestRemove.prefix
|
|
|
|
def test_remove_no_prune_deps(self, env_created):
|
|
helpers.install("xframe", "-n", TestRemove.env_name, no_dry_run=True)
|
|
|
|
res = helpers.remove("xtensor", "-p", TestRemove.prefix, "--json", "--no-prune-deps")
|
|
|
|
keys = {"dry_run", "success", "prefix", "actions"}
|
|
assert keys.issubset(set(res.keys()))
|
|
assert res["success"]
|
|
assert len(res["actions"]["UNLINK"]) == 2
|
|
removed_names = [x["name"] for x in res["actions"]["UNLINK"]]
|
|
assert "xtensor" in removed_names
|
|
assert "xframe" in removed_names
|
|
assert res["actions"]["PREFIX"] == TestRemove.prefix
|
|
|
|
def test_remove_in_use(self, env_created):
|
|
helpers.install("python=3.9", "-n", self.env_name, "--json", no_dry_run=True)
|
|
if platform.system() == "Windows":
|
|
pyexe = Path(self.prefix) / "python.exe"
|
|
else:
|
|
pyexe = Path(self.prefix) / "bin" / "python"
|
|
|
|
env = helpers.get_fake_activate(self.prefix)
|
|
|
|
pyproc = subprocess.Popen(
|
|
pyexe, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env
|
|
)
|
|
time.sleep(1)
|
|
|
|
helpers.remove("python", "-v", "-p", self.prefix, no_dry_run=True)
|
|
|
|
if platform.system() == "Windows":
|
|
pyexe_trash = Path(str(pyexe) + ".mamba_trash")
|
|
assert pyexe.exists() is False
|
|
pyexe_trash_exists = pyexe_trash.exists()
|
|
trash_file = Path(self.prefix) / "conda-meta" / "mamba_trash.txt"
|
|
|
|
if pyexe_trash_exists:
|
|
assert pyexe_trash.exists()
|
|
assert trash_file.exists()
|
|
all_trash_files = list(Path(self.prefix).rglob("*.mamba_trash"))
|
|
|
|
with open(trash_file, "r") as fi:
|
|
lines = [x.strip() for x in fi.readlines()]
|
|
assert all([line.endswith(".mamba_trash") for line in lines])
|
|
assert len(all_trash_files) == len(lines)
|
|
linesp = [Path(self.prefix) / line for line in lines]
|
|
for atf in all_trash_files:
|
|
assert atf in linesp
|
|
else:
|
|
assert trash_file.exists() is False
|
|
assert pyexe_trash.exists() is False
|
|
# No change if file still in use
|
|
helpers.install("cpp-filesystem", "-n", self.env_name, "--json", no_dry_run=True)
|
|
|
|
if pyexe_trash_exists:
|
|
assert trash_file.exists()
|
|
assert pyexe_trash.exists()
|
|
|
|
with open(trash_file, "r") as fi:
|
|
lines = [x.strip() for x in fi.readlines()]
|
|
assert all([line.endswith(".mamba_trash") for line in lines])
|
|
assert len(all_trash_files) == len(lines)
|
|
linesp = [Path(self.prefix) / line for line in lines]
|
|
for atf in all_trash_files:
|
|
assert atf in linesp
|
|
else:
|
|
assert trash_file.exists() is False
|
|
assert pyexe_trash.exists() is False
|
|
|
|
subprocess.Popen("TASKKILL /F /PID {pid} /T".format(pid=pyproc.pid))
|
|
# check that another env mod clears lingering trash files
|
|
time.sleep(0.5)
|
|
helpers.install("xsimd", "-n", self.env_name, "--json", no_dry_run=True)
|
|
assert trash_file.exists() is False
|
|
assert pyexe_trash.exists() is False
|
|
|
|
else:
|
|
assert pyexe.exists() is False
|
|
pyproc.kill()
|
|
|
|
|
|
class TestRemoveConfig:
|
|
current_root_prefix = os.environ["MAMBA_ROOT_PREFIX"]
|
|
current_prefix = os.environ["CONDA_PREFIX"]
|
|
|
|
env_name = helpers.random_string()
|
|
root_prefix = os.path.expanduser(os.path.join("~", "tmproot" + helpers.random_string()))
|
|
prefix = os.path.join(root_prefix, "envs", env_name)
|
|
|
|
@staticmethod
|
|
@pytest.fixture(scope="class")
|
|
def root(existing_cache):
|
|
os.environ["MAMBA_ROOT_PREFIX"] = TestRemoveConfig.root_prefix
|
|
os.environ["CONDA_PREFIX"] = TestRemoveConfig.prefix
|
|
helpers.create("-n", "base", no_dry_run=True)
|
|
helpers.create("-n", TestRemoveConfig.env_name, "--offline", no_dry_run=True)
|
|
|
|
yield
|
|
|
|
os.environ["MAMBA_ROOT_PREFIX"] = TestRemoveConfig.current_root_prefix
|
|
os.environ["CONDA_PREFIX"] = TestRemoveConfig.current_prefix
|
|
shutil.rmtree(TestRemoveConfig.root_prefix)
|
|
|
|
@staticmethod
|
|
@pytest.fixture
|
|
def env_created(root):
|
|
os.environ["MAMBA_ROOT_PREFIX"] = TestRemoveConfig.root_prefix
|
|
os.environ["CONDA_PREFIX"] = TestRemoveConfig.prefix
|
|
|
|
yield
|
|
|
|
for v in ("CONDA_CHANNELS", "MAMBA_TARGET_PREFIX"):
|
|
if v in os.environ:
|
|
os.environ.pop(v)
|
|
|
|
@classmethod
|
|
def common_tests(cls, res, root_prefix=root_prefix, target_prefix=prefix):
|
|
assert res["root_prefix"] == root_prefix
|
|
assert res["target_prefix"] == target_prefix
|
|
assert res["use_target_prefix_fallback"]
|
|
checks = (
|
|
helpers.MAMBA_ALLOW_EXISTING_PREFIX
|
|
| helpers.MAMBA_NOT_ALLOW_MISSING_PREFIX
|
|
| helpers.MAMBA_NOT_ALLOW_NOT_ENV_PREFIX
|
|
| helpers.MAMBA_EXPECT_EXISTING_PREFIX
|
|
)
|
|
assert res["target_prefix_checks"] == checks
|
|
|
|
def test_specs(self, env_created):
|
|
specs = ["xframe", "xtl"]
|
|
cmd = list(specs)
|
|
|
|
res = helpers.remove(*cmd, "--print-config-only")
|
|
|
|
TestRemoveConfig.common_tests(res)
|
|
assert res["env_name"] == ""
|
|
assert res["specs"] == specs
|
|
|
|
def test_remove_then_clean(self, env_created):
|
|
env_file = __this_dir__ / "env-requires-pip-install.yaml"
|
|
env_name = "env_to_clean"
|
|
helpers.create("-n", env_name, "-f", env_file, no_dry_run=True)
|
|
helpers.remove("-n", env_name, "pip", no_dry_run=True)
|
|
helpers.clean("-ay", no_dry_run=True)
|
|
|
|
@pytest.mark.parametrize("root_prefix", (None, "env_var", "cli"))
|
|
@pytest.mark.parametrize("target_is_root", (False, True))
|
|
@pytest.mark.parametrize("cli_prefix", (False, True))
|
|
@pytest.mark.parametrize("cli_env_name", (False, True))
|
|
@pytest.mark.parametrize("env_var", (False, True))
|
|
@pytest.mark.parametrize("fallback", (False, True))
|
|
def test_target_prefix(
|
|
self,
|
|
root_prefix,
|
|
target_is_root,
|
|
cli_prefix,
|
|
cli_env_name,
|
|
env_var,
|
|
fallback,
|
|
env_created,
|
|
):
|
|
cmd = []
|
|
|
|
if root_prefix in (None, "cli"):
|
|
os.environ["MAMBA_DEFAULT_ROOT_PREFIX"] = os.environ.pop("MAMBA_ROOT_PREFIX")
|
|
|
|
if root_prefix == "cli":
|
|
cmd += ["-r", TestRemoveConfig.root_prefix]
|
|
|
|
r = TestRemoveConfig.root_prefix
|
|
|
|
if target_is_root:
|
|
p = r
|
|
n = "base"
|
|
else:
|
|
p = TestRemoveConfig.prefix
|
|
n = TestRemoveConfig.env_name
|
|
|
|
if cli_prefix:
|
|
cmd += ["-p", p]
|
|
|
|
if cli_env_name:
|
|
cmd += ["-n", n]
|
|
|
|
if env_var:
|
|
os.environ["MAMBA_TARGET_PREFIX"] = p
|
|
|
|
if not fallback:
|
|
os.environ.pop("CONDA_PREFIX")
|
|
else:
|
|
os.environ["CONDA_PREFIX"] = p
|
|
|
|
if (cli_prefix and cli_env_name) or not (cli_prefix or cli_env_name or env_var or fallback):
|
|
with pytest.raises(subprocess.CalledProcessError):
|
|
helpers.remove(*cmd, "--print-config-only")
|
|
else:
|
|
res = helpers.remove(*cmd, "--print-config-only")
|
|
TestRemoveConfig.common_tests(res, root_prefix=r, target_prefix=p)
|