diff options
Diffstat (limited to 'lib/spack/spack/test/env.py')
-rw-r--r-- | lib/spack/spack/test/env.py | 210 |
1 files changed, 192 insertions, 18 deletions
diff --git a/lib/spack/spack/test/env.py b/lib/spack/spack/test/env.py index 77ccd7889e..913eb7bf9e 100644 --- a/lib/spack/spack/test/env.py +++ b/lib/spack/spack/test/env.py @@ -3,8 +3,8 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) """Test environment internals without CLI""" -import io import os +import pickle import sys import pytest @@ -13,16 +13,28 @@ import llnl.util.filesystem as fs import spack.environment as ev import spack.spec +from spack.environment.environment import SpackEnvironmentViewError, _error_on_nonempty_view_dir pytestmark = pytest.mark.skipif( sys.platform == "win32", reason="Envs are not supported on windows" ) -def test_hash_change_no_rehash_concrete(tmpdir, mock_packages, config): +class TestDirectoryInitialization: + def test_environment_dir_from_name(self, mutable_mock_env_path): + """Test the function mapping a managed environment name to its folder.""" + env = ev.create("test") + environment_dir = ev.environment_dir_from_name("test") + assert env.path == environment_dir + with pytest.raises(ev.SpackEnvironmentError, match="environment already exists"): + ev.environment_dir_from_name("test", exists_ok=False) + + +def test_hash_change_no_rehash_concrete(tmp_path, mock_packages, config): # create an environment - env_path = tmpdir.mkdir("env_dir").strpath - env = ev.Environment(env_path) + env_path = tmp_path / "env_dir" + env_path.mkdir(exist_ok=False) + env = ev.create_in_dir(env_path) env.write() # add a spec with a rewritten build hash @@ -48,9 +60,10 @@ def test_hash_change_no_rehash_concrete(tmpdir, mock_packages, config): assert read_in.specs_by_hash[read_in.concretized_order[0]]._hash == new_hash -def test_env_change_spec(tmpdir, mock_packages, config): - env_path = tmpdir.mkdir("env_dir").strpath - env = ev.Environment(env_path) +def test_env_change_spec(tmp_path, mock_packages, config): + env_path = tmp_path / "env_dir" + env_path.mkdir(exist_ok=False) + env = ev.create_in_dir(env_path) env.write() spec = spack.spec.Spec("mpileaks@2.1~shared+debug") @@ -80,9 +93,10 @@ env: """ -def test_env_change_spec_in_definition(tmpdir, mock_packages, config, mutable_mock_env_path): - initial_yaml = io.StringIO(_test_matrix_yaml) - e = ev.create("test", initial_yaml) +def test_env_change_spec_in_definition(tmp_path, mock_packages, config, mutable_mock_env_path): + manifest_file = tmp_path / ev.manifest_name + manifest_file.write_text(_test_matrix_yaml) + e = ev.create("test", manifest_file) e.concretize() e.write() @@ -96,10 +110,11 @@ def test_env_change_spec_in_definition(tmpdir, mock_packages, config, mutable_mo def test_env_change_spec_in_matrix_raises_error( - tmpdir, mock_packages, config, mutable_mock_env_path + tmp_path, mock_packages, config, mutable_mock_env_path ): - initial_yaml = io.StringIO(_test_matrix_yaml) - e = ev.create("test", initial_yaml) + manifest_file = tmp_path / ev.manifest_name + manifest_file.write_text(_test_matrix_yaml) + e = ev.create("test", manifest_file) e.concretize() e.write() @@ -131,8 +146,8 @@ def test_user_view_path_is_not_canonicalized_in_yaml(tmpdir, config): # Serialize environment with relative view path with fs.working_dir(str(tmpdir)): - fst = ev.Environment(env_path, with_view=view) - fst.write() + fst = ev.create_in_dir(env_path, with_view=view) + fst.regenerate_views() # The view link should be created assert os.path.isdir(absolute_view) @@ -141,7 +156,7 @@ def test_user_view_path_is_not_canonicalized_in_yaml(tmpdir, config): # and also check that the getter is pointing to the right dir. with fs.working_dir(str(tmpdir)): snd = ev.Environment(env_path) - assert snd.yaml["spack"]["view"] == view + assert snd.manifest["spack"]["view"] == view assert os.path.samefile(snd.default_view.root, absolute_view) @@ -184,8 +199,167 @@ def test_roundtrip_spack_yaml_with_comments(original_content, mock_packages, con spack_yaml = tmp_path / "spack.yaml" spack_yaml.write_text(original_content) - e = ev.Environment(str(tmp_path)) - e.update_manifest() + e = ev.Environment(tmp_path) + e.manifest.flush() content = spack_yaml.read_text() assert content == original_content + + +def test_adding_anonymous_specs_to_env_fails(tmp_path): + """Tests that trying to add an anonymous spec to the 'specs' section of an environment + raises an exception + """ + env = ev.create_in_dir(tmp_path) + with pytest.raises(ev.SpackEnvironmentError, match="cannot add anonymous"): + env.add("%gcc") + + +def test_removing_from_non_existing_list_fails(tmp_path): + """Tests that trying to remove a spec from a non-existing definition fails.""" + env = ev.create_in_dir(tmp_path) + with pytest.raises(ev.SpackEnvironmentError, match="'bar' does not exist"): + env.remove("%gcc", list_name="bar") + + +@pytest.mark.parametrize( + "init_view,update_value", + [ + (True, False), + (True, "./view"), + (False, True), + ("./view", True), + ("./view", False), + (True, True), + (False, False), + ], +) +def test_update_default_view(init_view, update_value, tmp_path, mock_packages, config): + """Tests updating the default view with different values.""" + env = ev.create_in_dir(tmp_path, with_view=init_view) + env.update_default_view(update_value) + env.write(regenerate=True) + if not isinstance(update_value, bool): + assert env.default_view.raw_root == update_value + + expected_value = update_value + if isinstance(init_view, str) and update_value is True: + expected_value = init_view + + assert env.manifest.pristine_yaml_content["spack"]["view"] == expected_value + + +@pytest.mark.parametrize( + "initial_content,update_value,expected_view", + [ + ( + """ +spack: + specs: + - mpileaks + view: + default: + root: ./view-gcc + select: ['%gcc'] + link_type: symlink +""", + "./another-view", + {"root": "./another-view", "select": ["%gcc"], "link_type": "symlink"}, + ), + ( + """ +spack: + specs: + - mpileaks + view: + default: + root: ./view-gcc + select: ['%gcc'] + link_type: symlink +""", + True, + {"root": "./view-gcc", "select": ["%gcc"], "link_type": "symlink"}, + ), + ], +) +def test_update_default_complex_view( + initial_content, update_value, expected_view, tmp_path, mock_packages, config +): + spack_yaml = tmp_path / "spack.yaml" + spack_yaml.write_text(initial_content) + + env = ev.Environment(tmp_path) + env.update_default_view(update_value) + env.write(regenerate=True) + + assert env.default_view.to_dict() == expected_view + + +@pytest.mark.parametrize("filename", [ev.manifest_name, ev.lockfile_name]) +def test_cannot_initialize_in_dir_with_init_file(tmp_path, filename): + """Tests that initializing an environment in a directory with an already existing + spack.yaml or spack.lock raises an exception. + """ + init_file = tmp_path / filename + init_file.touch() + with pytest.raises(ev.SpackEnvironmentError, match="cannot initialize"): + ev.create_in_dir(tmp_path) + + +def test_cannot_initiliaze_if_dirname_exists_as_a_file(tmp_path): + """Tests that initializing an environment using as a location an existing file raises + an error. + """ + dir_name = tmp_path / "dir" + dir_name.touch() + with pytest.raises(ev.SpackEnvironmentError, match="cannot initialize"): + ev.create_in_dir(dir_name) + + +def test_cannot_initiliaze_if_init_file_does_not_exist(tmp_path): + """Tests that initializing an environment passing a non-existing init file raises an error.""" + init_file = tmp_path / ev.manifest_name + with pytest.raises(ev.SpackEnvironmentError, match="cannot initialize"): + ev.create_in_dir(tmp_path, init_file=init_file) + + +def test_cannot_initialize_from_random_file(tmp_path): + init_file = tmp_path / "foo.txt" + init_file.touch() + with pytest.raises(ev.SpackEnvironmentError, match="cannot initialize"): + ev.create_in_dir(tmp_path, init_file=init_file) + + +def test_environment_pickle(tmp_path): + env1 = ev.create_in_dir(tmp_path) + obj = pickle.dumps(env1) + env2 = pickle.loads(obj) + assert isinstance(env2, ev.Environment) + + +def test_error_on_nonempty_view_dir(tmpdir): + """Error when the target is not an empty dir""" + with tmpdir.as_cwd(): + os.mkdir("empty_dir") + os.mkdir("nonempty_dir") + with open(os.path.join("nonempty_dir", "file"), "wb"): + pass + os.symlink("empty_dir", "symlinked_empty_dir") + os.symlink("does_not_exist", "broken_link") + os.symlink("broken_link", "file") + + # This is OK. + _error_on_nonempty_view_dir("empty_dir") + + # This is not OK. + with pytest.raises(SpackEnvironmentViewError): + _error_on_nonempty_view_dir("nonempty_dir") + + with pytest.raises(SpackEnvironmentViewError): + _error_on_nonempty_view_dir("symlinked_empty_dir") + + with pytest.raises(SpackEnvironmentViewError): + _error_on_nonempty_view_dir("broken_link") + + with pytest.raises(SpackEnvironmentViewError): + _error_on_nonempty_view_dir("file") |