[PATCH xorg-gtest 2/2] xserver: install default X error handler
Peter Hutterer
peter.hutterer at who-t.net
Tue Nov 6 19:57:20 PST 2012
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 <peter.hutterer at who-t.net>
---
include/xorg/gtest/xorg-gtest-xserver.h | 13 ++++++
src/xserver.cpp | 54 +++++++++++++++++++++++-
test/xserver-test.cpp | 73 +++++++++++++++++++++++++++++++++
3 files changed, 139 insertions(+), 1 deletion(-)
diff --git a/include/xorg/gtest/xorg-gtest-xserver.h b/include/xorg/gtest/xorg-gtest-xserver.h
index 8bf7996..11fc93d 100644
--- a/include/xorg/gtest/xorg-gtest-xserver.h
+++ b/include/xorg/gtest/xorg-gtest-xserver.h
@@ -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_;
diff --git a/src/xserver.cpp b/src/xserver.cpp
index ad018a1..4faa8e9 100644
--- a/src/xserver.cpp
+++ b/src/xserver.cpp
@@ -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();
@@ -464,7 +507,15 @@ void xorg::testing::XServer::Start(const std::string &program) {
args.push_back(it->second);
}
- Process::Start(program.empty() ? d_->path_to_server : program, args);
+ std::string server_binary = program.empty() ? d_->path_to_server : program;
+
+ if (getenv("XORG_GTEST_XSERVER_USE_VALGRIND")) {
+ args.insert(args.begin(), server_binary);
+ server_binary = "valgrind";
+ args.insert(args.begin(), "--leak-check=full");
+ }
+
+ Process::Start(server_binary, args);
/* noreturn */
}
@@ -494,6 +545,7 @@ void xorg::testing::XServer::Start(const std::string &program) {
signal(SIGUSR1 ,SIG_IGN);
RegisterXIOErrorHandler();
+ RegisterXErrorHandler();
}
bool xorg::testing::XServer::Terminate(unsigned int timeout) {
diff --git a/test/xserver-test.cpp b/test/xserver-test.cpp
index cdf0bd9..32792e6 100644
--- a/test/xserver-test.cpp
+++ b/test/xserver-test.cpp
@@ -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"
--
1.7.11.7
More information about the xorg-devel
mailing list