tests/cmd/external.py: use mock packages (#50363)
Signed-off-by: Massimiliano Culpo <massimiliano.culpo@gmail.com> Co-authored-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
parent
f1ba23316b
commit
0d586695a0
@ -18,6 +18,8 @@
|
|||||||
from spack.main import SpackCommand
|
from spack.main import SpackCommand
|
||||||
from spack.spec import Spec
|
from spack.spec import Spec
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.usefixtures("mock_packages")]
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def executables_found(monkeypatch):
|
def executables_found(monkeypatch):
|
||||||
@ -67,13 +69,24 @@ def test_get_executables(working_env, mock_executable):
|
|||||||
# TODO: this test should be made to work, but in the meantime it is
|
# TODO: this test should be made to work, but in the meantime it is
|
||||||
# causing intermittent (spurious) CI failures on all PRs
|
# causing intermittent (spurious) CI failures on all PRs
|
||||||
@pytest.mark.not_on_windows("Test fails intermittently on Windows")
|
@pytest.mark.not_on_windows("Test fails intermittently on Windows")
|
||||||
def test_find_external_cmd_not_buildable(mutable_config, working_env, mock_executable):
|
def test_find_external_cmd_not_buildable(
|
||||||
|
mutable_config, working_env, mock_executable, monkeypatch
|
||||||
|
):
|
||||||
"""When the user invokes 'spack external find --not-buildable', the config
|
"""When the user invokes 'spack external find --not-buildable', the config
|
||||||
for any package where Spack finds an external version should be marked as
|
for any package where Spack finds an external version should be marked as
|
||||||
not buildable.
|
not buildable.
|
||||||
"""
|
"""
|
||||||
cmake_path1 = mock_executable("cmake", output="echo cmake version 1.foo")
|
version = "1.foo"
|
||||||
os.environ["PATH"] = os.pathsep.join([os.path.dirname(cmake_path1)])
|
|
||||||
|
@classmethod
|
||||||
|
def _determine_version(cls, exe):
|
||||||
|
return version
|
||||||
|
|
||||||
|
cmake_cls = spack.repo.PATH.get_pkg_class("cmake")
|
||||||
|
monkeypatch.setattr(cmake_cls, "determine_version", _determine_version)
|
||||||
|
|
||||||
|
cmake_path = mock_executable("cmake", output=f"echo cmake version {version}")
|
||||||
|
os.environ["PATH"] = str(cmake_path.parent)
|
||||||
external("find", "--not-buildable", "cmake")
|
external("find", "--not-buildable", "cmake")
|
||||||
pkgs_cfg = spack.config.get("packages")
|
pkgs_cfg = spack.config.get("packages")
|
||||||
assert "cmake" in pkgs_cfg
|
assert "cmake" in pkgs_cfg
|
||||||
@ -89,10 +102,12 @@ def test_find_external_cmd_not_buildable(mutable_config, working_env, mock_execu
|
|||||||
["detectable"],
|
["detectable"],
|
||||||
[],
|
[],
|
||||||
[
|
[
|
||||||
|
"builtin.mock.cmake",
|
||||||
"builtin.mock.find-externals1",
|
"builtin.mock.find-externals1",
|
||||||
"builtin.mock.gcc",
|
"builtin.mock.gcc",
|
||||||
"builtin.mock.llvm",
|
|
||||||
"builtin.mock.intel-oneapi-compilers",
|
"builtin.mock.intel-oneapi-compilers",
|
||||||
|
"builtin.mock.llvm",
|
||||||
|
"builtin.mock.mpich",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
# find --all --exclude find-externals1
|
# find --all --exclude find-externals1
|
||||||
@ -100,26 +115,38 @@ def test_find_external_cmd_not_buildable(mutable_config, working_env, mock_execu
|
|||||||
None,
|
None,
|
||||||
["detectable"],
|
["detectable"],
|
||||||
["builtin.mock.find-externals1"],
|
["builtin.mock.find-externals1"],
|
||||||
["builtin.mock.gcc", "builtin.mock.llvm", "builtin.mock.intel-oneapi-compilers"],
|
[
|
||||||
|
"builtin.mock.cmake",
|
||||||
|
"builtin.mock.gcc",
|
||||||
|
"builtin.mock.intel-oneapi-compilers",
|
||||||
|
"builtin.mock.llvm",
|
||||||
|
"builtin.mock.mpich",
|
||||||
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
None,
|
None,
|
||||||
["detectable"],
|
["detectable"],
|
||||||
["find-externals1"],
|
["find-externals1"],
|
||||||
["builtin.mock.gcc", "builtin.mock.llvm", "builtin.mock.intel-oneapi-compilers"],
|
[
|
||||||
|
"builtin.mock.cmake",
|
||||||
|
"builtin.mock.gcc",
|
||||||
|
"builtin.mock.intel-oneapi-compilers",
|
||||||
|
"builtin.mock.llvm",
|
||||||
|
"builtin.mock.mpich",
|
||||||
|
],
|
||||||
),
|
),
|
||||||
# find cmake (and cmake is not detectable)
|
# find hwloc (and mock hwloc is not detectable)
|
||||||
(["cmake"], ["detectable"], [], []),
|
(["hwloc"], ["detectable"], [], []),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_package_selection(names, tags, exclude, expected, mutable_mock_repo):
|
def test_package_selection(names, tags, exclude, expected):
|
||||||
"""Tests various cases of selecting packages"""
|
"""Tests various cases of selecting packages"""
|
||||||
# In the mock repo we only have 'find-externals1' that is detectable
|
# In the mock repo we only have 'find-externals1' that is detectable
|
||||||
result = spack.cmd.external.packages_to_search_for(names=names, tags=tags, exclude=exclude)
|
result = spack.cmd.external.packages_to_search_for(names=names, tags=tags, exclude=exclude)
|
||||||
assert set(result) == set(expected)
|
assert set(result) == set(expected)
|
||||||
|
|
||||||
|
|
||||||
def test_find_external_no_manifest(mutable_config, working_env, mutable_mock_repo, monkeypatch):
|
def test_find_external_no_manifest(mutable_config, working_env, monkeypatch):
|
||||||
"""The user runs 'spack external find'; the default path for storing
|
"""The user runs 'spack external find'; the default path for storing
|
||||||
manifest files does not exist. Ensure that the command does not
|
manifest files does not exist. Ensure that the command does not
|
||||||
fail.
|
fail.
|
||||||
@ -132,7 +159,7 @@ def test_find_external_no_manifest(mutable_config, working_env, mutable_mock_rep
|
|||||||
|
|
||||||
|
|
||||||
def test_find_external_empty_default_manifest_dir(
|
def test_find_external_empty_default_manifest_dir(
|
||||||
mutable_config, working_env, mutable_mock_repo, tmpdir, monkeypatch
|
mutable_config, working_env, tmpdir, monkeypatch
|
||||||
):
|
):
|
||||||
"""The user runs 'spack external find'; the default path for storing
|
"""The user runs 'spack external find'; the default path for storing
|
||||||
manifest files exists but is empty. Ensure that the command does not
|
manifest files exists but is empty. Ensure that the command does not
|
||||||
@ -147,7 +174,7 @@ def test_find_external_empty_default_manifest_dir(
|
|||||||
@pytest.mark.not_on_windows("Can't chmod on Windows")
|
@pytest.mark.not_on_windows("Can't chmod on Windows")
|
||||||
@pytest.mark.skipif(getuid() == 0, reason="user is root")
|
@pytest.mark.skipif(getuid() == 0, reason="user is root")
|
||||||
def test_find_external_manifest_with_bad_permissions(
|
def test_find_external_manifest_with_bad_permissions(
|
||||||
mutable_config, working_env, mutable_mock_repo, tmpdir, monkeypatch
|
mutable_config, working_env, tmpdir, monkeypatch
|
||||||
):
|
):
|
||||||
"""The user runs 'spack external find'; the default path for storing
|
"""The user runs 'spack external find'; the default path for storing
|
||||||
manifest files exists but with insufficient permissions. Check that
|
manifest files exists but with insufficient permissions. Check that
|
||||||
@ -167,7 +194,7 @@ def test_find_external_manifest_with_bad_permissions(
|
|||||||
os.chmod(test_manifest_file_path, 0o700)
|
os.chmod(test_manifest_file_path, 0o700)
|
||||||
|
|
||||||
|
|
||||||
def test_find_external_manifest_failure(mutable_config, mutable_mock_repo, tmpdir, monkeypatch):
|
def test_find_external_manifest_failure(mutable_config, tmpdir, monkeypatch):
|
||||||
"""The user runs 'spack external find'; the manifest parsing fails with
|
"""The user runs 'spack external find'; the manifest parsing fails with
|
||||||
some exception. Ensure that the command still succeeds (i.e. moves on
|
some exception. Ensure that the command still succeeds (i.e. moves on
|
||||||
to other external detection mechanisms).
|
to other external detection mechanisms).
|
||||||
@ -187,7 +214,7 @@ def fail():
|
|||||||
assert "Skipping manifest and continuing" in output
|
assert "Skipping manifest and continuing" in output
|
||||||
|
|
||||||
|
|
||||||
def test_find_external_merge(mutable_config, mutable_mock_repo, tmp_path):
|
def test_find_external_merge(mutable_config, tmp_path):
|
||||||
"""Checks that 'spack find external' doesn't overwrite an existing spec in packages.yaml."""
|
"""Checks that 'spack find external' doesn't overwrite an existing spec in packages.yaml."""
|
||||||
pkgs_cfg_init = {
|
pkgs_cfg_init = {
|
||||||
"find-externals1": {
|
"find-externals1": {
|
||||||
@ -213,7 +240,7 @@ def test_find_external_merge(mutable_config, mutable_mock_repo, tmp_path):
|
|||||||
assert {"spec": "find-externals1@1.2", "prefix": "/x/y2"} in pkg_externals
|
assert {"spec": "find-externals1@1.2", "prefix": "/x/y2"} in pkg_externals
|
||||||
|
|
||||||
|
|
||||||
def test_list_detectable_packages(mutable_config, mutable_mock_repo):
|
def test_list_detectable_packages(mutable_config):
|
||||||
external("list")
|
external("list")
|
||||||
assert external.returncode == 0
|
assert external.returncode == 0
|
||||||
|
|
||||||
@ -259,13 +286,23 @@ def test_new_entries_are_reported_correctly(mock_executable, mutable_config, mon
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("command_args", [("-t", "build-tools"), ("-t", "build-tools", "cmake")])
|
@pytest.mark.parametrize("command_args", [("-t", "build-tools"), ("-t", "build-tools", "cmake")])
|
||||||
|
@pytest.mark.not_on_windows("the test uses bash scripts")
|
||||||
def test_use_tags_for_detection(command_args, mock_executable, mutable_config, monkeypatch):
|
def test_use_tags_for_detection(command_args, mock_executable, mutable_config, monkeypatch):
|
||||||
|
versions = {"cmake": "3.19.1", "openssl": "2.8.3"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _determine_version(cls, exe):
|
||||||
|
return versions[os.path.basename(exe)]
|
||||||
|
|
||||||
|
cmake_cls = spack.repo.PATH.get_pkg_class("cmake")
|
||||||
|
monkeypatch.setattr(cmake_cls, "determine_version", _determine_version)
|
||||||
|
|
||||||
# Prepare an environment to detect a fake cmake
|
# Prepare an environment to detect a fake cmake
|
||||||
cmake_exe = mock_executable("cmake", output="echo cmake version 3.19.1")
|
cmake_exe = mock_executable("cmake", output=f"echo cmake version {versions['cmake']}")
|
||||||
prefix = os.path.dirname(cmake_exe)
|
prefix = os.path.dirname(cmake_exe)
|
||||||
monkeypatch.setenv("PATH", prefix)
|
monkeypatch.setenv("PATH", prefix)
|
||||||
|
|
||||||
openssl_exe = mock_executable("openssl", output="OpenSSL 2.8.3")
|
openssl_exe = mock_executable("openssl", output=f"OpenSSL {versions['openssl']}")
|
||||||
prefix = os.path.dirname(openssl_exe)
|
prefix = os.path.dirname(openssl_exe)
|
||||||
monkeypatch.setenv("PATH", prefix)
|
monkeypatch.setenv("PATH", prefix)
|
||||||
|
|
||||||
@ -282,6 +319,16 @@ def test_failures_in_scanning_do_not_result_in_an_error(
|
|||||||
mock_executable, monkeypatch, mutable_config
|
mock_executable, monkeypatch, mutable_config
|
||||||
):
|
):
|
||||||
"""Tests that scanning paths with wrong permissions, won't cause `external find` to error."""
|
"""Tests that scanning paths with wrong permissions, won't cause `external find` to error."""
|
||||||
|
versions = {"first": "3.19.1", "second": "3.23.3"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _determine_version(cls, exe):
|
||||||
|
bin_parent = os.path.dirname(exe).split(os.sep)[-2]
|
||||||
|
return versions[bin_parent]
|
||||||
|
|
||||||
|
cmake_cls = spack.repo.PATH.get_pkg_class("cmake")
|
||||||
|
monkeypatch.setattr(cmake_cls, "determine_version", _determine_version)
|
||||||
|
|
||||||
cmake_exe1 = mock_executable(
|
cmake_exe1 = mock_executable(
|
||||||
"cmake", output="echo cmake version 3.19.1", subdir=("first", "bin")
|
"cmake", output="echo cmake version 3.19.1", subdir=("first", "bin")
|
||||||
)
|
)
|
||||||
@ -299,21 +346,30 @@ def test_failures_in_scanning_do_not_result_in_an_error(
|
|||||||
assert external.returncode == 0
|
assert external.returncode == 0
|
||||||
assert "The following specs have been" in output
|
assert "The following specs have been" in output
|
||||||
assert "cmake" in output
|
assert "cmake" in output
|
||||||
assert "3.23.3" in output
|
for vers in versions.values():
|
||||||
assert "3.19.1" not in output
|
assert vers in output
|
||||||
|
|
||||||
|
|
||||||
def test_detect_virtuals(mock_executable, mutable_config, monkeypatch):
|
def test_detect_virtuals(mock_executable, mutable_config, monkeypatch):
|
||||||
"""Test whether external find --not-buildable sets virtuals as non-buildable (unless user
|
"""Test whether external find --not-buildable sets virtuals as non-buildable (unless user
|
||||||
config sets them to buildable)"""
|
config sets them to buildable)"""
|
||||||
mpich = mock_executable("mpichversion", output="echo MPICH Version: 4.0.2")
|
version = "4.0.2"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _determine_version(cls, exe):
|
||||||
|
return version
|
||||||
|
|
||||||
|
cmake_cls = spack.repo.PATH.get_pkg_class("mpich")
|
||||||
|
monkeypatch.setattr(cmake_cls, "determine_version", _determine_version)
|
||||||
|
|
||||||
|
mpich = mock_executable("mpichversion", output=f"echo MPICH Version: {version}")
|
||||||
prefix = os.path.dirname(mpich)
|
prefix = os.path.dirname(mpich)
|
||||||
external("find", "--path", prefix, "--not-buildable", "mpich")
|
external("find", "--path", prefix, "--not-buildable", "mpich")
|
||||||
|
|
||||||
# Check that mpich was correctly detected
|
# Check that mpich was correctly detected
|
||||||
mpich = mutable_config.get("packages:mpich")
|
mpich = mutable_config.get("packages:mpich")
|
||||||
assert mpich["buildable"] is False
|
assert mpich["buildable"] is False
|
||||||
assert Spec(mpich["externals"][0]["spec"]).satisfies("mpich@4.0.2")
|
assert Spec(mpich["externals"][0]["spec"]).satisfies(f"mpich@{version}")
|
||||||
|
|
||||||
# Check that the virtual package mpi was marked as non-buildable
|
# Check that the virtual package mpi was marked as non-buildable
|
||||||
assert mutable_config.get("packages:mpi:buildable") is False
|
assert mutable_config.get("packages:mpi:buildable") is False
|
||||||
|
@ -21,6 +21,7 @@ class Cmake(Package):
|
|||||||
url = "https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz"
|
url = "https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz"
|
||||||
|
|
||||||
tags = ["build-tools"]
|
tags = ["build-tools"]
|
||||||
|
executables = ["^cmake[0-9]*$"]
|
||||||
|
|
||||||
depends_on("c", type="build")
|
depends_on("c", type="build")
|
||||||
depends_on("cxx", type="build")
|
depends_on("cxx", type="build")
|
||||||
@ -36,6 +37,12 @@ class Cmake(Package):
|
|||||||
url="https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz",
|
url="https://cmake.org/files/v3.4/cmake-3.4.3.tar.gz",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def determine_version(cls, exe):
|
||||||
|
output = Executable(exe)("--version", output=str, error=str)
|
||||||
|
match = re.search(r"cmake.*version\s+(\S+)", output)
|
||||||
|
return match.group(1) if match else None
|
||||||
|
|
||||||
def setup_build_environment(self, env: EnvironmentModifications) -> None:
|
def setup_build_environment(self, env: EnvironmentModifications) -> None:
|
||||||
spack_cc # Ensure spack module-scope variable is avaiable
|
spack_cc # Ensure spack module-scope variable is avaiable
|
||||||
env.set("for_install", "for_install")
|
env.set("for_install", "for_install")
|
||||||
|
@ -12,6 +12,7 @@ class Mpich(Package):
|
|||||||
list_depth = 2
|
list_depth = 2
|
||||||
|
|
||||||
tags = ["tag1", "tag2"]
|
tags = ["tag1", "tag2"]
|
||||||
|
executables = ["^mpichversion$"]
|
||||||
|
|
||||||
variant("debug", default=False, description="Compile MPICH with debug flags.")
|
variant("debug", default=False, description="Compile MPICH with debug flags.")
|
||||||
|
|
||||||
@ -30,6 +31,12 @@ class Mpich(Package):
|
|||||||
depends_on("cxx", type="build")
|
depends_on("cxx", type="build")
|
||||||
depends_on("fortran", type="build")
|
depends_on("fortran", type="build")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def determine_version(cls, exe):
|
||||||
|
output = Executable(exe)(output=str, error=str)
|
||||||
|
match = re.search(r"MPICH Version:\s+(\S+)", output)
|
||||||
|
return match.group(1) if match else None
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
def install(self, spec, prefix):
|
||||||
touch(prefix.mpich)
|
touch(prefix.mpich)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user