From 120c3429e2bd3c34570a43d6b3d35fca19f16b6a Mon Sep 17 00:00:00 2001
From: iamashwin99 <ashwin-kumar.karnad@mpsd.mpg.de>
Date: Fri, 4 Aug 2023 14:06:26 +0200
Subject: [PATCH] add tests for remove command

- removed the old test_remove_environment
- modified the create_fake_environment to current specs
- add tests for removing package_sets and releases
---
 tests/test_mpsd_software.py | 188 +++++++++++++++++++++++++++---------
 1 file changed, 144 insertions(+), 44 deletions(-)

diff --git a/tests/test_mpsd_software.py b/tests/test_mpsd_software.py
index 2813417..f7ca722 100644
--- a/tests/test_mpsd_software.py
+++ b/tests/test_mpsd_software.py
@@ -8,8 +8,9 @@ from pathlib import Path
 import logging
 import datetime
 import sys
-
+import yaml
 import pytest
+import copy
 
 mod = importlib.import_module("mpsd_software_manager.mpsd_software")
 
@@ -468,8 +469,9 @@ def create_fake_environment(tmp_path, mpsd_release, expected_toolchain_map=None)
         toolchain_lmod_folder.mkdir(parents=True, exist_ok=True)
         spack_folder = tmp_path / mpsd_release / microarch / "spack"
         spack_folder.mkdir(parents=True, exist_ok=True)
-        logs_folder = tmp_path / mpsd_release / microarch / "logs"
+        logs_folder = tmp_path / mpsd_release / "logs"
         logs_folder.mkdir(parents=True, exist_ok=True)
+        (logs_folder / "test.log").touch()
         for toolchain in expected_toolchain_map[microarch]:
             toolchain_lua_file = toolchain_lmod_folder / f"{toolchain}.lua"
             toolchain_lua_file.touch()
@@ -477,48 +479,6 @@ def create_fake_environment(tmp_path, mpsd_release, expected_toolchain_map=None)
     return expected_toolchain_map
 
 
-def test_environment_status(tmp_path):
-    """Test that the environment status is correct."""
-    toolchain_map = mod.environment_status("fake-release", tmp_path)
-    assert toolchain_map is None
-    mpsd_release = "dev-23a"
-    expected_toolchain_map = create_fake_environment(tmp_path, mpsd_release)
-    # check that the environment statuxis is correct
-    toolchain_map = mod.environment_status(mpsd_release, tmp_path)
-    # convert each list to a set to ensure that the order doesn't matter
-    for microarch in expected_toolchain_map.keys():
-        assert set(toolchain_map[microarch]) == set(expected_toolchain_map[microarch])
-
-
-def test_remove_environment(tmp_path):
-    """Test that the remove_environment works as expected."""
-    mpsd_release = "dev-23a"
-    # create a fake environment
-    create_fake_environment(tmp_path, mpsd_release)
-    # check that the environment status is correct
-    toolchain_map = mod.environment_status(mpsd_release, tmp_path)
-    assert toolchain_map is not None
-
-    # test removal  without arguments (should sys.exit(1))
-    create_fake_environment(tmp_path, mpsd_release)
-    with pytest.raises(SystemExit) as pytest_wrapped_e:
-        mod.remove_environment(mpsd_release, tmp_path, force_remove=True)
-    assert pytest_wrapped_e.type == SystemExit
-    assert pytest_wrapped_e.value.code == 1
-
-    # test removal of the complete environment
-    create_fake_environment(tmp_path, mpsd_release)
-    mod.remove_environment(mpsd_release, tmp_path, ["ALL"], force_remove=True)
-    toolchain_map = mod.environment_status(mpsd_release, tmp_path)
-    assert toolchain_map is None
-    # ensure that logs folder remains
-    logs_folder = tmp_path / mpsd_release / mod.get_native_microarchitecture() / "logs"
-    assert logs_folder.exists()
-
-    # test removal of a single toolchain
-    # done in test_install_environment_zlib
-
-
 def test_initialise_environment(tmp_path):
     """Test that init_file is created as expected."""
     # test that the init file is created as expected
@@ -658,6 +618,146 @@ def test_argument_parsing_logic(mocker):
     ### Copy from 'install' when the time has come.)
 
 
