[PATCH xorg-gtest] xserver: add default X IO error handler

Peter Hutterer peter.hutterer at who-t.net
Tue Oct 16 20:15:33 PDT 2012


Once a server is started, set the X IO error handler to throw an exception.
This way our test cases will survive a server crash and googletest will just
continue with the next test case instead of exiting the process completely.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 include/xorg/gtest/xorg-gtest-xserver.h | 34 +++++++++++++++++++++++++++++++++
 src/xserver.cpp                         | 17 +++++++++++++++++
 test/xserver-test.cpp                   | 17 +++++++++++++++++
 3 files changed, 68 insertions(+)

diff --git a/include/xorg/gtest/xorg-gtest-xserver.h b/include/xorg/gtest/xorg-gtest-xserver.h
index 8721b94..623e672 100644
--- a/include/xorg/gtest/xorg-gtest-xserver.h
+++ b/include/xorg/gtest/xorg-gtest-xserver.h
@@ -33,11 +33,29 @@
 #include <gtest/gtest.h>
 #include <xorg/gtest/xorg-gtest.h>
 #include <X11/Xlib.h>
+#include <stdexcept>
 
 namespace xorg {
 namespace testing {
 
 /**
+ * @class XIOError
+ *
+ * Exception thrown if the display connection encounters an IO error and
+ * calls the XIOErrorHandler function.
+ *
+ * This exception requires an XIOErrorHandler to be registered.
+ * XServer::Start() will register this error handler. For tests that do not
+ * use the provided XServer object, call XServer::RegisterXIOErrorHandler()
+ * instead.
+ */
+class XIOError : public std::runtime_error {
+public:
+  /** Create a new XIOError with the given message */
+  XIOError(const std::string& msg) : std::runtime_error(msg) {}
+};
+
+/**
  * @class XServer xorg-gtest-xserver.h xorg/gtest/xorg-gtest-xserver.h
  *
  * Class representing the X server process.
@@ -55,6 +73,9 @@ namespace testing {
  *     std::cerr << "Problem killing server" << std::endl;
  * }
  * @endcode
+ *
+ * Once a XServer is started, a default XIOErrorHandler is installed and
+ * subsequent IO errors on the display connection will throw an XIOError.
  */
 class XServer : public xorg::testing::Process {
   public:
@@ -221,6 +242,19 @@ class XServer : public xorg::testing::Process {
      */
     static bool WaitForEventOfType(::Display *display, int type, int extension, int evtype, time_t timeout = 1000);
 
+    /**
+     * Install a default XIOErrorHandler. That error handler will throw an
+     * xorg::testing::XIOError when encountered.
+     *
+     * 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 XIOErrorHandler is not the default handler used by Xlib.
+     */
+    static void RegisterXIOErrorHandler();
+
   private:
     struct Private;
     std::auto_ptr<Private> d_;
diff --git a/src/xserver.cpp b/src/xserver.cpp
index 1ba4e08..1ff8ee8 100644
--- a/src/xserver.cpp
+++ b/src/xserver.cpp
@@ -45,6 +45,7 @@
 #include <fstream>
 
 #include <X11/Xlib.h>
+#include <X11/Xlibint.h>
 #include <X11/extensions/XInput2.h>
 
 struct xorg::testing::XServer::Private {
@@ -295,6 +296,20 @@ const std::string& xorg::testing::XServer::GetVersion(void) {
   return d_->version;
 }
 
+static int _x_io_error_handler(Display *dpy)
+{
+  throw xorg::testing::XIOError("Connection to X Server lost. Possible server crash.");
+}
+
+void xorg::testing::XServer::RegisterXIOErrorHandler()
+{
+  XIOErrorHandler old_handler;
+  old_handler = XSetIOErrorHandler(_x_io_error_handler);
+
+  if (old_handler != _XDefaultIOError)
+    XSetIOErrorHandler(old_handler);
+}
+
 void xorg::testing::XServer::Start(const std::string &program) {
   TestStartup();
 
@@ -351,6 +366,8 @@ void xorg::testing::XServer::Start(const std::string &program) {
   sigemptyset(&sig_mask);
   sigaddset(&sig_mask, SIGCHLD);
   sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
+
+  RegisterXIOErrorHandler();
 }
 
 bool xorg::testing::XServer::Terminate(unsigned int timeout) {
diff --git a/test/xserver-test.cpp b/test/xserver-test.cpp
index 5faa6ca..b50b181 100644
--- a/test/xserver-test.cpp
+++ b/test/xserver-test.cpp
@@ -3,6 +3,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <fstream>
+#include <stdexcept>
 
 #include <xorg/gtest/xorg-gtest.h>
 
@@ -71,6 +72,22 @@ TEST(XServer, WaitForSIGUSR1)
   }
 }
 
+TEST(XServer, IOErrorException)
+{
+  ASSERT_THROW({
+  XServer server;
+  server.SetOption("-logfile", "/tmp/xorg-io-error-test.log");
+  server.SetOption("-noreset", "");
+  server.Start();
+  ASSERT_EQ(server.GetState(), Process::RUNNING);
+  ::Display *dpy = XOpenDisplay(server.GetDisplayString().c_str());
+  ASSERT_TRUE(dpy != NULL);
+  close(ConnectionNumber(dpy));
+  XSync(dpy, False);
+  }, XIOError);
+}
+
+
 int main(int argc, char *argv[]) {
   testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
-- 
1.7.11.4



More information about the xorg-devel mailing list