Fix wrong hash in spliced specs, and improve unit-tests (#48574)

Modifications:
* Fix a severe bug where a spliced spec has the same hash as the original build spec
* Removed CacheManager in favor of install_mockery. The latter sets up a temporary store, and removes it at the end 
   of the test.
* Deleted a couple of helper functions e.g. _has_dependencies
* Checked that SolverException is raised, rather than Exception (more specific)
* Extended, and renamed the splicing_setup fixture (now called install_specs)
* Added more specific assertions in each test

One test is currently flaky, due to some instability when sorting multiple specs. It's currently marked xfail
This commit is contained in:
Massimiliano Culpo 2025-01-15 19:43:55 +01:00 committed by GitHub
parent 00e804a94b
commit 59a71959e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 245 additions and 222 deletions

View File

@ -3653,6 +3653,7 @@ def _resolve_automatic_splices(self):
): ):
continue continue
new_spec = spec.copy(deps=False) new_spec = spec.copy(deps=False)
new_spec.clear_caches(ignore=("package_hash",))
new_spec.build_spec = spec new_spec.build_spec = spec
for edge in spec.edges_to_dependencies(): for edge in spec.edges_to_dependencies():
depflag = edge.depflag & ~dt.BUILD depflag = edge.depflag & ~dt.BUILD

View File

