test ensure_user_environment

verify behavior for:

- current version (no change)
- old, supported version (upgrade, but not too far)
- too old, re-run installer
- directory exists, no conda
This commit is contained in:
Min RK
2023-03-23 12:34:44 +01:00
parent 594b61003f
commit 4d42f24e48
4 changed files with 120 additions and 3 deletions

View File

@@ -1,10 +1,16 @@
""" """
Unit test functions in installer.py Unit test functions in installer.py
""" """
import json
import os import os
from unittest import mock
from subprocess import run, PIPE
import pytest import pytest
from tljh import conda
from tljh import installer from tljh import installer
from tljh.utils import parse_version as V
from tljh.yaml import yaml from tljh.yaml import yaml
@@ -36,3 +42,111 @@ def test_ensure_admins(tljh_dir, admins, expected_config):
# verify the list was flattened # verify the list was flattened
assert config["users"]["admin"] == expected_config assert config["users"]["admin"] == expected_config
def setup_conda(distro, version, prefix):
"""Install mambaforge or miniconda in a prefix"""
if distro == "mambaforge":
installer_url, _ = installer._mambaforge_url(version)
elif distro == "miniconda":
arch = os.uname().machine
installer_url = (
f"https://repo.anaconda.com/miniconda/Miniconda3-{version}-Linux-{arch}.sh"
)
else:
raise ValueError(f"{distro=} must be 'miniconda' or 'mambaforge'")
with conda.download_miniconda_installer(installer_url, None) as installer_path:
conda.install_miniconda(installer_path, str(prefix))
@pytest.fixture
def user_env_prefix(tmp_path):
user_env_prefix = tmp_path / "user_env"
with mock.patch.object(installer, "USER_ENV_PREFIX", str(user_env_prefix)):
yield user_env_prefix
@pytest.mark.parametrize(
"distro, version, conda_version, mamba_version",
[
(
None,
None,
installer.MAMBAFORGE_CONDA_VERSION,
installer.MAMBAFORGE_MAMBA_VERSION,
),
(
"exists",
None,
installer.MAMBAFORGE_CONDA_VERSION,
installer.MAMBAFORGE_MAMBA_VERSION,
),
(
"mambaforge",
"22.11.1-4",
installer.MAMBAFORGE_CONDA_VERSION,
installer.MAMBAFORGE_MAMBA_VERSION,
),
("mambaforge", "4.10.3-7", "4.10.3", "0.16.0"),
(
"miniconda",
"4.7.10",
installer.MAMBAFORGE_CONDA_VERSION,
installer.MAMBAFORGE_MAMBA_VERSION,
),
(
"miniconda",
"4.5.1",
installer.MAMBAFORGE_CONDA_VERSION,
installer.MAMBAFORGE_MAMBA_VERSION,
),
],
)
def test_ensure_user_environment(
user_env_prefix,
distro,
version,
conda_version,
mamba_version,
):
if version and V(version) < V("4.10.1") and os.uname().machine == "aarch64":
pytest.skip(f"Miniconda {version} not available for aarch64")
canary_file = user_env_prefix / "test-file.txt"
canary_package = "types-backports_abc"
if distro:
if distro == "exists":
user_env_prefix.mkdir()
else:
setup_conda(distro, version, user_env_prefix)
# install a noarch: python package that won't be used otherwise
# should depend on Python, so it will interact with possible upgrades
run(
[str(user_env_prefix / "bin/conda"), "install", "-y", canary_package],
input="",
check=True,
)
# make a file not managed by conda, to check for wipeouts
with canary_file.open("w") as f:
f.write("I'm here\n")
installer.ensure_user_environment("")
p = run(
[str(user_env_prefix / "bin/conda"), "list", "--json"],
stdout=PIPE,
text=True,
check=True,
)
package_list = json.loads(p.stdout)
packages = {package["name"]: package for package in package_list}
if distro:
# make sure we didn't wipe out files
assert canary_file.exists()
if distro != "exists":
# make sure we didn't delete the installed package
assert canary_package in packages
assert "conda" in packages
assert packages["conda"]["version"] == conda_version
assert "mamba" in packages
assert packages["mamba"]["version"] == mamba_version

View File

@@ -96,7 +96,7 @@ def download_miniconda_installer(installer_url, sha256sum):
t = time.perf_counter() - tic t = time.perf_counter() - tic
logger.info(f"Downloaded conda installer {installer_url} in {t:.1f}s") logger.info(f"Downloaded conda installer {installer_url} in {t:.1f}s")
if sha256_file(f.name) != sha256sum: if sha256sum and sha256_file(f.name) != sha256sum:
raise Exception("sha256sum hash mismatch! Downloaded file corrupted") raise Exception("sha256sum hash mismatch! Downloaded file corrupted")
yield f.name yield f.name

View File

@@ -224,7 +224,7 @@ def ensure_user_environment(user_requirements_txt_file):
if not found_conda: if not found_conda:
if os.path.exists(USER_ENV_PREFIX): if os.path.exists(USER_ENV_PREFIX):
logger.warning( logger.warning(
f"Found prefix at {USER_ENV_PREFIX}, but too old or missing conda/mamba ({have_versions}). Rebuilding env from scratch!!" f"Found prefix at {USER_ENV_PREFIX}, but too old or missing conda/mamba ({have_versions}). Upgrading from mambaforge."
) )
# FIXME: should this fail? I'm not sure how destructive it is # FIXME: should this fail? I'm not sure how destructive it is
logger.info("Downloading & setting up user environment...") logger.info("Downloading & setting up user environment...")

View File

@@ -2,6 +2,7 @@
Miscellaneous functions useful in at least two places unrelated to each other Miscellaneous functions useful in at least two places unrelated to each other
""" """
import logging import logging
import re
import subprocess import subprocess
# Copied into bootstrap/bootstrap.py. Make sure these two copies are exactly the same! # Copied into bootstrap/bootstrap.py. Make sure these two copies are exactly the same!
@@ -67,4 +68,6 @@ def parse_version(version_string):
Finds all numbers and returns a tuple of ints Finds all numbers and returns a tuple of ints
_very_ loose version parsing, like the old distutils.version.LooseVersion _very_ loose version parsing, like the old distutils.version.LooseVersion
""" """
return tuple(int(part) for part in version_string.split(".")) # return a tuple of all the numbers in the version string
# always succeeds, even if passed nonsense
return tuple(int(part) for part in re.findall(r"\d+", version_string))