Merge lp:~alan-griffiths/miral/first-cut-at-test-server into lp:miral

Proposed by Alan Griffiths
Status: Merged
Approved by: Gerry Boland
Approved revision: 271
Merged at revision: 272
Proposed branch: lp:~alan-griffiths/miral/first-cut-at-test-server
Merge into: lp:miral
Diff against target: 245 lines (+225/-0)
3 files modified
test/CMakeLists.txt (+1/-0)
test/test_server.cpp (+154/-0)
test/test_server.h (+70/-0)
To merge this branch: bzr merge lp:~alan-griffiths/miral/first-cut-at-test-server
Reviewer Review Type Date Requested Status
Gerry Boland (community) Approve
Review via email: mp+302677@code.launchpad.net

Commit message

Add a TestServer fixture for writing miral tests

Description of the change

Add a TestServer fixture for writing miral tests

Prerequisite for writing further tests of miral

To post a comment you must log in.
271. By Alan Griffiths

Don't report startup until after init

Revision history for this message
Gerry Boland (gerboland) wrote :

The mir test framework has a bunch of test servers, why is this needed? Isn't the HeadlessTestServer enough?

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> The mir test framework has a bunch of test servers, why is this needed? Isn't
> the HeadlessTestServer enough?

The objective is to enable tests of the MirAL infrastructure.

A lot of the logic is similar to HeadlessTestServer, but it uses the MirAL infrastructure (MirRunner et alia) to start the server. Once we start to consolidate the MirAL work with Mir there will be opportunities to simplify.

Revision history for this message
Gerry Boland (gerboland) wrote :

