summaryrefslogtreecommitdiff
path: root/lib/spack/spack/test/cmd/bootstrap.py
blob: 277a279222b8d7e29d85058182f7b387e92ad84a (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# Copyright 2013-2023 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.path
import sys

import pytest

from llnl.path import convert_to_posix_path

import spack.bootstrap
import spack.bootstrap.core
import spack.config
import spack.environment as ev
import spack.main
import spack.mirror

_bootstrap = spack.main.SpackCommand("bootstrap")


@pytest.mark.parametrize("scope", [None, "site", "system", "user"])
def test_enable_and_disable(mutable_config, scope):
    scope_args = []
    if scope:
        scope_args = ["--scope={0}".format(scope)]

    _bootstrap("enable", *scope_args)
    assert spack.config.get("bootstrap:enable", scope=scope) is True

    _bootstrap("disable", *scope_args)
    assert spack.config.get("bootstrap:enable", scope=scope) is False


@pytest.mark.parametrize("scope", [None, "site", "system", "user"])
def test_root_get_and_set(mutable_config, scope):
    scope_args, path = [], "/scratch/spack/bootstrap"
    if scope:
        scope_args = ["--scope={0}".format(scope)]

    _bootstrap("root", path, *scope_args)
    out = _bootstrap("root", *scope_args, output=str)
    if sys.platform == "win32":
        out = convert_to_posix_path(out)
    assert out.strip() == path


@pytest.mark.parametrize("scopes", [("site",), ("system", "user")])
def test_reset_in_file_scopes(mutable_config, scopes):
    # Assert files are created in the right scopes
    bootstrap_yaml_files = []
    for s in scopes:
        _bootstrap("disable", "--scope={0}".format(s))
        scope_path = spack.config.CONFIG.scopes[s].path
        bootstrap_yaml = os.path.join(scope_path, "bootstrap.yaml")
        assert os.path.exists(bootstrap_yaml)
        bootstrap_yaml_files.append(bootstrap_yaml)

    _bootstrap("reset", "-y")
    for bootstrap_yaml in bootstrap_yaml_files:
        assert not os.path.exists(bootstrap_yaml)


def test_reset_in_environment(mutable_mock_env_path, mutable_config):
    env = spack.main.SpackCommand("env")
    env("create", "bootstrap-test")
    current_environment = ev.read("bootstrap-test")

    with current_environment:
        _bootstrap("disable")
        assert spack.config.get("bootstrap:enable") is False
        _bootstrap("reset", "-y")
        # We have no default settings in tests
        assert spack.config.get("bootstrap:enable") is None

    # Check that reset didn't delete the entire file
    spack_yaml = os.path.join(current_environment.path, "spack.yaml")
    assert os.path.exists(spack_yaml)


def test_reset_in_file_scopes_overwrites_backup_files(mutable_config):
    # Create a bootstrap.yaml with some config
    _bootstrap("disable", "--scope=site")
    scope_path = spack.config.CONFIG.scopes["site"].path
    bootstrap_yaml = os.path.join(scope_path, "bootstrap.yaml")
    assert os.path.exists(bootstrap_yaml)

    # Reset the bootstrap configuration
    _bootstrap("reset", "-y")
    backup_file = bootstrap_yaml + ".bkp"
    assert not os.path.exists(bootstrap_yaml)
    assert os.path.exists(backup_file)

    # Iterate another time
    _bootstrap("disable", "--scope=site")
    assert os.path.exists(bootstrap_yaml)
    assert os.path.exists(backup_file)
    _bootstrap("reset", "-y")
    assert not os.path.exists(bootstrap_yaml)
    assert os.path.exists(backup_file)


def test_list_sources(config, capsys):
    # Get the merged list and ensure we get our defaults
    with capsys.disabled():
        output = _bootstrap("list")
    assert "github-actions" in output

    # Ask for a specific scope and check that the list of sources is empty
    with capsys.disabled():
        output = _bootstrap("list", "--scope", "user")
    assert "No method available" in output


@pytest.mark.parametrize("command,value", [("enable", True), ("disable", False)])
def test_enable_or_disable_sources(mutable_config, command, value):
    key = "bootstrap:trusted:github-actions"
    trusted = spack.config.get(key, default=None)
    assert trusted is None

    _bootstrap(command, "github-actions")
    trusted = spack.config.get(key, default=None)
    assert trusted is value


def test_enable_or_disable_fails_with_no_method(mutable_config):
    with pytest.raises(RuntimeError, match="no bootstrapping method"):
        _bootstrap("enable", "foo")


def test_enable_or_disable_fails_with_more_than_one_method(mutable_config):
    wrong_config = {
        "sources": [
            {"name": "github-actions", "metadata": "$spack/share/spack/bootstrap/github-actions"},
            {"name": "github-actions", "metadata": "$spack/share/spack/bootstrap/github-actions"},
        ],
        "trusted": {},
    }
    with spack.config.override("bootstrap", wrong_config):
        with pytest.raises(RuntimeError, match="more than one"):
            _bootstrap("enable", "github-actions")


@pytest.mark.parametrize("use_existing_dir", [True, False])
def test_add_failures_for_non_existing_files(mutable_config, tmpdir, use_existing_dir):
    metadata_dir = str(tmpdir) if use_existing_dir else "/foo/doesnotexist"
    with pytest.raises(RuntimeError, match="does not exist"):
        _bootstrap("add", "mock-mirror", metadata_dir)


def test_add_failures_for_already_existing_name(mutable_config):
    with pytest.raises(RuntimeError, match="already exist"):
        _bootstrap("add", "github-actions", "some-place")


def test_remove_failure_for_non_existing_names(mutable_config):
    with pytest.raises(RuntimeError, match="cannot find"):
        _bootstrap("remove", "mock-mirror")


def test_remove_and_add_a_source(mutable_config):
    # Check we start with a single bootstrapping source
    sources = spack.bootstrap.core.bootstrapping_sources()
    assert len(sources) == 1

    # Remove it and check the result
    _bootstrap("remove", "github-actions")
    sources = spack.bootstrap.core.bootstrapping_sources()
    assert not sources

    # Add it back and check we restored the initial state
    _bootstrap("add", "github-actions", "$spack/share/spack/bootstrap/github-actions-v0.5")
    sources = spack.bootstrap.core.bootstrapping_sources()
    assert len(sources) == 1


@pytest.mark.maybeslow
@pytest.mark.not_on_windows("Not supported on Windows (yet)")
def test_bootstrap_mirror_metadata(mutable_config, linux_os, monkeypatch, tmpdir):
    """Test that `spack bootstrap mirror` creates a folder that can be ingested by
    `spack bootstrap add`. Here we don't download data, since that would be an
    expensive operation for a unit test.
    """
    old_create = spack.mirror.create
    monkeypatch.setattr(spack.mirror, "create", lambda p, s: old_create(p, []))
    monkeypatch.setattr(spack.spec.Spec, "concretized", lambda p: p)

    # Create the mirror in a temporary folder
    compilers = [
        {
            "compiler": {
                "spec": "gcc@12.0.1",
                "operating_system": "{0.name}{0.version}".format(linux_os),
                "modules": [],
                "paths": {
                    "cc": "/usr/bin",
                    "cxx": "/usr/bin",
                    "fc": "/usr/bin",
                    "f77": "/usr/bin",
                },
            }
        }
    ]
    with spack.config.override("compilers", compilers):
        _bootstrap("mirror", str(tmpdir))

    # Register the mirror
    metadata_dir = tmpdir.join("metadata", "sources")
    _bootstrap("add", "--trust", "test-mirror", str(metadata_dir))

    assert _bootstrap.returncode == 0
    assert any(m["name"] == "test-mirror" for m in spack.bootstrap.core.bootstrapping_sources())