Speed-up unit tests by caching default mock concretization (#33755)

This commit is contained in:
Massimiliano Culpo 2022-11-11 21:32:40 +01:00 committed by GitHub
parent 5f8511311c
commit 022a2d2eaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 217 additions and 179 deletions

View File

@ -17,7 +17,7 @@
import spack.target
@pytest.fixture
@pytest.fixture(scope="module")
def current_host_platform():
"""Return the platform of the current host as detected by the
'platform' stdlib package.
@ -34,23 +34,23 @@ def current_host_platform():
# Valid keywords for os=xxx or target=xxx
valid_keywords = ["fe", "be", "frontend", "backend"]
VALID_KEYWORDS = ["fe", "be", "frontend", "backend"]
TEST_PLATFORM = spack.platforms.Test()
@pytest.fixture(
params=([x for x in spack.platforms.Test().targets] + valid_keywords + ["default_target"])
)
@pytest.fixture(params=([str(x) for x in TEST_PLATFORM.targets] + VALID_KEYWORDS), scope="module")
def target_str(request):
"""All the possible strings that can be used for targets"""
return str(request.param)
return request.param
@pytest.fixture(
params=([x for x in spack.platforms.Test().operating_sys] + valid_keywords + ["default_os"])
params=([str(x) for x in TEST_PLATFORM.operating_sys] + VALID_KEYWORDS), scope="module"
)
def os_str(request):
"""All the possible strings that can be used for operating systems"""
return str(request.param)
return request.param
def test_platform(current_host_platform):
@ -64,16 +64,19 @@ def test_user_input_combination(config, target_str, os_str):
"""Test for all the valid user input combinations that both the target and
the operating system match.
"""
platform = spack.platforms.Test()
spec_str = "libelf"
if os_str != "default_os":
spec_str += " os={0}".format(os_str)
if target_str != "default_target":
spec_str += " target={0}".format(target_str)
spec = spack.spec.Spec(spec_str).concretized()
spec_str = "libelf os={} target={}".format(os_str, target_str)
spec = spack.spec.Spec(spec_str)
assert spec.architecture.os == str(TEST_PLATFORM.operating_system(os_str))
assert spec.architecture.target == TEST_PLATFORM.target(target_str)
assert spec.architecture.os == str(platform.operating_system(os_str))
assert spec.architecture.target == platform.target(target_str)
def test_default_os_and_target(config):
"""Test that is we don't specify `os=` or `target=` we get the default values
after concretization.
"""
spec = spack.spec.Spec("libelf").concretized()
assert spec.architecture.os == str(TEST_PLATFORM.operating_system("default_os"))
assert spec.architecture.target == TEST_PLATFORM.target("default_target")
def test_operating_system_conversion_to_dict():

View File

@ -27,9 +27,9 @@
@pytest.fixture()
def concretize_and_setup():
def concretize_and_setup(default_mock_concretization):
def _func(spec_str):
s = Spec("mpich").concretized()
s = default_mock_concretization(spec_str)
setup_package(s.package, False)
return s
@ -95,8 +95,8 @@ def test_negative_ninja_check(self, input_dir, test_dir, concretize_and_setup):
@pytest.mark.usefixtures("config", "mock_packages")
class TestAutotoolsPackage(object):
def test_with_or_without(self):
s = Spec("a").concretized()
def test_with_or_without(self, default_mock_concretization):
s = default_mock_concretization("a")
options = s.package.with_or_without("foo")
# Ensure that values that are not representing a feature
@ -127,8 +127,8 @@ def activate(value):
options = s.package.with_or_without("lorem-ipsum", variant="lorem_ipsum")
assert "--without-lorem-ipsum" in options
def test_none_is_allowed(self):
s = Spec("a foo=none").concretized()
def test_none_is_allowed(self, default_mock_concretization):
s = default_mock_concretization("a foo=none")
options = s.package.with_or_without("foo")
# Ensure that values that are not representing a feature
@ -138,9 +138,11 @@ def test_none_is_allowed(self):
assert "--without-baz" in options
assert "--no-fee" in options
def test_libtool_archive_files_are_deleted_by_default(self, mutable_database):
def test_libtool_archive_files_are_deleted_by_default(
self, default_mock_concretization, mutable_database
):
# Install a package that creates a mock libtool archive
s = Spec("libtool-deletion").concretized()
s = default_mock_concretization("libtool-deletion")
s.package.do_install(explicit=True)
# Assert the libtool archive is not there and we have
@ -151,24 +153,25 @@ def test_libtool_archive_files_are_deleted_by_default(self, mutable_database):
assert libtool_deletion_log
def test_libtool_archive_files_might_be_installed_on_demand(
self, mutable_database, monkeypatch
self, mutable_database, monkeypatch, default_mock_concretization
):
# Install a package that creates a mock libtool archive,
# patch its package to preserve the installation
s = Spec("libtool-deletion").concretized()
s = default_mock_concretization("libtool-deletion")
monkeypatch.setattr(type(s.package.builder), "install_libtool_archives", True)
s.package.do_install(explicit=True)
# Assert libtool archives are installed
assert os.path.exists(s.package.builder.libtool_archive_file)
def test_autotools_gnuconfig_replacement(self, mutable_database):
def test_autotools_gnuconfig_replacement(self, default_mock_concretization, mutable_database):
"""
Tests whether only broken config.sub and config.guess are replaced with
files from working alternatives from the gnuconfig package.
"""
s = Spec("autotools-config-replacement +patch_config_files +gnuconfig")
s.concretize()
s = default_mock_concretization(
"autotools-config-replacement +patch_config_files +gnuconfig"
)
s.package.do_install()
with open(os.path.join(s.prefix.broken, "config.sub")) as f:
@ -183,12 +186,15 @@ def test_autotools_gnuconfig_replacement(self, mutable_database):
with open(os.path.join(s.prefix.working, "config.guess")) as f:
assert "gnuconfig version of config.guess" not in f.read()
def test_autotools_gnuconfig_replacement_disabled(self, mutable_database):
def test_autotools_gnuconfig_replacement_disabled(
self, default_mock_concretization, mutable_database
):
"""
Tests whether disabling patch_config_files
"""
s = Spec("autotools-config-replacement ~patch_config_files +gnuconfig")
s.concretize()
s = default_mock_concretization(
"autotools-config-replacement ~patch_config_files +gnuconfig"
)
s.package.do_install()
with open(os.path.join(s.prefix.broken, "config.sub")) as f:
@ -252,29 +258,29 @@ def test_broken_external_gnuconfig(self, mutable_database, tmpdir):
@pytest.mark.usefixtures("config", "mock_packages")
class TestCMakePackage(object):
def test_cmake_std_args(self):
def test_cmake_std_args(self, default_mock_concretization):
# Call the function on a CMakePackage instance
s = Spec("cmake-client").concretized()
s = default_mock_concretization("cmake-client")
expected = spack.build_systems.cmake.CMakeBuilder.std_args(s.package)
assert s.package.builder.std_cmake_args == expected
# Call it on another kind of package
s = Spec("mpich").concretized()
s = default_mock_concretization("mpich")
assert spack.build_systems.cmake.CMakeBuilder.std_args(s.package)
def test_cmake_bad_generator(self, monkeypatch):
s = Spec("cmake-client").concretized()
def test_cmake_bad_generator(self, monkeypatch, default_mock_concretization):
s = default_mock_concretization("cmake-client")
monkeypatch.setattr(type(s.package), "generator", "Yellow Sticky Notes", raising=False)
with pytest.raises(spack.package_base.InstallError):
s.package.builder.std_cmake_args
def test_cmake_secondary_generator(config, mock_packages):
s = Spec("cmake-client").concretized()
def test_cmake_secondary_generator(self, default_mock_concretization):
s = default_mock_concretization("cmake-client")
s.package.generator = "CodeBlocks - Unix Makefiles"
assert s.package.builder.std_cmake_args
def test_define(self):
s = Spec("cmake-client").concretized()
def test_define(self, default_mock_concretization):
s = default_mock_concretization("cmake-client")
define = s.package.define
for cls in (list, tuple):
@ -324,8 +330,8 @@ class TestDownloadMixins(object):
),
],
)
def test_attributes_defined(self, spec_str, expected_url):
s = Spec(spec_str).concretized()
def test_attributes_defined(self, default_mock_concretization, spec_str, expected_url):
s = default_mock_concretization(spec_str)
assert s.package.urls[0] == expected_url
@pytest.mark.parametrize(
@ -344,33 +350,33 @@ def test_attributes_defined(self, spec_str, expected_url):
("mirror-xorg-broken", r"{0} must define a `xorg_mirror_path` attribute"),
],
)
def test_attributes_missing(self, spec_str, error_fmt):
s = Spec(spec_str).concretized()
def test_attributes_missing(self, default_mock_concretization, spec_str, error_fmt):
s = default_mock_concretization(spec_str)
error_msg = error_fmt.format(type(s.package).__name__)
with pytest.raises(AttributeError, match=error_msg):
s.package.urls
def test_cmake_define_from_variant_conditional(config, mock_packages):
def test_cmake_define_from_variant_conditional(default_mock_concretization):
"""Test that define_from_variant returns empty string when a condition on a variant
is not met. When this is the case, the variant is not set in the spec."""
s = Spec("cmake-conditional-variants-test").concretized()
s = default_mock_concretization("cmake-conditional-variants-test")
assert "example" not in s.variants
assert s.package.define_from_variant("EXAMPLE", "example") == ""
def test_autotools_args_from_conditional_variant(config, mock_packages):
def test_autotools_args_from_conditional_variant(default_mock_concretization):
"""Test that _activate_or_not returns an empty string when a condition on a variant
is not met. When this is the case, the variant is not set in the spec."""
s = Spec("autotools-conditional-variants-test").concretized()
s = default_mock_concretization("autotools-conditional-variants-test")
assert "example" not in s.variants
assert len(s.package.builder._activate_or_not("example", "enable", "disable")) == 0
def test_autoreconf_search_path_args_multiple(config, mock_packages, tmpdir):
def test_autoreconf_search_path_args_multiple(default_mock_concretization, tmpdir):
"""autoreconf should receive the right -I flags with search paths for m4 files
for build deps."""
spec = Spec("dttop").concretized()
spec = default_mock_concretization("dttop")
aclocal_fst = str(tmpdir.mkdir("fst").mkdir("share").mkdir("aclocal"))
aclocal_snd = str(tmpdir.mkdir("snd").mkdir("share").mkdir("aclocal"))
build_dep_one, build_dep_two = spec.dependencies(deptype="build")
@ -384,11 +390,11 @@ def test_autoreconf_search_path_args_multiple(config, mock_packages, tmpdir):
]
def test_autoreconf_search_path_args_skip_automake(config, mock_packages, tmpdir):
def test_autoreconf_search_path_args_skip_automake(default_mock_concretization, tmpdir):
"""automake's aclocal dir should not be added as -I flag as it is a default
3rd party dir search path, and if it's a system version it usually includes
m4 files shadowing spack deps."""
spec = Spec("dttop").concretized()
spec = default_mock_concretization("dttop")
tmpdir.mkdir("fst").mkdir("share").mkdir("aclocal")
aclocal_snd = str(tmpdir.mkdir("snd").mkdir("share").mkdir("aclocal"))
build_dep_one, build_dep_two = spec.dependencies(deptype="build")
@ -398,9 +404,9 @@ def test_autoreconf_search_path_args_skip_automake(config, mock_packages, tmpdir
assert spack.build_systems.autotools._autoreconf_search_path_args(spec) == ["-I", aclocal_snd]
def test_autoreconf_search_path_args_external_order(config, mock_packages, tmpdir):
def test_autoreconf_search_path_args_external_order(default_mock_concretization, tmpdir):
"""When a build dep is external, its -I flag should occur last"""
spec = Spec("dttop").concretized()
spec = default_mock_concretization("dttop")
aclocal_fst = str(tmpdir.mkdir("fst").mkdir("share").mkdir("aclocal"))
aclocal_snd = str(tmpdir.mkdir("snd").mkdir("share").mkdir("aclocal"))
build_dep_one, build_dep_two = spec.dependencies(deptype="build")
@ -414,18 +420,18 @@ def test_autoreconf_search_path_args_external_order(config, mock_packages, tmpdi
]
def test_autoreconf_search_path_skip_nonexisting(config, mock_packages, tmpdir):
def test_autoreconf_search_path_skip_nonexisting(default_mock_concretization, tmpdir):
"""Skip -I flags for non-existing directories"""
spec = Spec("dttop").concretized()
spec = default_mock_concretization("dttop")
build_dep_one, build_dep_two = spec.dependencies(deptype="build")
build_dep_one.prefix = str(tmpdir.join("fst"))
build_dep_two.prefix = str(tmpdir.join("snd"))
assert spack.build_systems.autotools._autoreconf_search_path_args(spec) == []
def test_autoreconf_search_path_dont_repeat(config, mock_packages, tmpdir):
def test_autoreconf_search_path_dont_repeat(default_mock_concretization, tmpdir):
"""Do not add the same -I flag twice to keep things readable for humans"""
spec = Spec("dttop").concretized()
spec = default_mock_concretization("dttop")
aclocal = str(tmpdir.mkdir("prefix").mkdir("share").mkdir("aclocal"))
build_dep_one, build_dep_two = spec.dependencies(deptype="build")
build_dep_one.external_path = str(tmpdir.join("prefix"))

View File

@ -18,7 +18,6 @@
import spack.environment as ev
import spack.error
import spack.paths as spack_paths
import spack.spec as spec
import spack.util.gpg
import spack.util.spack_yaml as syaml
@ -145,13 +144,12 @@ def test_download_and_extract_artifacts(tmpdir, monkeypatch, working_env):
ci.download_and_extract_artifacts(url, working_dir)
def test_ci_copy_stage_logs_to_artifacts_fail(tmpdir, config, mock_packages, monkeypatch, capfd):
def test_ci_copy_stage_logs_to_artifacts_fail(tmpdir, default_mock_concretization, capfd):
"""The copy will fail because the spec is not concrete so does not have
a package."""
log_dir = tmpdir.join("log_dir")
s = spec.Spec("printing-package").concretized()
ci.copy_stage_logs_to_artifacts(s, log_dir)
concrete_spec = default_mock_concretization("printing-package")
ci.copy_stage_logs_to_artifacts(concrete_spec, log_dir)
_, err = capfd.readouterr()
assert "Unable to copy files" in err
assert "No such file or directory" in err
@ -456,17 +454,16 @@ def test_get_spec_filter_list(mutable_mock_env_path, config, mutable_mock_repo):
assert affected_pkg_names == expected_affected_pkg_names
@pytest.mark.maybeslow
@pytest.mark.regression("29947")
def test_affected_specs_on_first_concretization(mutable_mock_env_path, config):
def test_affected_specs_on_first_concretization(mutable_mock_env_path, mock_packages, config):
e = ev.create("first_concretization")
e.add("hdf5~mpi~szip")
e.add("hdf5~mpi+szip")
e.add("mpileaks~shared")
e.add("mpileaks+shared")
e.concretize()
affected_specs = spack.ci.get_spec_filter_list(e, ["zlib"])
hdf5_specs = [s for s in affected_specs if s.name == "hdf5"]
assert len(hdf5_specs) == 2
affected_specs = spack.ci.get_spec_filter_list(e, ["callpath"])
mpileaks_specs = [s for s in affected_specs if s.name == "mpileaks"]
assert len(mpileaks_specs) == 2, e.all_specs()
@pytest.mark.skipif(
@ -515,14 +512,14 @@ def test_ci_create_buildcache(tmpdir, working_env, config, mock_packages, monkey
def test_ci_run_standalone_tests_missing_requirements(
tmpdir, working_env, config, mock_packages, capfd
tmpdir, working_env, default_mock_concretization, capfd
):
"""This test case checks for failing prerequisite checks."""
ci.run_standalone_tests()
err = capfd.readouterr()[1]
assert "Job spec is required" in err
args = {"job_spec": spec.Spec("printing-package").concretized()}
args = {"job_spec": default_mock_concretization("printing-package")}
ci.run_standalone_tests(**args)
err = capfd.readouterr()[1]
assert "Reproduction directory is required" in err
@ -532,12 +529,12 @@ def test_ci_run_standalone_tests_missing_requirements(
sys.platform == "win32", reason="Reliance on bash script not supported on Windows"
)
def test_ci_run_standalone_tests_not_installed_junit(
tmpdir, working_env, config, mock_packages, mock_test_stage, capfd
tmpdir, working_env, default_mock_concretization, mock_test_stage, capfd
):
log_file = tmpdir.join("junit.xml").strpath
args = {
"log_file": log_file,
"job_spec": spec.Spec("printing-package").concretized(),
"job_spec": default_mock_concretization("printing-package"),
"repro_dir": tmpdir.join("repro_dir").strpath,
"fail_fast": True,
}
@ -553,13 +550,13 @@ def test_ci_run_standalone_tests_not_installed_junit(
sys.platform == "win32", reason="Reliance on bash script not supported on Windows"
)
def test_ci_run_standalone_tests_not_installed_cdash(
tmpdir, working_env, config, mock_packages, mock_test_stage, capfd
tmpdir, working_env, default_mock_concretization, mock_test_stage, capfd
):
"""Test run_standalone_tests with cdash and related options."""
log_file = tmpdir.join("junit.xml").strpath
args = {
"log_file": log_file,
"job_spec": spec.Spec("printing-package").concretized(),
"job_spec": default_mock_concretization("printing-package"),
"repro_dir": tmpdir.join("repro_dir").strpath,
}
os.makedirs(args["repro_dir"])

View File

@ -1852,3 +1852,27 @@ def _factory(rpaths, message="Hello world!"):
return executable
return _factory
@pytest.fixture(scope="session")
def concretized_specs_cache():
"""Cache for mock concrete specs"""
return {}
@pytest.fixture
def default_mock_concretization(config, mock_packages, concretized_specs_cache):
"""Return the default mock concretization of a spec literal, obtained using the mock
repository and the mock configuration.
This fixture is unsafe to call in a test when either the default configuration or mock
repository are not used or have been modified.
"""
def _func(spec_str, tests=False):
key = spec_str, tests
if key not in concretized_specs_cache:
concretized_specs_cache[key] = spack.spec.Spec(spec_str).concretized(tests=tests)
return concretized_specs_cache[key].copy()
return _func

View File

@ -835,7 +835,7 @@ def _is(db, spec):
@pytest.mark.db
def test_clear_failure_forced(mutable_database, monkeypatch, capfd):
def test_clear_failure_forced(default_mock_concretization, mutable_database, monkeypatch, capfd):
"""Add test coverage for clear_failure operation when force."""
def _is(db, spec):
@ -846,7 +846,7 @@ def _is(db, spec):
# Ensure raise OSError when try to remove the non-existent marking
monkeypatch.setattr(spack.database.Database, "prefix_failure_marked", _is)
s = spack.spec.Spec("a").concretized()
s = default_mock_concretization("a")
spack.store.db.clear_failure(s, force=True)
out = capfd.readouterr()[1]
assert "Removing failure marking despite lock" in out
@ -854,7 +854,7 @@ def _is(db, spec):
@pytest.mark.db
def test_mark_failed(mutable_database, monkeypatch, tmpdir, capsys):
def test_mark_failed(default_mock_concretization, mutable_database, monkeypatch, tmpdir, capsys):
"""Add coverage to mark_failed."""
def _raise_exc(lock):
@ -864,7 +864,7 @@ def _raise_exc(lock):
monkeypatch.setattr(lk.Lock, "acquire_write", _raise_exc)
with tmpdir.as_cwd():
s = spack.spec.Spec("a").concretized()
s = default_mock_concretization("a")
spack.store.db.mark_failed(s)
out = str(capsys.readouterr()[1])
@ -876,13 +876,13 @@ def _raise_exc(lock):
@pytest.mark.db
def test_prefix_failed(mutable_database, monkeypatch):
def test_prefix_failed(default_mock_concretization, mutable_database, monkeypatch):
"""Add coverage to prefix_failed operation."""
def _is(db, spec):
return True
s = spack.spec.Spec("a").concretized()
s = default_mock_concretization("a")
# Confirm the spec is not already marked as failed
assert not spack.store.db.prefix_failed(s)
@ -900,13 +900,13 @@ def _is(db, spec):
assert spack.store.db.prefix_failed(s)
def test_prefix_read_lock_error(mutable_database, monkeypatch):
def test_prefix_read_lock_error(default_mock_concretization, mutable_database, monkeypatch):
"""Cover the prefix read lock exception."""
def _raise(db, spec):
raise lk.LockError("Mock lock error")
s = spack.spec.Spec("a").concretized()
s = default_mock_concretization("a")
# Ensure subsequent lock operations fail
monkeypatch.setattr(lk.Lock, "acquire_read", _raise)
@ -916,13 +916,13 @@ def _raise(db, spec):
assert False
def test_prefix_write_lock_error(mutable_database, monkeypatch):
def test_prefix_write_lock_error(default_mock_concretization, mutable_database, monkeypatch):
"""Cover the prefix write lock exception."""
def _raise(db, spec):
raise lk.LockError("Mock lock error")
s = spack.spec.Spec("a").concretized()
s = default_mock_concretization("a")
# Ensure subsequent lock operations fail
monkeypatch.setattr(lk.Lock, "acquire_write", _raise)

View File

@ -24,11 +24,10 @@
max_packages = 10
def test_yaml_directory_layout_parameters(tmpdir, config):
def test_yaml_directory_layout_parameters(tmpdir, default_mock_concretization):
"""This tests the various parameters that can be used to configure
the install location"""
spec = Spec("python")
spec.concretize()
spec = default_mock_concretization("python")
# Ensure default layout matches expected spec format
layout_default = DirectoryLayout(str(tmpdir))
@ -215,11 +214,9 @@ def test_find(temporary_store, config, mock_packages):
assert found_specs[name].eq_dag(spec)
def test_yaml_directory_layout_build_path(tmpdir, config):
def test_yaml_directory_layout_build_path(tmpdir, default_mock_concretization):
"""This tests build path method."""
spec = Spec("python")
spec.concretize()
spec = default_mock_concretization("python")
layout = DirectoryLayout(str(tmpdir))
rel_path = os.path.join(layout.metadata_dir, layout.packages_dir)
assert layout.build_packages_path(spec) == os.path.join(spec.prefix, rel_path)

View File

@ -83,7 +83,13 @@ def test_bad_git(tmpdir, mock_bad_git):
@pytest.mark.parametrize("type_of_test", ["default", "branch", "tag", "commit"])
@pytest.mark.parametrize("secure", [True, False])
def test_fetch(
type_of_test, secure, mock_git_repository, config, mutable_mock_repo, git_version, monkeypatch
type_of_test,
secure,
mock_git_repository,
default_mock_concretization,
mutable_mock_repo,
git_version,
monkeypatch,
):
"""Tries to:
@ -104,7 +110,7 @@ def test_fetch(
monkeypatch.delattr(pkg_class, "git")
# Construct the package under test
s = Spec("git-test").concretized()
s = default_mock_concretization("git-test")
monkeypatch.setitem(s.package.versions, ver("git"), t.args)
# Enter the stage directory and check some properties
@ -136,7 +142,7 @@ def test_fetch(
@pytest.mark.disable_clean_stage_check
def test_fetch_pkg_attr_submodule_init(
mock_git_repository, config, mutable_mock_repo, monkeypatch, mock_stage
mock_git_repository, default_mock_concretization, mutable_mock_repo, monkeypatch, mock_stage
):
"""In this case the version() args do not contain a 'git' URL, so
the fetcher must be assembled using the Package-level 'git' attribute.
@ -151,7 +157,7 @@ def test_fetch_pkg_attr_submodule_init(
monkeypatch.setattr(pkg_class, "git", mock_git_repository.url)
# Construct the package under test
s = Spec("git-test").concretized()
s = default_mock_concretization("git-test")
monkeypatch.setitem(s.package.versions, ver("git"), t.args)
s.package.do_stage()
@ -193,13 +199,15 @@ def test_adhoc_version_submodules(
@pytest.mark.parametrize("type_of_test", ["branch", "commit"])
def test_debug_fetch(mock_packages, type_of_test, mock_git_repository, config, monkeypatch):
def test_debug_fetch(
mock_packages, type_of_test, mock_git_repository, default_mock_concretization, monkeypatch
):
"""Fetch the repo with debug enabled."""
# Retrieve the right test parameters
t = mock_git_repository.checks[type_of_test]
# Construct the package under test
s = Spec("git-test").concretized()
s = default_mock_concretization("git-test")
monkeypatch.setitem(s.package.versions, ver("git"), t.args)
# Fetch then ensure source path exists
@ -231,7 +239,12 @@ def test_needs_stage():
@pytest.mark.parametrize("get_full_repo", [True, False])
def test_get_full_repo(
get_full_repo, git_version, mock_git_repository, config, mutable_mock_repo, monkeypatch
get_full_repo,
git_version,
mock_git_repository,
default_mock_concretization,
mutable_mock_repo,
monkeypatch,
):
"""Ensure that we can clone a full repository."""
@ -243,7 +256,7 @@ def test_get_full_repo(
t = mock_git_repository.checks[type_of_test]
s = Spec("git-test").concretized()
s = default_mock_concretization("git-test")
args = copy.copy(t.args)
args["get_full_repo"] = get_full_repo
monkeypatch.setitem(s.package.versions, ver("git"), args)
@ -273,7 +286,9 @@ def test_get_full_repo(
@pytest.mark.disable_clean_stage_check
@pytest.mark.parametrize("submodules", [True, False])
def test_gitsubmodule(submodules, mock_git_repository, config, mutable_mock_repo, monkeypatch):
def test_gitsubmodule(
submodules, mock_git_repository, default_mock_concretization, mutable_mock_repo, monkeypatch
):
"""
Test GitFetchStrategy behavior with submodules. This package
has a `submodules` property which is always True: when a specific
@ -286,7 +301,7 @@ def test_gitsubmodule(submodules, mock_git_repository, config, mutable_mock_repo
t = mock_git_repository.checks[type_of_test]
# Construct the package under test
s = Spec("git-test").concretized()
s = default_mock_concretization("git-test")
args = copy.copy(t.args)
args["submodules"] = submodules
monkeypatch.setitem(s.package.versions, ver("git"), args)
@ -304,7 +319,9 @@ def test_gitsubmodule(submodules, mock_git_repository, config, mutable_mock_repo
@pytest.mark.disable_clean_stage_check
def test_gitsubmodules_callable(mock_git_repository, config, mutable_mock_repo, monkeypatch):
def test_gitsubmodules_callable(
mock_git_repository, default_mock_concretization, mutable_mock_repo, monkeypatch
):
"""
Test GitFetchStrategy behavior with submodules selected after concretization
"""
@ -317,7 +334,7 @@ def submodules_callback(package):
t = mock_git_repository.checks[type_of_test]
# Construct the package under test
s = Spec("git-test").concretized()
s = default_mock_concretization("git-test")
args = copy.copy(t.args)
args["submodules"] = submodules_callback
monkeypatch.setitem(s.package.versions, ver("git"), args)
@ -330,7 +347,9 @@ def submodules_callback(package):
@pytest.mark.disable_clean_stage_check
def test_gitsubmodules_delete(mock_git_repository, config, mutable_mock_repo, monkeypatch):
def test_gitsubmodules_delete(
mock_git_repository, default_mock_concretization, mutable_mock_repo, monkeypatch
):
"""
Test GitFetchStrategy behavior with submodules_delete
"""
@ -338,7 +357,7 @@ def test_gitsubmodules_delete(mock_git_repository, config, mutable_mock_repo, mo
t = mock_git_repository.checks[type_of_test]
# Construct the package under test
s = Spec("git-test").concretized()
s = default_mock_concretization("git-test")
args = copy.copy(t.args)
args["submodules"] = True
args["submodules_delete"] = ["third_party/submodule0", "third_party/submodule1"]

View File

@ -570,7 +570,9 @@ def fake_fn(self):
"manual,instr", [(False, False), (False, True), (True, False), (True, True)]
)
@pytest.mark.disable_clean_stage_check
def test_manual_download(install_mockery, mock_download, monkeypatch, manual, instr):
def test_manual_download(
install_mockery, mock_download, default_mock_concretization, monkeypatch, manual, instr
):
"""
Ensure expected fetcher fail message based on manual download and instr.
"""
@ -579,7 +581,7 @@ def test_manual_download(install_mockery, mock_download, monkeypatch, manual, in
def _instr(pkg):
return "Download instructions for {0}".format(pkg.spec.name)
spec = Spec("a").concretized()
spec = default_mock_concretization("a")
pkg = spec.package
pkg.manual_download = manual
@ -605,16 +607,20 @@ def fetch(self):
monkeypatch.setattr(spack.package_base.PackageBase, "fetcher", fetcher)
def test_fetch_without_code_is_noop(install_mockery, fetching_not_allowed):
def test_fetch_without_code_is_noop(
default_mock_concretization, install_mockery, fetching_not_allowed
):
"""do_fetch for packages without code should be a no-op"""
pkg = Spec("a").concretized().package
pkg = default_mock_concretization("a").package
pkg.has_code = False
pkg.do_fetch()
def test_fetch_external_package_is_noop(install_mockery, fetching_not_allowed):
def test_fetch_external_package_is_noop(
default_mock_concretization, install_mockery, fetching_not_allowed
):
"""do_fetch for packages without code should be a no-op"""
spec = Spec("a").concretized()
spec = default_mock_concretization("a")
spec.external_path = "/some/where"
assert spec.external
spec.package.do_fetch()

View File

@ -719,9 +719,8 @@ def test_exceptional_paths_for_constructor(self):
with pytest.raises(ValueError):
Spec("libelf foo")
def test_spec_formatting(self):
spec = Spec("multivalue-variant cflags=-O2")
spec.concretize()
def test_spec_formatting(self, default_mock_concretization):
spec = default_mock_concretization("multivalue-variant cflags=-O2")
# Since the default is the full spec see if the string rep of
# spec is the same as the output of spec.format()
@ -797,9 +796,8 @@ def test_spec_formatting(self):
actual = spec.format(named_str)
assert expected == actual
def test_spec_formatting_escapes(self):
spec = Spec("multivalue-variant cflags=-O2")
spec.concretize()
def test_spec_formatting_escapes(self, default_mock_concretization):
spec = default_mock_concretization("multivalue-variant cflags=-O2")
sigil_mismatches = [
"{@name}",
@ -881,7 +879,7 @@ def test_spec_flags_maintain_order(self):
# different orderings for repeated concretizations of the same
# spec and config
spec_str = "libelf %gcc@11.1.0 os=redhat6"
for _ in range(25):
for _ in range(3):
s = Spec(spec_str).concretized()
assert all(
s.compiler_flags[x] == ["-O0", "-g"] for x in ("cflags", "cxxflags", "fflags")
@ -954,13 +952,11 @@ def test_forwarding_of_architecture_attributes(self):
assert spec.target < "broadwell"
@pytest.mark.parametrize("transitive", [True, False])
def test_splice(self, transitive):
def test_splice(self, transitive, default_mock_concretization):
# Tests the new splice function in Spec using a somewhat simple case
# with a variant with a conditional dependency.
spec = Spec("splice-t")
dep = Spec("splice-h+foo")
spec.concretize()
dep.concretize()
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-h+foo")
# Sanity checking that these are not the same thing.
assert dep.dag_hash() != spec["splice-h"].dag_hash()
@ -993,11 +989,9 @@ def test_splice(self, transitive):
assert out.spliced
@pytest.mark.parametrize("transitive", [True, False])
def test_splice_with_cached_hashes(self, transitive):
spec = Spec("splice-t")
dep = Spec("splice-h+foo")
spec.concretize()
dep.concretize()
def test_splice_with_cached_hashes(self, default_mock_concretization, transitive):
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-h+foo")
# monkeypatch hashes so we can test that they are cached
spec._hash = "aaaaaa"
@ -1014,9 +1008,9 @@ def test_splice_with_cached_hashes(self, transitive):
assert out["splice-z"].dag_hash() == out_z_expected.dag_hash()
@pytest.mark.parametrize("transitive", [True, False])
def test_splice_input_unchanged(self, transitive):
spec = Spec("splice-t").concretized()
dep = Spec("splice-h+foo").concretized()
def test_splice_input_unchanged(self, default_mock_concretization, transitive):
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-h+foo")
orig_spec_hash = spec.dag_hash()
orig_dep_hash = dep.dag_hash()
spec.splice(dep, transitive)
@ -1026,16 +1020,13 @@ def test_splice_input_unchanged(self, transitive):
assert dep.dag_hash() == orig_dep_hash
@pytest.mark.parametrize("transitive", [True, False])
def test_splice_subsequent(self, transitive):
spec = Spec("splice-t")
dep = Spec("splice-h+foo")
spec.concretize()
dep.concretize()
def test_splice_subsequent(self, default_mock_concretization, transitive):
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-h+foo")
out = spec.splice(dep, transitive)
# Now we attempt a second splice.
dep = Spec("splice-z+bar")
dep.concretize()
dep = default_mock_concretization("splice-z+bar")
# Transitivity shouldn't matter since Splice Z has no dependencies.
out2 = out.splice(dep, transitive)
@ -1046,11 +1037,9 @@ def test_splice_subsequent(self, transitive):
assert out2.spliced
@pytest.mark.parametrize("transitive", [True, False])
def test_splice_dict(self, transitive):
spec = Spec("splice-t")
dep = Spec("splice-h+foo")
spec.concretize()
dep.concretize()
def test_splice_dict(self, default_mock_concretization, transitive):
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-h+foo")
out = spec.splice(dep, transitive)
# Sanity check all hashes are unique...
@ -1065,11 +1054,9 @@ def test_splice_dict(self, transitive):
assert len(build_spec_nodes) == 1
@pytest.mark.parametrize("transitive", [True, False])
def test_splice_dict_roundtrip(self, transitive):
spec = Spec("splice-t")
dep = Spec("splice-h+foo")
spec.concretize()
dep.concretize()
def test_splice_dict_roundtrip(self, default_mock_concretization, transitive):
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-h+foo")
out = spec.splice(dep, transitive)
# Sanity check all hashes are unique...
@ -1132,21 +1119,17 @@ def test_satisfies_dependencies_ordered(self):
assert s.satisfies("mpileaks ^zmpi ^fake", strict=True)
@pytest.mark.parametrize("transitive", [True, False])
def test_splice_swap_names(self, transitive):
spec = Spec("splice-t")
dep = Spec("splice-a+foo")
spec.concretize()
dep.concretize()
def test_splice_swap_names(self, default_mock_concretization, transitive):
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-a+foo")
out = spec.splice(dep, transitive)
assert dep.name in out
assert transitive == ("+foo" in out["splice-z"])
@pytest.mark.parametrize("transitive", [True, False])
def test_splice_swap_names_mismatch_virtuals(self, transitive):
spec = Spec("splice-t")
dep = Spec("splice-vh+foo")
spec.concretize()
dep.concretize()
def test_splice_swap_names_mismatch_virtuals(self, default_mock_concretization, transitive):
spec = default_mock_concretization("splice-t")
dep = default_mock_concretization("splice-vh+foo")
with pytest.raises(spack.spec.SpliceError, match="will not provide the same virtuals."):
spec.splice(dep, transitive)
@ -1166,12 +1149,11 @@ def test_spec_override(self):
@pytest.mark.regression("3887")
@pytest.mark.parametrize("spec_str", ["git", "hdf5", "py-flake8"])
def test_is_extension_after_round_trip_to_dict(config, spec_str):
@pytest.mark.parametrize("spec_str", ["py-extension2", "extension1", "perl-extension"])
def test_is_extension_after_round_trip_to_dict(config, mock_packages, spec_str):
# x is constructed directly from string, y from a
# round-trip to dict representation
x = Spec(spec_str)
x.concretize()
x = Spec(spec_str).concretized()
y = Spec.from_dict(x.to_dict())
# Using 'y' since the round-trip make us lose build dependencies
@ -1231,7 +1213,7 @@ def test_merge_anonymous_spec_with_named_spec(anonymous, named, expected):
assert s == Spec(expected)
def test_spec_installed(install_mockery, database):
def test_spec_installed(default_mock_concretization, database):
"""Test whether Spec.installed works."""
# a known installed spec should say that it's installed
specs = database.query()
@ -1244,14 +1226,14 @@ def test_spec_installed(install_mockery, database):
assert not spec.installed
# 'a' is not in the mock DB and is not installed
spec = Spec("a").concretized()
spec = default_mock_concretization("a")
assert not spec.installed
@pytest.mark.regression("30678")
def test_call_dag_hash_on_old_dag_hash_spec(mock_packages, config):
def test_call_dag_hash_on_old_dag_hash_spec(mock_packages, default_mock_concretization):
# create a concrete spec
a = Spec("a").concretized()
a = default_mock_concretization("a")
dag_hashes = {spec.name: spec.dag_hash() for spec in a.traverse()}
# make it look like an old DAG hash spec with no package hash on the spec.
@ -1298,9 +1280,9 @@ def test_unsupported_compiler():
Spec("gcc%fake-compiler").validate_or_raise()
def test_package_hash_affects_dunder_and_dag_hash(mock_packages, config):
a1 = Spec("a").concretized()
a2 = Spec("a").concretized()
def test_package_hash_affects_dunder_and_dag_hash(mock_packages, default_mock_concretization):
a1 = default_mock_concretization("a")
a2 = default_mock_concretization("a")
assert hash(a1) == hash(a2)
assert a1.dag_hash() == a2.dag_hash()

View File

@ -136,18 +136,22 @@ def test_archive_file_errors(tmpdir, mock_archive, _fetch_method):
@pytest.mark.parametrize("secure", [True, False])
@pytest.mark.parametrize("_fetch_method", ["curl", "urllib"])
@pytest.mark.parametrize("mock_archive", files, indirect=True)
def test_fetch(mock_archive, secure, _fetch_method, checksum_type, config, mutable_mock_repo):
def test_fetch(
mock_archive,
secure,
_fetch_method,
checksum_type,
default_mock_concretization,
mutable_mock_repo,
):
"""Fetch an archive and make sure we can checksum it."""
mock_archive.url
mock_archive.path
algo = crypto.hash_fun_for_algo(checksum_type)()
with open(mock_archive.archive_file, "rb") as f:
algo.update(f.read())
checksum = algo.hexdigest()
# Get a spec and tweak the test package with new chcecksum params
s = Spec("url-test").concretized()
# Get a spec and tweak the test package with new checksum params
s = default_mock_concretization("url-test")
s.package.url = mock_archive.url
s.package.versions[ver("test")] = {checksum_type: checksum, "url": s.package.url}