summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/xorg/gtest/xorg-gtest-xserver.h34
-rw-r--r--src/xserver.cpp17
-rw-r--r--test/xserver-test.cpp17
3 files changed, 68 insertions, 0 deletions
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();