Testing: use spack.store.use_store everywhere (#21656)
Keep spack.store.store and spack.store.db consistent in unit tests * Remove calls to monkeypatch for spack.store.store and spack.store.db: tests that used these called one or the other, which lead to inconsistencies (the tests passed regardless but were fragile as a result) * Fixtures making use of monkeypatch with mock_store now use the updated use_store function, which sets store.store and store.db consistently * subprocess_context.TestState now transfers the serializes and restores spack.store.store (without the monkeypatch changes this would have created inconsistencies)
This commit is contained in:
parent
cbcf8d208b
commit
f2e3edf6db
11 changed files with 178 additions and 176 deletions
|
@ -1089,6 +1089,8 @@ def relocate_package(spec, allow_root):
|
||||||
"""
|
"""
|
||||||
Relocate the given package
|
Relocate the given package
|
||||||
"""
|
"""
|
||||||
|
import spack.hooks.sbang as sbang
|
||||||
|
|
||||||
workdir = str(spec.prefix)
|
workdir = str(spec.prefix)
|
||||||
buildinfo = read_buildinfo_file(workdir)
|
buildinfo = read_buildinfo_file(workdir)
|
||||||
new_layout_root = str(spack.store.layout.root)
|
new_layout_root = str(spack.store.layout.root)
|
||||||
|
@ -1127,7 +1129,6 @@ def relocate_package(spec, allow_root):
|
||||||
prefix_to_prefix_bin = OrderedDict({})
|
prefix_to_prefix_bin = OrderedDict({})
|
||||||
|
|
||||||
if old_sbang_install_path:
|
if old_sbang_install_path:
|
||||||
import spack.hooks.sbang as sbang
|
|
||||||
prefix_to_prefix_text[old_sbang_install_path] = sbang.sbang_install_path()
|
prefix_to_prefix_text[old_sbang_install_path] = sbang.sbang_install_path()
|
||||||
|
|
||||||
prefix_to_prefix_text[old_prefix] = new_prefix
|
prefix_to_prefix_text[old_prefix] = new_prefix
|
||||||
|
@ -1141,7 +1142,6 @@ def relocate_package(spec, allow_root):
|
||||||
# sbang was a bash script, and it lived in the spack prefix. It is
|
# sbang was a bash script, and it lived in the spack prefix. It is
|
||||||
# now a POSIX script that lives in the install prefix. Old packages
|
# now a POSIX script that lives in the install prefix. Old packages
|
||||||
# will have the old sbang location in their shebangs.
|
# will have the old sbang location in their shebangs.
|
||||||
import spack.hooks.sbang as sbang
|
|
||||||
orig_sbang = '#!/bin/bash {0}/bin/sbang'.format(old_spack_prefix)
|
orig_sbang = '#!/bin/bash {0}/bin/sbang'.format(old_spack_prefix)
|
||||||
new_sbang = sbang.sbang_shebang_line()
|
new_sbang = sbang.sbang_shebang_line()
|
||||||
prefix_to_prefix_text[orig_sbang] = new_sbang
|
prefix_to_prefix_text[orig_sbang] = new_sbang
|
||||||
|
@ -1160,7 +1160,7 @@ def is_backup_file(file):
|
||||||
if not is_backup_file(text_name):
|
if not is_backup_file(text_name):
|
||||||
text_names.append(text_name)
|
text_names.append(text_name)
|
||||||
|
|
||||||
# If we are not installing back to the same install tree do the relocation
|
# If we are not installing back to the same install tree do the relocation
|
||||||
if old_layout_root != new_layout_root:
|
if old_layout_root != new_layout_root:
|
||||||
files_to_relocate = [os.path.join(workdir, filename)
|
files_to_relocate = [os.path.join(workdir, filename)
|
||||||
for filename in buildinfo.get('relocate_binaries')
|
for filename in buildinfo.get('relocate_binaries')
|
||||||
|
|
|
@ -158,6 +158,8 @@ def __init__(
|
||||||
):
|
):
|
||||||
self.root = root
|
self.root = root
|
||||||
self.unpadded_root = unpadded_root or root
|
self.unpadded_root = unpadded_root or root
|
||||||
|
self.projections = projections
|
||||||
|
self.hash_length = hash_length
|
||||||
self.db = spack.database.Database(
|
self.db = spack.database.Database(
|
||||||
root, upstream_dbs=retrieve_upstream_dbs())
|
root, upstream_dbs=retrieve_upstream_dbs())
|
||||||
self.layout = spack.directory_layout.YamlDirectoryLayout(
|
self.layout = spack.directory_layout.YamlDirectoryLayout(
|
||||||
|
@ -167,6 +169,27 @@ def reindex(self):
|
||||||
"""Convenience function to reindex the store DB with its own layout."""
|
"""Convenience function to reindex the store DB with its own layout."""
|
||||||
return self.db.reindex(self.layout)
|
return self.db.reindex(self.layout)
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
"""Return a pickle-able object that can be used to reconstruct
|
||||||
|
a store.
|
||||||
|
"""
|
||||||
|
return (
|
||||||
|
self.root, self.unpadded_root, self.projections, self.hash_length
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def deserialize(token):
|
||||||
|
"""Return a store reconstructed from a token created by
|
||||||
|
the serialize method.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
token: return value of the serialize method
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Store object reconstructed from the token
|
||||||
|
"""
|
||||||
|
return Store(*token)
|
||||||
|
|
||||||
|
|
||||||
def _store():
|
def _store():
|
||||||
"""Get the singleton store instance."""
|
"""Get the singleton store instance."""
|
||||||
|
@ -240,7 +263,7 @@ def use_store(store_or_path):
|
||||||
Returns:
|
Returns:
|
||||||
Store object associated with the context manager's store
|
Store object associated with the context manager's store
|
||||||
"""
|
"""
|
||||||
global store
|
global store, db, layout, root, unpadded_root
|
||||||
|
|
||||||
# Normalize input arguments
|
# Normalize input arguments
|
||||||
temporary_store = store_or_path
|
temporary_store = store_or_path
|
||||||
|
@ -248,8 +271,14 @@ def use_store(store_or_path):
|
||||||
temporary_store = Store(store_or_path)
|
temporary_store = Store(store_or_path)
|
||||||
|
|
||||||
# Swap the store with the one just constructed and return it
|
# Swap the store with the one just constructed and return it
|
||||||
|
_ = store.db
|
||||||
original_store, store = store, temporary_store
|
original_store, store = store, temporary_store
|
||||||
|
db, layout = store.db, store.layout
|
||||||
|
root, unpadded_root = store.root, store.unpadded_root
|
||||||
|
|
||||||
yield temporary_store
|
yield temporary_store
|
||||||
|
|
||||||
# Restore the original store
|
# Restore the original store
|
||||||
store = original_store
|
store = original_store
|
||||||
|
db, layout = original_store.db, original_store.layout
|
||||||
|
root, unpadded_root = original_store.root, original_store.unpadded_root
|
||||||
|
|
|
@ -93,18 +93,21 @@ def __init__(self):
|
||||||
self.config = spack.config.config
|
self.config = spack.config.config
|
||||||
self.platform = spack.architecture.platform
|
self.platform = spack.architecture.platform
|
||||||
self.test_patches = store_patches()
|
self.test_patches = store_patches()
|
||||||
|
self.store_token = spack.store.store.serialize()
|
||||||
# TODO: transfer spack.store.store? note that you should not
|
|
||||||
# transfer spack.store.store and spack.store.db: 'db' is a
|
|
||||||
# shortcut that accesses the store (so transferring both can
|
|
||||||
# create an inconsistency). Some tests set 'db' directly, and
|
|
||||||
# others set 'store'
|
|
||||||
|
|
||||||
def restore(self):
|
def restore(self):
|
||||||
if _serialize:
|
if _serialize:
|
||||||
spack.repo.path = spack.repo._path(self.repo_dirs)
|
spack.repo.path = spack.repo._path(self.repo_dirs)
|
||||||
spack.config.config = self.config
|
spack.config.config = self.config
|
||||||
spack.architecture.platform = self.platform
|
spack.architecture.platform = self.platform
|
||||||
|
|
||||||
|
new_store = spack.store.Store.deserialize(self.store_token)
|
||||||
|
spack.store.store = new_store
|
||||||
|
spack.store.root = new_store.root
|
||||||
|
spack.store.unpadded_root = new_store.unpadded_root
|
||||||
|
spack.store.db = new_store.db
|
||||||
|
spack.store.layout = new_store.layout
|
||||||
|
|
||||||
self.test_patches.restore()
|
self.test_patches.restore()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -493,40 +493,39 @@ def test_update_sbang(tmpdir, test_mirror):
|
||||||
'${name}', '${version}',
|
'${name}', '${version}',
|
||||||
'${architecture}-${compiler.name}-${compiler.version}-${hash}'
|
'${architecture}-${compiler.name}-${compiler.version}-${hash}'
|
||||||
)
|
)
|
||||||
# Save the original store and layout before we touch ANYTHING.
|
spec_str = 'old-sbang'
|
||||||
real_store, real_layout = spack.store.store, spack.store.layout
|
|
||||||
|
|
||||||
# Concretize a package with some old-fashioned sbang lines.
|
# Concretize a package with some old-fashioned sbang lines.
|
||||||
sspec = Spec('old-sbang')
|
old_spec = Spec(spec_str).concretized()
|
||||||
sspec.concretize()
|
old_spec_hash_str = '/{0}'.format(old_spec.dag_hash())
|
||||||
|
|
||||||
# Need a fake mirror with *function* scope.
|
# Need a fake mirror with *function* scope.
|
||||||
mirror_dir = test_mirror
|
mirror_dir = test_mirror
|
||||||
|
mirror_url = 'file://{0}'.format(mirror_dir)
|
||||||
|
|
||||||
# Assumes all commands will concretize sspec the same way.
|
# Assume all commands will concretize old_spec the same way.
|
||||||
install_cmd('--no-cache', sspec.name)
|
install_cmd('--no-cache', old_spec.name)
|
||||||
|
|
||||||
# Create a buildcache with the installed spec.
|
# Create a buildcache with the installed spec.
|
||||||
buildcache_cmd('create', '-u', '-a', '-d', mirror_dir,
|
buildcache_cmd('create', '-u', '-a', '-d', mirror_dir, old_spec_hash_str)
|
||||||
'/%s' % sspec.dag_hash())
|
|
||||||
|
|
||||||
# Need to force an update of the buildcache index
|
# Need to force an update of the buildcache index
|
||||||
buildcache_cmd('update-index', '-d', 'file://%s' % mirror_dir)
|
buildcache_cmd('update-index', '-d', mirror_url)
|
||||||
|
|
||||||
# Uninstall the original package.
|
# Uninstall the original package.
|
||||||
uninstall_cmd('-y', '/%s' % sspec.dag_hash())
|
uninstall_cmd('-y', old_spec_hash_str)
|
||||||
|
|
||||||
try:
|
# Switch the store to the new install tree locations
|
||||||
# New install tree locations...
|
newtree_dir = tmpdir.join('newtree')
|
||||||
# Too fine-grained to do be done in a fixture
|
s = spack.store.Store(str(newtree_dir))
|
||||||
newtree_dir = tmpdir.join('newtree')
|
s.layout = YamlDirectoryLayout(str(newtree_dir), path_scheme=scheme)
|
||||||
spack.store.store = spack.store.Store(str(newtree_dir))
|
|
||||||
spack.store.layout = YamlDirectoryLayout(
|
with spack.store.use_store(s):
|
||||||
str(newtree_dir), path_scheme=scheme
|
new_spec = Spec('old-sbang')
|
||||||
)
|
new_spec.concretize()
|
||||||
|
assert new_spec.dag_hash() == old_spec.dag_hash()
|
||||||
|
|
||||||
# Install package from buildcache
|
# Install package from buildcache
|
||||||
buildcache_cmd('install', '-a', '-u', '-f', sspec.name)
|
buildcache_cmd('install', '-a', '-u', '-f', new_spec.name)
|
||||||
|
|
||||||
# Continue blowing away caches
|
# Continue blowing away caches
|
||||||
bindist.clear_spec_cache()
|
bindist.clear_spec_cache()
|
||||||
|
@ -537,23 +536,19 @@ def test_update_sbang(tmpdir, test_mirror):
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
{1}
|
{1}
|
||||||
'''.format(sbang.sbang_shebang_line(), sspec.prefix.bin)
|
'''.format(sbang.sbang_shebang_line(), new_spec.prefix.bin)
|
||||||
sbang_style_2_expected = '''{0}
|
sbang_style_2_expected = '''{0}
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
{1}
|
{1}
|
||||||
'''.format(sbang.sbang_shebang_line(), sspec.prefix.bin)
|
'''.format(sbang.sbang_shebang_line(), new_spec.prefix.bin)
|
||||||
|
|
||||||
installed_script_style_1_path = sspec.prefix.bin.join('sbang-style-1.sh')
|
installed_script_style_1_path = new_spec.prefix.bin.join('sbang-style-1.sh')
|
||||||
assert sbang_style_1_expected == \
|
assert sbang_style_1_expected == \
|
||||||
open(str(installed_script_style_1_path)).read()
|
open(str(installed_script_style_1_path)).read()
|
||||||
|
|
||||||
installed_script_style_2_path = sspec.prefix.bin.join('sbang-style-2.sh')
|
installed_script_style_2_path = new_spec.prefix.bin.join('sbang-style-2.sh')
|
||||||
assert sbang_style_2_expected == \
|
assert sbang_style_2_expected == \
|
||||||
open(str(installed_script_style_2_path)).read()
|
open(str(installed_script_style_2_path)).read()
|
||||||
|
|
||||||
uninstall_cmd('-y', '/%s' % sspec.dag_hash())
|
uninstall_cmd('-y', '/%s' % new_spec.dag_hash())
|
||||||
|
|
||||||
finally:
|
|
||||||
spack.store.store = real_store
|
|
||||||
spack.store.layout = real_layout
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ def ensure_module_files_are_there(
|
||||||
):
|
):
|
||||||
"""Generate module files for module tests."""
|
"""Generate module files for module tests."""
|
||||||
module = spack.main.SpackCommand('module')
|
module = spack.main.SpackCommand('module')
|
||||||
with spack.store.use_store(mock_store):
|
with spack.store.use_store(str(mock_store)):
|
||||||
with spack.config.use_configuration(*mock_configuration_scopes):
|
with spack.config.use_configuration(*mock_configuration_scopes):
|
||||||
with spack.repo.use_repositories(mock_repo_path):
|
with spack.repo.use_repositories(mock_repo_path):
|
||||||
module('tcl', 'refresh', '-y')
|
module('tcl', 'refresh', '-y')
|
||||||
|
|
|
@ -2,36 +2,30 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
import pytest
|
||||||
|
|
||||||
import spack.spec
|
import spack.spec
|
||||||
|
import spack.store
|
||||||
|
|
||||||
|
|
||||||
def test_set_install_hash_length(mock_packages, mutable_config, monkeypatch,
|
@pytest.mark.parametrize('hash_length', [1, 2, 3, 4, 5, 9])
|
||||||
tmpdir):
|
@pytest.mark.use_fixtures('mock_packages')
|
||||||
# spack.store.layout caches initial config values, so we monkeypatch
|
def test_set_install_hash_length(hash_length, mutable_config, tmpdir):
|
||||||
mutable_config.set('config:install_hash_length', 5)
|
mutable_config.set('config:install_hash_length', hash_length)
|
||||||
mutable_config.set('config:install_tree', {'root': str(tmpdir)})
|
mutable_config.set('config:install_tree', {'root': str(tmpdir)})
|
||||||
monkeypatch.setattr(spack.store, 'store', spack.store._store())
|
# The call below is to reinitialize the directory layout associated
|
||||||
|
# with the store according to the configuration changes above (i.e.
|
||||||
spec = spack.spec.Spec('libelf').concretized()
|
# with the shortened hash)
|
||||||
prefix = spec.prefix
|
store = spack.store._store()
|
||||||
hash = prefix.rsplit('-')[-1]
|
with spack.store.use_store(store):
|
||||||
|
spec = spack.spec.Spec('libelf').concretized()
|
||||||
assert len(hash) == 5
|
prefix = spec.prefix
|
||||||
|
hash_str = prefix.rsplit('-')[-1]
|
||||||
mutable_config.set('config:install_hash_length', 9)
|
assert len(hash_str) == hash_length
|
||||||
monkeypatch.setattr(spack.store, 'store', spack.store._store())
|
|
||||||
|
|
||||||
spec = spack.spec.Spec('libelf').concretized()
|
|
||||||
prefix = spec.prefix
|
|
||||||
hash = prefix.rsplit('-')[-1]
|
|
||||||
|
|
||||||
assert len(hash) == 9
|
|
||||||
|
|
||||||
|
|
||||||
def test_set_install_hash_length_upper_case(mock_packages, mutable_config,
|
@pytest.mark.use_fixtures('mock_packages')
|
||||||
monkeypatch, tmpdir):
|
def test_set_install_hash_length_upper_case(mutable_config, tmpdir):
|
||||||
# spack.store.layout caches initial config values, so we monkeypatch
|
|
||||||
mutable_config.set('config:install_hash_length', 5)
|
mutable_config.set('config:install_hash_length', 5)
|
||||||
mutable_config.set(
|
mutable_config.set(
|
||||||
'config:install_tree',
|
'config:install_tree',
|
||||||
|
@ -42,10 +36,12 @@ def test_set_install_hash_length_upper_case(mock_packages, mutable_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
monkeypatch.setattr(spack.store, 'store', spack.store._store())
|
# The call below is to reinitialize the directory layout associated
|
||||||
|
# with the store according to the configuration changes above (i.e.
|
||||||
spec = spack.spec.Spec('libelf').concretized()
|
# with the shortened hash and projection)
|
||||||
prefix = spec.prefix
|
store = spack.store._store()
|
||||||
hash = prefix.rsplit('-')[-1]
|
with spack.store.use_store(store):
|
||||||
|
spec = spack.spec.Spec('libelf').concretized()
|
||||||
assert len(hash) == 5
|
prefix = spec.prefix
|
||||||
|
hash_str = prefix.rsplit('-')[-1]
|
||||||
|
assert len(hash_str) == 5
|
||||||
|
|
|
@ -563,12 +563,10 @@ def _install(spec):
|
||||||
pkg = spack.repo.get(s)
|
pkg = spack.repo.get(s)
|
||||||
pkg.do_install(fake=True, explicit=True)
|
pkg.do_install(fake=True, explicit=True)
|
||||||
|
|
||||||
# Transaction used to avoid repeated writes.
|
_install('mpileaks ^mpich')
|
||||||
with mock_db.write_transaction():
|
_install('mpileaks ^mpich2')
|
||||||
_install('mpileaks ^mpich')
|
_install('mpileaks ^zmpi')
|
||||||
_install('mpileaks ^mpich2')
|
_install('externaltest')
|
||||||
_install('mpileaks ^zmpi')
|
|
||||||
_install('externaltest')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
|
@ -605,7 +603,7 @@ def mock_store(tmpdir_factory, mock_repo_path, mock_configuration_scopes,
|
||||||
# Make the DB filesystem read-only to ensure we can't modify entries
|
# Make the DB filesystem read-only to ensure we can't modify entries
|
||||||
store_path.join('.spack-db').chmod(mode=0o555, rec=1)
|
store_path.join('.spack-db').chmod(mode=0o555, rec=1)
|
||||||
|
|
||||||
yield store
|
yield store_path
|
||||||
|
|
||||||
store_path.join('.spack-db').chmod(mode=0o755, rec=1)
|
store_path.join('.spack-db').chmod(mode=0o755, rec=1)
|
||||||
|
|
||||||
|
@ -613,10 +611,9 @@ def mock_store(tmpdir_factory, mock_repo_path, mock_configuration_scopes,
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def database(mock_store, mock_packages, config, monkeypatch):
|
def database(mock_store, mock_packages, config, monkeypatch):
|
||||||
"""This activates the mock store, packages, AND config."""
|
"""This activates the mock store, packages, AND config."""
|
||||||
monkeypatch.setattr(spack.store, 'store', mock_store)
|
with spack.store.use_store(str(mock_store)) as store:
|
||||||
yield mock_store.db
|
yield store.db
|
||||||
# Force reading the database again between tests
|
store.db.last_seen_verifier = ''
|
||||||
mock_store.db.last_seen_verifier = ''
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
|
@ -687,20 +684,15 @@ def disable_compiler_execution(monkeypatch, request):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def install_mockery(tmpdir, config, mock_packages, monkeypatch):
|
def install_mockery(temporary_store, config, mock_packages):
|
||||||
"""Hooks a fake install directory, DB, and stage directory into Spack."""
|
"""Hooks a fake install directory, DB, and stage directory into Spack."""
|
||||||
monkeypatch.setattr(
|
|
||||||
spack.store, 'store', spack.store.Store(str(tmpdir.join('opt'))))
|
|
||||||
|
|
||||||
# We use a fake package, so temporarily disable checksumming
|
# We use a fake package, so temporarily disable checksumming
|
||||||
with spack.config.override('config:checksum', False):
|
with spack.config.override('config:checksum', False):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
tmpdir.join('opt').remove()
|
|
||||||
|
|
||||||
# Also wipe out any cached prefix failure locks (associated with
|
# Also wipe out any cached prefix failure locks (associated with
|
||||||
# the session-scoped mock archive).
|
# the session-scoped mock archive).
|
||||||
for pkg_id in list(spack.store.db._prefix_failures.keys()):
|
for pkg_id in list(temporary_store.db._prefix_failures.keys()):
|
||||||
lock = spack.store.db._prefix_failures.pop(pkg_id, None)
|
lock = spack.store.db._prefix_failures.pop(pkg_id, None)
|
||||||
if lock:
|
if lock:
|
||||||
try:
|
try:
|
||||||
|
@ -709,24 +701,29 @@ def install_mockery(tmpdir, config, mock_packages, monkeypatch):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function')
|
||||||
|
def temporary_store(tmpdir):
|
||||||
|
"""Hooks a temporary empty store for the test function."""
|
||||||
|
temporary_store_path = tmpdir.join('opt')
|
||||||
|
with spack.store.use_store(str(temporary_store_path)) as s:
|
||||||
|
yield s
|
||||||
|
temporary_store_path.remove()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def install_mockery_mutable_config(
|
def install_mockery_mutable_config(
|
||||||
tmpdir, mutable_config, mock_packages, monkeypatch):
|
temporary_store, mutable_config, mock_packages
|
||||||
|
):
|
||||||
"""Hooks a fake install directory, DB, and stage directory into Spack.
|
"""Hooks a fake install directory, DB, and stage directory into Spack.
|
||||||
|
|
||||||
This is specifically for tests which want to use 'install_mockery' but
|
This is specifically for tests which want to use 'install_mockery' but
|
||||||
also need to modify configuration (and hence would want to use
|
also need to modify configuration (and hence would want to use
|
||||||
'mutable config'): 'install_mockery' does not support this.
|
'mutable config'): 'install_mockery' does not support this.
|
||||||
"""
|
"""
|
||||||
monkeypatch.setattr(
|
|
||||||
spack.store, 'store', spack.store.Store(str(tmpdir.join('opt'))))
|
|
||||||
|
|
||||||
# We use a fake package, so temporarily disable checksumming
|
# We use a fake package, so temporarily disable checksumming
|
||||||
with spack.config.override('config:checksum', False):
|
with spack.config.override('config:checksum', False):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
tmpdir.join('opt').remove()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def mock_fetch(mock_archive, monkeypatch):
|
def mock_fetch(mock_archive, monkeypatch):
|
||||||
|
|
|
@ -37,16 +37,6 @@
|
||||||
pytestmark = pytest.mark.db
|
pytestmark = pytest.mark.db
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def test_store(tmpdir):
|
|
||||||
real_store = spack.store.store
|
|
||||||
spack.store.store = spack.store.Store(str(tmpdir.join('test_store')))
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
spack.store.store = real_store
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def upstream_and_downstream_db(tmpdir_factory, gen_mock_layout):
|
def upstream_and_downstream_db(tmpdir_factory, gen_mock_layout):
|
||||||
mock_db_root = str(tmpdir_factory.mktemp('mock_db_root'))
|
mock_db_root = str(tmpdir_factory.mktemp('mock_db_root'))
|
||||||
|
@ -180,8 +170,8 @@ def test_add_to_upstream_after_downstream(upstream_and_downstream_db):
|
||||||
spack.store.db = orig_db
|
spack.store.db = orig_db
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('config')
|
@pytest.mark.usefixtures('config', 'temporary_store')
|
||||||
def test_cannot_write_upstream(tmpdir_factory, test_store, gen_mock_layout):
|
def test_cannot_write_upstream(tmpdir_factory, gen_mock_layout):
|
||||||
roots = [str(tmpdir_factory.mktemp(x)) for x in ['a', 'b']]
|
roots = [str(tmpdir_factory.mktemp(x)) for x in ['a', 'b']]
|
||||||
layouts = [gen_mock_layout(x) for x in ['/ra/', '/rb/']]
|
layouts = [gen_mock_layout(x) for x in ['/ra/', '/rb/']]
|
||||||
|
|
||||||
|
@ -205,8 +195,8 @@ def test_cannot_write_upstream(tmpdir_factory, test_store, gen_mock_layout):
|
||||||
upstream_dbs[0].add(spec, layouts[1])
|
upstream_dbs[0].add(spec, layouts[1])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('config')
|
@pytest.mark.usefixtures('config', 'temporary_store')
|
||||||
def test_recursive_upstream_dbs(tmpdir_factory, test_store, gen_mock_layout):
|
def test_recursive_upstream_dbs(tmpdir_factory, gen_mock_layout):
|
||||||
roots = [str(tmpdir_factory.mktemp(x)) for x in ['a', 'b', 'c']]
|
roots = [str(tmpdir_factory.mktemp(x)) for x in ['a', 'b', 'c']]
|
||||||
layouts = [gen_mock_layout(x) for x in ['/ra/', '/rb/', '/rc/']]
|
layouts = [gen_mock_layout(x) for x in ['/ra/', '/rb/', '/rc/']]
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
This test verifies that the Spack directory layout works properly.
|
This test verifies that the Spack directory layout works properly.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import os.path
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import spack.paths
|
import spack.paths
|
||||||
|
@ -19,16 +20,6 @@
|
||||||
max_packages = 10
|
max_packages = 10
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
|
||||||
def layout_and_dir(tmpdir):
|
|
||||||
"""Returns a directory layout and the corresponding directory."""
|
|
||||||
layout = YamlDirectoryLayout(str(tmpdir))
|
|
||||||
old_layout = spack.store.layout
|
|
||||||
spack.store.layout = layout
|
|
||||||
yield layout, str(tmpdir)
|
|
||||||
spack.store.layout = old_layout
|
|
||||||
|
|
||||||
|
|
||||||
def test_yaml_directory_layout_parameters(tmpdir, config):
|
def test_yaml_directory_layout_parameters(tmpdir, config):
|
||||||
"""This tests the various parameters that can be used to configure
|
"""This tests the various parameters that can be used to configure
|
||||||
the install location """
|
the install location """
|
||||||
|
@ -84,14 +75,14 @@ def test_yaml_directory_layout_parameters(tmpdir, config):
|
||||||
projections=projections_package7)
|
projections=projections_package7)
|
||||||
|
|
||||||
|
|
||||||
def test_read_and_write_spec(layout_and_dir, config, mock_packages):
|
def test_read_and_write_spec(temporary_store, config, mock_packages):
|
||||||
"""This goes through each package in spack and creates a directory for
|
"""This goes through each package in spack and creates a directory for
|
||||||
it. It then ensures that the spec for the directory's
|
it. It then ensures that the spec for the directory's
|
||||||
installed package can be read back in consistently, and
|
installed package can be read back in consistently, and
|
||||||
finally that the directory can be removed by the directory
|
finally that the directory can be removed by the directory
|
||||||
layout.
|
layout.
|
||||||
"""
|
"""
|
||||||
layout, tmpdir = layout_and_dir
|
layout = temporary_store.layout
|
||||||
packages = list(spack.repo.path.all_packages())[:max_packages]
|
packages = list(spack.repo.path.all_packages())[:max_packages]
|
||||||
|
|
||||||
for pkg in packages:
|
for pkg in packages:
|
||||||
|
@ -114,7 +105,7 @@ def test_read_and_write_spec(layout_and_dir, config, mock_packages):
|
||||||
|
|
||||||
# Ensure directory has been created in right place.
|
# Ensure directory has been created in right place.
|
||||||
assert os.path.isdir(install_dir)
|
assert os.path.isdir(install_dir)
|
||||||
assert install_dir.startswith(str(tmpdir))
|
assert install_dir.startswith(temporary_store.root)
|
||||||
|
|
||||||
# Ensure spec file exists when directory is created
|
# Ensure spec file exists when directory is created
|
||||||
assert os.path.isfile(spec_path)
|
assert os.path.isfile(spec_path)
|
||||||
|
@ -160,7 +151,7 @@ def test_read_and_write_spec(layout_and_dir, config, mock_packages):
|
||||||
assert not os.path.exists(install_dir)
|
assert not os.path.exists(install_dir)
|
||||||
|
|
||||||
|
|
||||||
def test_handle_unknown_package(layout_and_dir, config, mock_packages):
|
def test_handle_unknown_package(temporary_store, config, mock_packages):
|
||||||
"""This test ensures that spack can at least do *some*
|
"""This test ensures that spack can at least do *some*
|
||||||
operations with packages that are installed but that it
|
operations with packages that are installed but that it
|
||||||
does not know about. This is actually not such an uncommon
|
does not know about. This is actually not such an uncommon
|
||||||
|
@ -171,7 +162,7 @@ def test_handle_unknown_package(layout_and_dir, config, mock_packages):
|
||||||
information about installed packages' specs to uninstall
|
information about installed packages' specs to uninstall
|
||||||
or query them again if the package goes away.
|
or query them again if the package goes away.
|
||||||
"""
|
"""
|
||||||
layout, _ = layout_and_dir
|
layout = temporary_store.layout
|
||||||
mock_db = spack.repo.RepoPath(spack.paths.mock_packages_path)
|
mock_db = spack.repo.RepoPath(spack.paths.mock_packages_path)
|
||||||
|
|
||||||
not_in_mock = set.difference(
|
not_in_mock = set.difference(
|
||||||
|
@ -209,9 +200,9 @@ def test_handle_unknown_package(layout_and_dir, config, mock_packages):
|
||||||
assert spec.dag_hash() == spec_from_file.dag_hash()
|
assert spec.dag_hash() == spec_from_file.dag_hash()
|
||||||
|
|
||||||
|
|
||||||
def test_find(layout_and_dir, config, mock_packages):
|
def test_find(temporary_store, config, mock_packages):
|
||||||
"""Test that finding specs within an install layout works."""
|
"""Test that finding specs within an install layout works."""
|
||||||
layout, _ = layout_and_dir
|
layout = temporary_store.layout
|
||||||
packages = list(spack.repo.path.all_packages())[:max_packages]
|
packages = list(spack.repo.path.all_packages())[:max_packages]
|
||||||
|
|
||||||
# Create install prefixes for all packages in the list
|
# Create install prefixes for all packages in the list
|
||||||
|
|
|
@ -183,70 +183,70 @@ def test_flatten_deps(
|
||||||
assert os.path.isdir(dependency_dir)
|
assert os.path.isdir(dependency_dir)
|
||||||
|
|
||||||
|
|
||||||
def test_installed_upstream_external(
|
@pytest.fixture()
|
||||||
tmpdir_factory, install_mockery, mock_fetch, gen_mock_layout,
|
def install_upstream(tmpdir_factory, gen_mock_layout, install_mockery):
|
||||||
monkeypatch):
|
"""Provides a function that installs a specified set of specs to an
|
||||||
"""Check that when a dependency package is recorded as installed in
|
upstream database. The function returns a store which points to the
|
||||||
an upstream database that it is not reinstalled.
|
upstream, as well as the upstream layout (for verifying that dependent
|
||||||
|
installs are using the upstream installs).
|
||||||
"""
|
"""
|
||||||
mock_db_root = str(tmpdir_factory.mktemp('mock_db_root'))
|
mock_db_root = str(tmpdir_factory.mktemp('mock_db_root'))
|
||||||
prepared_db = spack.database.Database(mock_db_root)
|
prepared_db = spack.database.Database(mock_db_root)
|
||||||
|
|
||||||
upstream_layout = gen_mock_layout('/a/')
|
upstream_layout = gen_mock_layout('/a/')
|
||||||
|
|
||||||
dependency = spack.spec.Spec('externaltool')
|
def _install_upstream(*specs):
|
||||||
dependency.concretize()
|
for spec_str in specs:
|
||||||
prepared_db.add(dependency, upstream_layout)
|
s = spack.spec.Spec(spec_str).concretized()
|
||||||
|
prepared_db.add(s, upstream_layout)
|
||||||
|
|
||||||
downstream_db_root = str(
|
downstream_root = str(tmpdir_factory.mktemp('mock_downstream_db_root'))
|
||||||
tmpdir_factory.mktemp('mock_downstream_db_root'))
|
db_for_test = spack.database.Database(
|
||||||
db_for_test = spack.database.Database(
|
downstream_root, upstream_dbs=[prepared_db]
|
||||||
downstream_db_root, upstream_dbs=[prepared_db])
|
)
|
||||||
monkeypatch.setattr(spack.store, 'db', db_for_test)
|
store = spack.store.Store(downstream_root)
|
||||||
dependent = spack.spec.Spec('externaltest')
|
store.db = db_for_test
|
||||||
dependent.concretize()
|
return store, upstream_layout
|
||||||
|
|
||||||
new_dependency = dependent['externaltool']
|
return _install_upstream
|
||||||
assert new_dependency.external
|
|
||||||
assert new_dependency.prefix == '/path/to/external_tool'
|
|
||||||
|
|
||||||
dependent.package.do_install()
|
|
||||||
|
|
||||||
assert not os.path.exists(new_dependency.prefix)
|
|
||||||
assert os.path.exists(dependent.prefix)
|
|
||||||
|
|
||||||
|
|
||||||
def test_installed_upstream(tmpdir_factory, install_mockery, mock_fetch,
|
def test_installed_upstream_external(install_upstream, mock_fetch):
|
||||||
gen_mock_layout, monkeypatch):
|
|
||||||
"""Check that when a dependency package is recorded as installed in
|
"""Check that when a dependency package is recorded as installed in
|
||||||
an upstream database that it is not reinstalled.
|
an upstream database that it is not reinstalled.
|
||||||
"""
|
"""
|
||||||
mock_db_root = str(tmpdir_factory.mktemp('mock_db_root'))
|
s, _ = install_upstream('externaltool')
|
||||||
prepared_db = spack.database.Database(mock_db_root)
|
with spack.store.use_store(s):
|
||||||
|
dependent = spack.spec.Spec('externaltest')
|
||||||
|
dependent.concretize()
|
||||||
|
|
||||||
upstream_layout = gen_mock_layout('/a/')
|
new_dependency = dependent['externaltool']
|
||||||
|
assert new_dependency.external
|
||||||
|
assert new_dependency.prefix == '/path/to/external_tool'
|
||||||
|
|
||||||
dependency = spack.spec.Spec('dependency-install')
|
dependent.package.do_install()
|
||||||
dependency.concretize()
|
|
||||||
prepared_db.add(dependency, upstream_layout)
|
|
||||||
|
|
||||||
downstream_db_root = str(
|
assert not os.path.exists(new_dependency.prefix)
|
||||||
tmpdir_factory.mktemp('mock_downstream_db_root'))
|
assert os.path.exists(dependent.prefix)
|
||||||
db_for_test = spack.database.Database(
|
|
||||||
downstream_db_root, upstream_dbs=[prepared_db])
|
|
||||||
monkeypatch.setattr(spack.store, 'db', db_for_test)
|
|
||||||
dependent = spack.spec.Spec('dependent-install')
|
|
||||||
dependent.concretize()
|
|
||||||
|
|
||||||
new_dependency = dependent['dependency-install']
|
|
||||||
assert new_dependency.package.installed_upstream
|
|
||||||
assert (new_dependency.prefix ==
|
|
||||||
upstream_layout.path_for_spec(dependency))
|
|
||||||
|
|
||||||
dependent.package.do_install()
|
def test_installed_upstream(install_upstream, mock_fetch):
|
||||||
|
"""Check that when a dependency package is recorded as installed in
|
||||||
|
an upstream database that it is not reinstalled.
|
||||||
|
"""
|
||||||
|
s, upstream_layout = install_upstream('dependency-install')
|
||||||
|
with spack.store.use_store(s):
|
||||||
|
dependency = spack.spec.Spec('dependency-install').concretized()
|
||||||
|
dependent = spack.spec.Spec('dependent-install').concretized()
|
||||||
|
|
||||||
assert not os.path.exists(new_dependency.prefix)
|
new_dependency = dependent['dependency-install']
|
||||||
assert os.path.exists(dependent.prefix)
|
assert new_dependency.package.installed_upstream
|
||||||
|
assert (new_dependency.prefix ==
|
||||||
|
upstream_layout.path_for_spec(dependency))
|
||||||
|
|
||||||
|
dependent.package.do_install()
|
||||||
|
|
||||||
|
assert not os.path.exists(new_dependency.prefix)
|
||||||
|
assert os.path.exists(dependent.prefix)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.disable_clean_stage_check
|
@pytest.mark.disable_clean_stage_check
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
|
||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
import spack.paths
|
||||||
|
import spack.store
|
||||||
|
|
||||||
|
|
||||||
class OldSbang(Package):
|
class OldSbang(Package):
|
||||||
"""Toy package for testing the old sbang replacement problem"""
|
"""Toy package for testing the old sbang replacement problem"""
|
||||||
|
@ -22,12 +23,12 @@ def install(self, spec, prefix):
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
{1}
|
{1}
|
||||||
'''.format(spack.paths.prefix, prefix.bin)
|
'''.format(spack.paths.prefix, prefix.bin)
|
||||||
sbang_style_2 = '''#!/bin/sh {0}/bin/sbang
|
sbang_style_2 = '''#!/bin/sh {0}/bin/sbang
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
{1}
|
{1}
|
||||||
'''.format(spack.store.unpadded_root, prefix.bin)
|
'''.format(spack.store.unpadded_root, prefix.bin)
|
||||||
with open('%s/sbang-style-1.sh' % self.prefix.bin, 'w') as f:
|
with open('%s/sbang-style-1.sh' % self.prefix.bin, 'w') as f:
|
||||||
f.write(sbang_style_1)
|
f.write(sbang_style_1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue