def test_merge_to_existing_directory(stage, link_tree): with working_dir(stage.path): touchp('dest/x') touchp('dest/a/b/y') link_tree.merge('dest') check_file_link('dest/1') check_file_link('dest/a/b/2') check_file_link('dest/a/b/3') check_file_link('dest/c/4') check_file_link('dest/c/d/5') check_file_link('dest/c/d/6') check_file_link('dest/c/d/e/7') assert os.path.isfile('dest/x') assert os.path.isfile('dest/a/b/y') link_tree.unmerge('dest') assert os.path.isfile('dest/x') assert os.path.isfile('dest/a/b/y') assert not os.path.isfile('dest/1') assert not os.path.isfile('dest/a/b/2') assert not os.path.isfile('dest/a/b/3') assert not os.path.isfile('dest/c/4') assert not os.path.isfile('dest/c/d/5') assert not os.path.isfile('dest/c/d/6') assert not os.path.isfile('dest/c/d/e/7')
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) fs.mkdirp(log_dir) with fs.working_dir(log_dir): fs.touch(log_path) fs.touch(spec.package.env_path) fs.touch(spec.package.env_mods_path) fs.touch(spec.package.configure_args_path) install_path = os.path.dirname(spec.package.install_log_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) assert os.path.exists(spec.package.install_log_path) 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)
def setup_install_test(source_paths, install_test_root): """ Set up the install test by creating sources and install test roots. The convention used here is to create an empty file if the path name ends with an extension otherwise, a directory is created. """ fs.mkdirp(install_test_root) for path in source_paths: if os.path.splitext(path)[1]: fs.touchp(path) else: fs.mkdirp(path)
def test_ignore(stage, link_tree): with working_dir(stage.path): touchp('source/.spec') touchp('dest/.spec') link_tree.merge('dest', ignore=lambda x: x == '.spec') link_tree.unmerge('dest', ignore=lambda x: x == '.spec') assert not os.path.exists('dest/1') assert not os.path.exists('dest/a') assert not os.path.exists('dest/c') assert os.path.isfile('source/.spec') assert os.path.isfile('dest/.spec')
def test_overwrite_install_backup_failure(temporary_store, config, mock_packages, tmpdir): """ When doing an overwrite install that fails, Spack should try to recover the original prefix. If that fails, the spec is lost, and it should be removed from the database. """ # Where to store the backups backup = str(tmpdir.mkdir("backup")) class InstallerThatAccidentallyDeletesTheBackupDir: def _install_task(self, task): # Remove the backup directory so that restoring goes terribly wrong shutil.rmtree(backup) raise Exception("Some fatal install error") class FakeDatabase: called = False def remove(self, spec): self.called = True # Get a build task. TODO: refactor this to avoid calling internal methods const_arg = installer_args(["b"]) installer = create_installer(const_arg) installer._init_queue() task = installer._pop_task() # Make sure the install prefix exists installed_file = os.path.join(task.pkg.prefix, 'some_file') fs.touchp(installed_file) fake_installer = InstallerThatAccidentallyDeletesTheBackupDir() fake_db = FakeDatabase() overwrite_install = inst.OverwriteInstall(fake_installer, fake_db, task, tmp_root=backup) # Installation should throw the installation exception, not the backup # failure. with pytest.raises(Exception, match='Some fatal install error'): overwrite_install.install() # Make sure that `remove` was called on the database after an unsuccessful # attempt to restore the backup. assert fake_db.called
def test_overwrite_install_backup_success(temporary_store, config, mock_packages, tmpdir): """ When doing an overwrite install that fails, Spack should restore the backup of the original prefix, and leave the original spec marked installed. """ # Where to store the backups backup = str(tmpdir.mkdir("backup")) # Get a build task. TODO: refactor this to avoid calling internal methods const_arg = installer_args(["b"]) installer = create_installer(const_arg) installer._init_queue() task = installer._pop_task() # Make sure the install prefix exists with some trivial file installed_file = os.path.join(task.pkg.prefix, 'some_file') fs.touchp(installed_file) class InstallerThatWipesThePrefixDir: def _install_task(self, task): shutil.rmtree(task.pkg.prefix, ignore_errors=True) fs.mkdirp(task.pkg.prefix) raise Exception("Some fatal install error") class FakeDatabase: called = False def remove(self, spec): self.called = True fake_installer = InstallerThatWipesThePrefixDir() fake_db = FakeDatabase() overwrite_install = inst.OverwriteInstall(fake_installer, fake_db, task, tmp_root=backup) # Installation should throw the installation exception, not the backup # failure. with pytest.raises(Exception, match='Some fatal install error'): overwrite_install.install() # Make sure the package is not marked uninstalled and the original dir # is back. assert not fake_db.called assert os.path.exists(installed_file)
def test_cache_init_entry_fails(file_cache): """Test init_entry failures.""" relpath = fs.join_path('test-dir', 'read-only-file.txt') cachefile = file_cache.cache_path(relpath) fs.touchp(cachefile) # Ensure directory causes exception with pytest.raises(CacheError, match='not a file'): file_cache.init_entry(os.path.dirname(relpath)) # Ensure non-readable file causes exception os.chmod(cachefile, 0o200) with pytest.raises(CacheError, match='Cannot access cache file'): file_cache.init_entry(relpath) # Ensure read-only parent causes exception relpath = fs.join_path('test-dir', 'another-file.txxt') cachefile = file_cache.cache_path(relpath) os.chmod(os.path.dirname(cachefile), 0o400) with pytest.raises(CacheError, match='Cannot access cache dir'): file_cache.init_entry(relpath)
def stage(): """Creates a stage with the directory structure for the tests.""" s = Stage('link-tree-test') s.create() with working_dir(s.path): touchp('source/1') touchp('source/a/b/2') touchp('source/a/b/3') touchp('source/c/4') touchp('source/c/d/5') touchp('source/c/d/6') touchp('source/c/d/e/7') yield s s.destroy()
def stage(tmpdir_factory): """Creates a stage with the directory structure for the tests.""" s = tmpdir_factory.mktemp('filesystem_test') with s.as_cwd(): # Create source file hierarchy fs.touchp('source/1') fs.touchp('source/a/b/2') fs.touchp('source/a/b/3') fs.touchp('source/c/4') fs.touchp('source/c/d/5') fs.touchp('source/c/d/6') fs.touchp('source/c/d/e/7') fs.touchp('source/g/h/i/8') fs.touchp('source/g/h/i/9') fs.touchp('source/g/i/j/10') # Create symlinks symlink(os.path.abspath('source/1'), 'source/2') symlink('b/2', 'source/a/b2') symlink('a/b', 'source/f') # Create destination directory fs.mkdirp('dest') yield s
def stage(tmpdir_factory): """Creates a stage with the directory structure for the tests.""" s = tmpdir_factory.mktemp('filesystem_test') with s.as_cwd(): # Create source file hierarchy fs.touchp('source/1') fs.touchp('source/a/b/2') fs.touchp('source/a/b/3') fs.touchp('source/c/4') fs.touchp('source/c/d/5') fs.touchp('source/c/d/6') fs.touchp('source/c/d/e/7') # Create symlinks os.symlink(os.path.abspath('source/1'), 'source/2') os.symlink('b/2', 'source/a/b2') os.symlink('a/b', 'source/f') # Create destination directory fs.mkdirp('dest') yield s