summaryrefslogtreecommitdiff
path: root/lib/spack/spack/test/cmd/load.py
blob: e2abe72e0e15d95f41f9572a704e551516627615 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
import re

import pytest

import spack.spec
import spack.user_environment as uenv
import spack.util.environment
from spack.main import SpackCommand

load = SpackCommand("load")
unload = SpackCommand("unload")
install = SpackCommand("install")
location = SpackCommand("location")

pytestmark = pytest.mark.not_on_windows("does not run on windows")


def test_manpath_trailing_colon(
    install_mockery, mock_fetch, mock_archive, mock_packages, working_env
):
    """Test that the commands generated by load add the MANPATH prefix
    inspections. Also test that Spack correctly preserves the default/existing
    manpath search path via a trailing colon"""
    install("mpileaks")

    sh_out = load("--sh", "mpileaks")
    lines = sh_out.split("\n")
    assert any(re.match(r"export MANPATH=.*:;", ln) for ln in lines)

    os.environ["MANPATH"] = "/tmp/man:"

    sh_out = load("--sh", "mpileaks")
    lines = sh_out.split("\n")
    assert any(re.match(r"export MANPATH=.*:/tmp/man:;", ln) for ln in lines)


def test_load_recursive(install_mockery, mock_fetch, mock_archive, mock_packages, working_env):
    """Test that `spack load` applies prefix inspections of its required runtime deps in
    topo-order"""
    install("mpileaks")
    mpileaks_spec = spack.spec.Spec("mpileaks").concretized()

    # Ensure our reference variable is cleed.
    os.environ["CMAKE_PREFIX_PATH"] = "/hello:/world"

    sh_out = load("--sh", "mpileaks")
    csh_out = load("--csh", "mpileaks")

    def extract_cmake_prefix_path(output, prefix):
        return next(cmd for cmd in output.split(";") if cmd.startswith(prefix))[
            len(prefix) :
        ].split(":")

    # Map a prefix found in CMAKE_PREFIX_PATH back to a package name in mpileaks' DAG.
    prefix_to_pkg = lambda prefix: next(
        s.name for s in mpileaks_spec.traverse() if s.prefix == prefix
    )

    paths_sh = extract_cmake_prefix_path(sh_out, prefix="export CMAKE_PREFIX_PATH=")
    paths_csh = extract_cmake_prefix_path(csh_out, prefix="setenv CMAKE_PREFIX_PATH ")

    # Shouldn't be a difference between loading csh / sh, so check they're the same.
    assert paths_sh == paths_csh

    # We should've prepended new paths, and keep old ones.
    assert paths_sh[-2:] == ["/hello", "/world"]

    # All but the last two paths are added by spack load; lookup what packages they're from.
    pkgs = [prefix_to_pkg(p) for p in paths_sh[:-2]]

    # Do we have all the runtime packages?
    assert set(pkgs) == set(
        s.name for s in mpileaks_spec.traverse(deptype=("link", "run"), root=True)
    )

    # Finally, do we list them in topo order?
    for i, pkg in enumerate(pkgs):
        set(s.name for s in mpileaks_spec[pkg].traverse(direction="parents")) in set(pkgs[:i])

    # Lastly, do we keep track that mpileaks was loaded?
    assert f"export {uenv.spack_loaded_hashes_var}={mpileaks_spec.dag_hash()}" in sh_out
    assert f"setenv {uenv.spack_loaded_hashes_var} {mpileaks_spec.dag_hash()}" in csh_out


def test_load_includes_run_env(install_mockery, mock_fetch, mock_archive, mock_packages):
    """Tests that environment changes from the package's
    `setup_run_environment` method are added to the user environment in
    addition to the prefix inspections"""
    install("mpileaks")

    sh_out = load("--sh", "mpileaks")
    csh_out = load("--csh", "mpileaks")

    assert "export FOOBAR=mpileaks" in sh_out
    assert "setenv FOOBAR mpileaks" in csh_out


def test_load_first(install_mockery, mock_fetch, mock_archive, mock_packages):
    """Test with and without the --first option"""
    install("libelf@0.8.12")
    install("libelf@0.8.13")

    # Now there are two versions of libelf, which should cause an error
    out = load("--sh", "libelf", fail_on_error=False)
    assert "matches multiple packages" in out
    assert "Use a more specific spec" in out

    # Using --first should avoid the error condition
    load("--sh", "--first", "libelf")


def test_load_fails_no_shell(install_mockery, mock_fetch, mock_archive, mock_packages):
    """Test that spack load prints an error message without a shell."""
    install("mpileaks")

    out = load("mpileaks", fail_on_error=False)
    assert "To set up shell support" in out


def test_unload(install_mockery, mock_fetch, mock_archive, mock_packages, working_env):
    """Tests that any variables set in the user environment are undone by the
    unload command"""
    install("mpileaks")
    mpileaks_spec = spack.spec.Spec("mpileaks").concretized()

    # Set so unload has something to do
    os.environ["FOOBAR"] = "mpileaks"
    os.environ[uenv.spack_loaded_hashes_var] = "%s:%s" % (mpileaks_spec.dag_hash(), "garbage")

    sh_out = unload("--sh", "mpileaks")
    csh_out = unload("--csh", "mpileaks")

    assert "unset FOOBAR" in sh_out
    assert "unsetenv FOOBAR" in csh_out

    assert "export %s=garbage" % uenv.spack_loaded_hashes_var in sh_out
    assert "setenv %s garbage" % uenv.spack_loaded_hashes_var in csh_out


def test_unload_fails_no_shell(
    install_mockery, mock_fetch, mock_archive, mock_packages, working_env
):
    """Test that spack unload prints an error message without a shell."""
    install("mpileaks")
    mpileaks_spec = spack.spec.Spec("mpileaks").concretized()
    os.environ[uenv.spack_loaded_hashes_var] = mpileaks_spec.dag_hash()

    out = unload("mpileaks", fail_on_error=False)
    assert "To set up shell support" in out