Commit 295af397 authored by Harald Sitter's avatar Harald Sitter 🌼

Add a integration test suite and fix a signal connect bug when attaching reports

Summary:
- Fix radios' updating UI as they are toggling not buttonclicking :(
- add a cmdline option to enable bringing up the dialog directly. in a testing scenario it makes sense to skip the notification popup thing and go directly to the dialog
- new env var DRKONQI_KDE_BUGZILLA_URL to override the bugzilla url. for testing purposes we'll want to change the bugzilla url to point to a double instance but otherwise not impact functionality of drkonqi
- new env var DRKONQI_IGNORE_QUALITY to bypass trace quality checks. during testing a proper trace may not be creatable, setting the env var allows bypassing the quality constraints
- set a11y names on text inputs to facilitate a11y enablement (also allows finding them through at-spi for testing purposes ;))

add an integration test based on xvfb+dbus+at-spi

- suite wrapper program isolates the environment a bit,
  starts a xvfb instance and runs a session bus
  inside, then starts the actual tests from inside the isolated environment
- duplicate_attach_test.rb starts an xmlrpc server, a defunct ruby, and
  a drkonqi to trace the defunct ruby. it then uses at-spi to massage the
  drkoknqi GUI into attaching a new trace to a bug via xmlrpc server.
- the xmlrpc server partially falls through to bugstest.kde.org but mostly
  doubles for bugzilla

fix a connect bug when attaching a new trace to an existing report

Test Plan:
`make test` should run the integration test assuming requirements are met (ruby+atspi+xmlrpc+xvfb-run).

`XEPHYR=1 make test` will run the test through xephyr rather than xvfb, which is somewhat more useful for test writing and debugging.

Reviewers: #plasma, mart

