Back to index

apport  2.4
Public Member Functions | Public Attributes
test_crash_digger.T Class Reference

List of all members.

Public Member Functions

def setUp
def tearDown
def call
def test_crashes
def test_crashes_error
def test_crashes_transient_error
def test_dupcheck
def test_stderr_redirection
def test_publish_db
def test_alternate_crashdb

Public Attributes

 workdir
 config_dir
 apport_retrace_log
 apport_retrace
 lock_file
 orig_report_dir

Detailed Description

Definition at line 17 of file test_crash_digger.py.


Member Function Documentation

def test_crash_digger.T.call (   self,
  args 
)
Call crash-digger with given arguments.

Return a pair (stdout, stderr).

Definition at line 59 of file test_crash_digger.py.

00059 
00060     def call(self, args):
00061         '''Call crash-digger with given arguments.
00062 
00063         Return a pair (stdout, stderr).
00064         '''
00065         s = subprocess.Popen(['crash-digger', '--apport-retrace',
00066                               self.apport_retrace] + args, stdout=subprocess.PIPE,
00067                              stderr=subprocess.PIPE)
00068         (out, err) = s.communicate()
00069         return (out.decode('UTF-8'), err.decode('UTF-8'))

Here is the caller graph for this function:

def test_crash_digger.T.setUp (   self)
Set up dummy config dir, crashdb.conf, and apport-retrace

Definition at line 18 of file test_crash_digger.py.

00018 
00019     def setUp(self):
00020         '''Set up dummy config dir, crashdb.conf, and apport-retrace'''
00021 
00022         self.workdir = tempfile.mkdtemp()
00023 
00024         crashdb_conf = os.path.join(self.workdir, 'crashdb.conf')
00025         with open(crashdb_conf, 'w') as f:
00026             f.write('''default = 'memory'
00027 databases = {
00028     'memory': {'impl': 'memory', 'distro': 'Testux', 'dummy_data': '1',
00029                'dupdb_url': '%s'},
00030     'empty': {'impl': 'memory', 'distro': 'Foonux'},
00031 }''' % os.path.join(self.workdir, 'dupdb'))
00032 
00033         self.config_dir = os.path.join(self.workdir, 'config')
00034         os.mkdir(self.config_dir)
00035         os.mkdir(os.path.join(self.config_dir, 'Testux 1.0'))
00036         os.mkdir(os.path.join(self.config_dir, 'Testux 2.2'))
00037 
00038         self.apport_retrace_log = os.path.join(self.workdir, 'apport-retrace.log')
00039 
00040         self.apport_retrace = os.path.join(self.workdir, 'apport-retrace')
00041         with open(self.apport_retrace, 'w') as f:
00042             f.write('''#!/bin/sh
00043 echo "$@" >> %s''' % self.apport_retrace_log)
00044         os.chmod(self.apport_retrace, 0o755)
00045 
00046         self.lock_file = os.path.join(self.workdir, 'lock')
00047 
00048         os.environ['APPORT_CRASHDB_CONF'] = crashdb_conf
00049         os.environ['PYTHONPATH'] = '.'
00050 
00051         self.orig_report_dir = apport.fileutils.report_dir
00052         apport.fileutils.report_dir = os.path.join(self.workdir, 'crashes')
00053         os.mkdir(apport.fileutils.report_dir)
00054         os.environ['APPORT_REPORT_DIR'] = apport.fileutils.report_dir

Definition at line 55 of file test_crash_digger.py.

00055 
00056     def tearDown(self):
00057         shutil.rmtree(self.workdir)
00058         apport.fileutils.report_dir = self.orig_report_dir

Alternate crash database name

Definition at line 219 of file test_crash_digger.py.

00219 
00220     def test_alternate_crashdb(self):
00221         '''Alternate crash database name'''
00222 
00223         # existing DB "empty" has no crashes
00224         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero',
00225                                 '-vl', self.lock_file, '--crash-db', 'empty'])
00226         self.assertEqual(err, '', 'no error messages:\n' + err)
00227         self.assertFalse('retracing #' in out)
00228         self.assertFalse('crash is' in out)
00229         self.assertFalse('failed with status' in out)
00230 
00231         # nonexisting DB
00232         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero',
00233                                 '-vl', self.lock_file, '--crash-db', 'nonexisting'])
00234         self.assertEqual(out, '', 'no output messages:\n' + out)
00235         self.assertFalse('Traceback' in err, err)
00236         self.assertTrue('nonexisting' in err, err)
00237 
00238 unittest.main()

Here is the call graph for this function:

Crash retracing

Definition at line 70 of file test_crash_digger.py.

00070 
00071     def test_crashes(self):
00072         '''Crash retracing'''
00073 
00074         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero', '-d',
00075                                 os.path.join(self.workdir, 'dup.db'), '-vl', self.lock_file])
00076         self.assertEqual(err, '', 'no error messages:\n' + err)
00077         self.assertTrue("Available releases: ['Testux 1.0', 'Testux 2.2']" in out)
00078         self.assertTrue('retracing #0' in out)
00079         self.assertTrue('retracing #1' in out)
00080         self.assertTrue('retracing #2' in out)
00081         self.assertTrue('crash is release FooLinux Pi/2 which does not have a config available' in out)
00082         self.assertFalse('failed with status' in out)
00083         self.assertFalse('#3' in out, 'dupcheck crashes are not retraced')
00084         self.assertFalse('#4' in out, 'dupcheck crashes are not retraced')
00085 
00086         with open(self.apport_retrace_log) as f:
00087             retrace_log = f.read()
00088         self.assertEqual(len(retrace_log.splitlines()), 2)
00089         self.assertFalse('dup.db -v 0\n' in retrace_log)
00090         self.assertTrue('dup.db -v 1\n' in retrace_log)
00091         self.assertTrue('dup.db -v 2\n' in retrace_log)
00092         self.assertFalse(os.path.exists(self.lock_file))
00093 
00094         self.assertFalse(os.path.isdir(os.path.join(self.workdir, 'dupdb', 'sig')))

Here is the call graph for this function:

Crash retracing if apport-retrace fails on bug #1

Definition at line 95 of file test_crash_digger.py.

00095 
00096     def test_crashes_error(self):
00097         '''Crash retracing if apport-retrace fails on bug #1'''
00098 
00099         # make apport-retrace fail on bug 1
00100         os.rename(self.apport_retrace, self.apport_retrace + '.bak')
00101         with open(self.apport_retrace, 'w') as f:
00102             f.write('''#!/bin/sh
00103 echo "$@" >> %s
00104 while [ -n "$2" ]; do shift; done
00105 if [ "$1" = 1 ]; then
00106     echo "cannot frobnicate bug" >&2
00107     exit 1
00108 fi
00109 ''' % self.apport_retrace_log)
00110         os.chmod(self.apport_retrace, 0o755)
00111 
00112         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero', '-d',
00113                                 os.path.join(self.workdir, 'dup.db'), '-vl', self.lock_file])
00114         self.assertTrue('Traceback' in err)
00115         self.assertTrue('SystemError: retracing #1 failed' in err)
00116         self.assertTrue("Available releases: ['Testux 1.0', 'Testux 2.2']" in out)
00117         self.assertTrue('retracing #0' in out)
00118         self.assertTrue('retracing #1' in out)
00119         self.assertFalse('retracing #2' in out, 'should not continue after errors')
00120         self.assertTrue('crash is release FooLinux Pi/2 which does not have a config available' in out)
00121         self.assertFalse('#0 failed with status' in out)
00122         self.assertTrue('#1 failed with status: 1' in out)
00123         self.assertFalse('#3' in out, 'dupcheck crashes are not retraced')
00124         self.assertFalse('#4' in out, 'dupcheck crashes are not retraced')
00125 
00126         with open(self.apport_retrace_log) as f:
00127             retrace_log = f.read()
00128         self.assertEqual(len(retrace_log.splitlines()), 1)
00129         self.assertFalse('dup.db -v 0\n' in retrace_log)
00130         self.assertTrue('dup.db -v 1\n' in retrace_log)
00131         # stops after failing #1
00132         self.assertFalse('dup.db -v 2\n' in retrace_log)
00133         self.assertTrue(os.path.exists(self.lock_file))
00134 
00135         os.rename(self.apport_retrace + '.bak', self.apport_retrace)
00136 
00137         # subsequent start should not do anything until the lock file is cleaned up
00138         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero', '-d',
00139                                 os.path.join(self.workdir, 'dup.db'), '-vl', self.lock_file])
00140         self.assertEqual(out, '')
00141         self.assertEqual(err, '')
00142 
00143         os.unlink(self.lock_file)
00144 
00145         # now it should run again
00146         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero', '-d',
00147                                 os.path.join(self.workdir, 'dup.db'), '-vl', self.lock_file])
00148         self.assertTrue('retracing #2' in out)
00149         self.assertEqual(err, '', 'no error messages:\n' + err)
00150         self.assertFalse(os.path.exists(self.lock_file))

