Your IP : 172.28.240.42


Current Path : /usr/share/apport/testsuite/
Upload File :
Current File : //usr/share/apport/testsuite/test_backend_apt_dpkg.py

import unittest, gzip, imp, subprocess, tempfile, shutil, os, os.path, time

if os.environ.get('APPORT_TEST_LOCAL'):
    impl = imp.load_source('', 'backends/packaging-apt-dpkg.py').impl
else:
    from apport.packaging_impl import impl

def _has_default_route():
    '''Return if there is a default route.

    This is a reasonable indicator that online tests can be run.
    '''
    if os.environ.get('SKIP_ONLINE_TESTS'):
        return False
    if _has_default_route.cache is None:
        _has_default_route.cache = False
        route = subprocess.Popen(['/sbin/route', '-n'],
            stdout=subprocess.PIPE)
        for l in route.stdout:
            if l.decode('UTF-8').startswith('0.0.0.0 '):
                _has_default_route.cache = True
        route.wait()

    return _has_default_route.cache

_has_default_route.cache = None

class T(unittest.TestCase):
    def setUp(self):
        # save and restore configuration file
        self.orig_conf = impl.configuration
        self.workdir = tempfile.mkdtemp()

        try:
            impl.get_available_version('coreutils-dbgsym')
            self.has_dbgsym = True
        except ValueError:
            self.has_dbgsym = False

    def tearDown(self):
        impl.configuration = self.orig_conf
        shutil.rmtree(self.workdir)

    def test_check_files_md5(self):
        '''_check_files_md5().'''

        td = tempfile.mkdtemp()
        try:
            f1 = os.path.join(td, 'test 1.txt')
            f2 = os.path.join(td, 'test:2.txt')
            sumfile = os.path.join(td, 'sums.txt')
            with open(f1, 'w') as fd:
                fd.write('Some stuff')
            with open(f2, 'w') as fd:
                fd.write('More stuff')
            # use one relative and one absolute path in checksums file
            with open(sumfile, 'wb') as fd:
                fd.write('''2e41290da2fa3f68bd3313174467e3b5  %s
f6423dfbc4faf022e58b4d3f5ff71a70  %s
deadbeef000001111110000011110000  /bin/\xc3\xa4
''' % (f1[1:], f2))
            self.assertEqual(impl._check_files_md5(sumfile), [], 'correct md5sums')

            with open(f1, 'w') as fd:
                fd.write('Some stuff!')
            self.assertEqual(impl._check_files_md5(sumfile), [f1[1:]], 'file 1 wrong')
            with open(f2, 'w') as fd:
                fd.write('More stuff!')
            self.assertEqual(impl._check_files_md5(sumfile), [f1[1:], f2], 'files 1 and 2 wrong')
            with open(f1, 'w') as fd:
                fd.write('Some stuff')
            self.assertEqual(impl._check_files_md5(sumfile), [f2], 'file 2 wrong')

            # check using a direct md5 list as argument
            with open(sumfile) as fd:
                self.assertEqual(impl._check_files_md5(fd.read()),
                    [f2], 'file 2 wrong')

        finally:
            shutil.rmtree(td)

    def test_get_version(self):
        '''get_version().'''

        self.assertTrue(impl.get_version('libc6').startswith('2'))
        self.assertRaises(ValueError, impl.get_version, 'nonexisting')
        self.assertRaises(ValueError, impl.get_version, 'wukrainian')

    def test_get_available_version(self):
        '''get_available_version().'''

        self.assertTrue(impl.get_available_version('libc6').startswith('2'))
        self.assertRaises(ValueError, impl.get_available_version, 'nonexisting')

    def test_get_dependencies(self):
        '''get_dependencies().'''

        # package with both Depends: and Pre-Depends:
        d  = impl.get_dependencies('bash')
        self.assertTrue(len(d) > 2)
        self.assertTrue('libc6' in d)
        for dep in d:
            self.assertTrue(impl.get_version(dep))

        # Pre-Depends: only
        d  = impl.get_dependencies('coreutils')
        self.assertTrue(len(d) >= 1)
        self.assertTrue('libc6' in d)
        for dep in d:
            self.assertTrue(impl.get_version(dep))

        # Depends: only
        d  = impl.get_dependencies('libc6')
        self.assertTrue(len(d) >= 1)
        for dep in d:
            self.assertTrue(impl.get_version(dep))

    def test_get_source(self):
        '''get_source().'''

        self.assertRaises(ValueError, impl.get_source, 'nonexisting')
        self.assertEqual(impl.get_source('bash'), 'bash')
        self.assertTrue('glibc' in impl.get_source('libc6'))

    def test_get_package_origin(self):
        '''get_package_origin().'''

        # determine distro name
        distro = subprocess.check_output(['lsb_release', '-si']).decode('UTF-8').strip()

        self.assertRaises(ValueError, impl.get_package_origin, 'nonexisting')
        # this assumes that this package is not installed
        self.assertRaises(ValueError, impl.get_package_origin, 'robocode-doc')
        # this assumes that bash is native
        self.assertEqual(impl.get_package_origin('bash'), distro)
        # no non-native test here, hard to come up with a generic one

    def test_is_distro_package(self):
        '''is_distro_package().'''

        self.assertRaises(ValueError, impl.is_distro_package, 'nonexisting')
        self.assertTrue(impl.is_distro_package('bash'))
        # no False test here, hard to come up with a generic one

    def test_get_architecture(self):
        '''get_architecture().'''

        self.assertRaises(ValueError, impl.get_architecture, 'nonexisting')
        # just assume that bash uses the native architecture
        d = subprocess.Popen(['dpkg', '--print-architecture'],
            stdout=subprocess.PIPE)
        system_arch = d.communicate()[0].decode().strip()
        assert d.returncode == 0
        self.assertEqual(impl.get_architecture('bash'), system_arch)

    def test_get_files(self):
        '''get_files().'''

        self.assertRaises(ValueError, impl.get_files, 'nonexisting')
        self.assertTrue('/bin/bash' in impl.get_files('bash'))

    def test_get_file_package(self):
        '''get_file_package() on installed files.'''

        self.assertEqual(impl.get_file_package('/bin/bash'), 'bash')
        self.assertEqual(impl.get_file_package('/bin/cat'), 'coreutils')
        self.assertEqual(impl.get_file_package('/etc/blkid.tab'), 'libblkid1')
        self.assertEqual(impl.get_file_package('/nonexisting'), None)

    def test_get_file_package_uninstalled(self):
        '''get_file_package() on uninstalled packages.'''

        # determine distro release code name
        lsb_release = subprocess.Popen(['lsb_release', '-sc'],
            stdout=subprocess.PIPE)
        release_name = lsb_release.communicate()[0].decode('UTF-8').strip()
        assert lsb_release.returncode == 0

        # generate a test Contents.gz
        basedir = tempfile.mkdtemp()
        try:
            mapdir = os.path.join(basedir, 'dists', release_name)
            os.makedirs(mapdir)
            with gzip.open(os.path.join(mapdir, 'Contents-%s.gz' %
                impl.get_system_architecture()), 'w') as f:
                f.write(b'''
foo header
FILE                                                    LOCATION
usr/bin/frobnicate                                      foo/frob
usr/bin/frob                                            foo/frob-utils
bo/gu/s                                                 na/mypackage
''')

            self.assertEqual(impl.get_file_package('usr/bin/frob', False, mapdir), None)
            # must not match frob (same file name prefix)
            self.assertEqual(impl.get_file_package('usr/bin/frob', True, mapdir), 'frob-utils')
            self.assertEqual(impl.get_file_package('/usr/bin/frob', True, mapdir), 'frob-utils')

            # invalid mirror
            impl.set_mirror('file:///foo/nonexisting')
            self.assertRaises(IOError, impl.get_file_package, 'usr/bin/frob', True)

            # valid mirror, no cache directory
            impl.set_mirror('file://' + basedir)
            self.assertEqual(impl.get_file_package('usr/bin/frob', True), 'frob-utils')
            self.assertEqual(impl.get_file_package('/usr/bin/frob', True), 'frob-utils')

            # valid mirror, test caching
            cache_dir = os.path.join(basedir, 'cache')
            os.mkdir(cache_dir)
            self.assertEqual(impl.get_file_package('usr/bin/frob', True, cache_dir), 'frob-utils')
            self.assertEqual(len(os.listdir(cache_dir)), 1)
            cache_file = os.listdir(cache_dir)[0]
            self.assertTrue(cache_file.startswith('Contents-'))
            self.assertEqual(impl.get_file_package('/bo/gu/s', True, cache_dir), 'mypackage')

            # valid cache, should not need to access the mirror
            impl.set_mirror('file:///foo/nonexisting')
            self.assertEqual(impl.get_file_package('/bo/gu/s', True, cache_dir), 'mypackage')

            # outdated cache, must refresh the cache and hit the invalid
            # mirror
            now = int(time.time())
            os.utime(os.path.join(cache_dir, cache_file), (now, now-90000))

            self.assertRaises(IOError, impl.get_file_package, '/bo/gu/s', True, cache_dir)
        finally:
            shutil.rmtree(basedir)

    def test_get_file_package_diversion(self):
        '''get_file_package() for a diverted file.'''

        # pick first diversion we have
        p = subprocess.Popen('LC_ALL=C dpkg-divert --list | head -n 1',
            shell=True, stdout=subprocess.PIPE)
        out = p.communicate()[0].decode('UTF-8')
        assert p.returncode == 0
        assert out
        fields = out.split()
        file = fields[2]
        pkg = fields[-1]

        self.assertEqual(impl.get_file_package(file), pkg)

    def test_get_modified_conffiles(self):
        '''get_modified_conffiles()'''

        # very shallow
        self.assertEqual(type(impl.get_modified_conffiles('bash')), type({}))
        self.assertEqual(type(impl.get_modified_conffiles('apport')), type({}))
        self.assertEqual(type(impl.get_modified_conffiles('nonexisting')), type({}))

    def test_get_system_architecture(self):
        '''get_system_architecture().'''

        arch = impl.get_system_architecture()
        # must be nonempty without line breaks
        self.assertNotEqual(arch, '')
        self.assertTrue('\n' not in arch)

    def test_get_library_paths(self):
        '''get_library_paths().'''

        paths = impl.get_library_paths()
        # must be nonempty without line breaks
        self.assertNotEqual(paths, '')
        self.assertTrue(':' in paths)
        self.assertTrue('/lib' in paths)
        self.assertTrue('\n' not in paths)

    def test_compare_versions(self):
        '''compare_versions.'''

        self.assertEqual(impl.compare_versions('1', '2'), -1)
        self.assertEqual(impl.compare_versions('1.0-1ubuntu1', '1.0-1ubuntu2'), -1)
        self.assertEqual(impl.compare_versions('1.0-1ubuntu1', '1.0-1ubuntu1'), 0)
        self.assertEqual(impl.compare_versions('1.0-1ubuntu2', '1.0-1ubuntu1'), 1)
        self.assertEqual(impl.compare_versions('1:1.0-1', '2007-2'), 1)
        self.assertEqual(impl.compare_versions('1:1.0-1~1', '1:1.0-1'), -1)

    def test_enabled(self):
        '''enabled.'''

        impl.configuration = '/nonexisting'
        self.assertEqual(impl.enabled(), True)

        f = tempfile.NamedTemporaryFile()
        impl.configuration = f.name
        f.write('# configuration file\nenabled = 1'.encode())
        f.flush()
        self.assertEqual(impl.enabled(), True)
        f.close()

        f = tempfile.NamedTemporaryFile()
        impl.configuration = f.name
        f.write('# configuration file\n  enabled =0  '.encode())
        f.flush()
        self.assertEqual(impl.enabled(), False)
        f.close()

        f = tempfile.NamedTemporaryFile()
        impl.configuration = f.name
        f.write('# configuration file\nnothing here'.encode())
        f.flush()
        self.assertEqual(impl.enabled(), True)
        f.close()

    def test_get_kernel_pacakge(self):
        '''get_kernel_package().'''

        self.assertTrue('linux' in impl.get_kernel_package())

    def test_package_name_glob(self):
        '''package_name_glob().'''

        self.assertTrue(len(impl.package_name_glob('a*')) > 5)
        self.assertTrue('bash' in impl.package_name_glob('ba*h'))
        self.assertEqual(impl.package_name_glob('bash'), ['bash'])
        self.assertEqual(impl.package_name_glob('xzywef*'), [])

    @unittest.skipUnless(_has_default_route(), 'online test')
    def test_install_packages_versioned(self):
        '''install_packages() with versions and with cache'''

        self._setup_foonux_config()
        impl.install_packages(self.rootdir, self.configdir, 'Foonux 1.2',
                [('coreutils', '7.4-2ubuntu2'),
                 ('libc6', '2.11.1-0ubuntu7'),
                 ('tzdata', '2010i-1'),
                ], False, self.cachedir)

        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/stat')))
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/lib/debug/usr/bin/stat')))
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/share/zoneinfo/zone.tab')))
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/share/doc/libc6/copyright')))

        # does not clobber config dir
        self.assertEqual(os.listdir(self.configdir), ['Foonux 1.2'])
        self.assertEqual(os.listdir(os.path.join(self.configdir, 'Foonux 1.2')),
                ['sources.list'])

        # caches packages
        cache = os.listdir(os.path.join(self.cachedir, 'Foonux 1.2', 'apt',
            'var', 'cache', 'apt', 'archives'))
        cache_names = [p.split('_')[0] for p in cache]
        self.assertTrue('coreutils' in cache_names)
        self.assertTrue('coreutils-dbgsym' in cache_names)
        self.assertTrue('tzdata' in cache_names)
        self.assertTrue('libc6' in cache_names)
        self.assertTrue('libc6-dbg' in cache_names)

        # installs cached packages
        os.unlink(os.path.join(self.rootdir, 'usr/bin/stat'))
        impl.install_packages(self.rootdir, self.configdir, 'Foonux 1.2',
                [('coreutils', '7.4-2ubuntu2'),
                ], False, self.cachedir)
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/stat')))

        # complains about obsolete packages
        result = impl.install_packages(self.rootdir, self.configdir,
                'Foonux 1.2', [('gnome-common', '1.1')])
        self.assertEqual(len(result.splitlines()), 1)
        self.assertTrue('gnome-common' in result)
        self.assertTrue('1.1' in result)
        # ... but installs the current version anyway
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/gnome-autogen.sh')))

        # does not crash on nonexisting packages
        result = impl.install_packages(self.rootdir, self.configdir,
                'Foonux 1.2', [('buggerbogger', None)])
        self.assertEqual(len(result.splitlines()), 1)
        self.assertTrue('buggerbogger' in result)
        self.assertTrue('not exist' in result)

        # can interleave with other operations
        dpkg = subprocess.Popen(['dpkg-query', '-Wf${Version}', 'dash'],
                stdout=subprocess.PIPE)
        coreutils_version = dpkg.communicate()[0].decode()
        self.assertEqual(dpkg.returncode, 0)

        self.assertEqual(impl.get_version('dash'), coreutils_version)
        self.assertRaises(ValueError, impl.get_available_version, 'buggerbogger')

        # still installs packages after above operations
        os.unlink(os.path.join(self.rootdir, 'usr/bin/stat'))
        impl.install_packages(self.rootdir, self.configdir, 'Foonux 1.2',
                [('coreutils', '7.4-2ubuntu2'),
                 ('dpkg', None),
                ], False, self.cachedir)
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/stat')))
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/dpkg')))

    @unittest.skipUnless(_has_default_route(), 'online test')
    def test_install_packages_unversioned(self):
        '''install_packages() without versions and no cache'''

        self._setup_foonux_config()
        impl.install_packages(self.rootdir, self.configdir, 'Foonux 1.2',
                [('coreutils', None),
                 ('tzdata', None),
                ], False, None)

        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/stat')))
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/lib/debug/usr/bin/stat')))
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/share/zoneinfo/zone.tab')))

        # does not clobber config dir
        self.assertEqual(os.listdir(self.configdir), ['Foonux 1.2'])
        self.assertEqual(os.listdir(os.path.join(self.configdir, 'Foonux 1.2')),
                ['sources.list'])

        # no cache
        self.assertEqual(os.listdir(self.cachedir), [])

    @unittest.skipUnless(_has_default_route(), 'online test')
    def test_install_packages_system(self):
        '''install_packages() with system configuration'''

        # trigger an unrelated package query here to get the cache set up,
        # reproducing an install failure when the internal caches are not
        # reset properly
        impl.get_version('dash')

        self._setup_foonux_config()
        result = impl.install_packages(self.rootdir, None, None,
                [('coreutils', impl.get_version('coreutils')),
                 ('tzdata', '1.1'),
                ], False, self.cachedir)

        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/stat')))
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/share/zoneinfo/zone.tab')))

        # complains about obsolete packages
        self.assertEqual(len(result.splitlines()), 1)
        self.assertTrue('tzdata' in result)
        self.assertTrue('1.1' in result)

        # caches packages
        cache = os.listdir(os.path.join(self.cachedir, 'system', 'apt',
            'var', 'cache', 'apt', 'archives'))
        cache_names = [p.split('_')[0] for p in cache]
        self.assertTrue('coreutils' in cache_names)
        self.assertEqual('coreutils-dbgsym' in cache_names, self.has_dbgsym)
        self.assertTrue('tzdata' in cache_names)

        # works with relative paths and existing cache
        os.unlink(os.path.join(self.rootdir, 'usr/bin/stat'))
        orig_cwd = os.getcwd()
        try:
            os.chdir(self.workdir)
            impl.install_packages('root', None, None,
                    [('coreutils', None)], False, 'cache')
        finally:
            os.chdir(orig_cwd)
        self.assertTrue(os.path.exists(os.path.join(self.rootdir,
            'usr/bin/stat')))

    @unittest.skipUnless(_has_default_route(), 'online test')
    def test_install_packages_error(self):
        '''install_packages() with errors'''

        # sources.list with invalid format
        self._setup_foonux_config()
        with open(os.path.join(self.configdir, 'Foonux 1.2', 'sources.list'), 'w') as f:
            f.write('bogus format')

        try:
            impl.install_packages(self.rootdir, self.configdir, 'Foonux 1.2',
                    [('tzdata', None)], False, self.cachedir)
            self.fail('install_packages() unexpectedly succeeded with broken sources.list')
        except SystemError as e:
            self.assertTrue('bogus' in str(e))
            self.assertFalse('Exception' in str(e))

        # sources.list with wrong server
        with open(os.path.join(self.configdir, 'Foonux 1.2', 'sources.list'), 'w') as f:
            f.write('deb http://archive.ubuntu.com/nosuchdistro/ lucid main\n')

        try:
            impl.install_packages(self.rootdir, self.configdir, 'Foonux 1.2',
                    [('tzdata', None)], False, self.cachedir)
            self.fail('install_packages() unexpectedly succeeded with broken server URL')
        except SystemError as e:
            self.assertTrue('nosuchdistro' in str(e), str(e))
            self.assertTrue('index files failed to download' in str(e))

    def _setup_foonux_config(self):
        '''Set up directories and configuration for install_packages()'''

        self.cachedir = os.path.join(self.workdir, 'cache')
        self.rootdir = os.path.join(self.workdir, 'root')
        self.configdir = os.path.join(self.workdir, 'config')
        os.mkdir(self.cachedir)
        os.mkdir(self.rootdir)
        os.mkdir(self.configdir)
        os.mkdir(os.path.join(self.configdir, 'Foonux 1.2'))
        with open(os.path.join(self.configdir, 'Foonux 1.2', 'sources.list'), 'w') as f:
            f.write('deb http://archive.ubuntu.com/ubuntu/ lucid main\n')
            f.write('deb http://ddebs.ubuntu.com/ lucid main\n')

# only execute if dpkg is available
try:
    if subprocess.call(['dpkg', '--help'], stdout=subprocess.PIPE,
        stderr=subprocess.PIPE) == 0:
        unittest.main()
except OSError:
    pass