Skip to content

Commit

Permalink
Convert app clean-up step into fixture
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoesters committed Jan 8, 2025
1 parent 67d08a9 commit 5dcdff4
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 186 deletions.
118 changes: 51 additions & 67 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,76 +1,60 @@
import itertools
import os
import subprocess
import shutil
import sys
from pathlib import Path

# TIP: You can debug the tests with this setup:
# CONDA_STANDALONE=src/entry_point.py pytest ...
CONDA_EXE = os.environ.get(
"CONDA_STANDALONE",
os.path.join(sys.prefix, "standalone_conda", "conda.exe"),
)
import pytest
from utils import _get_shortcut_dirs


menuinst_pkg_specs = [
(
"conda-test/label/menuinst-tests::package_1",
{
"win32": "Package 1/A.lnk",
"darwin": "A.app",
"linux": "package-1_a.desktop",
},
),
]
if os.name == "nt":
menuinst_pkg_specs.append(
@pytest.fixture
def menuinst_pkg_specs():
specs = [
(
"conda-forge::miniforge_console_shortcut",
{"win32": "{base}/{base} Prompt ({name}).lnk"},
"conda-test/label/menuinst-tests::package_1",
{
"win32": "Package 1/A.lnk",
"darwin": "A.app",
"linux": "package-1_a.desktop",
},
),
)


def run_conda(*args, **kwargs) -> subprocess.CompletedProcess:
check = kwargs.pop("check", False)
sudo = None
if "needs_sudo" in kwargs:
if kwargs["needs_sudo"]:
if sys.platform == "win32":
raise NotImplementedError(
"Calling run_conda with elevated privileged is not available on Windows"
)
sudo = ["sudo", "-E"]
del kwargs["needs_sudo"]
cmd = [*sudo, CONDA_EXE] if sudo else [CONDA_EXE]

process = subprocess.run([*cmd, *args], **kwargs)
if check:
if kwargs.get("capture_output"):
print(process.stdout)
print(process.stderr, file=sys.stderr)
process.check_returncode()
return process


def _get_shortcut_dirs() -> list[Path]:
if sys.platform == "win32":
from menuinst.platforms.win_utils.knownfolders import dirs_src as win_locations

return [
Path(win_locations["user"]["start"][0]),
Path(win_locations["system"]["start"][0]),
]
if sys.platform == "darwin":
return [
Path(os.environ["HOME"], "Applications"),
Path("/Applications"),
]
if sys.platform == "linux":
paths = [
Path(os.environ["HOME"], ".local", "share", "applications"),
Path("/usr/share/applications"),
]
if os.name == "nt":
specs.append(
(
"conda-forge::miniforge_console_shortcut",
{"win32": "{base}/{base} Prompt ({name}).lnk"},
),
)
return specs


# If the test app already exists, tests will fail,
# so clean up before and after the run.
def _clean_macos_apps(shortcuts: dict[str, list[Path]]):
if not sys.platform == "darwin":
return
for shortcut in itertools.chain.from_iterable(shortcuts.values()):
if shortcut.exists():
shutil.rmtree(shortcut)


@pytest.fixture
def clean_shortcuts(
tmp_path: Path, menuinst_pkg_specs: list[tuple[str, dict[str, str]]]
):
# The shortcut will take 'root_prefix' as the base, but conda-standalone
# sets that to its temporary 'sys.prefix' as provided by the pyinstaller
# self-extraction. We override it via 'CONDA_ROOT_PREFIX' in the same
# way 'constructor' will do it.
variables = {"base": Path(sys.prefix).name, "name": tmp_path.name}
shortcuts = {}
for package, spec in menuinst_pkg_specs:
shortcuts[package] = [
folder / spec[sys.platform].format(**variables)
for folder in _get_shortcut_dirs()
]
if xdg_data_home := os.environ.get("XDG_DATA_HOME"):
paths.append(Path(xdg_data_home, "applications"))
return paths
raise NotImplementedError(sys.platform)
_clean_macos_apps(shortcuts)
yield shortcuts
_clean_macos_apps(shortcuts)
202 changes: 87 additions & 115 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
from pathlib import Path

import pytest
from conftest import CONDA_EXE, _get_shortcut_dirs, menuinst_pkg_specs, run_conda
from ruamel.yaml import YAML
from utils import CONDA_EXE, run_conda

HERE = Path(__file__).parent

Expand Down Expand Up @@ -169,101 +169,66 @@ def test_extract_conda_pkgs_num_processors(tmp_path: Path):
)