Here is the call graph for this function:

Crash retracing if apport-retrace reports a transient error

Definition at line 151 of file test_crash_digger.py.

00151 
00152     def test_crashes_transient_error(self):
00153         '''Crash retracing if apport-retrace reports a transient error'''
00154 
00155         # make apport-retrace fail on bug 1
00156         os.rename(self.apport_retrace, self.apport_retrace + '.bak')
00157         with open(self.apport_retrace, 'w') as f:
00158             f.write('''#!/bin/sh
00159 echo "$@" >> %s
00160 while [ -n "$2" ]; do shift; done
00161 if [ "$1" = 1 ]; then
00162     echo "cannot frobnicate crash db" >&2
00163     exit 99
00164 fi
00165 ''' % self.apport_retrace_log)
00166         os.chmod(self.apport_retrace, 0o755)
00167 
00168         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero', '-d',
00169                                 os.path.join(self.workdir, 'dup.db'), '-vl', self.lock_file])
00170         self.assertTrue("Available releases: ['Testux 1.0', 'Testux 2.2']" in out)
00171         self.assertTrue('retracing #0' in out)
00172         self.assertTrue('retracing #1' in out)
00173         self.assertFalse('retracing #2' in out, 'should not continue after errors')
00174         self.assertTrue('transient error reported; halting' in out)
00175 
00176         with open(self.apport_retrace_log) as f:
00177             retrace_log = f.read()
00178         self.assertTrue('dup.db -v 1\n' in retrace_log)
00179         # stops after failing #1
00180         self.assertFalse('dup.db -v 2\n' in retrace_log)
00181 
00182         self.assertFalse(os.path.exists(self.lock_file))

Here is the call graph for this function:

Duplicate checking

Definition at line 183 of file test_crash_digger.py.

00183 
00184     def test_dupcheck(self):
00185         '''Duplicate checking'''
00186 
00187         (out, err) = self.call(['-a', '/dev/zero', '-d',
00188                                 os.path.join(self.workdir, 'dup.db'), '-vDl', self.lock_file])
00189         self.assertEqual(err, '', 'no error messages:\n' + err)
00190         self.assertFalse('#1' in out, 'signal crashes are not retraced')
00191         self.assertFalse('#2' in out, 'signal crashes are not retraced')
00192         self.assertTrue('checking #3 for duplicate' in out)
00193         self.assertTrue('checking #4 for duplicate' in out)
00194         self.assertTrue('Report is a duplicate of #3 (not fixed yet)' in out)
00195         self.assertFalse(os.path.exists(self.apport_retrace_log))
00196         self.assertFalse(os.path.exists(self.lock_file))

Here is the call graph for this function:

Duplicate database publishing

Definition at line 208 of file test_crash_digger.py.

00208 
00209     def test_publish_db(self):
00210         '''Duplicate database publishing'''
00211 
00212         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero', '-d',
00213                                 os.path.join(self.workdir, 'dup.db'), '-vl', self.lock_file,
00214                                 '--publish-db', os.path.join(self.workdir, 'dupdb')])
00215         self.assertEqual(err, '', 'no error messages:\n' + err)
00216         self.assertTrue('retracing #0' in out)
00217 
00218         self.assertTrue(os.path.isdir(os.path.join(self.workdir, 'dupdb', 'sig')))

Here is the call graph for this function:

apport-retrace's stderr is redirected to stdout

Definition at line 197 of file test_crash_digger.py.

00197 
00198     def test_stderr_redirection(self):
00199         '''apport-retrace's stderr is redirected to stdout'''
00200 
00201         with open(self.apport_retrace, 'w') as f:
00202             f.write('''#!/bin/sh
00203 echo ApportRetraceError >&2''')
00204         (out, err) = self.call(['-c', self.config_dir, '-a', '/dev/zero', '-d',
00205                                 os.path.join(self.workdir, 'dup.db'), '-vl', self.lock_file])
00206         self.assertEqual(err, '', 'no error messages:\n' + err)
00207         self.assertTrue('ApportRetraceError' in out)

Here is the call graph for this function:


Member Data Documentation

Definition at line 39 of file test_crash_digger.py.

Definition at line 37 of file test_crash_digger.py.

Definition at line 32 of file test_crash_digger.py.

Definition at line 45 of file test_crash_digger.py.

Definition at line 50 of file test_crash_digger.py.

Definition at line 21 of file test_crash_digger.py.


The documentation for this class was generated from the following file: