Apache/2.4.7 (Ubuntu) Linux sman1baleendah 3.13.0-24-generic #46-Ubuntu SMP Thu Apr 10 19:11:08 UTC 2014 x86_64 uid=33(www-data) gid=33(www-data) groups=33(www-data) safemode : OFF MySQL: ON | Perl: ON | cURL: OFF | WGet: ON > / usr / share / apport / testsuite / | server ip : 104.21.89.46 your ip : 172.69.58.120 H O M E |
Filename | /usr/share/apport/testsuite/test_ui_kde.py |
Size | 26.7 kb |
Permission | rw-r--r-- |
Owner | root : root |
Create time | 27-Apr-2025 09:55 |
Last modified | 04-Apr-2014 22:30 |
Last accessed | 06-Jul-2025 18:28 |
Actions | edit | rename | delete | download (gzip) |
View | text | code | image |
'''KDE 4 Apport User Interface tests'''
# Copyright (C) 2012 Canonical Ltd.
# Author: Evan Dandrea <[email protected]>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
import imp
import unittest
import tempfile
import sys
import os
import shutil
from mock import patch
try:
from PyQt4.QtCore import QTimer, QCoreApplication
from PyQt4.QtGui import QTreeWidget
from PyKDE4.kdecore import ki18n, KCmdLineArgs, KAboutData, KLocalizedString
from PyKDE4.kdeui import KApplication
except ImportError as e:
sys.stderr.write('SKIP: PyQt/PyKDE not available: %s\n' % str(e))
sys.exit(0)
import apport
from apport import unicode_gettext as _
import apport.crashdb_impl.memory
if os.environ.get('APPORT_TEST_LOCAL'):
apport_kde_path = 'kde/apport-kde'
else:
apport_kde_path = os.path.join(os.environ.get('APPORT_DATA_DIR', '/usr/share/apport'), 'apport-kde')
MainUserInterface = imp.load_source('', apport_kde_path).MainUserInterface
# Work around MainUserInterface using basename to find the KDE UI file.
sys.argv[0] = apport_kde_path
class T(unittest.TestCase):
@classmethod
def setUpClass(klass):
r = apport.Report()
r.add_os_info()
klass.distro = r['DistroRelease']
def setUp(self):
self.report_dir = tempfile.mkdtemp()
apport.fileutils.report_dir = self.report_dir
os.environ['APPORT_REPORT_DIR'] = self.report_dir
# do not cause eternal hangs because of error dialog boxes
os.environ['APPORT_DISABLE_DISTRO_CHECK'] = '1'
self.app = MainUserInterface()
# use in-memory crashdb
self.app.crashdb = apport.crashdb_impl.memory.CrashDatabase(None, {})
# disable package hooks, as they might ask for sudo password and other
# interactive bits; allow tests to install their own hooks
self.hook_dir = tempfile.mkdtemp()
apport.report._hook_dir = self.hook_dir
apport.report._common_hook_dir = self.hook_dir
# test report
self.app.report_file = os.path.join(self.report_dir, 'bash.crash')
self.app.report = apport.Report()
self.app.report['ExecutablePath'] = '/bin/bash'
self.app.report['Signal'] = '11'
self.app.report['CoreDump'] = b'\x01\x02'
with open(self.app.report_file, 'wb') as f:
self.app.report.write(f)
def tearDown(self):
if self.app.dialog:
QCoreApplication.processEvents()
self.app.dialog.done(0)
QCoreApplication.processEvents()
shutil.rmtree(self.report_dir)
shutil.rmtree(self.hook_dir)
def test_close_button(self):
'''Clicking the close button on the window does not report the crash.'''
def c(*args):
self.app.dialog.reject()
QTimer.singleShot(0, c)
result = self.app.ui_present_report_details(True)
self.assertFalse(result['report'])
def test_kernel_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ logo ] YourDistro has experienced an internal error. |
| |
| [x] Send an error report to help fix this problem. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'KernelCrash'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Sorry, %s has experienced an internal error.') % self.distro)
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
def test_package_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ error ] Sorry, a problem occurred while installing software. |
| Package: apport 1.2.3~0ubuntu1 |
| |
| [x] Send an error report to help fix this problem. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Package'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Sorry, a problem occurred while installing software.'))
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertEqual(self.app.dialog.text.text(),
_('Package: apport 1.2.3~0ubuntu1'))
def test_regular_crash_thread_layout(self):
'''A thread of execution has failed, but the application persists.'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['ProcStatus'] = 'Name:\tupstart\nPid:\t1'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
def test_regular_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ apport ] The application Apport has closed unexpectedly. |
| |
| [x] Send an error report to help fix this problem. |
| [ ] Ignore future problems of this program version. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['CrashCounter'] = '1'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
with tempfile.NamedTemporaryFile() as fp:
fp.write(b'''[Desktop Entry]
Version=1.0
Name=Apport
Type=Application''')
fp.flush()
self.app.report['DesktopFile'] = fp.name
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('The application Apport has closed unexpectedly.'))
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
# no ProcCmdline, cannot restart
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.ignore_future_problems.isVisible())
self.assertTrue(str(self.app.dialog.ignore_future_problems.text()).endswith(
'of this program version'))
def test_regular_crash_layout_restart(self):
'''
+-----------------------------------------------------------------+
| [ apport ] The application Apport has closed unexpectedly. |
| |
| [x] Send an error report to help fix this problem. |
| [ ] Ignore future problems of this program version. |
| |
| [ Show Details ] [ Leave Closed ] [ Relaunch ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['CrashCounter'] = '1'
self.app.report['ProcCmdline'] = 'apport-bug apport'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
with tempfile.NamedTemporaryFile() as fp:
fp.write(b'''[Desktop Entry]
Version=1.0
Name=Apport
Type=Application''')
fp.flush()
self.app.report['DesktopFile'] = fp.name
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(),
self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('The application Apport has closed unexpectedly.'))
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Relaunch'))
self.assertTrue(self.app.dialog.closed_button.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.ignore_future_problems.isVisible())
self.assertTrue(str(self.app.dialog.ignore_future_problems.text()).endswith(
'of this program version'))
def test_system_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ logo ] Sorry, YourDistro has experienced an internal error. |
| If you notice further problems, try restarting the |
| computer |
| |
| [x] Send an error report to help fix this problem. |
| [ ] Ignore future problems of this type. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['CrashCounter'] = '1'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Sorry, %s has experienced an internal error.') % self.distro)
self.assertEqual(self.app.dialog.text.text(),
_('If you notice further problems, try restarting the computer.'))
self.assertTrue(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertTrue(self.app.dialog.ignore_future_problems.isVisible())
self.assertTrue(str(self.app.dialog.ignore_future_problems.text()).endswith(
'of this type'))
def test_apport_bug_package_layout(self):
'''
+-------------------------------------------------------------------+
| [ error ] Send problem report to the developers? |
| |
| +----------------------------------------------------+ |
| | |> ApportVersion | |
| | ... | |
| +----------------------------------------------------+ |
| |
| [ Cancel ] [ Send ] |
+-------------------------------------------------------------------+
'''
self.app.report_file = None
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Send problem report to the developers?'))
self.assertFalse(self.app.dialog.text.isVisible())
self.assertFalse(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertFalse(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Send'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertTrue(self.app.dialog.cancel_button.isVisible())
self.assertTrue(self.app.dialog.treeview.isVisible())
def test_recoverable_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ logo ] The application Foo has experienced an internal error. |
| Developer-specified error text. |
| |
| [x] Send an error report to help fix this problem. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'RecoverableProblem'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
self.app.report['DialogBody'] = 'Some developer-specified error text.'
with tempfile.NamedTemporaryFile() as fp:
fp.write(b'''[Desktop Entry]
Version=1.0
Name=Apport
Type=Application''')
fp.flush()
self.app.report['DesktopFile'] = fp.name
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(),
self.distro.split()[0])
msg = 'The application Apport has experienced an internal error.'
self.assertEqual(self.app.dialog.heading.text(), msg)
msg = 'Some developer-specified error text.'
self.assertEqual(self.app.dialog.text.text(), msg)
self.assertTrue(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
@patch.object(MainUserInterface, 'open_url')
def test_1_crash_nodetails(self, *args):
'''Crash report without showing details'''
self.visible_progress = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
QTimer.singleShot(200, check_progress)
return
# try again
QTimer.singleShot(1000, cont)
def check_progress(*args):
self.visible_progress = (self.app.progress is not None)
QTimer.singleShot(1000, cont)
self.app.run_crash(self.app.report_file)
# we should have reported one crash
self.assertEqual(self.app.crashdb.latest_id(), 0)
r = self.app.crashdb.download(0)
self.assertEqual(r['ProblemType'], 'Crash')
self.assertEqual(r['ExecutablePath'], '/bin/bash')
# should show a progress bar for info collection
self.assertEqual(self.visible_progress, True)
# data was collected
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('Stacktrace' in r)
# URL was opened
self.assertEqual(self.app.open_url.call_count, 1)
@patch.object(MainUserInterface, 'open_url')
def test_1_crash_details(self, *args):
'''Crash report with showing details'''
self.visible_progress = None
def show_details(*args):
if self.app.dialog and self.app.dialog.show_details.isVisible():
self.app.dialog.show_details.click()
QTimer.singleShot(1000, cont)
return
# try again
QTimer.singleShot(200, show_details)
def cont(*args):
# wait until data collection is done and tree filled
details = self.app.dialog.findChild(QTreeWidget, 'details')
if details.topLevelItemCount() == 0:
QTimer.singleShot(200, cont)
return
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
QTimer.singleShot(200, check_progress)
return
# try again
QTimer.singleShot(200, cont)
def check_progress(*args):
self.visible_progress = (self.app.progress is not None)
QTimer.singleShot(200, show_details)
self.app.run_crash(self.app.report_file)
# we should have reported one crash
self.assertEqual(self.app.crashdb.latest_id(), 0)
r = self.app.crashdb.download(0)
self.assertEqual(r['ProblemType'], 'Crash')
self.assertEqual(r['ExecutablePath'], '/bin/bash')
# we already collected details, do not show the progress dialog again
self.assertFalse(self.visible_progress)
# data was collected
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('Stacktrace' in r)
# URL was opened
self.assertEqual(self.app.open_url.call_count, 1)
@patch.object(MainUserInterface, 'open_url')
def test_1_crash_noaccept(self, *args):
'''Crash report with non-accepting crash DB'''
self.visible_progress = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
QTimer.singleShot(200, check_progress)
return
# try again
QTimer.singleShot(1000, cont)
def check_progress(*args):
self.visible_progress = (self.app.progress is not None)
QTimer.singleShot(1000, cont)
self.app.crashdb.options['problem_types'] = ['bug']
self.app.run_crash(self.app.report_file)
# we should not have reported the crash
self.assertEqual(self.app.crashdb.latest_id(), -1)
self.assertEqual(self.app.open_url.call_count, 0)
# no progress dialog for non-accepting DB
self.assertNotEqual(self.visible_progress, True)
# data was collected for whoopsie
r = self.app.report
self.assertEqual(r['ProblemType'], 'Crash')
self.assertEqual(r['ExecutablePath'], '/bin/bash')
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('Stacktrace' in r)
def test_bug_report_installed_package(self):
'''Bug report for installed package'''
self.app.report_file = None
self.app.options.package = 'bash'
def c(*args):
if self.app.dialog and self.app.dialog.cancel_button.isVisible():
self.app.dialog.cancel_button.click()
return
# try again
QTimer.singleShot(1000, c)
QTimer.singleShot(1000, c)
self.app.run_report_bug()
self.assertEqual(self.app.report['ProblemType'], 'Bug')
self.assertEqual(self.app.report['SourcePackage'], 'bash')
self.assertTrue(self.app.report['Package'].startswith('bash '))
self.assertNotEqual(self.app.report['Dependencies'], '')
def test_bug_report_uninstalled_package(self):
'''Bug report for uninstalled package'''
pkg = apport.packaging.get_uninstalled_package()
self.app.report_file = None
self.app.options.package = pkg
def c(*args):
if self.app.dialog and self.app.dialog.cancel_button.isVisible():
self.app.dialog.cancel_button.click()
return
# try again
QTimer.singleShot(1000, c)
QTimer.singleShot(1000, c)
self.app.run_report_bug()
self.assertEqual(self.app.report['ProblemType'], 'Bug')
self.assertEqual(self.app.report['SourcePackage'],
apport.packaging.get_source(pkg))
self.assertEqual(self.app.report['Package'], '%s (not installed)' % pkg)
@patch.object(MainUserInterface, 'open_url')
def test_1_update_report(self, *args):
'''Updating an existing report'''
self.app.report_file = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
return
# try again
QTimer.singleShot(200, cont)
# upload empty report
id = self.app.crashdb.upload({})
self.assertEqual(id, 0)
self.app.options.update_report = 0
self.app.options.package = 'bash'
QTimer.singleShot(200, cont)
self.app.run_update_report()
# no new bug reported
self.assertEqual(self.app.crashdb.latest_id(), 0)
# bug was updated
r = self.app.crashdb.download(0)
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('DistroRelease' in r)
# No URL in this mode
self.assertEqual(self.app.open_url.call_count, 0)
@patch.object(MainUserInterface, 'open_url')
def test_1_update_report_different_binary_source(self, *args):
'''Updating an existing report on a source package which does not have a binary of the same name'''
self.app.report_file = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
return
# try again
QTimer.singleShot(200, cont)
kernel_pkg = apport.packaging.get_kernel_package()
kernel_src = apport.packaging.get_source(kernel_pkg)
self.assertNotEqual(kernel_pkg, kernel_src,
'this test assumes that the kernel binary package != kernel source package')
self.assertNotEqual(apport.packaging.get_version(kernel_pkg), '',
'this test assumes that the kernel binary package %s is installed' % kernel_pkg)
# this test assumes that the kernel source package name is not an
# installed binary package
self.assertRaises(ValueError, apport.packaging.get_version, kernel_src)
# create source package hook, as otherwise there is nothing to collect
with open(os.path.join(self.hook_dir, 'source_%s.py' % kernel_src), 'w') as f:
f.write('def add_info(r, ui):\n r["MachineType"]="Laptop"\n')
# upload empty report
id = self.app.crashdb.upload({})
self.assertEqual(id, 0)
# run in update mode for that bug
self.app.options.update_report = 0
self.app.options.package = kernel_src
QTimer.singleShot(200, cont)
self.app.run_update_report()
# no new bug reported
self.assertEqual(self.app.crashdb.latest_id(), 0)
# bug was updated
r = self.app.crashdb.download(0)
self.assertTrue('ProcEnviron' in r)
self.assertTrue('DistroRelease' in r)
self.assertTrue('Uname' in r)
self.assertEqual(r['MachineType'], 'Laptop')
# No URL in this mode
self.assertEqual(self.app.open_url.call_count, 0)
def test_administrator_disabled_reporting(self):
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(False)
self.assertFalse(self.app.dialog.send_error_report.isVisible())
self.assertFalse(self.app.dialog.send_error_report.isChecked())
appName = 'apport-kde'
catalog = 'apport'
programName = ki18n(b'Apport KDE')
version = '1.0'
description = ki18n(b'KDE 4 frontend tests for the apport')
license = KAboutData.License_GPL
copyright = ki18n(b'2012 Canonical Ltd.')
text = KLocalizedString()
homePage = 'https://wiki.ubuntu.com/AutomatedProblemReports'
bugEmail = '[email protected]'
aboutData = KAboutData(appName, catalog, programName, version, description,
license, copyright, text, homePage, bugEmail)
KCmdLineArgs.init([''], aboutData)
app = KApplication()
unittest.main()
# Copyright (C) 2012 Canonical Ltd.
# Author: Evan Dandrea <[email protected]>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
# the full text of the license.
import imp
import unittest
import tempfile
import sys
import os
import shutil
from mock import patch
try:
from PyQt4.QtCore import QTimer, QCoreApplication
from PyQt4.QtGui import QTreeWidget
from PyKDE4.kdecore import ki18n, KCmdLineArgs, KAboutData, KLocalizedString
from PyKDE4.kdeui import KApplication
except ImportError as e:
sys.stderr.write('SKIP: PyQt/PyKDE not available: %s\n' % str(e))
sys.exit(0)
import apport
from apport import unicode_gettext as _
import apport.crashdb_impl.memory
if os.environ.get('APPORT_TEST_LOCAL'):
apport_kde_path = 'kde/apport-kde'
else:
apport_kde_path = os.path.join(os.environ.get('APPORT_DATA_DIR', '/usr/share/apport'), 'apport-kde')
MainUserInterface = imp.load_source('', apport_kde_path).MainUserInterface
# Work around MainUserInterface using basename to find the KDE UI file.
sys.argv[0] = apport_kde_path
class T(unittest.TestCase):
@classmethod
def setUpClass(klass):
r = apport.Report()
r.add_os_info()
klass.distro = r['DistroRelease']
def setUp(self):
self.report_dir = tempfile.mkdtemp()
apport.fileutils.report_dir = self.report_dir
os.environ['APPORT_REPORT_DIR'] = self.report_dir
# do not cause eternal hangs because of error dialog boxes
os.environ['APPORT_DISABLE_DISTRO_CHECK'] = '1'
self.app = MainUserInterface()
# use in-memory crashdb
self.app.crashdb = apport.crashdb_impl.memory.CrashDatabase(None, {})
# disable package hooks, as they might ask for sudo password and other
# interactive bits; allow tests to install their own hooks
self.hook_dir = tempfile.mkdtemp()
apport.report._hook_dir = self.hook_dir
apport.report._common_hook_dir = self.hook_dir
# test report
self.app.report_file = os.path.join(self.report_dir, 'bash.crash')
self.app.report = apport.Report()
self.app.report['ExecutablePath'] = '/bin/bash'
self.app.report['Signal'] = '11'
self.app.report['CoreDump'] = b'\x01\x02'
with open(self.app.report_file, 'wb') as f:
self.app.report.write(f)
def tearDown(self):
if self.app.dialog:
QCoreApplication.processEvents()
self.app.dialog.done(0)
QCoreApplication.processEvents()
shutil.rmtree(self.report_dir)
shutil.rmtree(self.hook_dir)
def test_close_button(self):
'''Clicking the close button on the window does not report the crash.'''
def c(*args):
self.app.dialog.reject()
QTimer.singleShot(0, c)
result = self.app.ui_present_report_details(True)
self.assertFalse(result['report'])
def test_kernel_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ logo ] YourDistro has experienced an internal error. |
| |
| [x] Send an error report to help fix this problem. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'KernelCrash'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Sorry, %s has experienced an internal error.') % self.distro)
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
def test_package_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ error ] Sorry, a problem occurred while installing software. |
| Package: apport 1.2.3~0ubuntu1 |
| |
| [x] Send an error report to help fix this problem. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Package'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Sorry, a problem occurred while installing software.'))
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertEqual(self.app.dialog.text.text(),
_('Package: apport 1.2.3~0ubuntu1'))
def test_regular_crash_thread_layout(self):
'''A thread of execution has failed, but the application persists.'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['ProcStatus'] = 'Name:\tupstart\nPid:\t1'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
def test_regular_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ apport ] The application Apport has closed unexpectedly. |
| |
| [x] Send an error report to help fix this problem. |
| [ ] Ignore future problems of this program version. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['CrashCounter'] = '1'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
with tempfile.NamedTemporaryFile() as fp:
fp.write(b'''[Desktop Entry]
Version=1.0
Name=Apport
Type=Application''')
fp.flush()
self.app.report['DesktopFile'] = fp.name
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('The application Apport has closed unexpectedly.'))
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
# no ProcCmdline, cannot restart
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.ignore_future_problems.isVisible())
self.assertTrue(str(self.app.dialog.ignore_future_problems.text()).endswith(
'of this program version'))
def test_regular_crash_layout_restart(self):
'''
+-----------------------------------------------------------------+
| [ apport ] The application Apport has closed unexpectedly. |
| |
| [x] Send an error report to help fix this problem. |
| [ ] Ignore future problems of this program version. |
| |
| [ Show Details ] [ Leave Closed ] [ Relaunch ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['CrashCounter'] = '1'
self.app.report['ProcCmdline'] = 'apport-bug apport'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
with tempfile.NamedTemporaryFile() as fp:
fp.write(b'''[Desktop Entry]
Version=1.0
Name=Apport
Type=Application''')
fp.flush()
self.app.report['DesktopFile'] = fp.name
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(),
self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('The application Apport has closed unexpectedly.'))
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Relaunch'))
self.assertTrue(self.app.dialog.closed_button.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertFalse(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.ignore_future_problems.isVisible())
self.assertTrue(str(self.app.dialog.ignore_future_problems.text()).endswith(
'of this program version'))
def test_system_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ logo ] Sorry, YourDistro has experienced an internal error. |
| If you notice further problems, try restarting the |
| computer |
| |
| [x] Send an error report to help fix this problem. |
| [ ] Ignore future problems of this type. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'Crash'
self.app.report['CrashCounter'] = '1'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Sorry, %s has experienced an internal error.') % self.distro)
self.assertEqual(self.app.dialog.text.text(),
_('If you notice further problems, try restarting the computer.'))
self.assertTrue(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertTrue(self.app.dialog.ignore_future_problems.isVisible())
self.assertTrue(str(self.app.dialog.ignore_future_problems.text()).endswith(
'of this type'))
def test_apport_bug_package_layout(self):
'''
+-------------------------------------------------------------------+
| [ error ] Send problem report to the developers? |
| |
| +----------------------------------------------------+ |
| | |> ApportVersion | |
| | ... | |
| +----------------------------------------------------+ |
| |
| [ Cancel ] [ Send ] |
+-------------------------------------------------------------------+
'''
self.app.report_file = None
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(), self.distro.split()[0])
self.assertEqual(self.app.dialog.heading.text(),
_('Send problem report to the developers?'))
self.assertFalse(self.app.dialog.text.isVisible())
self.assertFalse(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertFalse(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Send'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
self.assertTrue(self.app.dialog.cancel_button.isVisible())
self.assertTrue(self.app.dialog.treeview.isVisible())
def test_recoverable_crash_layout(self):
'''
+-----------------------------------------------------------------+
| [ logo ] The application Foo has experienced an internal error. |
| Developer-specified error text. |
| |
| [x] Send an error report to help fix this problem. |
| |
| [ Show Details ] [ Continue ] |
+-----------------------------------------------------------------+
'''
self.app.report['ProblemType'] = 'RecoverableProblem'
self.app.report['Package'] = 'apport 1.2.3~0ubuntu1'
self.app.report['DialogBody'] = 'Some developer-specified error text.'
with tempfile.NamedTemporaryFile() as fp:
fp.write(b'''[Desktop Entry]
Version=1.0
Name=Apport
Type=Application''')
fp.flush()
self.app.report['DesktopFile'] = fp.name
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(True)
self.assertEqual(self.app.dialog.windowTitle(),
self.distro.split()[0])
msg = 'The application Apport has experienced an internal error.'
self.assertEqual(self.app.dialog.heading.text(), msg)
msg = 'Some developer-specified error text.'
self.assertEqual(self.app.dialog.text.text(), msg)
self.assertTrue(self.app.dialog.text.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isVisible())
self.assertTrue(self.app.dialog.send_error_report.isChecked())
self.assertTrue(self.app.dialog.details.isVisible())
self.assertTrue(self.app.dialog.continue_button.isVisible())
self.assertEqual(self.app.dialog.continue_button.text(), _('Continue'))
self.assertFalse(self.app.dialog.closed_button.isVisible())
@patch.object(MainUserInterface, 'open_url')
def test_1_crash_nodetails(self, *args):
'''Crash report without showing details'''
self.visible_progress = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
QTimer.singleShot(200, check_progress)
return
# try again
QTimer.singleShot(1000, cont)
def check_progress(*args):
self.visible_progress = (self.app.progress is not None)
QTimer.singleShot(1000, cont)
self.app.run_crash(self.app.report_file)
# we should have reported one crash
self.assertEqual(self.app.crashdb.latest_id(), 0)
r = self.app.crashdb.download(0)
self.assertEqual(r['ProblemType'], 'Crash')
self.assertEqual(r['ExecutablePath'], '/bin/bash')
# should show a progress bar for info collection
self.assertEqual(self.visible_progress, True)
# data was collected
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('Stacktrace' in r)
# URL was opened
self.assertEqual(self.app.open_url.call_count, 1)
@patch.object(MainUserInterface, 'open_url')
def test_1_crash_details(self, *args):
'''Crash report with showing details'''
self.visible_progress = None
def show_details(*args):
if self.app.dialog and self.app.dialog.show_details.isVisible():
self.app.dialog.show_details.click()
QTimer.singleShot(1000, cont)
return
# try again
QTimer.singleShot(200, show_details)
def cont(*args):
# wait until data collection is done and tree filled
details = self.app.dialog.findChild(QTreeWidget, 'details')
if details.topLevelItemCount() == 0:
QTimer.singleShot(200, cont)
return
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
QTimer.singleShot(200, check_progress)
return
# try again
QTimer.singleShot(200, cont)
def check_progress(*args):
self.visible_progress = (self.app.progress is not None)
QTimer.singleShot(200, show_details)
self.app.run_crash(self.app.report_file)
# we should have reported one crash
self.assertEqual(self.app.crashdb.latest_id(), 0)
r = self.app.crashdb.download(0)
self.assertEqual(r['ProblemType'], 'Crash')
self.assertEqual(r['ExecutablePath'], '/bin/bash')
# we already collected details, do not show the progress dialog again
self.assertFalse(self.visible_progress)
# data was collected
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('Stacktrace' in r)
# URL was opened
self.assertEqual(self.app.open_url.call_count, 1)
@patch.object(MainUserInterface, 'open_url')
def test_1_crash_noaccept(self, *args):
'''Crash report with non-accepting crash DB'''
self.visible_progress = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
QTimer.singleShot(200, check_progress)
return
# try again
QTimer.singleShot(1000, cont)
def check_progress(*args):
self.visible_progress = (self.app.progress is not None)
QTimer.singleShot(1000, cont)
self.app.crashdb.options['problem_types'] = ['bug']
self.app.run_crash(self.app.report_file)
# we should not have reported the crash
self.assertEqual(self.app.crashdb.latest_id(), -1)
self.assertEqual(self.app.open_url.call_count, 0)
# no progress dialog for non-accepting DB
self.assertNotEqual(self.visible_progress, True)
# data was collected for whoopsie
r = self.app.report
self.assertEqual(r['ProblemType'], 'Crash')
self.assertEqual(r['ExecutablePath'], '/bin/bash')
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('Stacktrace' in r)
def test_bug_report_installed_package(self):
'''Bug report for installed package'''
self.app.report_file = None
self.app.options.package = 'bash'
def c(*args):
if self.app.dialog and self.app.dialog.cancel_button.isVisible():
self.app.dialog.cancel_button.click()
return
# try again
QTimer.singleShot(1000, c)
QTimer.singleShot(1000, c)
self.app.run_report_bug()
self.assertEqual(self.app.report['ProblemType'], 'Bug')
self.assertEqual(self.app.report['SourcePackage'], 'bash')
self.assertTrue(self.app.report['Package'].startswith('bash '))
self.assertNotEqual(self.app.report['Dependencies'], '')
def test_bug_report_uninstalled_package(self):
'''Bug report for uninstalled package'''
pkg = apport.packaging.get_uninstalled_package()
self.app.report_file = None
self.app.options.package = pkg
def c(*args):
if self.app.dialog and self.app.dialog.cancel_button.isVisible():
self.app.dialog.cancel_button.click()
return
# try again
QTimer.singleShot(1000, c)
QTimer.singleShot(1000, c)
self.app.run_report_bug()
self.assertEqual(self.app.report['ProblemType'], 'Bug')
self.assertEqual(self.app.report['SourcePackage'],
apport.packaging.get_source(pkg))
self.assertEqual(self.app.report['Package'], '%s (not installed)' % pkg)
@patch.object(MainUserInterface, 'open_url')
def test_1_update_report(self, *args):
'''Updating an existing report'''
self.app.report_file = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
return
# try again
QTimer.singleShot(200, cont)
# upload empty report
id = self.app.crashdb.upload({})
self.assertEqual(id, 0)
self.app.options.update_report = 0
self.app.options.package = 'bash'
QTimer.singleShot(200, cont)
self.app.run_update_report()
# no new bug reported
self.assertEqual(self.app.crashdb.latest_id(), 0)
# bug was updated
r = self.app.crashdb.download(0)
self.assertTrue(r['Package'].startswith('bash '))
self.assertTrue('libc' in r['Dependencies'])
self.assertTrue('DistroRelease' in r)
# No URL in this mode
self.assertEqual(self.app.open_url.call_count, 0)
@patch.object(MainUserInterface, 'open_url')
def test_1_update_report_different_binary_source(self, *args):
'''Updating an existing report on a source package which does not have a binary of the same name'''
self.app.report_file = None
def cont(*args):
if self.app.dialog and self.app.dialog.continue_button.isVisible():
self.app.dialog.continue_button.click()
return
# try again
QTimer.singleShot(200, cont)
kernel_pkg = apport.packaging.get_kernel_package()
kernel_src = apport.packaging.get_source(kernel_pkg)
self.assertNotEqual(kernel_pkg, kernel_src,
'this test assumes that the kernel binary package != kernel source package')
self.assertNotEqual(apport.packaging.get_version(kernel_pkg), '',
'this test assumes that the kernel binary package %s is installed' % kernel_pkg)
# this test assumes that the kernel source package name is not an
# installed binary package
self.assertRaises(ValueError, apport.packaging.get_version, kernel_src)
# create source package hook, as otherwise there is nothing to collect
with open(os.path.join(self.hook_dir, 'source_%s.py' % kernel_src), 'w') as f:
f.write('def add_info(r, ui):\n r["MachineType"]="Laptop"\n')
# upload empty report
id = self.app.crashdb.upload({})
self.assertEqual(id, 0)
# run in update mode for that bug
self.app.options.update_report = 0
self.app.options.package = kernel_src
QTimer.singleShot(200, cont)
self.app.run_update_report()
# no new bug reported
self.assertEqual(self.app.crashdb.latest_id(), 0)
# bug was updated
r = self.app.crashdb.download(0)
self.assertTrue('ProcEnviron' in r)
self.assertTrue('DistroRelease' in r)
self.assertTrue('Uname' in r)
self.assertEqual(r['MachineType'], 'Laptop')
# No URL in this mode
self.assertEqual(self.app.open_url.call_count, 0)
def test_administrator_disabled_reporting(self):
QTimer.singleShot(0, QCoreApplication.quit)
self.app.ui_present_report_details(False)
self.assertFalse(self.app.dialog.send_error_report.isVisible())
self.assertFalse(self.app.dialog.send_error_report.isChecked())
appName = 'apport-kde'
catalog = 'apport'
programName = ki18n(b'Apport KDE')
version = '1.0'
description = ki18n(b'KDE 4 frontend tests for the apport')
license = KAboutData.License_GPL
copyright = ki18n(b'2012 Canonical Ltd.')
text = KLocalizedString()
homePage = 'https://wiki.ubuntu.com/AutomatedProblemReports'
bugEmail = '[email protected]'
aboutData = KAboutData(appName, catalog, programName, version, description,
license, copyright, text, homePage, bugEmail)
KCmdLineArgs.init([''], aboutData)
app = KApplication()
unittest.main()