+def test_remove_environment(tmp_path, mocker):
+    """Test that the remove_environment function works as expected."""
+
+    release_to_test = "dev-23a"
+
+    # check exit 50 when no package_sets are provided
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        mod.remove_environment("dev-23a", tmp_path)
+    assert pytest_wrapped_e.type == SystemExit
+    assert pytest_wrapped_e.value.code == 50
+
+    # Test case2  - remove entire release
+    ## exit with 60 when force is not set
+    ### patch the input function to return 'n'
+    mocker.patch("builtins.input", return_value="n")
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        mod.remove_environment(release_to_test, tmp_path, "ALL")
+    assert pytest_wrapped_e.type == SystemExit
+    assert pytest_wrapped_e.value.code == 60
+    ### patch the input function to return 'y'
+    mocker.patch("builtins.input", return_value="y")
+    # check that the release directory is removed and logs are kept
+    # create a release directory
+    create_fake_environment(tmp_path, release_to_test)
+    release_dir = tmp_path / release_to_test / mod.get_native_microarchitecture()
+    logs_dir = tmp_path / release_to_test / "logs"
+
+    toolchain_map = mod.environment_status(release_to_test, tmp_path)
+    assert toolchain_map is not None
+    mod.remove_environment(release_to_test, tmp_path, "ALL")
+
+    toolchain_map = mod.environment_status(release_to_test, tmp_path)
+    # check that no toolchain remains
+    assert toolchain_map is None
+    # check that the release directory is empty
+    assert len(list(release_dir.iterdir())) == 0
+    # check that the logs directory is non-empty
+    assert len(list(logs_dir.iterdir())) == 1
+
+    # Test case3  - remove specific package_sets
+    # defined in test_remove_package_sets
+
+
+@pytest.fixture
+def simple_toolchain():
+    """returns a dict for a simple toolchain"""
+    dict = {
+        "spack": {
+            "specs": ["zlib@1.2.13"],
+            "view": True,
+            "concretizer": {"reuse": False, "unify": True},
+        }
+    }
+    return dict
+
+
+def install_test_release(tmp_path, simple_toolchain):
+    """Install a test release
+
+    with toolchain1 and toolchain2 to use for testing.
+    """
+
+    release_to_test = "dev-23a"
+    # prepare a release directory
+    mod.prepare_environment(mpsd_release=release_to_test, root_dir=tmp_path)
+
+    tmp_path / release_to_test / mod.get_native_microarchitecture()
+    spe_dir = tmp_path / release_to_test / "spack-environments"
+
+    # create sample toolchains
+    simple_toolchain_string = yaml.dump(simple_toolchain)
+    simple_toolchain_2 = copy.deepcopy(simple_toolchain)
+    simple_toolchain_2["spack"]["specs"] = ["zlib@1.2.13", "zstd@1.5.2"]
+    simple_toolchain2_string = yaml.dump(simple_toolchain_2)
+    toolchain1_dir = spe_dir / "toolchains" / "toolchain1"
+    toolchain2_dir = spe_dir / "toolchains" / "toolchain2"
+    toolchain1_dir.mkdir(parents=True)
+    toolchain2_dir.mkdir(parents=True)
+    (toolchain1_dir / "spack.yaml").write_text(simple_toolchain_string)
+    (toolchain2_dir / "spack.yaml").write_text(simple_toolchain2_string)
+
+    # install the release
+    mod.install_environment(
+        mpsd_release=release_to_test,
+        package_sets=["toolchain1", "toolchain2"],
+        root_dir=tmp_path,
+    )
+
+
+def test_remove_package_sets(tmp_path, simple_toolchain):
+    """Test removal of package_sets via spack."""
+
+    release_to_test = "dev-23a"
+
+    # Case1 - remove global / global_generic package_sets
+
+    # Case2 - remove specific package_sets (toolchains)
+    # Create a test install
+    install_test_release(tmp_path, simple_toolchain)
+    # check that the installation went through
+    release_dir = tmp_path / release_to_test / mod.get_native_microarchitecture()
+    assert len(list(release_dir.iterdir())) == 2  # spack and lmod
+    # check that the two toolchains are installed
+    assert (
+        len(list((release_dir / "spack" / "var" / "spack" / "environments").iterdir()))
+        == 2
+    )
+
+    # remove toolchain2
+    # toolchain1 contains - zlib@1.2
+    # toolchain2 contains - zlib@1.2 and zstd@1.5
+    # we check that removing toolchain2 removes zstd@1.5 but NOT zlib@1.2
+    # and the environment toolchain2 is also removed
+
+    mod.remove_environment(
+        mpsd_release=release_to_test,
+        root_dir=tmp_path,
+        package_sets=["toolchain2"],
+        force_remove=True,
+    )
+    # now check that only toolchain1 is installed
+    assert (
+        len(list((release_dir / "spack" / "var" / "spack" / "environments").iterdir()))
+        == 1
+    )
+    # check that zlib@1.2 is still installed
+    # spack location -i <package> exit 0 if installed and 1 if not installed
+    source_spack = (
+        f'source {release_dir / "spack" / "share" / "spack" / "setup-env.sh"}'
+    )
+    mod.run(f"{source_spack} && spack location -i zlib", shell=True, check=True)
+    # check that zstd@1.5 is not installed
+    # we are here flipping the exit code to check that it is not installed
+    mod.run(
+        f"{source_spack} && (spack location -i zstd && exit 1 || exit 0 )",
+        shell=True,
+        check=True,
+    )
+
+
 def test_interface(tmp_path):
     """Test other things (not implemented yet)."""
     pass
-- 
GitLab