diff options
-rw-r--r-- | include/xorg/gtest/xorg-gtest-xserver.h | 34 | ||||
-rw-r--r-- | src/xserver.cpp | 17 | ||||
-rw-r--r-- | test/xserver-test.cpp | 17 |
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(); |