ok, looks reasonable

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'test/CMakeLists.txt'
2--- test/CMakeLists.txt 2016-08-02 09:05:46 +0000
3+++ test/CMakeLists.txt 2016-08-11 15:06:12 +0000
4@@ -9,6 +9,7 @@
5 add_executable(miral-test
6 mru_window_list.cpp
7 active_outputs.cpp
8+ test_server.cpp test_server.h
9 )
10
11 target_link_libraries(miral-test
12
13=== added file 'test/test_server.cpp'
14--- test/test_server.cpp 1970-01-01 00:00:00 +0000
15+++ test/test_server.cpp 2016-08-11 15:06:12 +0000
16@@ -0,0 +1,154 @@
17+/*
18+ * Copyright © 2016 Canonical Ltd.
19+ *
20+ * This program is free software: you can redistribute it and/or modify it
21+ * under the terms of the GNU General Public License version 3,
22+ * as published by the Free Software Foundation.
23+ *
24+ * This program is distributed in the hope that it will be useful,
25+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+ * GNU General Public License for more details.
28+ *
29+ * You should have received a copy of the GNU General Public License
30+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
31+ *
32+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
33+ */
34+
35+#include "test_server.h"
36+
37+#include <miral/canonical_window_manager.h>
38+#include <miral/set_window_managment_policy.h>
39+
40+#include <mir_test_framework/executable_path.h>
41+#include "mir_test_framework/stub_server_platform_factory.h"
42+
43+#include <mir/fd.h>
44+#include <mir/main_loop.h>
45+#include <mir/server.h>
46+#include <mir/version.h>
47+
48+#include <boost/throw_exception.hpp>
49+
50+
51+using namespace miral;
52+using namespace testing;
53+namespace mtf = mir_test_framework;
54+
55+namespace
56+{
57+std::chrono::seconds const timeout{20};
58+char const* dummy_args[2] = { "TestServer", nullptr };
59+}
60+
61+miral::TestServer::TestServer() :
62+ runner{1, dummy_args}
63+{
64+ add_to_environment("MIR_SERVER_PLATFORM_GRAPHICS_LIB", mtf::server_platform("graphics-dummy.so").c_str());
65+ add_to_environment("MIR_SERVER_PLATFORM_INPUT_LIB", mtf::server_platform("input-stub.so").c_str());
66+}
67+
68+void miral::TestServer::SetUp()
69+{
70+#if MIR_SERVER_VERSION < MIR_VERSION_NUMBER(0, 25, 0)
71+ mtf::set_next_preset_display({}); // Workaround for lp:1611337
72+#endif
73+
74+ mir::test::AutoJoinThread t([this]
75+ {
76+ auto init = [this](mir::Server& server)
77+ {
78+ server.add_init_callback([&]
79+ {
80+ auto const main_loop = server.the_main_loop();
81+ // By enqueuing the notification code in the main loop, we are
82+ // ensuring that the server has really and fully started before
83+ // leaving start_mir_server().
84+ main_loop->enqueue(this, [&]
85+ {
86+ std::lock_guard<std::mutex> lock(mutex);
87+ server_running = &server;
88+ started.notify_one();
89+ });
90+ });
91+ };
92+
93+ try
94+ {
95+ runner.run_with({init, set_window_managment_policy<TestWindowManagerPolicy>(*this)});
96+ }
97+ catch (std::exception const& e)
98+ {
99+ FAIL() << e.what();
100+ }
101+
102+ std::lock_guard<std::mutex> lock(mutex);
103+ server_running = nullptr;
104+ started.notify_one();
105+ });
106+
107+ std::unique_lock<std::mutex> lock(mutex);
108+ started.wait_for(lock, timeout, [&] { return server_running; });
109+
110+ if (!server_running)
111+ BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to start server thread"});
112+
113+ server_thread = std::move(t);
114+}
115+
116+void miral::TestServer::TearDown()
117+{
118+ std::unique_lock<std::mutex> lock(mutex);
119+
120+ if (server_running)
121+ server_running->stop();
122+
123+ started.wait_for(lock, timeout, [&] { return !server_running; });
124+
125+ if (server_running)
126+ BOOST_THROW_EXCEPTION(std::logic_error{"Failed to stop server"});
127+
128+ server_thread.stop();
129+}
130+
131+auto miral::TestServer::connect_client(std::string name) -> toolkit::Connection
132+{
133+ std::lock_guard<std::mutex> lock(mutex);
134+
135+ if (!server_running)
136+ BOOST_THROW_EXCEPTION(std::runtime_error{"Server not running"});
137+
138+ char connect_string[64] = {0};
139+ sprintf(connect_string, "fd://%d", dup(server_running->open_client_socket()));
140+
141+ return toolkit::Connection{mir_connect_sync(connect_string, name.c_str())};
142+}
143+
144+void miral::TestRuntimeEnvironment::add_to_environment(char const* key, char const* value)
145+{
146+ env.emplace_back(key, value);
147+}
148+
149+struct miral::TestServer::TestWindowManagerPolicy : CanonicalWindowManagerPolicy
150+{
151+ TestWindowManagerPolicy(WindowManagerTools const& tools, TestServer& test_fixture) :
152+ CanonicalWindowManagerPolicy{tools}
153+ {
154+ test_fixture.tools = tools;
155+ }
156+
157+ bool handle_keyboard_event(MirKeyboardEvent const*) override { return false; }
158+ bool handle_pointer_event(MirPointerEvent const*) override { return false; }
159+ bool handle_touch_event(MirTouchEvent const*) override { return false; }
160+};
161+
162+using miral::TestServer;
163+
164+// Minimal test to ensure the server runs and exits
165+TEST_F(TestServer, connect_client_works)
166+{
167+ auto const connection = connect_client(__PRETTY_FUNCTION__);
168+
169+ EXPECT_TRUE(mir_connection_is_valid(connection));
170+}
171
172=== added file 'test/test_server.h'
173--- test/test_server.h 1970-01-01 00:00:00 +0000
174+++ test/test_server.h 2016-08-11 15:06:12 +0000
175@@ -0,0 +1,70 @@
176+/*
177+ * Copyright © 2016 Canonical Ltd.
178+ *
179+ * This program is free software: you can redistribute it and/or modify it
180+ * under the terms of the GNU General Public License version 3,
181+ * as published by the Free Software Foundation.
182+ *
183+ * This program is distributed in the hope that it will be useful,
184+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
185+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
186+ * GNU General Public License for more details.
187+ *
188+ * You should have received a copy of the GNU General Public License
189+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
190+ *
191+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
192+ */
193+
194+#ifndef MIRAL_TEST_SERVER_H
195+#define MIRAL_TEST_SERVER_H
196+
197+#include <miral/toolkit/connection.h>
198+
199+#include <miral/runner.h>
200+#include <miral/window_manager_tools.h>
201+
202+#include <mir/test/auto_unblock_thread.h>
203+#include <mir_test_framework/temporary_environment_value.h>
204+
205+#include <gtest/gtest.h>
206+
207+#include <condition_variable>
208+#include <list>
209+#include <mutex>
210+
211+namespace miral
212+{
213+class TestRuntimeEnvironment
214+{
215+public:
216+ void add_to_environment(char const* key, char const* value);
217+
218+private:
219+ std::list<mir_test_framework::TemporaryEnvironmentValue> env;
220+};
221+
222+struct TestServer : testing::Test, private TestRuntimeEnvironment
223+{
224+ TestServer();
225+
226+ void SetUp() override;
227+ void TearDown() override;
228+
229+ auto connect_client(std::string name) -> toolkit::Connection;
230+
231+ using TestRuntimeEnvironment::add_to_environment;
232+ WindowManagerTools tools{nullptr};
233+
234+private:
235+ struct TestWindowManagerPolicy;
236+
237+ MirRunner runner;
238+ mir::test::AutoJoinThread server_thread;
239+ std::mutex mutex;
240+ std::condition_variable started;
241+ mir::Server* server_running{nullptr};
242+};
243+}
244+
245+#endif //MIRAL_TEST_SERVER_H

Subscribers

People subscribed via source and target branches