Reviewed By: #plasma, mart

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D6161
parent 604b3ae3
......@@ -17,7 +17,6 @@ add_definitions(-DKDE_DEFAULT_DEBUG_AREA=1410)
add_subdirectory( data )
add_subdirectory( parser )
add_subdirectory( tests )
if ( WIN32 )
add_subdirectory( kdbgwin )
endif ()
......@@ -114,3 +113,7 @@ if (HAVE_X11)
endif()
install(TARGETS drkonqi DESTINATION ${KDE_INSTALL_LIBEXECDIR})
# Only go into tests once we have a drkonqi target so the tests can reference
# it.
add_subdirectory( tests )
......@@ -130,7 +130,7 @@ AboutBugReportingDialog::AboutBugReportingDialog(QWidget * parent):
"you "
"need to have an account on the KDE bug tracking system. If you do "
"not have one, you can create one here: <link>%1</link>",
QStringLiteral(KDE_BUGZILLA_CREATE_ACCOUNT_URL)),
KDE_BUGZILLA_CREATE_ACCOUNT_URL),
xi18nc("@info/rich","Then, enter your username and password and "
"press the Login button. You can use this login to directly access the "
"KDE bug tracking system later."),
......
......@@ -26,13 +26,12 @@ class BugReportAddress : public QString
public:
inline BugReportAddress() : QString() {}
inline BugReportAddress(const QString & address)
: QString(address == QLatin1String("submit@bugs.kde.org") ?
QLatin1String(KDE_BUGZILLA_URL) : address)
: QString(address == QLatin1String("submit@bugs.kde.org") ? KDE_BUGZILLA_URL : address)
{}
inline bool isKdeBugzilla() const
{
return *this == QLatin1String(KDE_BUGZILLA_URL);
return *this == KDE_BUGZILLA_URL;
}
inline bool isEmail() const
......
......@@ -104,6 +104,10 @@ bool CrashInformationPage::showNextPage()
BacktraceParser::Usefulness use =
DrKonqi::debuggerManager()->backtraceGenerator()->parser()->backtraceUsefulness();
if (DrKonqi::ignoreQuality()) {
return true;
}
if ((use == BacktraceParser::InvalidUsefulness || use == BacktraceParser::ProbablyUseless
|| use == BacktraceParser::Useless) && m_backtraceWidget->canInstallDebugPackages()) {
if ( KMessageBox::Yes == KMessageBox::questionYesNo(this,
......@@ -137,6 +141,8 @@ BugAwarenessPage::BugAwarenessPage(ReportAssistantDialog * parent)
DrKonqi::crashedApplication()->name()));
connect(ui.m_rememberGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &BugAwarenessPage::updateCheckBoxes);
// Also listen to toggle so radio buttons are covered.
connect(ui.m_rememberGroup, static_cast<void (QButtonGroup::*)(int, bool)>(&QButtonGroup::buttonToggled), this, &BugAwarenessPage::updateCheckBoxes);
ui.m_appSpecificDetailsExamples->setVisible(reportInterface()->appDetailsExamples()->hasExamples());
ui.m_appSpecificDetailsExamples->setContextMenuPolicy(Qt::NoContextMenu);
......@@ -309,7 +315,7 @@ void ConclusionPage::aboutToShow()
"Reporting Guide by clicking on the "
"<interface>Help</interface> button.</note>"));
//but this guide doesn't mention bt packages? that's techbase
//->>and the help guide mention techbase page...
//->>and the help guide mention techbase page...
}
break;
}
......
......@@ -59,7 +59,7 @@ static const char kWalletEntryName[] = "drkonqi_bugzilla";
static const char kWalletEntryUsername[] = "username";
static const char kWalletEntryPassword[] = "password";
static const char konquerorKWalletEntryName[] = KDE_BUGZILLA_URL "index.cgi#login";
static QString konquerorKWalletEntryName = KDE_BUGZILLA_URL + "index.cgi#login";
static const char konquerorKWalletEntryUsername[] = "Bugzilla_login";
static const char konquerorKWalletEntryPassword[] = "Bugzilla_password";
......@@ -102,7 +102,7 @@ BugzillaLoginPage::BugzillaLoginPage(ReportAssistantDialog * parent) :
"one, you can freely <link url='%2'>create one here</link>. "
"Please do not use disposable email accounts.</note>",
DrKonqi::crashedApplication()->bugReportAddress(),
QLatin1String(KDE_BUGZILLA_CREATE_ACCOUNT_URL)));
KDE_BUGZILLA_CREATE_ACCOUNT_URL));
}
bool BugzillaLoginPage::isComplete()
......@@ -202,7 +202,7 @@ void BugzillaLoginPage::walletLogin()
ui.m_passwordEdit->setText(password);
}
}
} else if (kWalletEntryExists(QLatin1String(konquerorKWalletEntryName))) {
} else if (kWalletEntryExists(konquerorKWalletEntryName)) {
//If the DrKonqi entry is empty, but a Konqueror entry exists, use and copy it.
openWallet();
if (m_wallet) {
......@@ -210,7 +210,7 @@ void BugzillaLoginPage::walletLogin()
//Fetch Konqueror data
QMap<QString, QString> values;
m_wallet->readMap(QLatin1String(konquerorKWalletEntryName), values);
m_wallet->readMap(konquerorKWalletEntryName, values);
QString username = values.value(QLatin1String(konquerorKWalletEntryUsername));
QString password = values.value(QLatin1String(konquerorKWalletEntryPassword));
......@@ -256,7 +256,7 @@ bool BugzillaLoginPage::canSetCookies()
QLatin1String("/modules/kcookiejar"),
QLatin1String("org.kde.KCookieServer"));
QDBusReply<QString> advice = kcookiejar.call(QLatin1String("getDomainAdvice"),
QLatin1String(KDE_BUGZILLA_URL));
KDE_BUGZILLA_URL);
if (!advice.isValid()) {
KMessageBox::error(this, i18n("Failed to communicate with KCookieServer."));
......@@ -279,9 +279,9 @@ bool BugzillaLoginPage::canSetCookies()
"to set cookies", "No, do not allow"));
if (KMessageBox::warningYesNo(this, msg, QString(), yesItem, noItem) == KMessageBox::Yes) {
QDBusReply<bool> success = kcookiejar.call(QLatin1String("setDomainAdvice"),
QLatin1String(KDE_BUGZILLA_URL),
QLatin1String("Accept"));
QDBusReply<bool> success = kcookiejar.call(QStringLiteral("setDomainAdvice"),
KDE_BUGZILLA_URL,
QStringLiteral("Accept"));
if (!success.isValid() || !success.value()) {
qWarning() << "Failed to set domain advice in KCookieServer";
return false;
......
......@@ -938,6 +938,11 @@ BugzillaReportConfirmationDialog::BugzillaReportConfirmationDialog(int bugNumber
connect(ui.buttonGroupProceed, SIGNAL(buttonClicked(int)), this, SLOT(checkProceed()));
connect(ui.buttonGroupProceedQuestion, SIGNAL(buttonClicked(int)), this, SLOT(checkProceed()));
// Also listen to toggle so radio buttons are covered.
connect(ui.buttonGroupProceed, static_cast<void (QButtonGroup::*)(int, bool)>(&QButtonGroup::buttonToggled),
this, &BugzillaReportConfirmationDialog::checkProceed);
connect(ui.buttonGroupProceedQuestion, static_cast<void (QButtonGroup::*)(int, bool)>(&QButtonGroup::buttonToggled),
this, &BugzillaReportConfirmationDialog::checkProceed);
if (!m_showProceedQuestion) {
ui.proceedLabel->setEnabled(false);
......
......@@ -54,7 +54,7 @@ ReportInterface::ReportInterface(QObject *parent)
}
void ReportInterface::setBugAwarenessPageData(bool rememberSituation,
Reproducible reproducible, bool actions,
Reproducible reproducible, bool actions,
bool unusual, bool configuration)
{
//Save the information the user can provide about the crash from the assistant page
......@@ -367,6 +367,10 @@ QStringList ReportInterface::relatedBugzillaProducts() const
bool ReportInterface::isWorthReporting() const
{
if (DrKonqi::ignoreQuality()) {
return true;
}
//Evaluate if the provided information is useful enough to enable the automatic report
bool needToReport = false;
......
......@@ -44,6 +44,9 @@
</item>
<item>
<widget class="QTextEdit" name="m_detailsEdit">
<property name="accessibleName">
<string>Information about the crash text</string>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
......
......@@ -48,6 +48,9 @@
</item>
<item row="1" column="1">
<widget class="KLineEdit" name="m_passwordEdit">
<property name="accessibleName">
<string>Password input</string>
</property>
<property name="trapEnterKeyEvent" stdset="0">
<bool>true</bool>
</property>
......@@ -58,6 +61,9 @@
</item>
<item row="0" column="1">
<widget class="KLineEdit" name="m_userEdit">
<property name="accessibleName">
<string>Username input</string>
</property>
<property name="trapEnterKeyEvent" stdset="0">
<bool>true</bool>
</property>
......
......@@ -327,3 +327,26 @@ int DrKonqi::thread()
{
return instance()->m_thread;
}
bool DrKonqi::ignoreQuality()
{
return qEnvironmentVariableIsSet("DRKONQI_IGNORE_QUALITY");
}
const QString &DrKonqi::kdeBugzillaURL()
{
// NB: for practical reasons this cannot use the shared instance. Initing the instances requires
// knowing the URL already, so we'd have an init loop. Use a local static instead.
static QString url;
if (!url.isEmpty()) {
return url;
}
url = QString::fromLocal8Bit(qgetenv("DRKONQI_KDE_BUGZILLA_URL"));
if (!url.isEmpty()) {
return url;
}
url = QStringLiteral("https://bugs.kde.org/");
return url;
}
......@@ -63,6 +63,8 @@ public:
static bool isRestarted();
static bool isKeepRunning();
static int thread();
static bool ignoreQuality();
static const QString &kdeBugzillaURL();
private:
DrKonqi();
......
......@@ -20,6 +20,8 @@
#include <KGuiItem>
#include <QIcon>
#include "drkonqi.h"
/** This class provides a custom constructor to fill the "toolTip"
* and "whatsThis" texts of KGuiItem with the same text.
*/
......@@ -31,8 +33,8 @@ public:
};
/* Urls are defined globally here, so that they can change easily */
#define KDE_BUGZILLA_URL "https://bugs.kde.org/"
#define KDE_BUGZILLA_CREATE_ACCOUNT_URL KDE_BUGZILLA_URL "createaccount.cgi"
#define KDE_BUGZILLA_URL DrKonqi::kdeBugzillaURL()
#define KDE_BUGZILLA_CREATE_ACCOUNT_URL KDE_BUGZILLA_URL + QStringLiteral("createaccount.cgi")
#define KDE_BUGZILLA_SHORT_URL "bugs.kde.org"
#define TECHBASE_HOWTO_DOC "https://community.kde.org/Guidelines_and_HOWTOs/Debugging/How_to_create_useful_crash_reports#Preparing_your_KDE_packages"
......
......@@ -42,8 +42,7 @@
#endif
static const char ABOUT_BUG_REPORTING_URL[] = "#aboutbugreporting";
static const char DRKONQI_REPORT_BUG_URL[] =
KDE_BUGZILLA_URL "enter_bug.cgi?product=drkonqi&format=guided";
static QString DRKONQI_REPORT_BUG_URL = KDE_BUGZILLA_URL + QStringLiteral("enter_bug.cgi?product=drkonqi&format=guided");
DrKonqiDialog::DrKonqiDialog(QWidget * parent) :
QDialog(parent),
......@@ -121,7 +120,7 @@ void DrKonqiDialog::buildIntroWidget()
"to the KDE bug tracking system. Do not forget to include "
"the backtrace from the <interface>Developer Information</interface> "
"tab.</para>",
QLatin1String(DRKONQI_REPORT_BUG_URL));
DRKONQI_REPORT_BUG_URL);
} else if (DrKonqi::isSafer()) {
reportMessage = xi18nc("@info", "<para>The reporting assistant is disabled because "
"the crash handler dialog was started in safe mode."
......@@ -279,7 +278,7 @@ void DrKonqiDialog::linkActivated(const QString& link)
{
if (link == QLatin1String(ABOUT_BUG_REPORTING_URL)) {
showAboutBugReporting();
} else if (link == QLatin1String(DRKONQI_REPORT_BUG_URL)) {
} else if (link == DRKONQI_REPORT_BUG_URL) {
QDesktopServices::openUrl(QUrl(link));
} else if (link.startsWith(QLatin1String("http"))) {
qWarning() << "unexpected link";
......
......@@ -100,6 +100,7 @@ int main(int argc, char* argv[])
QCommandLineOption keepRunningOption(QStringLiteral("keeprunning"), i18nc("@info:shell","Keep the program running and generate "
"the backtrace at startup"));
QCommandLineOption threadOption(QStringLiteral("thread"), i18nc("@info:shell","The <thread id> of the failing thread"), QStringLiteral("threadid"));
QCommandLineOption dialogOption(QStringLiteral("dialog"), i18nc("@info:shell","Do not show a notification but launch the debug dialog directly"));
parser.addOption(signalOption);
parser.addOption(appNameOption);
......@@ -114,6 +115,7 @@ int main(int argc, char* argv[])
parser.addOption(restartedOption);
parser.addOption(keepRunningOption);
parser.addOption(threadOption);
parser.addOption(dialogOption);
aboutData.setupCommandLine(&parser);
parser.process(qa);
......@@ -131,6 +133,7 @@ int main(int argc, char* argv[])
DrKonqi::setRestarted(parser.isSet(restartedOption));
DrKonqi::setKeepRunning(parser.isSet(keepRunningOption));
DrKonqi::setThread(parser.value(threadOption).toInt());
auto forceDialog = parser.isSet(dialogOption);
#if HAVE_X11
const QString startupId = parser.value(startupIdOption);
......@@ -156,7 +159,7 @@ int main(int argc, char* argv[])
// if no notification service is running (eg. shell crashed, or other desktop environment)
// and we didn't auto-restart the app, open DrKonqi dialog instead of showing an SNI
// and emitting a desktop notification
if (!restarted && !StatusNotifier::notificationServiceRegistered()) {
if (forceDialog || (!restarted && !StatusNotifier::notificationServiceRegistered())) {
openDrKonqiDialog();
} else {
StatusNotifier *statusNotifier = new StatusNotifier();
......
......@@ -3,3 +3,30 @@ add_subdirectory(backtraceparsertest)
if(KF5XmlRpcClient_FOUND)
add_subdirectory(bugzillalibtest)
endif()
if(NOT RUBY_EXECTUABLE)
find_program(RUBY_EXECTUABLE ruby)
endif()
if(RUBY_EXECUTABLE)
execute_process(COMMAND ${RUBY_EXECUTABLE} -e "require 'atspi'"
RESULT_VARIABLE RUBY_ATSPI)
execute_process(COMMAND ${RUBY_EXECUTABLE} -e "require 'xmlrpc/server'"
RESULT_VARIABLE RUBY_XMLRPC)
endif()
if(NOT XVFB_RUN_EXECTUABLE)
find_program(XVFB_RUN_EXECTUABLE xvfb-run)
endif()
if(NOT ATSPI_BUS_LAUNCHER_EXECUTABLE)
find_program(ATSPI_BUS_LAUNCHER_EXECUTABLE
NAMES at-spi-bus-launcher
PATHS /usr/lib/at-spi2-core/
DOC "AT-SPI accessibility dbus launcher")
endif()
if(RUBY_EXECUTABLE AND XVFB_RUN_EXECTUABLE AND ATSPI_BUS_LAUNCHER_EXECUTABLE
AND RUBY_ATSPI EQUAL 0 AND RUBY_XMLRPC EQUAL 0)
set(WITH_DRKONI_INTEGRATION_TESTING TRUE)
endif()
add_feature_info(DrKonqiIntegrationTesting WITH_DRKONI_INTEGRATION_TESTING
"Needs Ruby, functional atspi and xmlrpc gems, as well as xvfb-run.")
add_subdirectory(integration)
add_test(NAME drkonqi_integration_suite
COMMAND ${RUBY_EXECTUABLE}
${CMAKE_CURRENT_SOURCE_DIR}/suite
--drkonqi $<TARGET_FILE:drkonqi>
--at-spi-bus-launcher ${ATSPI_BUS_LAUNCHER_EXECUTABLE})
# Hack to get rb files to show in qtc.
file(GLOB RUBIES suite *.rb)
add_custom_target(Rubies ALL echo SOURCES ${RUBIES})
# Copyright (C) 2017 Harald Sitter <sitter@kde.org>
#
# 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) version 3 or any later version
# accepted by the membership of KDE e.V. (or its successor approved
# by the membership of KDE e.V.), which shall act as a proxy
# defined in Section 14 of version 3 of the license.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require_relative 'test_helper'
require 'xmlrpc/client'
require 'xmlrpc/server'
# Monkey patch the xmlrpc server to let us handle regular GET requests.
# Drkonqi partially goes through regular bugzilla cgi's simply requesting xml
# output.
module XMLServerInterceptor
# raw xml data is here
# def process(*args)
# warn "+++ #{__method__} +++"
# p args
# warn "--- #{__method__} ---"
# super
# end
def service(req, resp)
# Where webrick comes in with request, server rejects non-xmlrpc requests
# so we'll manually handle GET requests as necessary and forward to an
# actual bugzilla so we don't have to reimplement everything.
warn "+++ #{__method__} +++"
if req.request_method == 'GET'
if req.request_uri.path.include?('buglist.cgi') # Returns CSV.
resp.body = <<-EOF
bug_id,"bug_severity","priority","bug_status","product","short_desc","resolution"
375161,"crash","NOR","NEEDSINFO","dolphin","Dolphin crash, copy from Samba share","BACKTRACE"
EOF
return
end
if req.request_uri.path.include?('show_bug.cgi')
uri = req.request_uri.dup
uri.host = 'bugstest.kde.org'
uri.scheme = 'https'
uri.port = nil
resp.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, uri.to_s)
return
end
end
warn "--- #{__method__} ---"
super
end
end
class XMLRPC::Server
prepend XMLServerInterceptor
# Expose webrick server so we can get our port :|
# https://github.com/ruby/xmlrpc/issues/17
attr_accessor :server
end
class TestDuplicateAttach < ATSPITest
def setup
server = XMLRPC::Server.new(0)
port = server.server.config.fetch(:Port)
ENV['DRKONQI_KDE_BUGZILLA_URL'] = "http://localhost:#{port}/"
@got_comment = false
server.set_default_handler do |name, args|
puts '+++ handler +++'
p name, args
if name == 'User.login'
next {"id"=>12345, "token"=>"12345-cJ5o717AbC"}
end
if name == 'Bug.update'
id = args.fetch('ids').fetch(0)
cc_to_add = args.fetch('cc').fetch('add')
next {"bugs"=>[{"last_change_time"=>DateTime.now, "id"=>id, "changes"=>{"cc"=>{"removed"=>"", "added"=>cc_to_add}}, "alias"=>[]}]}
end
if name == 'Bug.add_attachment'
# Check for garbage string from test
@got_comment = args.fetch('comment').include?('yyyyyyyyyyyyyyyy')
next { "ids" => [1234] }
end
puts '~~~ bugzilla ~~~'
# Pipe request through bugstest.
# The arguments are killing me.
client = XMLRPC::Client.new('bugstest.kde.org', '/xmlrpc.cgi', 443,
nil, nil, nil, nil, true)
bugzilla = client.call(name, *args)
p bugzilla
next bugzilla
end
@xml_server_thread = Thread.start { server.serve }
@tracee = fork { loop { sleep(999_999_999) } }
assert File.exist?(DRKONQI_PATH), "drkonqi not at #{DRKONQI_PATH}"
# Will die with our Xephyr in case of errors.
pid = spawn("#{DRKONQI_PATH} --signal 11 --pid #{@tracee} --bugaddress submit@bugs.kde.org --dialog")
sleep 4 # Grace to give time to appear on at-spi
assert_nil Process.waitpid(pid, Process::WNOHANG),
'drkonqi failed to start or died'
end
def teardown
Process.kill('KILL', @tracee)
Process.waitpid2(@tracee)
@xml_server_thread.kill
@xml_server_thread.join
end
# When evaluating duplicates
def test_duplicate_attach
drkonqi = ATSPI.desktops[0].applications.find { |x| x.name == 'drkonqi' }
refute_nil drkonqi
accessible = find_in(drkonqi.windows[-1], name: 'Report Bug')
press(accessible)
find_in(drkonqi, name: 'Crash Reporting Assistant') do |window|
accessible = find_in(window, name: 'Next')
press(accessible)
accessible = find_in(window, name: 'Yes')
toggle_on(accessible)
accessible = find_in(window, name: /^What I was doing when the application.+/)
toggle_on(accessible)
accessible = find_in(window, name: 'Next')
press(accessible)
loop do
# Drkonqi is now doing the trace, wait until it is done.
accessible = find_in(window, name: 'Next')
refute_nil accessible
if accessible.states.include?(:sensitive)
press(accessible)
break
end
warn accessible.states
sleep 2
end
# Set pseudo login data if there are none.
accessible = find_in(window, name: 'Username input')
accessible.text.set_to 'xxx' if accessible.text.length <= 0
accessible = find_in(window, name: 'Password input')
accessible.text.set_to 'yyy' if accessible.text.length <= 0
accessible = find_in(window, name: 'Login')
press(accessible)
sleep 2 # Wait for login and bug listing
accessible = find_in(window, name: '375161')
toggle_on(accessible)
accessible = find_in(window, name: 'Open selected report')
press(accessible)
end
find_in(drkonqi, name: 'Bug Description') do |window|
accessible = find_in(window, name: 'Suggest this crash is related')
press(accessible)
end
find_in(drkonqi, name: 'Related Bug Report') do |window|
accessible = find_in(window, name: /^Completely sure: attach my information.+/)
toggle_on(accessible)
accessible = find_in(window, name: 'Continue')
press(accessible)
end
find_in(drkonqi, name: 'Crash Reporting Assistant') do |window|
accessible = find_in(window, name: /^The report is going to be attached.+/)
refute_nil accessible
accessible = find_in(window, name: 'Next')
press(accessible)
accessible = find_in(window, name: 'Information about the crash text')
accessible.text.set_to(accessible.text.to_s +
Array.new(128).collect { 'y' }.join)
accessible = find_in(window, name: 'Next')
press(accessible)
accessible = find_in(window, name: 'Next')
press(accessible)
accessible = find_in(window, name: /.*Crash report sent.*/)
refute_nil accessible
accessible = find_in(window, name: 'Finish')
press(accessible)
end
assert @got_comment # only true iff the server go tour yyyyyy garbage string
end
end
#!/usr/bin/env ruby
#
# Copyright (C) 2017 Harald Sitter <sitter@kde.org>
#
# 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) version 3 or any later version
# accepted by the membership of KDE e.V. (or its successor approved
# by the membership of KDE e.V.), which shall act as a proxy
# defined in Section 14 of version 3 of the license.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
require 'fileutils'
require 'optparse'
require 'tmpdir'
# Isolates GUI via xephyr
class XephyrIsolator
def run(cmd)
ephemeral('Xephyr -screen 1024x768x24+32 :666') do
ENV['DISPLAY'] = ':666'
system(cmd) || raise
end
end
private
def ephemeral(*args)
pid = spawn(*args)
yield
ensure
Process.kill('KILL', pid) if pid
Process.waitpid2(pid) if pid
end
end
# Isolates GUI via xvfb-run
class XvfbIsolator
def run(cmd)
system("xvfb-run -a --server-args=\"-screen 0 1024x768x24\" #{cmd}") || raise
end
end
OptionParser.new do |opts|
opts.banner = "Usage: #{$0} ARGS"
opts.separator('')
opts.on('--drkonqi PATH', 'Path to drkonqi bin to test.') do |v|
ENV['DRKONQI_PATH'] = v
end
opts.on('--at-spi-bus-launcher PATH',
'Path to --at-spi-bus-launcher bin to use for testing.') do |v|
ENV['AT_SPI_BUS_LAUNCHER_PATH'] = v
end
end.parse!
ENV['DRKONQI_PATH'] ||= '/usr/lib/x86_64-linux-gnu/libexec/drkonqi'
ENV['AT_SPI_BUS_LAUNCHER_PATH'] ||= '/usr/lib/at-spi2-core/at-spi-bus-launcher'
# Isolate ourselves by forcing into a separate home and unsetting the XDG path
# variables. Then spin up a suitable virtual X, run a new dbus session bus
# and our test in that environment.
Dir.mktmpdir do |tmpdir|
ENV['HOME'] = tmpdir
ENV.keys.each { |k| ENV.delete(k) if k.start_with?('XDG_') }
Dir.glob("#{__dir__}/*_test.rb").each do |test|
isolator = ENV['XEPHYR'] ? XephyrIsolator.new : XvfbIsolator.new
isolator.run("dbus-run-session -- ruby #{test} -p")
end
sleep 8 # Wait a bit to make sure all children are dead.
end
# Copyright (C) 2017 Harald Sitter <sitter@kde.org>
#
# 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) version 3 or any later version
# accepted by the membership of KDE e.V. (or its successor approved
# by the membership of KDE e.V.), which shall act as a proxy
# defined in Section 14 of version 3 of the license.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License