def test_cache_doesnt_grow_unboundedly(request, dir_server): os.environ['RPMDEPLINT_EXPIRY_SECONDS'] = '1' p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) firstrepo = rpmfluff.YumRepoBuild((p1, )) firstrepo.make('i386') dir_server.basepath = firstrepo.repoDir def cleanup(): shutil.rmtree(firstrepo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanup) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0 first_primary_cache_path = expected_cache_path(firstrepo.repoDir, 'primary.xml.gz') first_filelists_cache_path = expected_cache_path(firstrepo.repoDir, 'filelists.xml.gz') assert os.path.exists(first_primary_cache_path) assert os.path.exists(first_filelists_cache_path) p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) secondrepo = rpmfluff.YumRepoBuild((p2, )) secondrepo.make('i386') dir_server.basepath = secondrepo.repoDir def cleanup2(): shutil.rmtree(secondrepo.repoDir) shutil.rmtree(p2.get_base_dir()) request.addfinalizer(cleanup2) # ensure time period of cache has expired time.sleep(2) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p2.get_built_rpm('i386') ]) assert exitcode == 0 second_primary_cache_path = expected_cache_path(secondrepo.repoDir, 'primary.xml.gz') second_filelists_cache_path = expected_cache_path(secondrepo.repoDir, 'filelists.xml.gz') # Ensure the cache only has files from the second one assert not os.path.exists(first_primary_cache_path) assert not os.path.exists(first_filelists_cache_path) assert os.path.exists(second_primary_cache_path) assert os.path.exists(second_filelists_cache_path)
def test_cache_doesnt_grow_unboundedly(request, dir_server): os.environ['RPMDEPLINT_EXPIRY_SECONDS'] = '1' p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) firstrepo = rpmfluff.YumRepoBuild((p1, )) firstrepo.make('i386') dir_server.basepath = firstrepo.repoDir def cleanup(): shutil.rmtree(firstrepo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanup) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 0 first_primary_cache_path = expected_cache_path(firstrepo.repoDir, 'primary.xml.gz') first_filelists_cache_path = expected_cache_path(firstrepo.repoDir, 'filelists.xml.gz') assert os.path.exists(first_primary_cache_path) assert os.path.exists(first_filelists_cache_path) p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) secondrepo = rpmfluff.YumRepoBuild((p2, )) secondrepo.make('i386') dir_server.basepath = secondrepo.repoDir def cleanup2(): shutil.rmtree(secondrepo.repoDir) shutil.rmtree(p2.get_base_dir()) request.addfinalizer(cleanup2) # ensure time period of cache has expired time.sleep(2) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p2.get_built_rpm('i386')]) assert exitcode == 0 second_primary_cache_path = expected_cache_path(secondrepo.repoDir, 'primary.xml.gz') second_filelists_cache_path = expected_cache_path(secondrepo.repoDir, 'filelists.xml.gz') # Ensure the cache only has files from the second one assert not os.path.exists(first_primary_cache_path) assert not os.path.exists(first_filelists_cache_path) assert os.path.exists(second_primary_cache_path) assert os.path.exists(second_filelists_cache_path)
def test_catches_soname_change_with_package_rename(request, dir_server): # Slightly more complicated version of the above, where the old provider is # not being updated but rather obsoleted. p_older = rpmfluff.SimpleRpmBuild('foolib', '4.0', '1', ['i386']) p_older.add_provides('libfoo.so.4') p_depending = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p_depending.add_requires('libfoo.so.4') baserepo = rpmfluff.YumRepoBuild([p_older, p_depending]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p_newer = rpmfluff.SimpleRpmBuild('libfoo', '5.0', '1', ['i386']) p_newer.add_obsoletes('foolib < 5.0-1') p_newer.add_provides('libfoo.so.5') p_newer.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p_depending.get_base_dir()) shutil.rmtree(p_older.get_base_dir()) shutil.rmtree(p_newer.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--repo=base,{}'.format(dir_server.url), p_newer.get_built_rpm('i386')]) assert exitcode == 3 assert err == ('Dependency problems with repos:\n' 'package b-0.1-1.i386 requires libfoo.so.4, but none of the providers can be installed\n')
def test_works_on_different_platform_to_current(request, dir_server): grep = rpmfluff.SimpleRpmBuild('grep', '2.20', '3.el6', ['ppc64']) needs_grep = rpmfluff.SimpleRpmBuild('search-tool-5000', '1.0', '3.el6', ['ppc64']) needs_grep.add_requires('grep = 2.20-3.el6') baserepo = rpmfluff.YumRepoBuild((grep, needs_grep)) baserepo.make('ppc64') dir_server.basepath = baserepo.repoDir package_to_test = rpmfluff.SimpleRpmBuild('test-tool', '10', '3.el6', ['ppc64']) package_to_test.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(grep.get_base_dir()) shutil.rmtree(needs_grep.get_base_dir()) shutil.rmtree(package_to_test.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--repo=base,{}'.format(dir_server.url), package_to_test.get_built_rpm('ppc64')]) assert exitcode == 0 assert out == '' assert err == ''
def test_warns_on_preexisting_repoclosure_problems(request, dir_server): # If the repos have some existing dependency problems, we don't want that # to be an error -- otherwise a bad repo will make it impossible to get any # results until the problem is fixed. p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p2.add_requires('doesnotexist') baserepo = rpmfluff.YumRepoBuild((p2,)) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 0 assert ('Ignoring pre-existing repoclosure problem: ' 'nothing provides doesnotexist needed by b-0.1-1.i386\n' in err)
def test_ignores_problems_in_obsoleted_packages(request, dir_server): # As above, we also don't care about any dependency problems in packages # that have been obsoleted. p_older = rpmfluff.SimpleRpmBuild('a', '4.0', '1', ['i386']) p_older.add_provides('libfoo.so.4') p_older.add_provides('libfoo.so.5') p_obsolete_depending = rpmfluff.SimpleRpmBuild('foofouruser', '1.0', '1', ['i386']) p_obsolete_depending.add_requires('libfoo.so.4') p_newer_depending = rpmfluff.SimpleRpmBuild('foofiveuser', '0.1', '1', ['i386']) p_newer_depending.add_requires('libfoo.so.5') p_newer_depending.add_obsoletes('foofouruser <= 1.0-1') baserepo = rpmfluff.YumRepoBuild([p_older, p_obsolete_depending, p_newer_depending]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p_newer = rpmfluff.SimpleRpmBuild('a', '5.0', '1', ['i386']) p_newer.add_provides('libfoo.so.5') p_newer.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p_obsolete_depending.get_base_dir()) shutil.rmtree(p_newer_depending.get_base_dir()) shutil.rmtree(p_older.get_base_dir()) shutil.rmtree(p_newer.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--repo=base,{}'.format(dir_server.url), p_newer.get_built_rpm('i386')]) assert exitcode == 0
def test_catches_soname_change(request, dir_server): # This is the classic mistake repoclosure is supposed to find... the # updated package has changed its soname, causing some other package's # dependencies to become unresolvable. p_older = rpmfluff.SimpleRpmBuild('a', '4.0', '1', ['i386']) p_older.add_provides('libfoo.so.4') p_depending = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p_depending.add_requires('libfoo.so.4') baserepo = rpmfluff.YumRepoBuild([p_older, p_depending]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p_newer = rpmfluff.SimpleRpmBuild('a', '5.0', '1', ['i386']) p_newer.add_provides('libfoo.so.5') p_newer.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p_depending.get_base_dir()) shutil.rmtree(p_older.get_base_dir()) shutil.rmtree(p_newer.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--repo=base,{}'.format(dir_server.url), p_newer.get_built_rpm('i386')]) assert exitcode == 3 assert err == ('Dependency problems with repos:\n' 'package b-0.1-1.i386 requires libfoo.so.4, but none of the providers can be installed\n')
def test_ignores_problems_in_older_packages(request, dir_server): # We only care if the *latest* version of each package in the repos is # satisfied. If there are dependency problems with an older version, it is # irrelevant because nobody will be installing it anyway. p_older = rpmfluff.SimpleRpmBuild('a', '4.0', '1', ['i386']) p_older.add_provides('libfoo.so.4') p_older.add_provides('libfoo.so.5') p_older_depending = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p_older_depending.add_requires('libfoo.so.4') p_newer_depending = rpmfluff.SimpleRpmBuild('b', '0.2', '1', ['i386']) p_newer_depending.add_requires('libfoo.so.5') baserepo = rpmfluff.YumRepoBuild([p_older, p_older_depending, p_newer_depending]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p_newer = rpmfluff.SimpleRpmBuild('a', '5.0', '1', ['i386']) p_newer.add_provides('libfoo.so.5') p_newer.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p_older_depending.get_base_dir()) shutil.rmtree(p_newer_depending.get_base_dir()) shutil.rmtree(p_older.get_base_dir()) shutil.rmtree(p_newer.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--repo=base,{}'.format(dir_server.url), p_newer.get_built_rpm('i386')]) assert exitcode == 0
def test_ignores_dependency_problems_in_packages_under_test( request, dir_server): # The check-sat command will find and report these problems, it would be # redundant for check-repoclosure to also report the same problems. p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild((p2, )) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_requires('doesnotexist') p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-repoclosure', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0 assert err == ''
def test_finds_undeclared_file_conflict(request, dir_server): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n')) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'different content\n')) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 3 assert err == ('Undeclared file conflicts:\n' 'a-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n')
def test_package_does_not_conflict_with_earlier_version_of_itself( request, dir_server): p2 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n')) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '2', ['i386']) p1.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'different content\n')) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0
def test_migrates_old_cache_layout(request, dir_server): p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) repo = rpmfluff.YumRepoBuild([p1]) repo.make('i386') dir_server.basepath = repo.repoDir def cleanUp(): shutil.rmtree(repo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) old_cache_path = expected_cache_path(repo.repoDir, 'primary.xml.gz', old=True) new_cache_path = expected_cache_path(repo.repoDir, 'primary.xml.gz') # Simulate the old cache path left over from an older version of rpmdeplint os.makedirs(os.path.dirname(old_cache_path)) with open(old_cache_path, 'w') as f: f.write('lol\n') exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 0 assert err == '' assert not os.path.exists(old_cache_path) assert os.path.isfile(new_cache_path)
def test_lists_dependencies_for_rpms(request, dir_server): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild((p2, )) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_requires('b') p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'list-deps', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0 assert err == '' assert out == ('a-0.1-1.i386 has 2 dependencies:\n' '\ta-0.1-1.i386\n' '\tb-0.1-1.i386\n\n')
def test_conflict_not_ignored_if_contents_match_but_perms_differ( request, dir_server): basepackage = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) basepackage.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'content\n')) baserepo = rpmfluff.YumRepoBuild([basepackage]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir different_mode = rpmfluff.SimpleRpmBuild('x', '0.1', '1', ['i386']) different_mode.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'content\n'), mode='0600') different_mode.make() different_owner = rpmfluff.SimpleRpmBuild('y', '0.1', '1', ['i386']) different_owner.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'content\n'), owner='apache') different_owner.make() different_group = rpmfluff.SimpleRpmBuild('z', '0.1', '1', ['i386']) different_group.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'content\n'), group='apache') different_group.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(basepackage.get_base_dir()) shutil.rmtree(different_mode.get_base_dir()) shutil.rmtree(different_owner.get_base_dir()) shutil.rmtree(different_group.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), different_mode.get_built_rpm('i386'), different_owner.get_built_rpm('i386'), different_group.get_built_rpm('i386') ]) assert exitcode == 3 assert err == ( 'Undeclared file conflicts:\n' 'x-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'x-0.1-1.i386 provides /usr/share/thing which is also provided by y-0.1-1.i386\n' 'x-0.1-1.i386 provides /usr/share/thing which is also provided by z-0.1-1.i386\n' 'y-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'y-0.1-1.i386 provides /usr/share/thing which is also provided by x-0.1-1.i386\n' 'y-0.1-1.i386 provides /usr/share/thing which is also provided by z-0.1-1.i386\n' 'z-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'z-0.1-1.i386 provides /usr/share/thing which is also provided by x-0.1-1.i386\n' 'z-0.1-1.i386 provides /usr/share/thing which is also provided by y-0.1-1.i386\n' )
def test_conflict_is_ignored_if_not_installable_concurrently(request, dir_server): glib_26 = rpmfluff.SimpleRpmBuild('glib', '2.26', '1.el6', ['i686']) glib_26.add_devel_subpackage() glib_26.add_installed_file( installPath="usr/share/gtk-doc/html/gio/annotation-glossary.html", sourceFile=rpmfluff.SourceFile('annotation-glossary.html', 'something\n'), subpackageSuffix='devel') glib_28 = rpmfluff.SimpleRpmBuild('glib', '2.28', '8.el6', ['i686']) glib_doc = glib_28.add_subpackage('doc') glib_doc.add_requires('glib = 2.28-8.el6') glib_28.add_installed_file( installPath="usr/share/gtk-doc/html/gio/annotation-glossary.html", sourceFile=rpmfluff.SourceFile('annotation-glossary.html', 'some other content\n'), subpackageSuffix='doc') glib_28.make() repo = rpmfluff.YumRepoBuild((glib_26,)) repo.make('i686') dir_server.basepath = repo.repoDir def cleanUp(): shutil.rmtree(repo.repoDir) shutil.rmtree(glib_28.get_base_dir()) shutil.rmtree(glib_26.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), glib_28.get_built_rpm('i686'), glib_28.get_built_rpm('i686', 'glib-doc')]) assert exitcode == 0 assert err == '' assert out == ''
def test_conflict_is_ignored_for_rpm_level_conflicts(request, dir_server): # Having two packages intentionally conflict, with a corresponding # Conflicts declaration at the RPM level, is discouraged by Fedora but # sometimes necessary. # https://fedoraproject.org/wiki/Packaging:Conflicts p2 = rpmfluff.SimpleRpmBuild('mysql', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/bin/mysql', sourceFile=rpmfluff.SourceFile('mysql', b'\177ELF-mysql', encoding=None)) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('mariadb', '0.1', '1', ['i386']) p1.add_conflicts('mysql') p1.add_installed_file(installPath='usr/bin/mysql', sourceFile=rpmfluff.SourceFile('mysql', b'\177ELF-mariadb', encoding=None)) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0
def test_conflict_is_ignored_for_rpm_level_conflicts(request, dir_server): # Having two packages intentionally conflict, with a corresponding # Conflicts declaration at the RPM level, is discouraged by Fedora but # sometimes necessary. # https://fedoraproject.org/wiki/Packaging:Conflicts p2 = rpmfluff.SimpleRpmBuild('mysql', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/bin/mysql', sourceFile=rpmfluff.SourceFile('mysql', b'\177ELF-mysql', encoding=None)) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('mariadb', '0.1', '1', ['i386']) p1.add_conflicts('mysql') p1.add_installed_file(installPath='usr/bin/mysql', sourceFile=rpmfluff.SourceFile('mysql', b'\177ELF-mariadb', encoding=None)) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 0
def test_conflict_is_ignored_if_files_match(request, dir_server): # RPM allows multiple packages to own the same file if the file compares equal # according to rpmfilesCompare() in both packages -- that is, the same # owner, group, mode, and contents. p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'same content\n')) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'same content\n')) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 0
def test_prints_error_on_repodata_file_download_failure(request, dir_server): # Similar to the above, but in this case repomd.xml works but # primary.xml.gz is broken. We test this case specifically, because the # code paths for fetching repomd.xml and the other repodata files are # separate. p1 = rpmfluff.SimpleRpmBuild('test-tool', '10', '3.el6', ['x86_64']) p1.add_requires('unsatisfied') repo = rpmfluff.YumRepoBuild([p1]) repo.make('x86_64') for repodata_filename in os.listdir(os.path.join(repo.repoDir, 'repodata')): if 'primary' in repodata_filename: os.unlink(os.path.join(repo.repoDir, 'repodata', repodata_filename)) dir_server.basepath = repo.repoDir def cleanUp(): shutil.rmtree(repo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('x86_64')]) assert exitcode == 1 assert err.startswith('Failed to download repodata') assert '404' in err assert 'Traceback' not in err
def test_does_not_fail_with_signed_rpms(request, dir_server): p2 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['x86_64']) # Add an undeclared conflict to make rpmdeplint loading the rpms into a # transaction. That would usually trigger a rpm signature verification. p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n'), mode='0600') baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('x86_64') dir_server.basepath = baserepo.repoDir p1 = os.path.join(os.path.dirname(__file__), 'data', 'b-0.1-1.i386.rpm') def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1 ]) assert exitcode == 3 assert err == ( 'Undeclared file conflicts:\n' 'b-0.1-1.i386 provides /usr/share/thing which is also provided by a-0.1-1.x86_64\n' )
def test_finds_conflicts_in_installonly_packages(request, dir_server): kernel1 = rpmfluff.SimpleRpmBuild('kernel-core', '0.1', '1', ['i386']) kernel1.add_installed_file( installPath='usr/share/licenses/kernel-core/COPYING', sourceFile=rpmfluff.SourceFile('COPYING', 'content\n')) # The modern mechanism for telling DNF a package is installonly is to add this virtual provide. kernel1.add_provides('installonlypkg(kernel)') baserepo = rpmfluff.YumRepoBuild([kernel1]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir kernel2 = rpmfluff.SimpleRpmBuild('kernel-core', '0.2', '1', ['i386']) kernel2.add_installed_file( installPath='usr/share/licenses/kernel-core/COPYING', sourceFile=rpmfluff.SourceFile('COPYING', 'different content\n')) kernel2.add_provides('installonlypkg(kernel)') kernel2.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(kernel1.get_base_dir()) shutil.rmtree(kernel2.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), kernel2.get_built_rpm('i386') ]) assert exitcode == 3 assert err == ( 'Undeclared file conflicts:\n' 'kernel-core-0.2-1.i386 provides /usr/share/licenses/kernel-core/COPYING ' 'which is also provided by kernel-core-0.1-1.i386\n')
def test_obeys_xml_base_when_downloading_packages(request, tmpdir, dir_server): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['x86_64']) p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'same content\n')) p2.make() # Set up a repo at http://$dirserver/therepo/ pointing at packages stored # in http://$dirserver/thepackages/ using xml:base. dir_server.basepath = tmpdir.strpath shutil.copy(p2.get_built_rpm('x86_64'), tmpdir.mkdir('thepackages').strpath) subprocess.check_output(['createrepo_c', '--baseurl={}/thepackages'.format(dir_server.url), '--outputdir=.', '../thepackages'], stderr=subprocess.STDOUT, cwd=tmpdir.mkdir('therepo').strpath) p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['x86_64']) p1.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'same content\n')) p1.make() def cleanUp(): shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}/therepo'.format(dir_server.url), p1.get_built_rpm('x86_64')]) assert exitcode == 0
def test_migrates_old_cache_layout(request, dir_server): p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) repo = rpmfluff.YumRepoBuild([p1]) repo.make('i386') dir_server.basepath = repo.repoDir def cleanUp(): shutil.rmtree(repo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) old_cache_path = expected_cache_path(repo.repoDir, 'primary.xml.gz', old=True) new_cache_path = expected_cache_path(repo.repoDir, 'primary.xml.gz') # Simulate the old cache path left over from an older version of rpmdeplint os.makedirs(os.path.dirname(old_cache_path)) with open(old_cache_path, 'w') as f: f.write('lol\n') exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0 assert err == '' assert not os.path.exists(old_cache_path) assert os.path.isfile(new_cache_path)
def test_finds_conflicts_in_installonly_packages(request, dir_server): kernel1 = rpmfluff.SimpleRpmBuild('kernel-core', '0.1', '1', ['i386']) kernel1.add_installed_file(installPath='usr/share/licenses/kernel-core/COPYING', sourceFile=rpmfluff.SourceFile('COPYING', 'content\n')) # The modern mechanism for telling DNF a package is installonly is to add this virtual provide. kernel1.add_provides('installonlypkg(kernel)') baserepo = rpmfluff.YumRepoBuild([kernel1]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir kernel2 = rpmfluff.SimpleRpmBuild('kernel-core', '0.2', '1', ['i386']) kernel2.add_installed_file(installPath='usr/share/licenses/kernel-core/COPYING', sourceFile=rpmfluff.SourceFile('COPYING', 'different content\n')) kernel2.add_provides('installonlypkg(kernel)') kernel2.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(kernel1.get_base_dir()) shutil.rmtree(kernel2.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), kernel2.get_built_rpm('i386')]) assert exitcode == 3 assert err == ('Undeclared file conflicts:\n' 'kernel-core-0.2-1.i386 provides /usr/share/licenses/kernel-core/COPYING ' 'which is also provided by kernel-core-0.1-1.i386\n')
def test_finds_undeclared_file_conflict_with_repo_on_local_filesystem(request): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n')) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'different content\n')) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(baserepo.repoDir), p1.get_built_rpm('i386') ]) assert exitcode == 3 assert err == ( 'Undeclared file conflicts:\n' 'a-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' )
def test_guesses_arch_when_combined_with_noarch_package(request, dir_server): # A more realistic case is an archful package with a noarch subpackage, # but rpmfluff currently can't produce that. p_noarch = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['noarch']) p_noarch.add_requires('libfoo.so.4') p_noarch.make() p_archful = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p_archful.add_requires('libfoo.so.4') p_archful.make() baserepo = rpmfluff.YumRepoBuild([]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p_noarch.get_base_dir()) shutil.rmtree(p_archful.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p_noarch.get_built_rpm('noarch'), p_archful.get_built_rpm('i386') ]) assert exitcode == 3, err assert err == ('Problems with dependency set:\n' 'nothing provides libfoo.so.4 needed by a-0.1-1.noarch\n' 'nothing provides libfoo.so.4 needed by b-0.1-1.i386\n')
def test_prints_error_on_repodata_file_download_failure(request, dir_server): # Similar to the above, but in this case repomd.xml works but # primary.xml.gz is broken. We test this case specifically, because the # code paths for fetching repomd.xml and the other repodata files are # separate. p1 = rpmfluff.SimpleRpmBuild('test-tool', '10', '3.el6', ['x86_64']) p1.add_requires('unsatisfied') repo = rpmfluff.YumRepoBuild([p1]) repo.make('x86_64') for repodata_filename in os.listdir(os.path.join(repo.repoDir, 'repodata')): if 'primary' in repodata_filename: os.unlink(os.path.join(repo.repoDir, 'repodata', repodata_filename)) dir_server.basepath = repo.repoDir def cleanUp(): shutil.rmtree(repo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('x86_64') ]) assert exitcode == 1 assert err.startswith('Failed to download repodata') assert '404' in err assert 'Traceback' not in err
def test_conflict_is_ignored_if_files_match(request, dir_server): # RPM allows multiple packages to own the same file if the file compares equal # according to rpmfilesCompare() in both packages -- that is, the same # owner, group, mode, and contents. p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'same content\n')) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'same content\n')) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0
def test_prints_usage_when_no_subcommand_is_given(): exitcode, out, err = run_rpmdeplint(['rpmdeplint']) assert 'usage:' in err # The first wording is on Python < 3.3, the second wording is on Python 3.3+ assert ('error: too few arguments' in err or 'error: the following arguments are required: subcommand' in err) assert exitcode == 2
def test_cache_is_used_when_available(request, dir_server): p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild((p1, )) baserepo.make('i386') dir_server.basepath = baserepo.repoDir def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) # Assuming cache is cleaned first assert dir_server.num_requests == 0 run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) cache_path = expected_cache_path(baserepo.repoDir, 'primary.xml.gz') assert os.path.exists(cache_path) original_cache_mtime = os.path.getmtime(cache_path) # A single run of rpmdeplint with a clean cache should expect network # requests for - repomd.xml, primary.xml.gz and filelists.xml.gz. Requiring # a total of 3 assert dir_server.num_requests == 3 run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) new_cache_mtime = os.path.getmtime(cache_path) assert new_cache_mtime > original_cache_mtime # Executing 2 subprocesses should expect 4 requests if repodata cache is # functioning correctly. A single request for each file in the repo # - repomd.xml, primary.xml.gz, filelists.xml.gz, with an additional # request from the second process checking metadata. The additional # single request shows that the files are skipped in the second process assert dir_server.num_requests == 4
def test_arch_set_manually_is_passed_to_sack(request, dir_server): grep = rpmfluff.SimpleRpmBuild('grep', '2.20', '3.el6', ['i686']) needs_grep = rpmfluff.SimpleRpmBuild('search-tool-5000', '1.0', '3.el6', ['i686']) needs_grep.add_requires('grep = 2.20-3.el6') package_to_test = rpmfluff.SimpleRpmBuild('test-tool', '10', '3.el6', ['i586']) package_to_test.make() baserepo = rpmfluff.YumRepoBuild((grep, needs_grep)) baserepo.make('i686') dir_server.basepath = baserepo.repoDir def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(grep.get_base_dir()) shutil.rmtree(needs_grep.get_base_dir()) shutil.rmtree(package_to_test.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-repoclosure', '--arch=i586', '--repo=base,{}'.format(dir_server.url), package_to_test.get_built_rpm('i586') ]) assert exitcode == 0 assert out == '' assert err == '' exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-repoclosure', '--arch=i686', '--repo=base,{}'.format(dir_server.url), package_to_test.get_built_rpm('i586') ]) assert exitcode == 0 assert out == '' assert err == ''
def test_finds_all_problems(request, dir_server): p_newer = rpmfluff.SimpleRpmBuild('a', '5.0', '1', ['i386']) p_with_content = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p_with_content.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'content\n')) p_old_soname = rpmfluff.SimpleRpmBuild('c', '0.1', '1', ['i386']) p_old_soname.add_provides('libfoo.so.4') p_depending = rpmfluff.SimpleRpmBuild('d', '0.1', '1', ['i386']) p_depending.add_requires('libfoo.so.4') repo_packages = [p_newer, p_with_content, p_old_soname, p_depending] baserepo = rpmfluff.YumRepoBuild(repo_packages) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p_older = rpmfluff.SimpleRpmBuild('a', '4.0', '1', ['i386']) p_older.make() p_broken = rpmfluff.SimpleRpmBuild('e', '1.0', '1', ['i386']) p_broken.add_requires('doesnotexist') p_broken.make() p_with_different_content = rpmfluff.SimpleRpmBuild('f', '0.1', '1', ['i386']) p_with_different_content.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile( 'thing', 'different content\n')) p_with_different_content.make() p_soname_changed = rpmfluff.SimpleRpmBuild('c', '0.2', '1', ['i386']) p_soname_changed.add_provides('libfoo.so.5') p_soname_changed.make() test_packages = [ p_older, p_broken, p_with_different_content, p_soname_changed ] def cleanUp(): shutil.rmtree(baserepo.repoDir) for p in repo_packages + test_packages: shutil.rmtree(p.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint( ['rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url)] + [p.get_built_rpm('i386') for p in test_packages]) assert exitcode == 3 assert err == ( 'Problems with dependency set:\n' 'nothing provides doesnotexist needed by e-1.0-1.i386\n' 'Dependency problems with repos:\n' 'package d-0.1-1.i386 requires libfoo.so.4, but none of the providers can be installed\n' 'Undeclared file conflicts:\n' 'f-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'Upgrade problems:\n' 'a-4.0-1.i386 would be upgraded by a-5.0-1.i386 from repo base\n')
def test_conflict_not_ignored_if_contents_match_but_perms_differ(request, dir_server): basepackage = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) basepackage.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n')) baserepo = rpmfluff.YumRepoBuild([basepackage]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir different_mode = rpmfluff.SimpleRpmBuild('x', '0.1', '1', ['i386']) different_mode.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n'), mode='0600') different_mode.make() different_owner = rpmfluff.SimpleRpmBuild('y', '0.1', '1', ['i386']) different_owner.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n'), owner='apache') different_owner.make() different_group = rpmfluff.SimpleRpmBuild('z', '0.1', '1', ['i386']) different_group.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n'), group='apache') different_group.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(basepackage.get_base_dir()) shutil.rmtree(different_mode.get_base_dir()) shutil.rmtree(different_owner.get_base_dir()) shutil.rmtree(different_group.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), different_mode.get_built_rpm('i386'), different_owner.get_built_rpm('i386'), different_group.get_built_rpm('i386')]) assert exitcode == 3 assert err == ('Undeclared file conflicts:\n' 'x-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'x-0.1-1.i386 provides /usr/share/thing which is also provided by y-0.1-1.i386\n' 'x-0.1-1.i386 provides /usr/share/thing which is also provided by z-0.1-1.i386\n' 'y-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'y-0.1-1.i386 provides /usr/share/thing which is also provided by x-0.1-1.i386\n' 'y-0.1-1.i386 provides /usr/share/thing which is also provided by z-0.1-1.i386\n' 'z-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'z-0.1-1.i386 provides /usr/share/thing which is also provided by x-0.1-1.i386\n' 'z-0.1-1.i386 provides /usr/share/thing which is also provided by y-0.1-1.i386\n' )
def test_arch_set_manually_is_passed_to_sack(request, dir_server): grep = rpmfluff.SimpleRpmBuild('grep', '2.20', '3.el6', ['i686']) needs_grep = rpmfluff.SimpleRpmBuild('search-tool-5000', '1.0', '3.el6', ['i686']) needs_grep.add_requires('grep = 2.20-3.el6') package_to_test = rpmfluff.SimpleRpmBuild('test-tool', '10', '3.el6', ['i586']) package_to_test.make() baserepo = rpmfluff.YumRepoBuild((grep, needs_grep)) baserepo.make('i686') dir_server.basepath = baserepo.repoDir def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(grep.get_base_dir()) shutil.rmtree(needs_grep.get_base_dir()) shutil.rmtree(package_to_test.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--arch=i586', '--repo=base,{}'.format(dir_server.url), package_to_test.get_built_rpm('i586')]) assert exitcode == 0 assert out == '' assert err == '' exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-repoclosure', '--arch=i686', '--repo=base,{}'.format(dir_server.url), package_to_test.get_built_rpm('i586')]) assert exitcode == 0 assert out == '' assert err == ''
def test_cache_is_used_when_available(request, dir_server): p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild((p1,)) baserepo.make('i386') dir_server.basepath = baserepo.repoDir def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) # Assuming cache is cleaned first assert dir_server.num_requests == 0 run_rpmdeplint(['rpmdeplint', 'check', '--repo=base,{}'.format( dir_server.url), p1.get_built_rpm('i386')]) cache_path = expected_cache_path(baserepo.repoDir, 'primary.xml.gz') assert os.path.exists(cache_path) original_cache_mtime = os.path.getmtime(cache_path) # A single run of rpmdeplint with a clean cache should expect network # requests for - repomd.xml, primary.xml.gz and filelists.xml.gz. Requiring # a total of 3 assert dir_server.num_requests == 3 run_rpmdeplint(['rpmdeplint', 'check', '--repo=base,{}'.format( dir_server.url), p1.get_built_rpm('i386')]) new_cache_mtime = os.path.getmtime(cache_path) assert new_cache_mtime > original_cache_mtime # Executing 2 subprocesses should expect 4 requests if repodata cache is # functioning correctly. A single request for each file in the repo # - repomd.xml, primary.xml.gz, filelists.xml.gz, with an additional # request from the second process checking metadata. The additional # single request shows that the files are skipped in the second process assert dir_server.num_requests == 4
def test_rpmdeplint_errors_on_unavailble_url(request): url = 'http://example.test' p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.make() def cleanUp(): shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'list-deps', '--repo=base,{}'.format(url), p1.get_built_rpm('i386')]) assert exitcode == 1
def test_prints_error_on_repo_download_failure(request, dir_server): # Specifically we don't want an unhandled exception, because that triggers abrt. test_tool_rpm = rpmfluff.SimpleRpmBuild('test-tool', '10', '3.el6', ['x86_64']) test_tool_rpm.make() def cleanUp(): shutil.rmtree(test_tool_rpm.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=broken,http://notexist.example/', test_tool_rpm.get_built_rpm('x86_64') ]) assert exitcode == 1 assert err.startswith('Failed to download repodata') assert 'Traceback' not in err
def test_finds_all_problems(request, dir_server): p_newer = rpmfluff.SimpleRpmBuild('a', '5.0', '1', ['i386']) p_with_content = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) p_with_content.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n')) p_old_soname = rpmfluff.SimpleRpmBuild('c', '0.1', '1', ['i386']) p_old_soname.add_provides('libfoo.so.4') p_depending = rpmfluff.SimpleRpmBuild('d', '0.1', '1', ['i386']) p_depending.add_requires('libfoo.so.4') repo_packages = [p_newer, p_with_content, p_old_soname, p_depending] baserepo = rpmfluff.YumRepoBuild(repo_packages) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p_older = rpmfluff.SimpleRpmBuild('a', '4.0', '1', ['i386']) p_older.make() p_broken = rpmfluff.SimpleRpmBuild('e', '1.0', '1', ['i386']) p_broken.add_requires('doesnotexist') p_broken.make() p_with_different_content = rpmfluff.SimpleRpmBuild('f', '0.1', '1', ['i386']) p_with_different_content.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'different content\n')) p_with_different_content.make() p_soname_changed = rpmfluff.SimpleRpmBuild('c', '0.2', '1', ['i386']) p_soname_changed.add_provides('libfoo.so.5') p_soname_changed.make() test_packages = [p_older, p_broken, p_with_different_content, p_soname_changed] def cleanUp(): shutil.rmtree(baserepo.repoDir) for p in repo_packages + test_packages: shutil.rmtree(p.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint( ['rpmdeplint', 'check', '--repo=base,{}'.format(dir_server.url)] + [p.get_built_rpm('i386') for p in test_packages]) assert exitcode == 3 assert err == ('Problems with dependency set:\n' 'nothing provides doesnotexist needed by e-1.0-1.i386\n' 'Dependency problems with repos:\n' 'package d-0.1-1.i386 requires libfoo.so.4, but none of the providers can be installed\n' 'Undeclared file conflicts:\n' 'f-0.1-1.i386 provides /usr/share/thing which is also provided by b-0.1-1.i386\n' 'Upgrade problems:\n' 'a-4.0-1.i386 would be upgraded by a-5.0-1.i386 from repo base\n')
def test_finds_conflict_against_older_subpackage(request, dir_server): conflicting_path = 'usr/share/man/man1/vim.1.gz' oldvim = rpmfluff.SimpleRpmBuild('vim', '7.4.1989', '2', ['x86_64']) oldvim.add_subpackage('common') oldvim.add_subpackage('minimal') oldvim.add_installed_file(installPath=conflicting_path, sourceFile=rpmfluff.SourceFile( 'vim.1', 'oldcontent\n'), subpackageSuffix='common') oldvim.get_subpackage( 'minimal').section_files += '/%s\n' % conflicting_path baserepo = rpmfluff.YumRepoBuild([oldvim]) baserepo.make('x86_64') dir_server.basepath = baserepo.repoDir newvim = rpmfluff.SimpleRpmBuild('vim', '8.0.118', '1', ['x86_64']) newvim.add_subpackage('common') newvim.add_subpackage('minimal') newvim.add_installed_file(installPath=conflicting_path, sourceFile=rpmfluff.SourceFile( 'vim.1', 'newcontent\n'), subpackageSuffix='common') newvim.get_subpackage( 'minimal').section_files += '/%s\n' % conflicting_path newvim.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(oldvim.get_base_dir()) shutil.rmtree(newvim.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), newvim.get_built_rpm('x86_64', name='vim-common'), newvim.get_built_rpm('x86_64', name='vim-minimal') ]) assert exitcode == 3 assert err == ( 'Undeclared file conflicts:\n' 'vim-common-8.0.118-1.x86_64 provides /usr/share/man/man1/vim.1.gz ' 'which is also provided by vim-minimal-7.4.1989-2.x86_64\n' 'vim-minimal-8.0.118-1.x86_64 provides /usr/share/man/man1/vim.1.gz ' 'which is also provided by vim-common-7.4.1989-2.x86_64\n')
def test_conflict_is_ignored_if_file_colors_are_different(request, dir_server): # This is part of RPM's multilib support. If two packages own the same file # but the file color is different in each, the preferred color wins (and # there is no conflict). This lets both .i386 and .x86_64 packages own # /bin/bash while installing only the .x86_64 version. p2 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386', 'x86_64']) p2.add_simple_compilation(installPath='usr/bin/thing') baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386', 'x86_64') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.2', '1', ['i386', 'x86_64']) p1.add_simple_compilation(installPath='usr/bin/thing') p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) # Make sure we really have different files with different colors # (this was surprisingly hard to get right) rpmheader_32 = p1.get_built_rpm_header('i386') rpmheader_64 = p1.get_built_rpm_header('x86_64') if hasattr(rpm, 'files'): # rpm 4.12+ assert 1 == rpm.files(rpmheader_32)['/usr/bin/thing'].color assert 2 == rpm.files(rpmheader_64)['/usr/bin/thing'].color else: # sad old rpm < 4.12 fi_32 = rpm.fi(rpmheader_32) while fi_32.FN() != '/usr/bin/thing': fi_32.next() assert fi_32.FColor() == 1 fi_64 = rpm.fi(rpmheader_64) while fi_64.FN() != '/usr/bin/thing': fi_64.next() assert fi_64.FColor() == 2 exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386') ]) assert exitcode == 0
def test_lists_dependencies_for_rpms_served_from_filesystem(request): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild((p2,)) baserepo.make('i386') p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_requires('doesnotexist') p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'list-deps', '--repo=base,{}'.format(baserepo.repoDir), p1.get_built_rpm('i386')]) assert exitcode == 3
def test_raises_error_for_noarch_rpms_without_arch_specified( request, dir_server): # This is an error because if rpmdeplint is only given noarch rpms, # it cannot guess which arch you want to test them against. # The caller has to pass --arch explicitly in this case. p_noarch = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['noarch']) p_noarch.make() def cleanUp(): shutil.rmtree(p_noarch.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint([ 'rpmdeplint', 'check', '--repo=doesntmatter,http://fakeurl', p_noarch.get_built_rpm('noarch') ]) assert exitcode == 2, err assert 'Cannot determine test arch from noarch packages, pass --arch option explicitly' in err
def test_conflict_is_ignored_if_file_colors_are_different(request, dir_server): # This is part of RPM's multilib support. If two packages own the same file # but the file color is different in each, the preferred color wins (and # there is no conflict). This lets both .i386 and .x86_64 packages own # /bin/bash while installing only the .x86_64 version. p2 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386', 'x86_64']) p2.add_simple_compilation(installPath='usr/bin/thing') baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386', 'x86_64') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.2', '1', ['i386', 'x86_64']) p1.add_simple_compilation(installPath='usr/bin/thing') p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) # Make sure we really have different files with different colors # (this was surprisingly hard to get right) rpmheader_32 = p1.get_built_rpm_header('i386') rpmheader_64 = p1.get_built_rpm_header('x86_64') if hasattr(rpm, 'files'): # rpm 4.12+ assert 1 == rpm.files(rpmheader_32)['/usr/bin/thing'].color assert 2 == rpm.files(rpmheader_64)['/usr/bin/thing'].color else: # sad old rpm < 4.12 fi_32 = rpm.fi(rpmheader_32) while fi_32.FN() != '/usr/bin/thing': fi_32.next() assert fi_32.FColor() == 1 fi_64 = rpm.fi(rpmheader_64) while fi_64.FN() != '/usr/bin/thing': fi_64.next() assert fi_64.FColor() == 2 exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 0
def test_errors_out_for_unsatisfiable_deps(request, dir_server): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild((p2,)) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_requires('doesnotexist') p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p1.get_base_dir()) shutil.rmtree(p2.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'list-deps', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 3
def test_handles_invalid_rpm_without_crashing(request, dir_server, tmpdir): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir # To trigger this bug, the contents of the invalid RPM are irrelevant but # the filename must end in '.rpm'. broken_package = tmpdir.join('broken.rpm') broken_package.write('lol\n') def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'list-deps', '--repo=base,{}'.format(dir_server.url), broken_package.strpath]) assert exitcode == 1 assert err == 'Failed to read package: {}: not a rpm\n'.format(broken_package.strpath)
def test_shows_error_for_rpms(request, dir_server): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '1', ['i386']) baserepo = rpmfluff.YumRepoBuild((p2,)) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.add_requires('doesnotexist') p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-sat', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 3 assert err == 'Problems with dependency set:\nnothing provides doesnotexist needed by a-0.1-1.i386\n' assert out == ''
def test_finds_obsoleting_package_in_repo(request, dir_server): p2 = rpmfluff.SimpleRpmBuild('b', '0.1', '2', ['i386']) p2.add_obsoletes('a < 0.1-2') baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-upgrade', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 3 assert err == ('Upgrade problems:\n' 'a-0.1-1.i386 would be obsoleted by b-0.1-2.i386 from repo base\n')
def test_finds_conflict_against_older_subpackage(request, dir_server): conflicting_path = 'usr/share/man/man1/vim.1.gz' oldvim = rpmfluff.SimpleRpmBuild('vim', '7.4.1989', '2', ['x86_64']) oldvim.add_subpackage('common') oldvim.add_subpackage('minimal') oldvim.add_installed_file(installPath=conflicting_path, sourceFile=rpmfluff.SourceFile('vim.1', 'oldcontent\n'), subpackageSuffix='common') oldvim.get_subpackage('minimal').section_files += '/%s\n' % conflicting_path baserepo = rpmfluff.YumRepoBuild([oldvim]) baserepo.make('x86_64') dir_server.basepath = baserepo.repoDir newvim = rpmfluff.SimpleRpmBuild('vim', '8.0.118', '1', ['x86_64']) newvim.add_subpackage('common') newvim.add_subpackage('minimal') newvim.add_installed_file(installPath=conflicting_path, sourceFile=rpmfluff.SourceFile('vim.1', 'newcontent\n'), subpackageSuffix='common') newvim.get_subpackage('minimal').section_files += '/%s\n' % conflicting_path newvim.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(oldvim.get_base_dir()) shutil.rmtree(newvim.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), newvim.get_built_rpm('x86_64', name='vim-common'), newvim.get_built_rpm('x86_64', name='vim-minimal')]) assert exitcode == 3 assert err == ('Undeclared file conflicts:\n' 'vim-common-8.0.118-1.x86_64 provides /usr/share/man/man1/vim.1.gz ' 'which is also provided by vim-minimal-7.4.1989-2.x86_64\n' 'vim-minimal-8.0.118-1.x86_64 provides /usr/share/man/man1/vim.1.gz ' 'which is also provided by vim-common-7.4.1989-2.x86_64\n')
def test_package_does_not_conflict_with_earlier_version_of_itself(request, dir_server): p2 = rpmfluff.SimpleRpmBuild('a', '0.1', '1', ['i386']) p2.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'content\n')) baserepo = rpmfluff.YumRepoBuild([p2]) baserepo.make('i386') dir_server.basepath = baserepo.repoDir p1 = rpmfluff.SimpleRpmBuild('a', '0.1', '2', ['i386']) p1.add_installed_file(installPath='usr/share/thing', sourceFile=rpmfluff.SourceFile('thing', 'different content\n')) p1.make() def cleanUp(): shutil.rmtree(baserepo.repoDir) shutil.rmtree(p2.get_base_dir()) shutil.rmtree(p1.get_base_dir()) request.addfinalizer(cleanUp) exitcode, out, err = run_rpmdeplint(['rpmdeplint', 'check-conflicts', '--repo=base,{}'.format(dir_server.url), p1.get_built_rpm('i386')]) assert exitcode == 0