testing: increase installer coverage (#15237)

This commit is contained in:
Tamara Dahlgren 2020-03-12 13:20:20 -07:00 committed by GitHub
parent b8064df495
commit f2a13af43e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 280 additions and 109 deletions

View file

@ -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):
"""

View file

@ -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)

View file

@ -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