Commit 0197de16 authored by Peter Hutterer's avatar Peter Hutterer
Browse files

xserver: install default X error handler



Xlib's default error handler prints the error and calls exit(1). Tests that
accidentally trigger an error thus quit without cleaning up properly.

Install a default error handler that prints the basic info and continue with
the test. Clients that expect to trigger errors should set a custom error
handler.
Signed-off-by: Peter Hutterer's avatarPeter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Chase Douglas's avatarChase Douglas <chase.douglas@ubuntu.com>
parent c29171c4
......@@ -265,6 +265,19 @@ class XServer : public xorg::testing::Process {
*/
static void RegisterXIOErrorHandler();
/**
* Install a default XErrorHandler. That error handler will cause a test
* failure if called.
*
* This function is called automatically by XServer::Start(). Usually,
* you will not need to call this function unless your test does not
* instantiate and Start() an XServer object.
*
* This function will only install a new error handler if the currently
* installed XErrorHandler is not the default handler used by Xlib.
*/
static void RegisterXErrorHandler();
private:
struct Private;
std::auto_ptr<Private> d_;
......
......@@ -394,6 +394,40 @@ const std::string& xorg::testing::XServer::GetVersion(void) {
return d_->version;
}
static int _x_error_handler(Display *dpy, XErrorEvent *err)
{
std::stringstream error;
switch(err->error_code) {
case BadRequest: error << "BadRequest"; break;
case BadValue: error << "BadValue"; break;
case BadWindow: error << "BadWindow"; break;
case BadPixmap: error << "BadPixmap"; break;
case BadAtom: error << "BadAtom"; break;
case BadCursor: error << "BadCursor"; break;
case BadFont: error << "BadFont"; break;
case BadMatch: error << "BadMatch"; break;
case BadDrawable: error << "BadDrawable"; break;
case BadAccess: error << "BadAccess"; break;
case BadAlloc: error << "BadAlloc"; break;
case BadColor: error << "BadColor"; break;
case BadGC: error << "BadGC"; break;
case BadIDChoice: error << "BadIDChoice"; break;
case BadName: error << "BadName"; break;
case BadLength: error << "BadLength"; break;
case BadImplementation: error << "BadImplementation"; break;
default:
error << err->error_code;
break;
}
ADD_FAILURE() << "XError received: " << error.str() << ", request " <<
(int)err->request_code << "(" << (int)err->minor_code << "), detail: "
<< err->resourceid << "\nThis error handler is likely to be triggered "
"more than once.\nCheck the first error for the real error";
return 0;
}
static int _x_io_error_handler(Display *dpy) _X_NORETURN;
static int _x_io_error_handler(Display *dpy)
{
......@@ -409,6 +443,15 @@ void xorg::testing::XServer::RegisterXIOErrorHandler()
XSetIOErrorHandler(old_handler);
}
void xorg::testing::XServer::RegisterXErrorHandler()
{
XErrorHandler old_handler;
old_handler = XSetErrorHandler(_x_error_handler);
if (old_handler != _XDefaultError)
XSetErrorHandler(old_handler);
}
void xorg::testing::XServer::Start(const std::string &program) {
TestStartup();
......@@ -494,6 +537,7 @@ void xorg::testing::XServer::Start(const std::string &program) {
signal(SIGUSR1 ,SIG_IGN);
RegisterXIOErrorHandler();
RegisterXErrorHandler();
}
bool xorg::testing::XServer::Terminate(unsigned int timeout) {
......
......@@ -6,6 +6,7 @@
#include <stdexcept>
#include <xorg/gtest/xorg-gtest.h>
#include <gtest/gtest-spi.h>
#include <X11/extensions/XInput2.h>
using namespace xorg::testing;
......@@ -213,6 +214,78 @@ TEST(XServer, IOErrorException)
}, XIOError);
}
TEST(XServer, ErrorHandler)
{
XORG_TESTCASE("Start a server, trigger a BadColor error and expect a "
"failure from the default error handler\n");
pid_t pid = fork();
if (pid == 0) {
EXPECT_NONFATAL_FAILURE({
XServer server;
server.SetOption("-logfile", LOGFILE_DIR "/xorg-error-handler-test.log");
server.SetOption("-config", DUMMY_CONF_PATH);
server.SetOption("-noreset", "");
server.Start();
ASSERT_EQ(server.GetState(), Process::RUNNING);
::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str());
ASSERT_TRUE(dpy != NULL);
XColor color;
XQueryColor(dpy, 0, &color);
XSync(dpy, False);
}, "BadColor");
exit(0);
}
/* if the Xlib default error handler triggers, child calls exit(1) */
int status;
ASSERT_EQ(waitpid(pid, &status, 0), pid);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(WEXITSTATUS(status), 0);
}
static bool error_handler_triggered = false;
static int _test_error_handler(Display *dpy, XErrorEvent *error) {
error_handler_triggered = true;
if (error->error_code != BadColor)
ADD_FAILURE() << "Error handler triggered with wrong error code\n";
return 0;
}
TEST(XServer, NondefaultErrorHandler)
{
XORG_TESTCASE("Set a custom error handler, start a server, trigger a "
"BadColor error and expect the custom error handler to be "
"triggered\n");
pid_t pid = fork();
if (pid == 0) {
XSetErrorHandler(_test_error_handler);
XServer server;
server.SetOption("-logfile", LOGFILE_DIR "/xorg-error-handler-test.log");
server.SetOption("-config", DUMMY_CONF_PATH);
server.SetOption("-noreset", "");
server.Start();
ASSERT_EQ(server.GetState(), Process::RUNNING);
::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str());
ASSERT_TRUE(dpy != NULL);
XColor color;
XQueryColor(dpy, 0, &color);
XSync(dpy, False);
exit(error_handler_triggered ? 0 : 1);
}
/* if the Xlib default error handler triggers, child calls exit(1) */
int status;
ASSERT_EQ(waitpid(pid, &status, 0), pid);
ASSERT_TRUE(WIFEXITED(status));
ASSERT_EQ(WEXITSTATUS(status), 0);
}
TEST(XServer, KeepAlive)
{
XORG_TESTCASE("If XORG_GTEST_XSERVER_KEEPALIVE is set,\n"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment