Mir

Merge lp:~alan-griffiths/mir/some-acceptance-tests-use-mir-Server-API into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: 2007
Merged at revision: 2009
Proposed branch: lp:~alan-griffiths/mir/some-acceptance-tests-use-mir-Server-API
Merge into: lp:mir
Prerequisite: lp:~alan-griffiths/mir/Migrate-ServerConfigurationWrapping-to-Server-API
Diff against target: 678 lines (+387/-84)
12 files modified
include/server/mir/server.h (+21/-1)
server-ABI-sha1sums (+1/-1)
src/server/server.cpp (+63/-0)
src/server/symbols.map (+1/-0)
tests/acceptance-tests/server_configuration_wrapping.cpp (+3/-41)
tests/acceptance-tests/test_client_library.cpp (+21/-6)
tests/include/mir_test_framework/headless_test.h (+71/-0)
tests/include/mir_test_framework/temporary_environment_value.h (+41/-0)
tests/mir_test_framework/CMakeLists.txt (+2/-0)
tests/mir_test_framework/headless_test.cpp (+113/-0)
tests/mir_test_framework/temporary_environment_value.cpp (+42/-0)
tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp (+8/-35)
To merge this branch: bzr merge lp:~alan-griffiths/mir/some-acceptance-tests-use-mir-Server-API
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Kevin DuBois (community) Approve
Alberto Aguirre (community) Approve
Andreas Pokorny (community) Approve
Alexandros Frantzis (community) Needs Fixing
Review via email: mp+239406@code.launchpad.net

Commit message

test: Move another of the acceptance test suites [ClientLibrary.*] to the mir::Server based API

Description of the change

test: Move another of the acceptance test suites [ClientLibrary.*] to the mir::Server based API

It cleans up the "AcceptanceTest" fixture from the prerequisite branch and introduces "HeadlessTest".

There's a similar "debt" with a new HeadlessInProcessServer fixtures and some ugly code in mir::Server that should evolve as the requirements of additional tests are addressed.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> typedef std::function<void(std::shared_ptr<frontend::Session> const& session)> ConnectHandler;

using ConnectHandler = ... , it's more consistent with other type definitions in the class.

> auto open_client_socket() -> int;

Although testing is a valid driver of the API, I am a bit skeptical of exposing functionality for tests only, since doing so may occasionally compromise the focus of the API, expose internals etc. This particular change seems OK, though, and if we want to provide such functionality we should also provide the same stability guarantees as we do for the "normal" public API (and stability should be an important factor in deciding whether we want a test-only method appear in the public API).

Needs fixing for the typedef.

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

> > typedef std::function<void(std::shared_ptr<frontend::Session> const&
> session)> ConnectHandler;
>
> using ConnectHandler = ... , it's more consistent with other type definitions
> in the class.

Fixed

> > auto open_client_socket() -> int;
>
> Although testing is a valid driver of the API, I am a bit skeptical of
> exposing functionality for tests only, since doing so may occasionally
> compromise the focus of the API, expose internals etc.

I totally agree. Although in the case of acceptance tests these should ideally be written in terms of the API.

Where acceptance tests need something other than the API exposes there should a clear distinction in the way such features are invoked.

> This particular change
> seems OK, though, and if we want to provide such functionality we should also
> provide the same stability guarantees as we do for the "normal" public API
> (and stability should be an important factor in deciding whether we want a
> test-only method appear in the public API).

I gave some thought to this and concluded supporting the test this way gives a potentially useful API: we don't always want to expose an endpoint on the filesystem for clients to use (doing so is a long standing issue with unity-system-compositor). It also allows a server to start in process "clients" using the normal client API.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

27 + auto open_client_socket() -> int;
Given the api, I'd assume that I own the returned fd after calling this function, but it would be a bit more clear if it returned a mir::Fd.

Otherwise, I'm persuaded that this can solve help solve the endpoint-on-filesystem and think its useful.

review: Needs Fixing
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

+1 for mir::Fd

looks good otherwise

Revision history for this message
Andreas Pokorny (andreas-pokorny) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

LGTM

review: Approve
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

The "needs fixing" items from the other 2 reviewers have been addressed so TA'ing.

Revision history for this message
Kevin DuBois (kdub) wrote :

looks good to me

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

[ FAILED ] 17 tests, listed below:
[ FAILED ] AvailableSurfaceFormatsTest.surface_pixel_formats_reach_client
[ FAILED ] SurfaceFirstFrameSync.surface_not_rendered_until_buffer_is_pushed
[ FAILED ] SwapIntervalSignalTest.swapinterval_test
[ FAILED ] ServerShutdown.server_can_shut_down_when_clients_are_blocked
[ FAILED ] SessionMediatorReport.session_connect_called
[ FAILED ] SessionMediatorReport.session_create_surface_called
[ FAILED ] SessionMediatorReport.session_next_buffer_called
[ FAILED ] SessionMediatorReport.session_exchange_buffer_called
[ FAILED ] SessionMediatorReport.session_release_surface_called
[ FAILED ] SessionMediatorReport.session_disconnect_called
[ FAILED ] SessionMediatorReport.prompt_session_start_called
[ FAILED ] SessionMediatorReport.prompt_session_stop_called
[ FAILED ] Process.a_main_fn_is_executed
[ FAILED ] Process.a_successful_exit_function_succeeds
[ FAILED ] BespokeDisplayServerTestFixture.starting_display_server_starts_input_manager
[ FAILED ] BespokeDisplayServerTestFixture.client_drm_auth_magic_calls_platform
[ FAILED ] BespokeDisplayServerTestFixture.drm_auth_magic_platform_error_reaches_client

WOW! (Not related AFAICS - those are integration tests I've not touched)

Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/server.h'
2--- include/server/mir/server.h 2014-10-24 13:39:38 +0000
3+++ include/server/mir/server.h 2014-10-28 09:41:16 +0000
4@@ -19,13 +19,15 @@
5 #ifndef MIR_SERVER_H_
6 #define MIR_SERVER_H_
7
8+#include "mir/fd.h"
9+
10 #include <functional>
11 #include <memory>
12
13 namespace mir
14 {
15 namespace compositor { class Compositor; class DisplayBufferCompositorFactory; }
16-namespace frontend { class SessionAuthorizer; }
17+namespace frontend { class SessionAuthorizer; class Session; }
18 namespace graphics { class Platform; class Display; class GLConfig; class DisplayConfigurationPolicy; }
19 namespace input { class CompositeEventFilter; class InputDispatcher; class CursorListener; }
20 namespace options { class Option; }
21@@ -234,6 +236,24 @@
22 auto the_surface_coordinator() const -> std::shared_ptr<scene::SurfaceCoordinator>;
23 /** @} */
24
25+/** @name Client side support
26+ * These facilitate use of the server through the client API.
27+ * They should be called while the server is running (i.e. run() has been called and
28+ * not exited) otherwise they throw a std::logic_error.
29+ * @{ */
30+ using ConnectHandler = std::function<void(std::shared_ptr<frontend::Session> const& session)>;
31+
32+ /// Get a file descriptor that can be used to connect a client
33+ /// It can be passed to another process, or used directly with mir_connect()
34+ /// using the format "fd://%d".
35+ auto open_client_socket() -> Fd;
36+
37+ /// Get a file descriptor that can be used to connect a client
38+ /// It can be passed to another process, or used directly with mir_connect()
39+ /// using the format "fd://%d".
40+ /// \param connect_handler callback to be invoked when the client connects
41+ auto open_client_socket(ConnectHandler const& connect_handler) -> Fd;
42+/** @} */
43 private:
44 void apply_settings() const;
45 struct ServerConfiguration;
46
47=== modified file 'server-ABI-sha1sums'
48--- server-ABI-sha1sums 2014-10-27 22:31:16 +0000
49+++ server-ABI-sha1sums 2014-10-28 09:41:16 +0000
50@@ -98,7 +98,7 @@
51 993e9f458ffc4288d304413f3fa0b1dcc95a093d include/server/mir/scene/surface_observer.h
52 7ef3e99901168cda296d74d05a979f47bf9c3ff1 include/server/mir/server_action_queue.h
53 8d83a51c278b8b71866d2178d9b6387c1f91a7d0 include/server/mir/server_configuration.h
54-a42b26d4796c66706c65be963468645620024820 include/server/mir/server.h
55+320c467bdd757c71d02a904cc6a30cba67e27030 include/server/mir/server.h
56 86098b500339bfccd07a9bed8298f75a68b18f5c include/server/mir/server_status_listener.h
57 860c04f32b60e680140148dc9dc2295de145b9c1 include/server/mir/shell/display_layout.h
58 6a2107b01feae13060d5c305804906e53c52e0be include/server/mir/shell/focus_controller.h
59
60=== modified file 'src/server/server.cpp'
61--- src/server/server.cpp 2014-10-24 13:39:38 +0000
62+++ src/server/server.cpp 2014-10-28 09:41:16 +0000
63@@ -18,12 +18,18 @@
64
65 #include "mir/server.h"
66
67+#include "mir/frontend/connector.h"
68 #include "mir/options/default_configuration.h"
69 #include "mir/default_server_configuration.h"
70 #include "mir/main_loop.h"
71 #include "mir/report_exception.h"
72 #include "mir/run_mir.h"
73
74+// TODO these are used to frig a stub renderer when running headless
75+#include "mir/compositor/renderer.h"
76+#include "mir/graphics/renderable.h"
77+#include "mir/compositor/renderer_factory.h"
78+
79 #include <iostream>
80
81 namespace mo = mir::options;
82@@ -118,6 +124,36 @@
83 return mir::DefaultServerConfiguration::wrap_##name(wrapped);\
84 }
85
86+// TODO these are used to frig a stub renderer when running headless
87+namespace
88+{
89+class StubRenderer : public mir::compositor::Renderer
90+{
91+public:
92+ void set_viewport(mir::geometry::Rectangle const&) override {}
93+
94+ void set_rotation(float) override {}
95+
96+ void render(mir::graphics::RenderableList const& renderables) const override
97+ {
98+ for (auto const& r : renderables)
99+ r->buffer(); // We need to consume a buffer to unblock client tests
100+ }
101+
102+ void suspend() override {}
103+};
104+
105+class StubRendererFactory : public mir::compositor::RendererFactory
106+{
107+public:
108+ auto create_renderer_for(mir::geometry::Rectangle const&, mir::compositor::DestinationAlpha)
109+ -> std::unique_ptr<mir::compositor::Renderer>
110+ {
111+ return std::unique_ptr<mir::compositor::Renderer>(new StubRenderer());
112+ }
113+};
114+}
115+
116 struct mir::Server::ServerConfiguration : mir::DefaultServerConfiguration
117 {
118 ServerConfiguration(
119@@ -128,6 +164,17 @@
120 {
121 }
122
123+ // TODO this is an ugly frig to avoid exposing the render factory to end users and tests running headless
124+ auto the_renderer_factory() -> std::shared_ptr<compositor::RendererFactory> override
125+ {
126+ auto const graphics_lib = the_options()->get<std::string>(options::platform_graphics_lib);
127+
128+ if (graphics_lib != "libmirplatformstub.so")
129+ return mir::DefaultServerConfiguration::the_renderer_factory();
130+ else
131+ return std::make_shared<StubRendererFactory>();
132+ }
133+
134 using mir::DefaultServerConfiguration::the_options;
135
136 // TODO the MIR_SERVER_CONFIG_OVERRIDE macro expects a CachePtr named
137@@ -256,6 +303,22 @@
138 return self->exit_status;
139 }
140
141+auto mir::Server::open_client_socket() -> Fd
142+{
143+ if (auto const config = self->server_config)
144+ return Fd{config->the_connector()->client_socket_fd()};
145+
146+ BOOST_THROW_EXCEPTION(std::logic_error("Cannot open connection when not running"));
147+}
148+
149+auto mir::Server::open_client_socket(ConnectHandler const& connect_handler) -> Fd
150+{
151+ if (auto const config = self->server_config)
152+ return Fd{config->the_connector()->client_socket_fd(connect_handler)};
153+
154+ BOOST_THROW_EXCEPTION(std::logic_error("Cannot open connection when not running"));
155+}
156+
157 #define MIR_SERVER_ACCESSOR(name)\
158 auto mir::Server::name() const -> decltype(self->server_config->name())\
159 {\
160
161=== modified file 'src/server/symbols.map'
162--- src/server/symbols.map 2014-10-27 22:31:16 +0000
163+++ src/server/symbols.map 2014-10-28 09:41:16 +0000
164@@ -397,6 +397,7 @@
165 mir::ServerConfiguration::the_server_status_listener*;
166 mir::Server::exited_normally*;
167 mir::Server::get_options*;
168+ mir::Server::open_client_socket*;
169 mir::Server::override_the_compositor*;
170 mir::Server::override_the_display_buffer_compositor_factory*;
171 mir::Server::override_the_cursor_listener*;
172
173=== modified file 'tests/acceptance-tests/server_configuration_wrapping.cpp'
174--- tests/acceptance-tests/server_configuration_wrapping.cpp 2014-10-22 02:50:44 +0000
175+++ tests/acceptance-tests/server_configuration_wrapping.cpp 2014-10-28 09:41:16 +0000
176@@ -19,7 +19,7 @@
177 #include "mir/shell/session_coordinator_wrapper.h"
178 #include "mir/shell/surface_coordinator_wrapper.h"
179
180-#include "mir/server.h"
181+#include "mir_test_framework/headless_test.h"
182
183 #include <gtest/gtest.h>
184 #include <gmock/gmock.h>
185@@ -44,46 +44,8 @@
186 MOCK_METHOD0(focus_next, void());
187 };
188
189-class TemporaryEnvironmentValue
190-{
191-public:
192- TemporaryEnvironmentValue(char const* name, char const* value)
193- : name{name},
194- has_old_value{getenv(name) != nullptr},
195- old_value{has_old_value ? getenv(name) : ""}
196- {
197- if (value)
198- setenv(name, value, overwrite);
199- else
200- unsetenv(name);
201- }
202-
203- ~TemporaryEnvironmentValue()
204- {
205- if (has_old_value)
206- setenv(name.c_str(), old_value.c_str(), overwrite);
207- else
208- unsetenv(name.c_str());
209- }
210-
211-private:
212- static int const overwrite = 1;
213- std::string const name;
214- bool const has_old_value;
215- std::string const old_value;
216-};
217-
218-struct AcceptanceTest : Test
219-{
220- AcceptanceTest() : platform("MIR_SERVER_PLATFORM_GRAPHICS_LIB", "libmirplatformstub.so") {}
221-
222- TemporaryEnvironmentValue platform;
223-};
224-
225-struct ServerConfigurationWrapping : AcceptanceTest
226-{
227- mir::Server server;
228-
229+struct ServerConfigurationWrapping : mir_test_framework::HeadlessTest
230+{
231 void SetUp() override
232 {
233 server.wrap_surface_coordinator([]
234
235=== modified file 'tests/acceptance-tests/test_client_library.cpp'
236--- tests/acceptance-tests/test_client_library.cpp 2014-10-27 22:31:16 +0000
237+++ tests/acceptance-tests/test_client_library.cpp 2014-10-28 09:41:16 +0000
238@@ -18,8 +18,7 @@
239
240 #include "mir_toolkit/mir_client_library.h"
241
242-#include "mir_test_framework/stubbed_server_configuration.h"
243-#include "mir_test_framework/in_process_server.h"
244+#include "mir_test_framework/headless_test.h"
245 #include "mir_test_framework/using_stub_client_platform.h"
246
247 #include "src/client/client_buffer.h"
248@@ -53,10 +52,26 @@
249
250 namespace
251 {
252-struct ClientLibrary : mir_test_framework::InProcessServer
253-{
254- mtf::StubbedServerConfiguration server_configuration;
255- mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
256+struct HeadlessInProcessServer : mir_test_framework::HeadlessTest
257+{
258+ HeadlessInProcessServer()
259+ {
260+ add_to_environment("MIR_SERVER_NO_FILE", "");
261+ }
262+
263+ void SetUp() override
264+ {
265+ start_server();
266+ }
267+
268+ void TearDown() override
269+ {
270+ stop_server();
271+ }
272+};
273+
274+struct ClientLibrary : HeadlessInProcessServer
275+{
276 mtf::UsingStubClientPlatform using_stub_client_platform;
277
278 std::set<MirSurface*> surfaces;
279
280=== added file 'tests/include/mir_test_framework/headless_test.h'
281--- tests/include/mir_test_framework/headless_test.h 1970-01-01 00:00:00 +0000
282+++ tests/include/mir_test_framework/headless_test.h 2014-10-28 09:41:16 +0000
283@@ -0,0 +1,71 @@
284+/*
285+ * Copyright © 2014 Canonical Ltd.
286+ *
287+ * This program is free software: you can redistribute it and/or modify it
288+ * under the terms of the GNU General Public License version 3,
289+ * as published by the Free Software Foundation.
290+ *
291+ * This program is distributed in the hope that it will be useful,
292+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
293+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
294+ * GNU General Public License for more details.
295+ *
296+ * You should have received a copy of the GNU General Public License
297+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
298+ *
299+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
300+ */
301+
302+#ifndef MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_
303+#define MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_
304+
305+#include "mir_test_framework/temporary_environment_value.h"
306+
307+#include "mir/server.h"
308+
309+#include <gtest/gtest.h>
310+
311+#include <condition_variable>
312+#include <list>
313+#include <mutex>
314+#include <thread>
315+
316+namespace mir_test_framework
317+{
318+/** Basic fixture for tests that don't use graphics hardware.
319+ * This provides a mechanism for temporarily setting environment variables.
320+ * It automatically sets "MIR_SERVER_PLATFORM_GRAPHICS_LIB" to "libmirplatformstub.so"
321+ * as the tests do not hit the graphics hardware.
322+ */
323+class HeadlessTest : public ::testing::Test
324+{
325+public:
326+ HeadlessTest();
327+ ~HeadlessTest() noexcept;
328+
329+ void add_to_environment(char const* key, char const* value);
330+
331+ /// Starts the server on a new thread
332+ void start_server();
333+
334+ /// Stops the server and joins thread
335+ void stop_server();
336+
337+ /// \return a connection string for a new client to connect to the server
338+ auto new_connection() -> std::string;
339+
340+ mir::Server server;
341+
342+private:
343+ std::list<TemporaryEnvironmentValue> env;
344+ std::thread server_thread;
345+
346+ std::list<mir::Fd> connections;
347+
348+ std::mutex mutex;
349+ std::condition_variable started;
350+ bool server_running{false};
351+};
352+}
353+
354+#endif /* MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_ */
355
356=== added file 'tests/include/mir_test_framework/temporary_environment_value.h'
357--- tests/include/mir_test_framework/temporary_environment_value.h 1970-01-01 00:00:00 +0000
358+++ tests/include/mir_test_framework/temporary_environment_value.h 2014-10-28 09:41:16 +0000
359@@ -0,0 +1,41 @@
360+/*
361+ * Copyright © 2014 Canonical Ltd.
362+ *
363+ * This program is free software: you can redistribute it and/or modify it
364+ * under the terms of the GNU General Public License version 3,
365+ * as published by the Free Software Foundation.
366+ *
367+ * This program is distributed in the hope that it will be useful,
368+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
369+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
370+ * GNU General Public License for more details.
371+ *
372+ * You should have received a copy of the GNU General Public License
373+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
374+ *
375+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
376+ */
377+
378+#ifndef MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_
379+#define MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_
380+
381+#include <string>
382+
383+namespace mir_test_framework
384+{
385+class TemporaryEnvironmentValue
386+{
387+public:
388+ TemporaryEnvironmentValue(char const* name, char const* value);
389+
390+ ~TemporaryEnvironmentValue();
391+
392+private:
393+ static int const overwrite = 1;
394+ std::string const name;
395+ bool const has_old_value;
396+ std::string const old_value;
397+};
398+}
399+
400+#endif /* MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_ */
401
402=== modified file 'tests/mir_test_framework/CMakeLists.txt'
403--- tests/mir_test_framework/CMakeLists.txt 2014-10-23 02:30:50 +0000
404+++ tests/mir_test_framework/CMakeLists.txt 2014-10-28 09:41:16 +0000
405@@ -15,7 +15,9 @@
406 executable_path.cpp
407 command_line_server_configuration.cpp
408 cross_process_sync.cpp
409+ headless_test.cpp
410 server_runner.cpp
411+ temporary_environment_value.cpp
412 testing_server_options.cpp
413 input_testing_server_options.cpp
414 stubbed_server_configuration.cpp
415
416=== added file 'tests/mir_test_framework/headless_test.cpp'
417--- tests/mir_test_framework/headless_test.cpp 1970-01-01 00:00:00 +0000
418+++ tests/mir_test_framework/headless_test.cpp 2014-10-28 09:41:16 +0000
419@@ -0,0 +1,113 @@
420+/*
421+ * Copyright © 2014 Canonical Ltd.
422+ *
423+ * This program is free software: you can redistribute it and/or modify it
424+ * under the terms of the GNU General Public License version 3,
425+ * as published by the Free Software Foundation.
426+ *
427+ * This program is distributed in the hope that it will be useful,
428+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
429+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
430+ * GNU General Public License for more details.
431+ *
432+ * You should have received a copy of the GNU General Public License
433+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
434+ *
435+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
436+ */
437+
438+#include "mir_test_framework/headless_test.h"
439+
440+#include "mir/main_loop.h"
441+
442+#include <boost/throw_exception.hpp>
443+
444+namespace mtf = mir_test_framework;
445+
446+namespace
447+{
448+std::chrono::seconds const timeout{10};
449+}
450+
451+mtf::HeadlessTest::HeadlessTest()
452+{
453+ add_to_environment("MIR_SERVER_PLATFORM_GRAPHICS_LIB", "libmirplatformstub.so");
454+}
455+
456+void mtf::HeadlessTest::add_to_environment(char const* key, char const* value)
457+{
458+ env.emplace_back(key, value);
459+}
460+
461+void mtf::HeadlessTest::start_server()
462+{
463+ server.add_init_callback([&]
464+ {
465+ auto const main_loop = server.the_main_loop();
466+ // By enqueuing the notification code in the main loop, we are
467+ // ensuring that the server has really and fully started before
468+ // leaving start_mir_server().
469+ main_loop->enqueue(
470+ this,
471+ [&]
472+ {
473+ std::lock_guard<std::mutex> lock(mutex);
474+ server_running = true;
475+ started.notify_one();
476+ });
477+ });
478+
479+ server_thread = std::thread([&]
480+ {
481+ try
482+ {
483+ server.run();
484+ }
485+ catch (std::exception const& e)
486+ {
487+ FAIL() << e.what();
488+ }
489+ std::lock_guard<std::mutex> lock(mutex);
490+ server_running = false;
491+ started.notify_one();
492+ });
493+
494+ std::unique_lock<std::mutex> lock(mutex);
495+ started.wait_for(lock, timeout, [&] { return server_running; });
496+
497+ if (!server_running)
498+ {
499+ BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to start server thread"});
500+ }
501+}
502+
503+void mtf::HeadlessTest::stop_server()
504+{
505+ connections.clear();
506+
507+ std::unique_lock<std::mutex> lock(mutex);
508+ if (server_running)
509+ {
510+ server.stop();
511+ started.wait_for(lock, timeout, [&] { return !server_running; });
512+ }
513+
514+ if (server_running)
515+ {
516+ BOOST_THROW_EXCEPTION(std::logic_error{"stop_server() failed to stop server"});
517+ }
518+}
519+
520+mtf::HeadlessTest::~HeadlessTest() noexcept
521+{
522+ if (server_thread.joinable()) server_thread.join();
523+}
524+
525+auto mtf::HeadlessTest::new_connection() -> std::string
526+{
527+ char connect_string[64] = {0};
528+ auto const client_socket = server.open_client_socket();
529+ connections.push_back(client_socket);
530+ sprintf(connect_string, "fd://%d", client_socket.operator int());
531+ return connect_string;
532+}
533
534=== added file 'tests/mir_test_framework/temporary_environment_value.cpp'
535--- tests/mir_test_framework/temporary_environment_value.cpp 1970-01-01 00:00:00 +0000
536+++ tests/mir_test_framework/temporary_environment_value.cpp 2014-10-28 09:41:16 +0000
537@@ -0,0 +1,42 @@
538+/*
539+ * Copyright © 2014 Canonical Ltd.
540+ *
541+ * This program is free software: you can redistribute it and/or modify it
542+ * under the terms of the GNU General Public License version 3,
543+ * as published by the Free Software Foundation.
544+ *
545+ * This program is distributed in the hope that it will be useful,
546+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
547+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
548+ * GNU General Public License for more details.
549+ *
550+ * You should have received a copy of the GNU General Public License
551+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
552+ *
553+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
554+ */
555+
556+#include "mir_test_framework/temporary_environment_value.h"
557+
558+#include <cstdlib>
559+
560+namespace mtf = mir_test_framework;
561+
562+mtf::TemporaryEnvironmentValue::TemporaryEnvironmentValue(char const* name, char const* value) :
563+ name{name},
564+ has_old_value{getenv(name) != nullptr},
565+ old_value{has_old_value ? getenv(name) : ""}
566+{
567+ if (value)
568+ setenv(name, value, overwrite);
569+ else
570+ unsetenv(name);
571+}
572+
573+mtf::TemporaryEnvironmentValue::~TemporaryEnvironmentValue()
574+{
575+ if (has_old_value)
576+ setenv(name.c_str(), old_value.c_str(), overwrite);
577+ else
578+ unsetenv(name.c_str());
579+}
580
581=== modified file 'tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp'
582--- tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp 2014-10-21 16:21:14 +0000
583+++ tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp 2014-10-28 09:41:16 +0000
584@@ -18,6 +18,8 @@
585
586 #include "src/platform/graphics/mesa/anonymous_shm_file.h"
587
588+#include "mir_test_framework/temporary_environment_value.h"
589+
590 #include <gtest/gtest.h>
591 #include <gmock/gmock.h>
592
593@@ -33,39 +35,10 @@
594
595 namespace mg = mir::graphics;
596 namespace mgm = mir::graphics::mesa;
597+namespace mtf = mir_test_framework;
598
599 namespace
600 {
601-
602-class TemporaryEnvironmentValue
603-{
604-public:
605- TemporaryEnvironmentValue(char const* name, char const* value)
606- : name{name},
607- has_old_value{getenv(name) != nullptr},
608- old_value{has_old_value ? getenv(name) : ""}
609- {
610- if (value)
611- setenv(name, value, overwrite);
612- else
613- unsetenv(name);
614- }
615-
616- ~TemporaryEnvironmentValue()
617- {
618- if (has_old_value)
619- setenv(name.c_str(), old_value.c_str(), overwrite);
620- else
621- unsetenv(name.c_str());
622- }
623-
624-private:
625- static int const overwrite = 1;
626- std::string const name;
627- bool const has_old_value;
628- std::string const old_value;
629-};
630-
631 class TemporaryDirectory
632 {
633 public:
634@@ -185,7 +158,7 @@
635 using namespace testing;
636
637 TemporaryDirectory const temp_dir;
638- TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()};
639+ mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()};
640 PathWatcher const path_watcher{temp_dir.path()};
641 size_t const file_size{100};
642
643@@ -202,7 +175,7 @@
644 {
645 using namespace testing;
646
647- TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", nullptr};
648+ mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", nullptr};
649 PathWatcher const path_watcher{"/tmp"};
650 size_t const file_size{100};
651
652@@ -219,7 +192,7 @@
653 {
654 using namespace testing;
655
656- TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", "/non-existent-dir"};
657+ mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", "/non-existent-dir"};
658 PathWatcher const path_watcher{"/tmp"};
659 size_t const file_size{100};
660
661@@ -237,7 +210,7 @@
662 using namespace testing;
663
664 TemporaryDirectory const temp_dir;
665- TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()};
666+ mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()};
667 size_t const file_size{100};
668
669 mgm::AnonymousShmFile shm_file{file_size};
670@@ -253,7 +226,7 @@
671 using namespace testing;
672
673 TemporaryDirectory const temp_dir;
674- TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()};
675+ mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()};
676 size_t const file_size{100};
677
678 mgm::AnonymousShmFile shm_file{file_size};

Subscribers

People subscribed via source and target branches