testing: increase installer coverage (#15237)
This commit is contained in:
parent
b8064df495
commit
f2a13af43e
3 changed files with 280 additions and 109 deletions
|
@ -36,6 +36,7 @@
|
|||
import sys
|
||||
import time
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.lock as lk
|
||||
import llnl.util.tty as tty
|
||||
import spack.binary_distribution as binary_distribution
|
||||
|
@ -43,14 +44,12 @@
|
|||
import spack.error
|
||||
import spack.hooks
|
||||
import spack.package
|
||||
import spack.package_prefs as prefs
|
||||
import spack.repo
|
||||
import spack.store
|
||||
|
||||
from llnl.util.filesystem import \
|
||||
chgrp, install, install_tree, mkdirp, touch, working_dir
|
||||
from llnl.util.tty.color import colorize, cwrite
|
||||
from llnl.util.tty.log import log_output
|
||||
from spack.package_prefs import get_package_dir_permissions, get_package_group
|
||||
from spack.util.environment import dump_environment
|
||||
from spack.util.executable import which
|
||||
|
||||
|
@ -133,21 +132,21 @@ def _do_fake_install(pkg):
|
|||
chmod = which('chmod')
|
||||
|
||||
# Install fake command
|
||||
mkdirp(pkg.prefix.bin)
|
||||
touch(os.path.join(pkg.prefix.bin, command))
|
||||
fs.mkdirp(pkg.prefix.bin)
|
||||
fs.touch(os.path.join(pkg.prefix.bin, command))
|
||||
chmod('+x', os.path.join(pkg.prefix.bin, command))
|
||||
|
||||
# Install fake header file
|
||||
mkdirp(pkg.prefix.include)
|
||||
touch(os.path.join(pkg.prefix.include, header + '.h'))
|
||||
fs.mkdirp(pkg.prefix.include)
|
||||
fs.touch(os.path.join(pkg.prefix.include, header + '.h'))
|
||||
|
||||
# Install fake shared and static libraries
|
||||
mkdirp(pkg.prefix.lib)
|
||||
fs.mkdirp(pkg.prefix.lib)
|
||||
for suffix in [dso_suffix, '.a']:
|
||||
touch(os.path.join(pkg.prefix.lib, library + suffix))
|
||||
fs.touch(os.path.join(pkg.prefix.lib, library + suffix))
|
||||
|
||||
# Install fake man page
|
||||
mkdirp(pkg.prefix.man.man1)
|
||||
fs.mkdirp(pkg.prefix.man.man1)
|
||||
|
||||
packages_dir = spack.store.layout.build_packages_path(pkg.spec)
|
||||
dump_packages(pkg.spec, packages_dir)
|
||||
|
@ -380,14 +379,14 @@ def dump_packages(spec, path):
|
|||
Dump all package information for a spec and its dependencies.
|
||||
|
||||
This creates a package repository within path for every namespace in the
|
||||
spec DAG, and fills the repos wtih package files and patch files for every
|
||||
spec DAG, and fills the repos with package files and patch files for every
|
||||
node in the DAG.
|
||||
|
||||
Args:
|
||||
spec (Spec): the Spack spec whose package information is to be dumped
|
||||
path (str): the path to the build packages directory
|
||||
"""
|
||||
mkdirp(path)
|
||||
fs.mkdirp(path)
|
||||
|
||||
# Copy in package.py files from any dependencies.
|
||||
# Note that we copy them in as they are in the *install* directory
|
||||
|
@ -428,7 +427,7 @@ def dump_packages(spec, path):
|
|||
if node is spec:
|
||||
spack.repo.path.dump_provenance(node, dest_pkg_dir)
|
||||
elif source_pkg_dir:
|
||||
install_tree(source_pkg_dir, dest_pkg_dir)
|
||||
fs.install_tree(source_pkg_dir, dest_pkg_dir)
|
||||
|
||||
|
||||
def install_msg(name, pid):
|
||||
|
@ -464,17 +463,17 @@ def log(pkg):
|
|||
tty.debug(e)
|
||||
|
||||
# Archive the whole stdout + stderr for the package
|
||||
install(pkg.log_path, pkg.install_log_path)
|
||||
fs.install(pkg.log_path, pkg.install_log_path)
|
||||
|
||||
# Archive the environment used for the build
|
||||
install(pkg.env_path, pkg.install_env_path)
|
||||
fs.install(pkg.env_path, pkg.install_env_path)
|
||||
|
||||
if os.path.exists(pkg.configure_args_path):
|
||||
# Archive the args used for the build
|
||||
install(pkg.configure_args_path, pkg.install_configure_args_path)
|
||||
fs.install(pkg.configure_args_path, pkg.install_configure_args_path)
|
||||
|
||||
# Finally, archive files that are specific to each package
|
||||
with working_dir(pkg.stage.path):
|
||||
with fs.working_dir(pkg.stage.path):
|
||||
errors = six.StringIO()
|
||||
target_dir = os.path.join(
|
||||
spack.store.layout.metadata_path(pkg.spec), 'archived-files')
|
||||
|
@ -496,8 +495,8 @@ def log(pkg):
|
|||
target = os.path.join(target_dir, f)
|
||||
# We must ensure that the directory exists before
|
||||
# copying a file in
|
||||
mkdirp(os.path.dirname(target))
|
||||
install(f, target)
|
||||
fs.mkdirp(os.path.dirname(target))
|
||||
fs.install(f, target)
|
||||
except Exception as e:
|
||||
tty.debug(e)
|
||||
|
||||
|
@ -508,7 +507,7 @@ def log(pkg):
|
|||
|
||||
if errors.getvalue():
|
||||
error_file = os.path.join(target_dir, 'errors.txt')
|
||||
mkdirp(target_dir)
|
||||
fs.mkdirp(target_dir)
|
||||
with open(error_file, 'w') as err:
|
||||
err.write(errors.getvalue())
|
||||
tty.warn('Errors occurred when archiving files.\n\t'
|
||||
|
@ -1074,10 +1073,10 @@ def build_process():
|
|||
pkg.name, 'src')
|
||||
tty.msg('{0} Copying source to {1}'
|
||||
.format(pre, src_target))
|
||||
install_tree(pkg.stage.source_path, src_target)
|
||||
fs.install_tree(pkg.stage.source_path, src_target)
|
||||
|
||||
# Do the real install in the source directory.
|
||||
with working_dir(pkg.stage.source_path):
|
||||
with fs.working_dir(pkg.stage.source_path):
|
||||
# Save the build environment in a file before building.
|
||||
dump_environment(pkg.env_path)
|
||||
|
||||
|
@ -1289,20 +1288,20 @@ def _setup_install_dir(self, pkg):
|
|||
spack.store.layout.create_install_directory(pkg.spec)
|
||||
else:
|
||||
# Set the proper group for the prefix
|
||||
group = get_package_group(pkg.spec)
|
||||
group = prefs.get_package_group(pkg.spec)
|
||||
if group:
|
||||
chgrp(pkg.spec.prefix, group)
|
||||
fs.chgrp(pkg.spec.prefix, group)
|
||||
|
||||
# Set the proper permissions.
|
||||
# This has to be done after group because changing groups blows
|
||||
# away the sticky group bit on the directory
|
||||
mode = os.stat(pkg.spec.prefix).st_mode
|
||||
perms = get_package_dir_permissions(pkg.spec)
|
||||
perms = prefs.get_package_dir_permissions(pkg.spec)
|
||||
if mode != perms:
|
||||
os.chmod(pkg.spec.prefix, perms)
|
||||
|
||||
# Ensure the metadata path exists as well
|
||||
mkdirp(spack.store.layout.metadata_path(pkg.spec), mode=perms)
|
||||
fs.mkdirp(spack.store.layout.metadata_path(pkg.spec), mode=perms)
|
||||
|
||||
def _update_failed(self, task, mark=False, exc=None):
|
||||
"""
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import pytest
|
||||
import shutil
|
||||
|
||||
from llnl.util.filesystem import mkdirp, touch, working_dir
|
||||
import llnl.util.filesystem as fs
|
||||
|
||||
from spack.package import InstallError, PackageBase, PackageStillNeededError
|
||||
import spack.error
|
||||
|
@ -380,11 +380,11 @@ def test_pkg_build_paths(install_mockery):
|
|||
|
||||
# Backward compatibility checks
|
||||
log_dir = os.path.dirname(log_path)
|
||||
mkdirp(log_dir)
|
||||
with working_dir(log_dir):
|
||||
fs.mkdirp(log_dir)
|
||||
with fs.working_dir(log_dir):
|
||||
# Start with the older of the previous log filenames
|
||||
older_log = 'spack-build.out'
|
||||
touch(older_log)
|
||||
fs.touch(older_log)
|
||||
assert spec.package.log_path.endswith(older_log)
|
||||
|
||||
# Now check the newer log filename
|
||||
|
@ -416,11 +416,11 @@ def test_pkg_install_paths(install_mockery):
|
|||
|
||||
# Backward compatibility checks
|
||||
log_dir = os.path.dirname(log_path)
|
||||
mkdirp(log_dir)
|
||||
with working_dir(log_dir):
|
||||
fs.mkdirp(log_dir)
|
||||
with fs.working_dir(log_dir):
|
||||
# Start with the older of the previous install log filenames
|
||||
older_log = 'build.out'
|
||||
touch(older_log)
|
||||
fs.touch(older_log)
|
||||
assert spec.package.install_log_path.endswith(older_log)
|
||||
|
||||
# Now check the newer install log filename
|
||||
|
@ -437,7 +437,8 @@ def test_pkg_install_paths(install_mockery):
|
|||
shutil.rmtree(log_dir)
|
||||
|
||||
|
||||
def test_pkg_install_log(install_mockery):
|
||||
def test_log_install_without_build_files(install_mockery):
|
||||
"""Test the installer log function when no build files are present."""
|
||||
# Get a basic concrete spec for the trivial install package.
|
||||
spec = Spec('trivial-install-test-package').concretized()
|
||||
|
||||
|
@ -445,17 +446,40 @@ def test_pkg_install_log(install_mockery):
|
|||
with pytest.raises(IOError, match="No such file or directory"):
|
||||
spack.installer.log(spec.package)
|
||||
|
||||
# Set up mock build files and try again
|
||||
|
||||
def test_log_install_with_build_files(install_mockery, monkeypatch):
|
||||
"""Test the installer's log function when have build files."""
|
||||
config_log = 'config.log'
|
||||
|
||||
# Retain the original function for use in the monkey patch that is used
|
||||
# to raise an exception under the desired condition for test coverage.
|
||||
orig_install_fn = fs.install
|
||||
|
||||
def _install(src, dest):
|
||||
orig_install_fn(src, dest)
|
||||
if src.endswith(config_log):
|
||||
raise Exception('Mock log install error')
|
||||
|
||||
monkeypatch.setattr(fs, 'install', _install)
|
||||
|
||||
spec = Spec('trivial-install-test-package').concretized()
|
||||
|
||||
# Set up mock build files and try again to include archive failure
|
||||
log_path = spec.package.log_path
|
||||
log_dir = os.path.dirname(log_path)
|
||||
mkdirp(log_dir)
|
||||
with working_dir(log_dir):
|
||||
touch(log_path)
|
||||
touch(spec.package.env_path)
|
||||
touch(spec.package.configure_args_path)
|
||||
fs.mkdirp(log_dir)
|
||||
with fs.working_dir(log_dir):
|
||||
fs.touch(log_path)
|
||||
fs.touch(spec.package.env_path)
|
||||
fs.touch(spec.package.configure_args_path)
|
||||
|
||||
install_path = os.path.dirname(spec.package.install_log_path)
|
||||
mkdirp(install_path)
|
||||
fs.mkdirp(install_path)
|
||||
|
||||
source = spec.package.stage.source_path
|
||||
config = os.path.join(source, 'config.log')
|
||||
fs.touchp(config)
|
||||
spec.package.archive_files = ['missing', '..', config]
|
||||
|
||||
spack.installer.log(spec.package)
|
||||
|
||||
|
@ -463,6 +487,21 @@ def test_pkg_install_log(install_mockery):
|
|||
assert os.path.exists(spec.package.install_env_path)
|
||||
assert os.path.exists(spec.package.install_configure_args_path)
|
||||
|
||||
archive_dir = os.path.join(install_path, 'archived-files')
|
||||
source_dir = os.path.dirname(source)
|
||||
rel_config = os.path.relpath(config, source_dir)
|
||||
|
||||
assert os.path.exists(os.path.join(archive_dir, rel_config))
|
||||
assert not os.path.exists(os.path.join(archive_dir, 'missing'))
|
||||
|
||||
expected_errs = [
|
||||
'OUTSIDE SOURCE PATH', # for '..'
|
||||
'FAILED TO ARCHIVE' # for rel_config
|
||||
]
|
||||
with open(os.path.join(archive_dir, 'errors.txt'), 'r') as fd:
|
||||
for ln, expected in zip(fd, expected_errs):
|
||||
assert expected in ln
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(log_dir)
|
||||
|
||||
|
|
|
@ -7,15 +7,19 @@
|
|||
import py
|
||||
import pytest
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.tty as tty
|
||||
import llnl.util.lock as ulk
|
||||
|
||||
import spack.binary_distribution
|
||||
import spack.compilers
|
||||
import spack.directory_layout as dl
|
||||
import spack.installer as inst
|
||||
import spack.util.lock as lk
|
||||
import spack.package_prefs as prefs
|
||||
import spack.repo
|
||||
import spack.spec
|
||||
import spack.store
|
||||
import spack.util.lock as lk
|
||||
|
||||
|
||||
def _mock_repo(root, namespace):
|
||||
|
@ -152,7 +156,7 @@ def test_process_external_package_module(install_mockery, monkeypatch, capfd):
|
|||
|
||||
def test_process_binary_cache_tarball_none(install_mockery, monkeypatch,
|
||||
capfd):
|
||||
"""Tests to cover _process_binary_cache_tarball when no tarball."""
|
||||
"""Tests of _process_binary_cache_tarball when no tarball."""
|
||||
monkeypatch.setattr(spack.binary_distribution, 'download_tarball', _none)
|
||||
|
||||
pkg = spack.repo.get('trivial-install-test-package')
|
||||
|
@ -162,7 +166,7 @@ def test_process_binary_cache_tarball_none(install_mockery, monkeypatch,
|
|||
|
||||
|
||||
def test_process_binary_cache_tarball_tar(install_mockery, monkeypatch, capfd):
|
||||
"""Tests to cover _process_binary_cache_tarball with a tar file."""
|
||||
"""Tests of _process_binary_cache_tarball with a tar file."""
|
||||
def _spec(spec):
|
||||
return spec
|
||||
|
||||
|
@ -179,6 +183,25 @@ def _spec(spec):
|
|||
assert 'Installing a from binary cache' in capfd.readouterr()[0]
|
||||
|
||||
|
||||
def test_try_install_from_binary_cache(install_mockery, mock_packages,
|
||||
monkeypatch, capsys):
|
||||
"""Tests SystemExit path for_try_install_from_binary_cache."""
|
||||
def _spec(spec, force):
|
||||
spec = spack.spec.Spec('mpi').concretized()
|
||||
return {spec: None}
|
||||
|
||||
spec = spack.spec.Spec('mpich')
|
||||
spec.concretize()
|
||||
|
||||
monkeypatch.setattr(spack.binary_distribution, 'get_spec', _spec)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
inst._try_install_from_binary_cache(spec.package, False, False)
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert 'add a spack mirror to allow download' in str(captured)
|
||||
|
||||
|
||||
def test_installer_init_errors(install_mockery):
|
||||
"""Test to ensure cover installer constructor errors."""
|
||||
with pytest.raises(ValueError, match='must be a package'):
|
||||
|
@ -189,17 +212,18 @@ def test_installer_init_errors(install_mockery):
|
|||
inst.PackageInstaller(pkg)
|
||||
|
||||
|
||||
def test_installer_strings(install_mockery):
|
||||
"""Tests of installer repr and str for coverage purposes."""
|
||||
def test_installer_repr(install_mockery):
|
||||
spec, installer = create_installer('trivial-install-test-package')
|
||||
|
||||
# Cover __repr__
|
||||
irep = installer.__repr__()
|
||||
assert irep.startswith(installer.__class__.__name__)
|
||||
assert "installed=" in irep
|
||||
assert "failed=" in irep
|
||||
|
||||
# Cover __str__
|
||||
|
||||
def test_installer_str(install_mockery):
|
||||
spec, installer = create_installer('trivial-install-test-package')
|
||||
|
||||
istr = str(installer)
|
||||
assert "#tasks=0" in istr
|
||||
assert "installed (0)" in istr
|
||||
|
@ -207,7 +231,6 @@ def test_installer_strings(install_mockery):
|
|||
|
||||
|
||||
def test_installer_last_phase_error(install_mockery, capsys):
|
||||
"""Test to cover last phase error."""
|
||||
spec = spack.spec.Spec('trivial-install-test-package')
|
||||
spec.concretize()
|
||||
assert spec.concrete
|
||||
|
@ -220,7 +243,6 @@ def test_installer_last_phase_error(install_mockery, capsys):
|
|||
|
||||
|
||||
def test_installer_ensure_ready_errors(install_mockery):
|
||||
"""Test to cover _ensure_ready errors."""
|
||||
spec, installer = create_installer('trivial-install-test-package')
|
||||
|
||||
fmt = r'cannot be installed locally.*{0}'
|
||||
|
@ -247,24 +269,102 @@ def test_installer_ensure_ready_errors(install_mockery):
|
|||
installer._ensure_install_ready(spec.package)
|
||||
|
||||
|
||||
def test_ensure_locked_have(install_mockery, tmpdir):
|
||||
"""Test to cover _ensure_locked when already have lock."""
|
||||
def test_ensure_locked_err(install_mockery, monkeypatch, tmpdir, capsys):
|
||||
"""Test _ensure_locked when a non-lock exception is raised."""
|
||||
mock_err_msg = 'Mock exception error'
|
||||
|
||||
def _raise(lock, timeout):
|
||||
raise RuntimeError(mock_err_msg)
|
||||
|
||||
spec, installer = create_installer('trivial-install-test-package')
|
||||
|
||||
monkeypatch.setattr(ulk.Lock, 'acquire_read', _raise)
|
||||
with tmpdir.as_cwd():
|
||||
with pytest.raises(RuntimeError):
|
||||
installer._ensure_locked('read', spec.package)
|
||||
|
||||
out = str(capsys.readouterr()[1])
|
||||
assert 'Failed to acquire a read lock' in out
|
||||
assert mock_err_msg in out
|
||||
|
||||
|
||||
def test_ensure_locked_have(install_mockery, tmpdir, capsys):
|
||||
"""Test _ensure_locked when already have lock."""
|
||||
spec, installer = create_installer('trivial-install-test-package')
|
||||
|
||||
with tmpdir.as_cwd():
|
||||
# Test "downgrade" of a read lock (to a read lock)
|
||||
lock = lk.Lock('./test', default_timeout=1e-9, desc='test')
|
||||
lock_type = 'read'
|
||||
tpl = (lock_type, lock)
|
||||
installer.locks[installer.pkg_id] = tpl
|
||||
assert installer._ensure_locked(lock_type, spec.package) == tpl
|
||||
|
||||
# Test "upgrade" of a read lock without read count to a write
|
||||
lock_type = 'write'
|
||||
err = 'Cannot upgrade lock'
|
||||
with pytest.raises(ulk.LockUpgradeError, match=err):
|
||||
installer._ensure_locked(lock_type, spec.package)
|
||||
|
||||
def test_package_id(install_mockery):
|
||||
"""Test to cover package_id functionality."""
|
||||
out = str(capsys.readouterr()[1])
|
||||
assert 'Failed to upgrade to a write lock' in out
|
||||
assert 'exception when releasing read lock' in out
|
||||
|
||||
# Test "upgrade" of the read lock *with* read count to a write
|
||||
lock._reads = 1
|
||||
tpl = (lock_type, lock)
|
||||
assert installer._ensure_locked(lock_type, spec.package) == tpl
|
||||
|
||||
# Test "downgrade" of the write lock to a read lock
|
||||
lock_type = 'read'
|
||||
tpl = (lock_type, lock)
|
||||
assert installer._ensure_locked(lock_type, spec.package) == tpl
|
||||
|
||||
|
||||
@pytest.mark.parametrize('lock_type,reads,writes', [
|
||||
('read', 1, 0),
|
||||
('write', 0, 1)])
|
||||
def test_ensure_locked_new_lock(
|
||||
install_mockery, tmpdir, lock_type, reads, writes):
|
||||
pkg_id = 'a'
|
||||
spec, installer = create_installer(pkg_id)
|
||||
with tmpdir.as_cwd():
|
||||
ltype, lock = installer._ensure_locked(lock_type, spec.package)
|
||||
assert ltype == lock_type
|
||||
assert lock is not None
|
||||
assert lock._reads == reads
|
||||
assert lock._writes == writes
|
||||
|
||||
|
||||
def test_ensure_locked_new_warn(install_mockery, monkeypatch, tmpdir, capsys):
|
||||
orig_pl = spack.database.Database.prefix_lock
|
||||
|
||||
def _pl(db, spec, timeout):
|
||||
lock = orig_pl(db, spec, timeout)
|
||||
lock.default_timeout = 1e-9 if timeout is None else None
|
||||
return lock
|
||||
|
||||
pkg_id = 'a'
|
||||
spec, installer = create_installer(pkg_id)
|
||||
|
||||
monkeypatch.setattr(spack.database.Database, 'prefix_lock', _pl)
|
||||
|
||||
lock_type = 'read'
|
||||
ltype, lock = installer._ensure_locked(lock_type, spec.package)
|
||||
assert ltype == lock_type
|
||||
assert lock is not None
|
||||
|
||||
out = str(capsys.readouterr()[1])
|
||||
assert 'Expected prefix lock timeout' in out
|
||||
|
||||
|
||||
def test_package_id_err(install_mockery):
|
||||
pkg = spack.repo.get('trivial-install-test-package')
|
||||
with pytest.raises(ValueError, match='spec is not concretized'):
|
||||
inst.package_id(pkg)
|
||||
|
||||
|
||||
def test_package_id_ok(install_mockery):
|
||||
spec = spack.spec.Spec('trivial-install-test-package')
|
||||
spec.concretize()
|
||||
assert spec.concrete
|
||||
|
@ -273,36 +373,44 @@ def test_package_id(install_mockery):
|
|||
|
||||
|
||||
def test_fake_install(install_mockery):
|
||||
"""Test to cover fake install basics."""
|
||||
spec = spack.spec.Spec('trivial-install-test-package')
|
||||
spec.concretize()
|
||||
assert spec.concrete
|
||||
|
||||
pkg = spec.package
|
||||
inst._do_fake_install(pkg)
|
||||
assert os.path.isdir(pkg.prefix.lib)
|
||||
|
||||
|
||||
def test_packages_needed_to_bootstrap_compiler(install_mockery, monkeypatch):
|
||||
"""Test to cover most of _packages_needed_to_boostrap_compiler."""
|
||||
# TODO: More work is needed to go beyond the dependency check
|
||||
def _no_compilers(pkg, arch_spec):
|
||||
return []
|
||||
|
||||
# Test path where no compiler packages returned
|
||||
def test_packages_needed_to_bootstrap_compiler_none(install_mockery):
|
||||
spec = spack.spec.Spec('trivial-install-test-package')
|
||||
spec.concretize()
|
||||
assert spec.concrete
|
||||
|
||||
packages = inst._packages_needed_to_bootstrap_compiler(spec.package)
|
||||
assert not packages
|
||||
|
||||
# Test up to the dependency check
|
||||
monkeypatch.setattr(spack.compilers, 'compilers_for_spec', _no_compilers)
|
||||
with pytest.raises(spack.repo.UnknownPackageError, match='not found'):
|
||||
inst._packages_needed_to_bootstrap_compiler(spec.package)
|
||||
|
||||
def test_packages_needed_to_bootstrap_compiler_packages(install_mockery,
|
||||
monkeypatch):
|
||||
spec = spack.spec.Spec('trivial-install-test-package')
|
||||
spec.concretize()
|
||||
|
||||
def _conc_spec(compiler):
|
||||
return spack.spec.Spec('a').concretized()
|
||||
|
||||
# Ensure we can get past functions that are precluding obtaining
|
||||
# packages.
|
||||
monkeypatch.setattr(spack.compilers, 'compilers_for_spec', _none)
|
||||
monkeypatch.setattr(spack.compilers, 'pkg_spec_for_compiler', _conc_spec)
|
||||
monkeypatch.setattr(spack.spec.Spec, 'concretize', _noop)
|
||||
|
||||
packages = inst._packages_needed_to_bootstrap_compiler(spec.package)
|
||||
assert packages
|
||||
|
||||
|
||||
def test_dump_packages_deps_ok(install_mockery, tmpdir, mock_repo_path):
|
||||
"""Test to add coverage to dump_packages with dependencies happy path."""
|
||||
"""Test happy path for dump_packages with dependencies."""
|
||||
|
||||
spec_name = 'simple-inheritance'
|
||||
spec = spack.spec.Spec(spec_name).concretized()
|
||||
|
@ -314,7 +422,7 @@ def test_dump_packages_deps_ok(install_mockery, tmpdir, mock_repo_path):
|
|||
|
||||
|
||||
def test_dump_packages_deps_errs(install_mockery, tmpdir, monkeypatch, capsys):
|
||||
"""Test to add coverage to dump_packages with dependencies."""
|
||||
"""Test error paths for dump_packages with dependencies."""
|
||||
orig_bpp = spack.store.layout.build_packages_path
|
||||
orig_dirname = spack.repo.Repo.dirname_for_package_name
|
||||
repo_err_msg = "Mock dirname_for_package_name"
|
||||
|
@ -354,59 +462,45 @@ def _repoerr(repo, name):
|
|||
assert "Couldn't copy in provenance for cmake" in out
|
||||
|
||||
|
||||
@pytest.mark.tld
|
||||
def test_check_deps_status_errs(install_mockery, monkeypatch):
|
||||
"""Test to cover _check_deps_status failures."""
|
||||
def test_check_deps_status_install_failure(install_mockery, monkeypatch):
|
||||
spec, installer = create_installer('a')
|
||||
|
||||
# Make sure the package is identified as failed
|
||||
orig_fn = spack.database.Database.prefix_failed
|
||||
monkeypatch.setattr(spack.database.Database, 'prefix_failed', _true)
|
||||
|
||||
with pytest.raises(inst.InstallError, match='install failure'):
|
||||
installer._check_deps_status()
|
||||
|
||||
monkeypatch.setattr(spack.database.Database, 'prefix_failed', orig_fn)
|
||||
|
||||
# Ensure do not acquire the lock
|
||||
def test_check_deps_status_write_locked(install_mockery, monkeypatch):
|
||||
spec, installer = create_installer('a')
|
||||
|
||||
# Ensure the lock is not acquired
|
||||
monkeypatch.setattr(inst.PackageInstaller, '_ensure_locked', _not_locked)
|
||||
|
||||
with pytest.raises(inst.InstallError, match='write locked by another'):
|
||||
installer._check_deps_status()
|
||||
|
||||
|
||||
@pytest.mark.tld
|
||||
def test_check_deps_status_external(install_mockery, monkeypatch):
|
||||
"""Test to cover _check_deps_status for external."""
|
||||
spec, installer = create_installer('a')
|
||||
|
||||
deps = spec.dependencies()
|
||||
assert len(deps) > 0
|
||||
dep_id = 'b'
|
||||
|
||||
# Ensure the known dependent is installed if flagged as external
|
||||
# Mock the known dependent, b, as external so assumed to be installed
|
||||
monkeypatch.setattr(spack.spec.Spec, 'external', True)
|
||||
installer._check_deps_status()
|
||||
assert dep_id in installer.installed
|
||||
assert 'b' in installer.installed
|
||||
|
||||
|
||||
@pytest.mark.tld
|
||||
def test_check_deps_status_upstream(install_mockery, monkeypatch):
|
||||
"""Test to cover _check_deps_status for upstream."""
|
||||
spec, installer = create_installer('a')
|
||||
|
||||
deps = spec.dependencies()
|
||||
assert len(deps) > 0
|
||||
dep_id = 'b'
|
||||
|
||||
# Ensure the known dependent, b, is installed if flagged as upstream
|
||||
# Mock the known dependent, b, as installed upstream
|
||||
monkeypatch.setattr(spack.package.PackageBase, 'installed_upstream', True)
|
||||
installer._check_deps_status()
|
||||
assert dep_id in installer.installed
|
||||
assert 'b' in installer.installed
|
||||
|
||||
|
||||
def test_add_bootstrap_compilers(install_mockery, monkeypatch):
|
||||
"""Test to cover _add_bootstrap_compilers."""
|
||||
def _pkgs(pkg):
|
||||
spec = spack.spec.Spec('mpi').concretized()
|
||||
return [(spec.package, True)]
|
||||
|
@ -445,7 +539,6 @@ def test_installer_init_queue(install_mockery):
|
|||
|
||||
|
||||
def test_install_task_use_cache(install_mockery, monkeypatch):
|
||||
"""Test _install_task to cover use_cache path."""
|
||||
spec, installer = create_installer('trivial-install-test-package')
|
||||
task = create_build_task(spec.package)
|
||||
|
||||
|
@ -454,25 +547,27 @@ def test_install_task_use_cache(install_mockery, monkeypatch):
|
|||
assert spec.package.name in installer.installed
|
||||
|
||||
|
||||
def test_install_task_stop_iter(install_mockery, monkeypatch, capfd):
|
||||
"""Test _install_task to cover the StopIteration exception."""
|
||||
mock_err_msg = 'mock stop iteration'
|
||||
def test_install_task_add_compiler(install_mockery, monkeypatch, capfd):
|
||||
config_msg = 'mock add_compilers_to_config'
|
||||
|
||||
def _raise(installer, pkg):
|
||||
raise StopIteration(mock_err_msg)
|
||||
def _add(_compilers):
|
||||
tty.msg(config_msg)
|
||||
|
||||
spec, installer = create_installer('a')
|
||||
task = create_build_task(spec.package)
|
||||
task.compiler = True
|
||||
|
||||
# Preclude any meaningful side-effects
|
||||
monkeypatch.setattr(spack.package.PackageBase, 'unit_test_check', _true)
|
||||
monkeypatch.setattr(inst.PackageInstaller, '_setup_install_dir', _raise)
|
||||
monkeypatch.setattr(inst.PackageInstaller, '_setup_install_dir', _noop)
|
||||
monkeypatch.setattr(spack.build_environment, 'fork', _noop)
|
||||
monkeypatch.setattr(spack.database.Database, 'add', _noop)
|
||||
monkeypatch.setattr(spack.compilers, 'add_compilers_to_config', _add)
|
||||
|
||||
installer._install_task(task)
|
||||
out = capfd.readouterr()[0]
|
||||
|
||||
assert mock_err_msg in out
|
||||
assert 'Package stage directory' in out
|
||||
assert spec.package.stage.source_path in out
|
||||
out = capfd.readouterr()[0]
|
||||
assert config_msg in out
|
||||
|
||||
|
||||
def test_release_lock_write_n_exception(install_mockery, tmpdir, capsys):
|
||||
|
@ -529,8 +624,36 @@ def _rmtask(installer, pkg_id):
|
|||
assert len(installer.build_tasks) == 1
|
||||
|
||||
|
||||
def test_cleanup_failed(install_mockery, tmpdir, monkeypatch, capsys):
|
||||
"""Test to increase coverage of _cleanup_failed."""
|
||||
def test_setup_install_dir_grp(install_mockery, monkeypatch, capfd):
|
||||
"""Test _setup_install_dir's group change."""
|
||||
mock_group = 'mockgroup'
|
||||
mock_chgrp_msg = 'Changing group for {0} to {1}'
|
||||
|
||||
def _get_group(spec):
|
||||
return mock_group
|
||||
|
||||
def _chgrp(path, group):
|
||||
tty.msg(mock_chgrp_msg.format(path, group))
|
||||
|
||||
monkeypatch.setattr(prefs, 'get_package_group', _get_group)
|
||||
monkeypatch.setattr(fs, 'chgrp', _chgrp)
|
||||
|
||||
spec, installer = create_installer('trivial-install-test-package')
|
||||
|
||||
fs.touchp(spec.prefix)
|
||||
metadatadir = spack.store.layout.metadata_path(spec)
|
||||
# Should fail with a "not a directory" error
|
||||
with pytest.raises(OSError, match=metadatadir):
|
||||
installer._setup_install_dir(spec.package)
|
||||
|
||||
out = str(capfd.readouterr()[0])
|
||||
|
||||
expected_msg = mock_chgrp_msg.format(spec.prefix, mock_group)
|
||||
assert expected_msg in out
|
||||
|
||||
|
||||
def test_cleanup_failed_err(install_mockery, tmpdir, monkeypatch, capsys):
|
||||
"""Test _cleanup_failed exception path."""
|
||||
msg = 'Fake release_write exception'
|
||||
|
||||
def _raise_except(lock):
|
||||
|
@ -550,13 +673,14 @@ def _raise_except(lock):
|
|||
assert msg in out
|
||||
|
||||
|
||||
def test_update_failed_no_mark(install_mockery):
|
||||
"""Test of _update_failed sans mark and dependent build tasks."""
|
||||
def test_update_failed_no_dependent_task(install_mockery):
|
||||
"""Test _update_failed with missing dependent build tasks."""
|
||||
spec, installer = create_installer('dependent-install')
|
||||
task = create_build_task(spec.package)
|
||||
|
||||
installer._update_failed(task)
|
||||
assert installer.failed['dependent-install'] is None
|
||||
for dep in spec.traverse(root=False):
|
||||
task = create_build_task(dep.package)
|
||||
installer._update_failed(task, mark=False)
|
||||
assert installer.failed[task.pkg_id] is None
|
||||
|
||||
|
||||
def test_install_uninstalled_deps(install_mockery, monkeypatch, capsys):
|
||||
|
@ -710,3 +834,12 @@ def _install(installer, task, **kwargs):
|
|||
installer.install()
|
||||
|
||||
assert 'b' in installer.installed
|
||||
|
||||
|
||||
def test_install_skip_patch(install_mockery, mock_fetch):
|
||||
"""Test the path skip_patch install path."""
|
||||
spec, installer = create_installer('b')
|
||||
|
||||
installer.install(fake=False, skip_patch=True)
|
||||
|
||||
assert 'b' in installer.installed
|
||||
|
|
Loading…
Reference in a new issue