_pkg_specs_params = pytest.mark.parametrize(
"pkg_spec, shortcut_path", menuinst_pkg_specs
)


@_pkg_specs_params
def test_menuinst_conda(tmp_path: Path, pkg_spec: str, shortcut_path: dict[str, str]):
def test_menuinst_conda(tmp_path: Path, clean_shortcuts: dict[str, list[Path]]):
"Check 'regular' conda can process menuinst JSONs"

# If the test app already exists, this test will fail,
# so clean up before and after the run.
def _clean_macos_apps(shortcuts: list[Path]):
if not sys.platform == "darwin":
return
for shortcut in shortcuts:
if shortcut.exists():
shutil.rmtree(shortcut)

env = os.environ.copy()
env["CONDA_ROOT_PREFIX"] = sys.prefix
# The shortcut will take 'root_prefix' as the base, but conda-standalone
# sets that to its temporary 'sys.prefix' as provided by the pyinstaller
# self-extraction. We override it via 'CONDA_ROOT_PREFIX' in the same
# way 'constructor' will do it.
variables = {"base": Path(sys.prefix).name, "name": tmp_path.name}
shortcuts = [
folder / shortcut_path[sys.platform].format(**variables)
for folder in _get_shortcut_dirs()
process = run_conda(
"create",
"-vvv",
"-p",
tmp_path,
"-y",
*clean_shortcuts.keys(),
"--no-deps",
env=env,
capture_output=True,
text=True,
check=True,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
assert "menuinst Exception" not in process.stdout
assert list(tmp_path.glob("Menu/*.json"))
shortcuts_found = [
package
for package, shortcuts in clean_shortcuts.items()
if any(shortcut.exists() for shortcut in shortcuts)
]
_clean_macos_apps(shortcuts)
try:
process = run_conda(
"create",
"-vvv",
"-p",
tmp_path,
"-y",
pkg_spec,
"--no-deps",
env=env,
capture_output=True,
text=True,
check=True,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
assert "menuinst Exception" not in process.stdout
assert list(tmp_path.glob("Menu/*.json"))
assert any(shortcut.exists() for shortcut in shortcuts)
process = run_conda(
"remove",
"-vvv",
"-p",
tmp_path,
"-y",
pkg_spec.split("::")[-1],
env=env,
capture_output=True,
text=True,
check=True,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
assert not any(shortcut.exists() for shortcut in shortcuts)
finally:
_clean_macos_apps(shortcuts)
assert sorted(shortcuts_found) == sorted(clean_shortcuts.keys())
process = run_conda(
"remove",
"-vvv",
"-p",
tmp_path,
"-y",
*[pkg_spec.split("::")[-1] for pkg_spec in clean_shortcuts.keys()],
env=env,
capture_output=True,
text=True,
check=True,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
shortcuts_found = [
package
for package, shortcuts in clean_shortcuts.items()
if any(shortcut.exists() for shortcut in shortcuts)
]
assert shortcuts_found == []


@_pkg_specs_params
def test_menuinst_constructor(tmp_path: Path, pkg_spec: str, shortcut_path: str):
def test_menuinst_constructor(tmp_path: Path, clean_shortcuts: dict[str, list[Path]]):
"The constructor helper should also be able to process menuinst JSONs"

# If the test app already exists, this test will fail,
# so clean up before and after the run.
def _clean_macos_apps(shortcuts: list[Path]):
if not sys.platform == "darwin":
return
for shortcut in shortcuts:
if shortcut.exists():
shutil.rmtree(shortcut)

run_kwargs = dict(capture_output=True, text=True, check=True)
variables = {"base": Path(sys.prefix).name, "name": tmp_path.name}
shortcuts = [
folder / shortcut_path[sys.platform].format(**variables)
for folder in _get_shortcut_dirs()
]
_clean_macos_apps(shortcuts)
process = run_conda(
"create",
"-vvv",
"-p",
tmp_path,
"-y",
pkg_spec,
*clean_shortcuts.keys(),
"--no-deps",
"--no-shortcuts",
**run_kwargs,
Expand All @@ -274,40 +239,47 @@ def _clean_macos_apps(shortcuts: list[Path]):

env = os.environ.copy()
env["CONDA_ROOT_PREFIX"] = sys.prefix
try:
process = run_conda(
"constructor",
# Not supported in micromamba's interface yet
# use CONDA_ROOT_PREFIX instead
# "--root-prefix",
# sys.prefix,
"--prefix",
tmp_path,
"--make-menus",
**run_kwargs,
env=env,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
assert any(shortcut.exists() for shortcut in shortcuts)

process = run_conda(
"constructor",
# Not supported in micromamba's interface yet
# use CONDA_ROOT_PREFIX instead
# "--root-prefix",
# sys.prefix,
"--prefix",
tmp_path,
"--rm-menus",
**run_kwargs,
env=env,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
assert not any(shortcut.exists() for shortcut in shortcuts)
finally:
_clean_macos_apps(shortcuts)
process = run_conda(
"constructor",
# Not supported in micromamba's interface yet
# use CONDA_ROOT_PREFIX instead
# "--root-prefix",
# sys.prefix,
"--prefix",
tmp_path,
"--make-menus",
**run_kwargs,
env=env,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
shortcuts_found = [
package
for package, shortcuts in clean_shortcuts.items()
if any(shortcut.exists() for shortcut in shortcuts)
]
assert sorted(shortcuts_found) == sorted(clean_shortcuts.keys())

process = run_conda(
"constructor",
# Not supported in micromamba's interface yet
# use CONDA_ROOT_PREFIX instead
# "--root-prefix",
# sys.prefix,
"--prefix",
tmp_path,
"--rm-menus",
**run_kwargs,
env=env,
)
print(process.stdout)
print(process.stderr, file=sys.stderr)
shortcuts_found = [
package
for package, shortcuts in clean_shortcuts.items()
if any(shortcut.exists() for shortcut in shortcuts)
]
assert shortcuts_found == []


def test_python():
Expand Down
9 changes: 5 additions & 4 deletions tests/test_uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
run_plan,
run_plan_elevated,
)
from conftest import _get_shortcut_dirs, menuinst_pkg_specs, run_conda
from ruamel.yaml import YAML
from utils import _get_shortcut_dirs, run_conda

if TYPE_CHECKING:
from conda.testing.fixtures import CondaCLIFixture, TmpEnvFixture
Expand Down Expand Up @@ -245,8 +245,9 @@ def test_uninstallation_keep_config_dir(
def test_uninstallation_menuinst(
mock_system_paths: dict[str, Path],
monkeypatch: MonkeyPatch,
menuinst_pkg_specs: list[tuple[str, dict[str, str]]],
):
def _shortcuts_found(shortcut_env: Path) -> list:
def _shortcuts_found(base_env: Path, shortcut_env: Path) -> list:
variables = {
"base": base_env.name,
"name": shortcut_env.name,
Expand Down Expand Up @@ -287,9 +288,9 @@ def _shortcuts_found(shortcut_env: Path) -> list:
shortcuts = [package[0] for package in menuinst_pkg_specs]
shortcut_env = base_env / "envs" / "shortcutenv"
run_conda("create", "-y", "-p", str(shortcut_env), *shortcuts)
assert _shortcuts_found(shortcut_env) == shortcuts
assert _shortcuts_found(base_env, shortcut_env) == shortcuts
run_uninstaller(base_env)
assert _shortcuts_found(shortcut_env) == []
assert _shortcuts_found(base_env, shortcut_env) == []


@pytest.mark.parametrize(
Expand Down
Loading

0 comments on commit 5dcdff4

Please sign in to comment.