@ -3591,25 +3591,16 @@ def patches(self):
return self._patches return self._patches
def _dup(self, other, deps: Union[bool, dt.DepTypes, dt.DepFlag] = True, cleardeps=True): def _dup(self, other: "Spec", deps: Union[bool, dt.DepTypes, dt.DepFlag] = True) -> bool:
"""Copy the spec other into self. This is an overwriting """Copies "other" into self, by overwriting all attributes.
copy. It does not copy any dependents (parents), but by default
copies dependencies.
To duplicate an entire DAG, call _dup() on the root of the DAG.
Args: Args:
other (Spec): spec to be copied onto ``self`` other: spec to be copied onto ``self``
deps: if True copies all the dependencies. If deps: if True copies all the dependencies. If False copies None.
False copies None. If deptype/depflag, copy matching types. If deptype, or depflag, copy matching types.
cleardeps (bool): if True clears the dependencies of ``self``,
before possibly copying the dependencies of ``other`` onto
``self``
Returns: Returns:
True if ``self`` changed because of the copy operation, True if ``self`` changed because of the copy operation, False otherwise.
False otherwise.
""" """
# We don't count dependencies as changes here # We don't count dependencies as changes here
changed = True changed = True
@ -3634,14 +3625,15 @@ def _dup(self, other, deps: Union[bool, dt.DepTypes, dt.DepFlag] = True, clearde
self.versions = other.versions.copy() self.versions = other.versions.copy()
self.architecture = other.architecture.copy() if other.architecture else None self.architecture = other.architecture.copy() if other.architecture else None
self.compiler = other.compiler.copy() if other.compiler else None self.compiler = other.compiler.copy() if other.compiler else None
if cleardeps:
self._dependents = _EdgeMap(store_by_child=False)
self._dependencies = _EdgeMap(store_by_child=True)
self.compiler_flags = other.compiler_flags.copy() self.compiler_flags = other.compiler_flags.copy()
self.compiler_flags.spec = self self.compiler_flags.spec = self
self.variants = other.variants.copy() self.variants = other.variants.copy()
self._build_spec = other._build_spec self._build_spec = other._build_spec
# Clear dependencies
self._dependents = _EdgeMap(store_by_child=False)
self._dependencies = _EdgeMap(store_by_child=True)
# FIXME: we manage _patches_in_order_of_appearance specially here # FIXME: we manage _patches_in_order_of_appearance specially here
# to keep it from leaking out of spec.py, but we should figure # to keep it from leaking out of spec.py, but we should figure
# out how to handle it more elegantly in the Variant classes. # out how to handle it more elegantly in the Variant classes.
@ -4524,7 +4516,7 @@ def mask_build_deps(in_spec):
return spec return spec
def clear_caches(self, ignore=()): def clear_caches(self, ignore: Tuple[str, ...] = ()) -> None:
""" """
Clears all cached hashes in a Spec, while preserving other properties. Clears all cached hashes in a Spec, while preserving other properties.
""" """

View File

@ -10,33 +10,11 @@
import spack.concretize import spack.concretize
import spack.config import spack.config
import spack.deptypes as dt import spack.deptypes as dt
import spack.solver.asp
from spack.installer import PackageInstaller from spack.installer import PackageInstaller
from spack.solver.asp import SolverError
from spack.spec import Spec from spack.spec import Spec
class CacheManager:
def __init__(self, specs: List[str]) -> None:
self.req_specs = specs
self.concr_specs: List[Spec]
self.concr_specs = []
def __enter__(self):
self.concr_specs = [spack.concretize.concretize_one(s) for s in self.req_specs]
for s in self.concr_specs:
PackageInstaller([s.package], fake=True, explicit=True).install()
def __exit__(self, exc_type, exc_val, exc_tb):
for s in self.concr_specs:
s.package.do_uninstall()
# MacOS and Windows only work if you pass this function pointer rather than a
# closure
def _mock_has_runtime_dependencies(_x):
return True
def _make_specs_non_buildable(specs: List[str]): def _make_specs_non_buildable(specs: List[str]):
output_config = {} output_config = {}
for spec in specs: for spec in specs:
@ -45,203 +23,263 @@ def _make_specs_non_buildable(specs: List[str]):
@pytest.fixture @pytest.fixture
def splicing_setup(mutable_database, mock_packages, monkeypatch): def install_specs(
spack.config.set("concretizer:reuse", True) mutable_database,
monkeypatch.setattr( mock_packages,
spack.solver.asp, "_has_runtime_dependencies", _mock_has_runtime_dependencies mutable_config,
) do_not_check_runtimes_on_reuse,
install_mockery,
):
"""Returns a function that concretizes and installs a list of abstract specs"""
mutable_config.set("concretizer:reuse", True)
def _impl(*specs_str):
concrete_specs = [Spec(s).concretized() for s in specs_str]
PackageInstaller([s.package for s in concrete_specs], fake=True, explicit=True).install()
return concrete_specs
return _impl
def _enable_splicing(): def _enable_splicing():
spack.config.set("concretizer:splice", {"automatic": True}) spack.config.set("concretizer:splice", {"automatic": True})
def _has_build_dependency(spec: Spec, name: str): @pytest.mark.parametrize("spec_str", ["splice-z", "splice-h@1"])
return any(s.name == name for s in spec.dependencies(None, dt.BUILD)) def test_spec_reuse(spec_str, install_specs, mutable_config):
"""Tests reuse of splice-z, without splicing, as a root and as a dependency of splice-h"""
splice_z = install_specs("splice-z@1.0.0+compat")[0]
mutable_config.set("packages", _make_specs_non_buildable(["splice-z"]))
concrete = spack.concretize.concretize_one(spec_str)
assert concrete["splice-z"].satisfies(splice_z)
def test_simple_reuse(splicing_setup): @pytest.mark.regression("48578")
with CacheManager(["splice-z@1.0.0+compat"]): def test_splice_installed_hash(install_specs, mutable_config):
spack.config.set("packages", _make_specs_non_buildable(["splice-z"])) """Tests splicing the dependency of an installed spec, for another installed spec"""
assert spack.concretize.concretize_one("splice-z").satisfies(Spec("splice-z")) splice_t, splice_h = install_specs(
def test_simple_dep_reuse(splicing_setup):
with CacheManager(["splice-z@1.0.0+compat"]):
spack.config.set("packages", _make_specs_non_buildable(["splice-z"]))
assert spack.concretize.concretize_one("splice-h@1").satisfies(Spec("splice-h@1"))
def test_splice_installed_hash(splicing_setup):
cache = [
"splice-t@1 ^splice-h@1.0.0+compat ^splice-z@1.0.0", "splice-t@1 ^splice-h@1.0.0+compat ^splice-z@1.0.0",
"splice-h@1.0.2+compat ^splice-z@1.0.0", "splice-h@1.0.2+compat ^splice-z@1.0.0",
] )
with CacheManager(cache): packages_config = _make_specs_non_buildable(["splice-t", "splice-h"])
packages_config = _make_specs_non_buildable(["splice-t", "splice-h"]) mutable_config.set("packages", packages_config)
spack.config.set("packages", packages_config)
goal_spec = Spec("splice-t@1 ^splice-h@1.0.2+compat ^splice-z@1.0.0") goal_spec = "splice-t@1 ^splice-h@1.0.2+compat ^splice-z@1.0.0"
with pytest.raises(Exception): with pytest.raises(SolverError):
spack.concretize.concretize_one(goal_spec) spack.concretize.concretize_one(goal_spec)
_enable_splicing() _enable_splicing()
assert spack.concretize.concretize_one(goal_spec).satisfies(goal_spec) concrete = spack.concretize.concretize_one(goal_spec)
# splice-t has a dependency that is changing, thus its hash should be different
assert concrete.dag_hash() != splice_t.dag_hash()
assert concrete.build_spec.satisfies(splice_t)
assert not concrete.satisfies(splice_t)
# splice-h is reused, so the hash should stay the same
assert concrete["splice-h"].satisfies(splice_h)
assert concrete["splice-h"].build_spec.satisfies(splice_h)
assert concrete["splice-h"].dag_hash() == splice_h.dag_hash()
def test_splice_build_splice_node(splicing_setup): def test_splice_build_splice_node(install_specs, mutable_config):
with CacheManager(["splice-t@1 ^splice-h@1.0.0+compat ^splice-z@1.0.0+compat"]): """Tests splicing the dependency of an installed spec, for a spec that is yet to be built"""
spack.config.set("packages", _make_specs_non_buildable(["splice-t"])) splice_t = install_specs("splice-t@1 ^splice-h@1.0.0+compat ^splice-z@1.0.0+compat")[0]
goal_spec = Spec("splice-t@1 ^splice-h@1.0.2+compat ^splice-z@1.0.0+compat") mutable_config.set("packages", _make_specs_non_buildable(["splice-t"]))
with pytest.raises(Exception):
spack.concretize.concretize_one(goal_spec) goal_spec = "splice-t@1 ^splice-h@1.0.2+compat ^splice-z@1.0.0+compat"
_enable_splicing() with pytest.raises(SolverError):
assert spack.concretize.concretize_one(goal_spec).satisfies(goal_spec) spack.concretize.concretize_one(goal_spec)
_enable_splicing()
concrete = spack.concretize.concretize_one(goal_spec)
# splice-t has a dependency that is changing, thus its hash should be different
assert concrete.dag_hash() != splice_t.dag_hash()
assert concrete.build_spec.satisfies(splice_t)
assert not concrete.satisfies(splice_t)
# splice-h should be different
assert concrete["splice-h"].dag_hash() != splice_t["splice-h"].dag_hash()
assert concrete["splice-h"].build_spec.dag_hash() == concrete["splice-h"].dag_hash()
def test_double_splice(splicing_setup): @pytest.mark.xfail(reason="the spliced splice-h has sometimes the original splice-h hash")
cache = [ def test_double_splice(install_specs, mutable_config):
"""Tests splicing two dependencies of an installed spec, for other installed specs"""
splice_t, splice_h, splice_z = install_specs(
"splice-t@1 ^splice-h@1.0.0+compat ^splice-z@1.0.0+compat", "splice-t@1 ^splice-h@1.0.0+compat ^splice-z@1.0.0+compat",
"splice-h@1.0.2+compat ^splice-z@1.0.1+compat", "splice-h@1.0.2+compat ^splice-z@1.0.1+compat",
"splice-z@1.0.2+compat", "splice-z@1.0.2+compat",
] )
with CacheManager(cache): mutable_config.set("packages", _make_specs_non_buildable(["splice-t", "splice-h", "splice-z"]))
freeze_builds_config = _make_specs_non_buildable(["splice-t", "splice-h", "splice-z"])
spack.config.set("packages", freeze_builds_config) goal_spec = "splice-t@1 ^splice-h@1.0.2+compat ^splice-z@1.0.2+compat"
goal_spec = Spec("splice-t@1 ^splice-h@1.0.2+compat ^splice-z@1.0.2+compat") with pytest.raises(SolverError):
with pytest.raises(Exception): spack.concretize.concretize_one(goal_spec)
spack.concretize.concretize_one(goal_spec)
_enable_splicing() _enable_splicing()
assert spack.concretize.concretize_one(goal_spec).satisfies(goal_spec) concrete = spack.concretize.concretize_one(goal_spec)
# splice-t and splice-h have a dependency that is changing, thus its hash should be different
assert concrete.dag_hash() != splice_t.dag_hash()
assert concrete.build_spec.satisfies(splice_t)
assert not concrete.satisfies(splice_t)
assert concrete["splice-h"].dag_hash() != splice_h.dag_hash()
assert concrete["splice-h"].build_spec.satisfies(splice_h)
assert not concrete["splice-h"].satisfies(splice_h)
# splice-z is reused, so the hash should stay the same
assert concrete["splice-z"].dag_hash() == splice_z.dag_hash()
# The next two tests are mirrors of one another @pytest.mark.parametrize(
def test_virtual_multi_splices_in(splicing_setup): "original_spec,goal_spec",
cache = [ [
"depends-on-virtual-with-abi ^virtual-abi-1", # `virtual-abi-1` can be spliced for `virtual-abi-multi abi=one` and vice-versa
"depends-on-virtual-with-abi ^virtual-abi-2", (
] "depends-on-virtual-with-abi ^virtual-abi-1",
goal_specs = [ "depends-on-virtual-with-abi ^virtual-abi-multi abi=one",
"depends-on-virtual-with-abi ^virtual-abi-multi abi=one", ),
"depends-on-virtual-with-abi ^virtual-abi-multi abi=two", (
] "depends-on-virtual-with-abi ^virtual-abi-multi abi=one",
with CacheManager(cache): "depends-on-virtual-with-abi ^virtual-abi-1",
spack.config.set("packages", _make_specs_non_buildable(["depends-on-virtual-with-abi"])) ),
for gs in goal_specs: # `virtual-abi-2` can be spliced for `virtual-abi-multi abi=two` and vice-versa
with pytest.raises(Exception): (
spack.concretize.concretize_one(gs) "depends-on-virtual-with-abi ^virtual-abi-2",
_enable_splicing() "depends-on-virtual-with-abi ^virtual-abi-multi abi=two",
for gs in goal_specs: ),
assert spack.concretize.concretize_one(gs).satisfies(gs) (
"depends-on-virtual-with-abi ^virtual-abi-multi abi=two",
"depends-on-virtual-with-abi ^virtual-abi-2",
),
],
)
def test_virtual_multi_splices_in(original_spec, goal_spec, install_specs, mutable_config):
"""Tests that we can splice a virtual dependency with a different, but compatible, provider."""
original = install_specs(original_spec)[0]
mutable_config.set("packages", _make_specs_non_buildable(["depends-on-virtual-with-abi"]))
with pytest.raises(SolverError):
spack.concretize.concretize_one(goal_spec)
_enable_splicing()
spliced = spack.concretize.concretize_one(goal_spec)
assert spliced.dag_hash() != original.dag_hash()
assert spliced.build_spec.dag_hash() == original.dag_hash()
assert spliced["virtual-with-abi"].name != spliced.build_spec["virtual-with-abi"].name
def test_virtual_multi_can_be_spliced(splicing_setup): @pytest.mark.parametrize(
cache = [ "original_spec,goal_spec",
"depends-on-virtual-with-abi ^virtual-abi-multi abi=one", [
"depends-on-virtual-with-abi ^virtual-abi-multi abi=two",
]
goal_specs = [
"depends-on-virtual-with-abi ^virtual-abi-1",
"depends-on-virtual-with-abi ^virtual-abi-2",
]
with CacheManager(cache):
spack.config.set("packages", _make_specs_non_buildable(["depends-on-virtual-with-abi"]))
for gs in goal_specs:
with pytest.raises(Exception):
spack.concretize.concretize_one(gs)
_enable_splicing()
for gs in goal_specs:
assert spack.concretize.concretize_one(gs).satisfies(gs)
def test_manyvariant_star_matching_variant_splice(splicing_setup):
cache = [
# can_splice("manyvariants@1.0.0", when="@1.0.1", match_variants="*") # can_splice("manyvariants@1.0.0", when="@1.0.1", match_variants="*")
"depends-on-manyvariants ^manyvariants@1.0.0+a+b c=v1 d=v2", (
"depends-on-manyvariants ^manyvariants@1.0.0~a~b c=v3 d=v3", "depends-on-manyvariants ^manyvariants@1.0.0+a+b c=v1 d=v2",
] "depends-on-manyvariants ^manyvariants@1.0.1+a+b c=v1 d=v2",
goal_specs = [ ),
Spec("depends-on-manyvariants ^manyvariants@1.0.1+a+b c=v1 d=v2"), (
Spec("depends-on-manyvariants ^manyvariants@1.0.1~a~b c=v3 d=v3"), "depends-on-manyvariants ^manyvariants@1.0.0~a~b c=v3 d=v3",
] "depends-on-manyvariants ^manyvariants@1.0.1~a~b c=v3 d=v3",
with CacheManager(cache): ),
freeze_build_config = {"depends-on-manyvariants": {"buildable": False}}
spack.config.set("packages", freeze_build_config)
for goal in goal_specs:
with pytest.raises(Exception):
spack.concretize.concretize_one(goal)
_enable_splicing()
for goal in goal_specs:
assert spack.concretize.concretize_one(goal).satisfies(goal)
def test_manyvariant_limited_matching(splicing_setup):
cache = [
# can_splice("manyvariants@2.0.0+a~b", when="@2.0.1~a+b", match_variants=["c", "d"]) # can_splice("manyvariants@2.0.0+a~b", when="@2.0.1~a+b", match_variants=["c", "d"])
"depends-on-manyvariants@2.0 ^manyvariants@2.0.0+a~b c=v3 d=v2", (
"depends-on-manyvariants@2.0 ^manyvariants@2.0.0+a~b c=v3 d=v2",
"depends-on-manyvariants@2.0 ^manyvariants@2.0.1~a+b c=v3 d=v2",
),
# can_splice("manyvariants@2.0.0 c=v1 d=v1", when="@2.0.1+a+b") # can_splice("manyvariants@2.0.0 c=v1 d=v1", when="@2.0.1+a+b")
"depends-on-manyvariants@2.0 ^manyvariants@2.0.0~a~b c=v1 d=v1", (
] "depends-on-manyvariants@2.0 ^manyvariants@2.0.0~a~b c=v1 d=v1",
goal_specs = [ "depends-on-manyvariants@2.0 ^manyvariants@2.0.1+a+b c=v3 d=v3",
Spec("depends-on-manyvariants@2.0 ^manyvariants@2.0.1~a+b c=v3 d=v2"), ),
Spec("depends-on-manyvariants@2.0 ^manyvariants@2.0.1+a+b c=v3 d=v3"), ],
] )
with CacheManager(cache): def test_manyvariant_matching_variant_splice(
freeze_build_config = {"depends-on-manyvariants": {"buildable": False}} original_spec, goal_spec, install_specs, mutable_config
spack.config.set("packages", freeze_build_config) ):
for s in goal_specs: """Tests splicing with different kind of matching on variants"""
with pytest.raises(Exception): original = install_specs(original_spec)[0]
spack.concretize.concretize_one(s) mutable_config.set("packages", {"depends-on-manyvariants": {"buildable": False}})
_enable_splicing()
for s in goal_specs: with pytest.raises(SolverError):
assert spack.concretize.concretize_one(s).satisfies(s) spack.concretize.concretize_one(goal_spec)
_enable_splicing()
spliced = spack.concretize.concretize_one(goal_spec)
assert spliced.dag_hash() != original.dag_hash()
assert spliced.build_spec.dag_hash() == original.dag_hash()
# The spliced 'manyvariants' is yet to be built
assert spliced["manyvariants"].dag_hash() != original["manyvariants"].dag_hash()
assert spliced["manyvariants"].build_spec.dag_hash() == spliced["manyvariants"].dag_hash()
def test_external_splice_same_name(splicing_setup): def test_external_splice_same_name(install_specs, mutable_config):
cache = [ """Tests that externals can be spliced for non-external specs"""
original_splice_h, original_splice_t = install_specs(
"splice-h@1.0.0 ^splice-z@1.0.0+compat", "splice-h@1.0.0 ^splice-z@1.0.0+compat",
"splice-t@1.0 ^splice-h@1.0.1 ^splice-z@1.0.1+compat", "splice-t@1.0 ^splice-h@1.0.1 ^splice-z@1.0.1+compat",
] )
packages_yaml = { mutable_config.set("packages", _make_specs_non_buildable(["splice-t", "splice-h"]))
"splice-z": {"externals": [{"spec": "splice-z@1.0.2+compat", "prefix": "/usr"}]} mutable_config.set(
} "packages",
goal_specs = [ {
Spec("splice-h@1.0.0 ^splice-z@1.0.2"), "splice-z": {
Spec("splice-t@1.0 ^splice-h@1.0.1 ^splice-z@1.0.2"), "externals": [{"spec": "splice-z@1.0.2+compat", "prefix": "/usr"}],
] "buildable": False,
with CacheManager(cache): }
spack.config.set("packages", packages_yaml) },
_enable_splicing() )
for s in goal_specs:
assert spack.concretize.concretize_one(s).satisfies(s) _enable_splicing()
concrete_splice_h = spack.concretize.concretize_one("splice-h@1.0.0 ^splice-z@1.0.2")
concrete_splice_t = spack.concretize.concretize_one(
"splice-t@1.0 ^splice-h@1.0.1 ^splice-z@1.0.2"
)
assert concrete_splice_h.dag_hash() != original_splice_h.dag_hash()
assert concrete_splice_h.build_spec.dag_hash() == original_splice_h.dag_hash()
assert concrete_splice_h["splice-z"].external
assert concrete_splice_t.dag_hash() != original_splice_t.dag_hash()
assert concrete_splice_t.build_spec.dag_hash() == original_splice_t.dag_hash()
assert concrete_splice_t["splice-z"].external
assert concrete_splice_t["splice-z"].dag_hash() == concrete_splice_h["splice-z"].dag_hash()
def test_spliced_build_deps_only_in_build_spec(splicing_setup): def test_spliced_build_deps_only_in_build_spec(install_specs):
cache = ["splice-t@1.0 ^splice-h@1.0.1 ^splice-z@1.0.0"] """Tests that build specs are not reported in the spliced spec"""
goal_spec = Spec("splice-t@1.0 ^splice-h@1.0.2 ^splice-z@1.0.0") install_specs("splice-t@1.0 ^splice-h@1.0.1 ^splice-z@1.0.0")
with CacheManager(cache): _enable_splicing()
_enable_splicing() spliced = spack.concretize.concretize_one("splice-t@1.0 ^splice-h@1.0.2 ^splice-z@1.0.0")
concr_goal = spack.concretize.concretize_one(goal_spec) build_spec = spliced.build_spec
build_spec = concr_goal._build_spec
# Spec has been spliced # Spec has been spliced
assert build_spec is not None assert build_spec.dag_hash() != spliced.dag_hash()
# Build spec has spliced build dependencies # Build spec has spliced build dependencies
assert _has_build_dependency(build_spec, "splice-h") assert build_spec.dependencies("splice-h", dt.BUILD)
assert _has_build_dependency(build_spec, "splice-z") assert build_spec.dependencies("splice-z", dt.BUILD)
# Spliced build dependencies are removed # Spliced build dependencies are removed
assert len(concr_goal.dependencies(None, dt.BUILD)) == 0 assert len(spliced.dependencies(None, dt.BUILD)) == 0
def test_spliced_transitive_dependency(splicing_setup): def test_spliced_transitive_dependency(install_specs, mutable_config):
cache = ["splice-depends-on-t@1.0 ^splice-h@1.0.1"] """Tests that build specs are not reported, even for spliced transitive dependencies"""
goal_spec = Spec("splice-depends-on-t^splice-h@1.0.2") install_specs("splice-depends-on-t@1.0 ^splice-h@1.0.1")
mutable_config.set("packages", _make_specs_non_buildable(["splice-depends-on-t"]))
with CacheManager(cache): _enable_splicing()
spack.config.set("packages", _make_specs_non_buildable(["splice-depends-on-t"])) spliced = spack.concretize.concretize_one("splice-depends-on-t^splice-h@1.0.2")
_enable_splicing()
concr_goal = spack.concretize.concretize_one(goal_spec) # Spec has been spliced
# Spec has been spliced assert spliced.build_spec.dag_hash() != spliced.dag_hash()
assert concr_goal._build_spec is not None assert spliced["splice-t"].build_spec.dag_hash() != spliced["splice-t"].dag_hash()
assert concr_goal["splice-t"]._build_spec is not None
assert concr_goal.satisfies(goal_spec) # Spliced build dependencies are removed
# Spliced build dependencies are removed assert len(spliced.dependencies(None, dt.BUILD)) == 0
assert len(concr_goal.dependencies(None, dt.BUILD)) == 0 assert len(spliced["splice-t"].dependencies(None, dt.BUILD)) == 0

View File

@ -2125,15 +2125,7 @@ def configure_reuse(reuse_mode, combined_env) -> Optional[ev.Environment]:
"from_environment_raise", "from_environment_raise",
], ],
) )
def test_env_include_concrete_reuse(monkeypatch, reuse_mode): def test_env_include_concrete_reuse(do_not_check_runtimes_on_reuse, reuse_mode):
# The mock packages do not use the gcc-runtime
def mock_has_runtime_dependencies(*args, **kwargs):
return True
monkeypatch.setattr(
spack.solver.asp, "_has_runtime_dependencies", mock_has_runtime_dependencies
)
# The default mpi version is 3.x provided by mpich in the mock repo. # The default mpi version is 3.x provided by mpich in the mock repo.
# This test verifies that concretizing with an included concrete # This test verifies that concretizing with an included concrete
# environment with "concretizer:reuse:true" the included # environment with "concretizer:reuse:true" the included

View File

@ -3122,14 +3122,13 @@ def test_concretization_version_order():
), ),
], ],
) )
@pytest.mark.usefixtures("mutable_database", "mock_store") @pytest.mark.usefixtures("mutable_database", "mock_store", "do_not_check_runtimes_on_reuse")
@pytest.mark.not_on_windows("Expected length is different on Windows") @pytest.mark.not_on_windows("Expected length is different on Windows")
def test_filtering_reused_specs( def test_filtering_reused_specs(
roots, reuse_yaml, expected, not_expected, expected_length, mutable_config, monkeypatch roots, reuse_yaml, expected, not_expected, expected_length, mutable_config
): ):
"""Tests that we can select which specs are to be reused, using constraints as filters""" """Tests that we can select which specs are to be reused, using constraints as filters"""
# Assume all specs have a runtime dependency # Assume all specs have a runtime dependency
monkeypatch.setattr(spack.solver.asp, "_has_runtime_dependencies", lambda x: True)
mutable_config.set("concretizer:reuse", reuse_yaml) mutable_config.set("concretizer:reuse", reuse_yaml)
selector = spack.solver.asp.ReusableSpecsSelector(mutable_config) selector = spack.solver.asp.ReusableSpecsSelector(mutable_config)
specs = selector.reusable_specs(roots) specs = selector.reusable_specs(roots)
@ -3149,10 +3148,11 @@ def test_filtering_reused_specs(
[({"from": [{"type": "local"}]}, 17), ({"from": [{"type": "buildcache"}]}, 0)], [({"from": [{"type": "local"}]}, 17), ({"from": [{"type": "buildcache"}]}, 0)],
) )
@pytest.mark.not_on_windows("Expected length is different on Windows") @pytest.mark.not_on_windows("Expected length is different on Windows")
def test_selecting_reused_sources(reuse_yaml, expected_length, mutable_config, monkeypatch): def test_selecting_reused_sources(
reuse_yaml, expected_length, mutable_config, do_not_check_runtimes_on_reuse
):
"""Tests that we can turn on/off sources of reusable specs""" """Tests that we can turn on/off sources of reusable specs"""
# Assume all specs have a runtime dependency # Assume all specs have a runtime dependency
monkeypatch.setattr(spack.solver.asp, "_has_runtime_dependencies", lambda x: True)
mutable_config.set("concretizer:reuse", reuse_yaml) mutable_config.set("concretizer:reuse", reuse_yaml)
selector = spack.solver.asp.ReusableSpecsSelector(mutable_config) selector = spack.solver.asp.ReusableSpecsSelector(mutable_config)
specs = selector.reusable_specs(["mpileaks"]) specs = selector.reusable_specs(["mpileaks"])