Your IP : 172.28.240.42


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

# coding: UTF-8
import unittest, tempfile, locale, subprocess, re, shutil, os.path, sys

import apport.hookutils

class T(unittest.TestCase):
    def setUp(self):
        self.workdir = tempfile.mkdtemp()

    def tearDown(self):
        shutil.rmtree(self.workdir)

    def test_module_license_evaluation(self):
        '''module licenses can be validated correctly'''

        def _build_ko(license):
            asm = tempfile.NamedTemporaryFile(prefix='%s-' % (license),
                                              suffix='.S')
            asm.write(('.section .modinfo\n.string "license=%s"\n' % (license)).encode())
            asm.flush()
            ko = tempfile.NamedTemporaryFile(prefix='%s-' % (license),
                                             suffix='.ko')
            subprocess.call(['/usr/bin/as',asm.name,'-o',ko.name])
            return ko

        good_ko = _build_ko('GPL')
        bad_ko  = _build_ko('BAD')

        # test:
        #  - loaded real module
        #  - unfindable module
        #  - fake GPL module
        #  - fake BAD module

        # direct license check
        self.assertTrue('GPL' in apport.hookutils._get_module_license('isofs'))
        self.assertEqual(apport.hookutils._get_module_license('does-not-exist'), 'invalid')
        self.assertTrue('GPL' in apport.hookutils._get_module_license(good_ko.name))
        self.assertTrue('BAD' in apport.hookutils._get_module_license(bad_ko.name))

        # check via nonfree_kernel_modules logic
        f = tempfile.NamedTemporaryFile()
        f.write(('isofs\ndoes-not-exist\n%s\n%s\n' %
                (good_ko.name,bad_ko.name)).encode())
        f.flush()
        nonfree = apport.hookutils.nonfree_kernel_modules(f.name)
        self.assertFalse('isofs' in nonfree)
        self.assertTrue('does-not-exist' in nonfree)
        self.assertFalse(good_ko.name in nonfree)
        self.assertTrue(bad_ko.name in nonfree)

    def test_attach_dmesg(self):
        '''attach_dmesg() does not overwrite already existing data'''

        report = {}

        apport.hookutils.attach_dmesg(report)
        self.assertTrue(report['BootDmesg'].startswith('['))
        self.assertTrue(len(report['BootDmesg']) > 500)
        self.assertTrue(report['CurrentDmesg'].startswith(b'['))

    def test_dmesg_overwrite(self):
        '''attach_dmesg() does not overwrite already existing data'''

        report = {'BootDmesg': 'existingboot'}

        apport.hookutils.attach_dmesg(report)
        self.assertEqual(report['BootDmesg'][:50], 'existingboot')
        self.assertTrue(report['CurrentDmesg'].startswith(b'['))

        report = {'BootDmesg': 'existingboot', 'CurrentDmesg': 'existingcurrent' }

        apport.hookutils.attach_dmesg(report)
        self.assertEqual(report['BootDmesg'], 'existingboot')
        self.assertEqual(report['CurrentDmesg'], 'existingcurrent')

    def test_attach_file(self):
        '''attach_file()'''

        with open('/etc/motd', 'rb') as f:
            motd_contents = f.read().strip()
        with open('/etc/issue', 'rb') as f:
            issue_contents = f.read().strip()

        # default key name
        report = {}
        apport.hookutils.attach_file(report, '/etc/motd')
        self.assertEqual(list(report), ['.etc.motd'])
        self.assertEqual(report['.etc.motd'], motd_contents)

        # custom key name
        report = {}
        apport.hookutils.attach_file(report, '/etc/motd', 'Motd')
        self.assertEqual(list(report), ['Motd'])
        self.assertEqual(report['Motd'], motd_contents)

        # nonexisting file
        report = {}
        apport.hookutils.attach_file(report, '/nonexisting')
        self.assertEqual(list(report), ['.nonexisting'])
        self.assertTrue(report['.nonexisting'].startswith('Error: '))

        # existing key
        report = {}
        apport.hookutils.attach_file(report, '/etc/motd')
        apport.hookutils.attach_file(report, '/etc/motd')
        self.assertEqual(list(report), ['.etc.motd'])
        self.assertEqual(report['.etc.motd'], motd_contents)

        apport.hookutils.attach_file(report, '/etc/issue', '.etc.motd', overwrite=False)
        self.assertEqual(sorted(report.keys()), ['.etc.motd', '.etc.motd_'])
        self.assertEqual(report['.etc.motd'], motd_contents)
        self.assertEqual(report['.etc.motd_'], issue_contents)

    def test_attach_file_if_exists(self):
        '''attach_file_if_exists()'''

        with open('/etc/motd', 'rb') as f:
            motd_contents = f.read().strip()

        # default key name
        report = {}
        apport.hookutils.attach_file_if_exists(report, '/etc/motd')
        self.assertEqual(list(report), ['.etc.motd'])
        self.assertEqual(report['.etc.motd'], motd_contents)

        # custom key name
        report = {}
        apport.hookutils.attach_file_if_exists(report, '/etc/motd', 'Motd')
        self.assertEqual(list(report), ['Motd'])
        self.assertEqual(report['Motd'], motd_contents)

        # nonexisting file
        report = {}
        apport.hookutils.attach_file_if_exists(report, '/nonexisting')
        self.assertEqual(list(report), [])

    def test_recent_logfile(self):
        '''recent_logfile'''

        self.assertEqual(apport.hookutils.recent_logfile('/nonexisting', re.compile('.')), '')
        self.assertEqual(apport.hookutils.recent_syslog(re.compile('ThisCantPossiblyHitAnything')), '')
        self.assertNotEqual(len(apport.hookutils.recent_syslog(re.compile('.'))), 0)

    def test_recent_logfile_overflow(self):
        '''recent_logfile on a huge file'''

        log = os.path.join(self.workdir, 'syslog')
        with open(log, 'w') as f:
            lines = 1000000
            while lines >= 0:
                f.write('Apr 20 11:30:00 komputer kernel: bogus message\n')
                lines -= 1

        mem_before = self._get_mem_usage()
        data = apport.hookutils.recent_logfile(log, re.compile('kernel'))
        mem_after = self._get_mem_usage()
        delta_kb = mem_after - mem_before
        sys.stderr.write('[Δ %i kB] ' % delta_kb)
        self.assertLess(delta_kb, 5000)

        self.assertTrue(data.startswith('Apr 20 11:30:00 komputer kernel: bogus message\n'))
        self.assertGreater(len(data), 100000)
        self.assertLess(len(data), 1000000)

    @unittest.skipIf(apport.hookutils.apport.hookutils.in_session_of_problem(apport.Report()) is None, 'no ConsoleKit session')
    def test_in_session_of_problem(self):
        '''in_session_of_problem()'''

        old_ctime = locale.getlocale(locale.LC_TIME)
        locale.setlocale(locale.LC_TIME, 'C')

        report = {'Date': 'Sat Jan  1 12:00:00 2011'}
        self.assertFalse(apport.hookutils.in_session_of_problem(report))

        report = {'Date': 'Mon Oct 10 21:06:03 2009'}
        self.assertFalse(apport.hookutils.in_session_of_problem(report))

        report = {'Date': 'Tue Jan  1 12:00:00 2211'}
        self.assertTrue(apport.hookutils.in_session_of_problem(report))

        locale.setlocale(locale.LC_TIME, '')

        report = {'Date': 'Sat Jan  1 12:00:00 2011'}
        self.assertFalse(apport.hookutils.in_session_of_problem(report))

        report = {'Date': 'Mon Oct 10 21:06:03 2009'}
        self.assertFalse(apport.hookutils.in_session_of_problem(report))

        report = apport.Report()
        self.assertTrue(apport.hookutils.in_session_of_problem(report))

        self.assertEqual(apport.hookutils.in_session_of_problem({}), None)

        locale.setlocale(locale.LC_TIME, old_ctime)

    def test_xsession_errors(self):
        '''xsession_errors()'''

        with open(os.path.join(self.workdir, '.xsession-errors'), 'w') as f:
            f.write('''Loading profile from /etc/profile
gnome-session[1948]: WARNING: standard glib warning
EggSMClient-CRITICAL **: egg_sm_client_set_mode: standard glib assertion
24/02/2012 11:14:46 Sending credentials s3kr1t

** WARNING **: nonstandard warning

WARN  2012-02-24 11:23:47 unity <unknown>:0 some unicode ♥ ♪

GNOME_KEYRING_CONTROL=/tmp/keyring-u7hrD6

(gnome-settings-daemon:5115): Gdk-WARNING **: The program 'gnome-settings-daemon' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadMatch (invalid parameter attributes)'.
  (Details: serial 723 error_code 8 request_code 143 minor_code 22)
  (Note to programmers: normally, X errors are reported asynchronously;
   that is, you will receive the error a while after causing it.
   To debug your program, run it with the --sync command line
   option to change this behavior. You can then get a meaningful
   backtrace from your debugger if you break on the gdk_x_error() function.)"

GdkPixbuf-CRITICAL **: gdk_pixbuf_scale_simple: another standard glib assertion
''')
        orig_home = os.environ.get('HOME')
        try:
            os.environ['HOME'] = self.workdir

            # explicit pattern
            pattern = re.compile('notfound')
            self.assertEqual(apport.hookutils.xsession_errors(pattern), '')

            pattern = re.compile('^\w+-CRITICAL')
            res = apport.hookutils.xsession_errors(pattern).splitlines()
            self.assertEqual(len(res), 2)
            self.assertTrue(res[0].startswith('EggSMClient-CRITICAL'))
            self.assertTrue(res[1].startswith('GdkPixbuf-CRITICAL'))

            # default pattern includes glib assertions and X Errors
            res = apport.hookutils.xsession_errors()
            self.assertFalse('nonstandard warning' in res)
            self.assertFalse('keyring' in res)
            self.assertFalse('credentials' in res)
            self.assertTrue('WARNING: standard glib warning' in res, res)
            self.assertTrue('GdkPixbuf-CRITICAL' in res, res)
            self.assertTrue("'gnome-settings-daemon' received an X Window" in res, res)
            self.assertTrue('BadMatch' in res, res)
            self.assertTrue('serial 723' in res, res)

        finally:
            if orig_home is not None:
                os.environ['HOME'] = orig_home
            else:
                os.unsetenv('HOME')

    def test_no_crashes(self):
        '''functions do not crash (very shallow)'''

        report = {}
        apport.hookutils.attach_hardware(report)
        apport.hookutils.attach_alsa(report)
        apport.hookutils.attach_network(report)
        apport.hookutils.attach_wifi(report)
        apport.hookutils.attach_printing(report)
        apport.hookutils.attach_conffiles(report, 'bash')
        apport.hookutils.attach_conffiles(report, 'apport')
        apport.hookutils.attach_conffiles(report, 'nonexisting')
        apport.hookutils.attach_upstart_overrides(report, 'apport')
        apport.hookutils.attach_upstart_overrides(report, 'nonexisting')

    def test_command_output(self):
        orig_lcm = os.environ.get('LC_MESSAGES')
        os.environ['LC_MESSAGES'] = 'en_US.UTF-8'
        try:
            # default mode: disable translations
            out = apport.hookutils.command_output(['env'])
            self.assertTrue('LC_MESSAGES=C' in out)

            # keep locale
            out = apport.hookutils.command_output(['env'], keep_locale=True)
            self.assertFalse('LC_MESSAGES=C' in out, out)
        finally:
            if orig_lcm is not None:
                os.environ['LC_MESSAGES'] = orig_lcm
            else:
                os.unsetenv('LC_MESSAGES')

        # nonexisting binary
        out = apport.hookutils.command_output(['/non existing'])
        self.assertTrue(out.startswith('Error: [Errno 2]'))

        # stdin
        out = apport.hookutils.command_output(['cat'], input='hello')
        self.assertEqual(out, 'hello')

    @classmethod
    def _get_mem_usage(klass):
        '''Get current memory usage in kB'''

        with open('/proc/self/status') as f:
            for line in f:
                if line.startswith('VmSize:'):
                    return int(line.split()[1])
            else:
                raise SystemError('did not find VmSize: in /proc/self/status')

unittest.main()