Mir

Merge lp:~afrantzis/mir/client-lifecycle-terminate-properly into lp:mir

Proposed by Alexandros Frantzis
Status: Work in progress
Proposed branch: lp:~afrantzis/mir/client-lifecycle-terminate-properly
Merge into: lp:mir
Diff against target: 653 lines (+169/-111)
16 files modified
include/test/mir_test_framework/basic_client_server_fixture.h (+2/-0)
include/test/mir_test_framework/display_server_test_fixture.h (+2/-0)
include/test/mir_test_framework/testing_process_manager.h (+3/-2)
src/client/mir_connection.cpp (+6/-1)
tests/acceptance-tests/test_client_input.cpp (+2/-0)
tests/acceptance-tests/test_client_screencast.cpp (+7/-43)
tests/acceptance-tests/test_client_surface_swap_buffers.cpp (+3/-15)
tests/acceptance-tests/test_prompt_session_client_api.cpp (+2/-0)
tests/acceptance-tests/test_server_disconnect.cpp (+60/-0)
tests/acceptance-tests/test_server_shutdown.cpp (+2/-0)
tests/acceptance-tests/test_stale_frames.cpp (+0/-2)
tests/integration-tests/shell/test_session_lifecycle_event.cpp (+37/-48)
tests/mir_test_framework/display_server_test_fixture.cpp (+5/-0)
tests/mir_test_framework/testing_process_manager.cpp (+22/-0)
tests/mir_test_framework/using_stub_client_platform.cpp (+5/-0)
tests/unit-tests/client/test_client_mir_surface.cpp (+11/-0)
To merge this branch: bzr merge lp:~afrantzis/mir/client-lifecycle-terminate-properly
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Mir development team Pending
Review via email: mp+229234@code.launchpad.net

Commit message

client: Fix SIGTERM dispatch in our default lifecycle event handler

Our default lifecycle event handler used to call raise() to send a TERM signal to the app when a connection break was detected. However, in a multi-threaded program raise() sends the signal to the current thread only. If the signal is blocked in that thread, then the signal is lost.

Depending on thread in which we detected that the connection was lost, the TERM signal would be dispatched (e.g. in the context of a driver callback asking for the next buffer) or not (e.g. in the context of our main RPC threads which block all signals). This MP fixes the issue by explicitly sending the signal to the process instead of the current thread. This ensures that it will be dispatched to some thread that doesn't block it.

Description of the change

client: Fix SIGTERM dispatch in our default lifecycle event handler

Our default lifecycle event handler used to call raise() to send a TERM signal to the app when a connection break was detected. However, in a multi-threaded program raise() sends the signal to the current thread only. If the signal is blocked in that thread, then the signal is lost.

Depending on thread in which we detected that the connection was lost, the TERM signal would be dispatched (e.g. in the context of a driver callback asking for the next buffer) or not (e.g. in the context of our main RPC threads which block all signals). This MP fixes the issue by explicitly sending the signal to the process instead of the current thread. This ensures that it will be dispatched to some thread that doesn't block it.

It turns out that we send a lifecycle connection lost event to ourselves when we release a client connection. With the signal dispatch issue fixed, this always leads to a SIGTERM being sent to the process when we call mir_connection_release() (with the default handler). This breaks most of the tests, since clients are expected to exit properly, not be terminated by a signal.

I assumed that sending a lifecycle event on release is a behavior we want, i.e. it's not accidental. If it's indeed accidental, we can remove it, along with the workaround in this MP.

The workaround proposed in this MP is for our stub client platform (used in almost all the tests that use full clients) to clear any lifecycle handlers just prior to disconnecting. This has the benefit that the default handler is active for the lifetime of the client and can therefore catch premature disconnections. It's not ideal, but it's reasonable for now (IMO).

As part of the workaround I refactored some of the test code to use newer infrastructure (like BasicClientServerFixture). However these refactorings are beneficial on their own and can remain even if we decide not to use the proposed workaround.

Finally, this change fixes some instances of the "client spinning when the server dies" issue, which is especially pronounced if we apply https://code.launchpad.net/~afrantzis/mir/fix-1347053/+merge/229221, since we won't abort() in driver code any more.

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

Unmerged revisions

1811. By Alexandros Frantzis

client: Fix SIGTERM dispatch in our default lifecycle event handler

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/test/mir_test_framework/basic_client_server_fixture.h'
2--- include/test/mir_test_framework/basic_client_server_fixture.h 2014-05-20 10:31:58 +0000
3+++ include/test/mir_test_framework/basic_client_server_fixture.h 2014-08-01 13:50:17 +0000
4@@ -22,6 +22,7 @@
5 #include "mir_toolkit/mir_client_library.h"
6
7 #include "mir_test_framework/in_process_server.h"
8+#include "mir_test_framework/using_stub_client_platform.h"
9
10 namespace mir_test_framework
11 {
12@@ -31,6 +32,7 @@
13 struct BasicClientServerFixture : InProcessServer
14 {
15 TestServerConfiguration server_configuration;
16+ UsingStubClientPlatform using_stub_client_platform;
17
18 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
19
20
21=== modified file 'include/test/mir_test_framework/display_server_test_fixture.h'
22--- include/test/mir_test_framework/display_server_test_fixture.h 2014-04-10 22:23:27 +0000
23+++ include/test/mir_test_framework/display_server_test_fixture.h 2014-08-01 13:50:17 +0000
24@@ -26,6 +26,7 @@
25
26 #include <memory>
27 #include <functional>
28+#include <vector>
29
30 namespace mir_test_framework
31 {
32@@ -65,6 +66,7 @@
33
34 bool shutdown_server_process();
35 Result wait_for_shutdown_server_process();
36+ std::vector<Result> wait_for_shutdown_client_processes();
37 bool kill_server_process();
38 void kill_client_processes();
39 void terminate_client_processes();
40
41=== modified file 'include/test/mir_test_framework/testing_process_manager.h'
42--- include/test/mir_test_framework/testing_process_manager.h 2014-04-10 22:23:27 +0000
43+++ include/test/mir_test_framework/testing_process_manager.h 2014-08-01 13:50:17 +0000
44@@ -27,7 +27,7 @@
45 #include "mir_test_framework/testing_client_configuration.h"
46
47 #include <memory>
48-#include <list>
49+#include <vector>
50 #include <functional>
51
52 namespace mir
53@@ -60,13 +60,14 @@
54 Result shutdown_server_process();
55 Result kill_server_process();
56 Result wait_for_shutdown_server_process();
57+ std::vector<Result> wait_for_shutdown_client_processes();
58 void kill_client_processes();
59 void terminate_client_processes();
60 void run_in_test_process(std::function<void()> const& run_code);
61
62 private:
63 std::shared_ptr<Process> server_process;
64- std::list<std::shared_ptr<Process>> clients;
65+ std::vector<std::shared_ptr<Process>> clients;
66
67 bool is_test_process;
68 bool server_process_was_started;
69
70=== modified file 'src/client/mir_connection.cpp'
71--- src/client/mir_connection.cpp 2014-07-17 11:05:42 +0000
72+++ src/client/mir_connection.cpp 2014-08-01 13:50:17 +0000
73@@ -241,7 +241,12 @@
74 {
75 if (transition == mir_lifecycle_connection_lost)
76 {
77- raise(SIGTERM);
78+ /*
79+ * We need to use kill() instead of raise() to ensure the signal
80+ * is dispatched to the process even if it's blocked in the current
81+ * thread.
82+ */
83+ kill(getpid(), SIGTERM);
84 }
85 }
86 }
87
88=== modified file 'tests/acceptance-tests/test_client_input.cpp'
89--- tests/acceptance-tests/test_client_input.cpp 2014-06-26 16:03:00 +0000
90+++ tests/acceptance-tests/test_client_input.cpp 2014-08-01 13:50:17 +0000
91@@ -32,6 +32,7 @@
92 #include "mir_test_framework/input_testing_server_configuration.h"
93 #include "mir_test_framework/input_testing_client_configuration.h"
94 #include "mir_test_framework/declarative_placement_strategy.h"
95+#include "mir_test_framework/using_stub_client_platform.h"
96
97 #include <gtest/gtest.h>
98 #include <gmock/gmock.h>
99@@ -120,6 +121,7 @@
100 mt::Barrier fence{2};
101 mt::WaitCondition second_client_done;
102 ServerConfiguration server_configuration{fence};
103+ mtf::UsingStubClientPlatform using_stub_client_platform;
104
105 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
106
107
108=== modified file 'tests/acceptance-tests/test_client_screencast.cpp'
109--- tests/acceptance-tests/test_client_screencast.cpp 2014-06-02 17:07:02 +0000
110+++ tests/acceptance-tests/test_client_screencast.cpp 2014-08-01 13:50:17 +0000
111@@ -22,8 +22,7 @@
112 #include "mir_toolkit/mir_client_library.h"
113
114 #include "mir_test_framework/stubbed_server_configuration.h"
115-#include "mir_test_framework/in_process_server.h"
116-#include "mir_test_framework/using_stub_client_platform.h"
117+#include "mir_test_framework/basic_client_server_fixture.h"
118
119 #include "mir_test_doubles/null_display_changer.h"
120 #include "mir_test_doubles/stub_display_configuration.h"
121@@ -84,15 +83,10 @@
122 mtd::MockScreencast mock_screencast;
123 };
124
125-class MirScreencastTest : public mir_test_framework::InProcessServer
126+struct MirScreencastTest : mtf::BasicClientServerFixture<StubServerConfig>
127 {
128-public:
129- mir::DefaultServerConfiguration& server_config() override { return server_config_; }
130-
131- mtd::MockScreencast& mock_screencast() { return server_config_.mock_screencast; }
132-
133- StubServerConfig server_config_;
134- mtf::UsingStubClientPlatform using_stub_client_platform;
135+ mtd::MockScreencast& mock_screencast() { return server_configuration.mock_screencast; }
136+
137 MirScreencastParameters default_screencast_params {
138 {0, 0, 1, 1}, 1, 1, mir_pixel_format_abgr_8888};
139 };
140@@ -111,9 +105,6 @@
141 {
142 using namespace testing;
143
144- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
145- ASSERT_TRUE(mir_connection_is_valid(connection));
146-
147 mf::ScreencastSessionId const screencast_session_id{99};
148
149 InSequence seq;
150@@ -130,17 +121,12 @@
151 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
152 ASSERT_NE(nullptr, screencast);
153 mir_screencast_release_sync(screencast);
154-
155- mir_connection_release(connection);
156 }
157
158 TEST_F(MirScreencastTest, contacts_server_screencast_with_provided_params)
159 {
160 using namespace testing;
161
162- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
163- ASSERT_TRUE(mir_connection_is_valid(connection));
164-
165 mf::ScreencastSessionId const screencast_session_id{99};
166
167 geom::Size const size{default_screencast_params.width, default_screencast_params.height};
168@@ -164,17 +150,12 @@
169 ASSERT_NE(nullptr, screencast);
170
171 mir_screencast_release_sync(screencast);
172-
173- mir_connection_release(connection);
174 }
175
176 TEST_F(MirScreencastTest, creation_with_invalid_params_fails)
177 {
178 using namespace testing;
179
180- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
181- ASSERT_TRUE(mir_connection_is_valid(connection));
182-
183 MirScreencastParameters params = default_screencast_params;
184 params.width = params.height = 0;
185 auto screencast = mir_connection_create_screencast_sync(connection, &params);
186@@ -190,17 +171,12 @@
187
188 screencast = mir_connection_create_screencast_sync(connection, &params);
189 ASSERT_EQ(nullptr, screencast);
190-
191- mir_connection_release(connection);
192 }
193
194 TEST_F(MirScreencastTest, gets_valid_egl_native_window)
195 {
196 using namespace testing;
197
198- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
199- ASSERT_TRUE(mir_connection_is_valid(connection));
200-
201 mf::ScreencastSessionId const screencast_session_id{99};
202
203 InSequence seq;
204@@ -217,24 +193,17 @@
205 EXPECT_NE(MirEGLNativeWindowType(), egl_native_window);
206
207 mir_screencast_release_sync(screencast);
208-
209- mir_connection_release(connection);
210 }
211
212 TEST_F(MirScreencastTest, fails_on_client_when_server_request_fails)
213 {
214 using namespace testing;
215
216- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
217- ASSERT_TRUE(mir_connection_is_valid(connection));
218-
219 EXPECT_CALL(mock_screencast(), create_session(_, _, _))
220 .WillOnce(Throw(std::runtime_error("")));
221
222 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
223 ASSERT_EQ(nullptr, screencast);
224-
225- mir_connection_release(connection);
226 }
227
228 namespace
229@@ -255,15 +224,10 @@
230 MockSessionAuthorizer mock_authorizer;
231 };
232
233-class UnauthorizedMirScreencastTest : public mir_test_framework::InProcessServer
234+struct UnauthorizedMirScreencastTest : mtf::BasicClientServerFixture<MockAuthorizerServerConfig>
235 {
236-public:
237- mir::DefaultServerConfiguration& server_config() override { return server_config_; }
238-
239- MockSessionAuthorizer& mock_authorizer() { return server_config_.mock_authorizer; }
240-
241- MockAuthorizerServerConfig server_config_;
242- mtf::UsingStubClientPlatform using_stub_client_platform;
243+ MockSessionAuthorizer& mock_authorizer() { return server_configuration.mock_authorizer; }
244+
245 MirScreencastParameters default_screencast_params {
246 {0, 0, 1, 1}, 1, 1, mir_pixel_format_abgr_8888};
247 };
248
249=== modified file 'tests/acceptance-tests/test_client_surface_swap_buffers.cpp'
250--- tests/acceptance-tests/test_client_surface_swap_buffers.cpp 2014-06-09 17:16:32 +0000
251+++ tests/acceptance-tests/test_client_surface_swap_buffers.cpp 2014-08-01 13:50:17 +0000
252@@ -19,8 +19,7 @@
253 #include "mir_toolkit/mir_client_library.h"
254
255 #include "mir_test_framework/stubbed_server_configuration.h"
256-#include "mir_test_framework/in_process_server.h"
257-#include "mir_test_framework/using_stub_client_platform.h"
258+#include "mir_test_framework/basic_client_server_fixture.h"
259 #include "mir_test_doubles/null_display_buffer_compositor_factory.h"
260 #include "mir_test/signal.h"
261
262@@ -43,30 +42,20 @@
263 }
264 };
265
266-class MirSurfaceSwapBuffersTest : public mir_test_framework::InProcessServer
267-{
268-public:
269- mir::DefaultServerConfiguration& server_config() override { return server_config_; }
270-
271- StubServerConfig server_config_;
272- mtf::UsingStubClientPlatform using_stub_client_platform;
273-};
274-
275 void swap_buffers_callback(MirSurface*, void* ctx)
276 {
277 auto buffers_swapped = static_cast<mt::Signal*>(ctx);
278 buffers_swapped->raise();
279 }
280
281+using MirSurfaceSwapBuffersTest = mtf::BasicClientServerFixture<StubServerConfig>;
282+
283 }
284
285 TEST_F(MirSurfaceSwapBuffersTest, swap_buffers_does_not_block_when_surface_is_not_composited)
286 {
287 using namespace testing;
288
289- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
290- ASSERT_TRUE(mir_connection_is_valid(connection));
291-
292 MirSurfaceParameters request_params =
293 {
294 __PRETTY_FUNCTION__,
295@@ -93,5 +82,4 @@
296 }
297
298 mir_surface_release_sync(surface);
299- mir_connection_release(connection);
300 }
301
302=== modified file 'tests/acceptance-tests/test_prompt_session_client_api.cpp'
303--- tests/acceptance-tests/test_prompt_session_client_api.cpp 2014-07-21 03:35:31 +0000
304+++ tests/acceptance-tests/test_prompt_session_client_api.cpp 2014-08-01 13:50:17 +0000
305@@ -27,6 +27,7 @@
306 #include "mir_test_doubles/stub_session_authorizer.h"
307 #include "mir_test_framework/stubbed_server_configuration.h"
308 #include "mir_test_framework/in_process_server.h"
309+#include "mir_test_framework/using_stub_client_platform.h"
310 #include "mir_test/popen.h"
311
312 #include <gtest/gtest.h>
313@@ -140,6 +141,7 @@
314 std::shared_ptr<mf::Session> application_session;
315
316 std::shared_ptr<ms::PromptSession> server_prompt_session;
317+ mtf::UsingStubClientPlatform using_stub_client_platform;
318
319 void SetUp() override
320 {
321
322=== modified file 'tests/acceptance-tests/test_server_disconnect.cpp'
323--- tests/acceptance-tests/test_server_disconnect.cpp 2014-03-26 05:48:59 +0000
324+++ tests/acceptance-tests/test_server_disconnect.cpp 2014-08-01 13:50:17 +0000
325@@ -130,6 +130,40 @@
326 mt::CrossProcessAction configure_display;
327 mt::CrossProcessAction disconnect;
328 };
329+
330+/*
331+ * This client will self-terminate on server connection break (through the default
332+ * lifecycle handler).
333+ */
334+struct TerminatingTestingClientConfiguration : mtf::TestingClientConfiguration
335+{
336+ void exec() override
337+ {
338+ MirConnection* connection{nullptr};
339+
340+ connect.exec([&] {
341+ connection = mir_connect_sync(mtf::test_socket_file().c_str() , __PRETTY_FUNCTION__);
342+ EXPECT_TRUE(mir_connection_is_valid(connection));
343+ });
344+
345+ create_surface_sync.wait_for_signal_ready_for();
346+
347+ MirSurfaceParameters const parameters =
348+ {
349+ __PRETTY_FUNCTION__,
350+ 1, 1,
351+ mir_pixel_format_abgr_8888,
352+ mir_buffer_usage_hardware,
353+ mir_display_output_id_invalid
354+ };
355+ mir_connection_create_surface_sync(connection, &parameters);
356+
357+ mir_connection_release(connection);
358+ }
359+
360+ mt::CrossProcessAction connect;
361+ mtf::CrossProcessSync create_surface_sync;
362+};
363 }
364
365 TEST_F(ServerDisconnect, client_detects_server_shutdown)
366@@ -168,3 +202,29 @@
367 client_config.disconnect();
368 });
369 }
370+
371+TEST_F(ServerDisconnect, causes_client_to_terminate_by_default)
372+{
373+ TestingServerConfiguration server_config;
374+ launch_server_process(server_config);
375+
376+ TerminatingTestingClientConfiguration client_config;
377+ launch_client_process(client_config);
378+
379+ run_in_test_process([this, &client_config]
380+ {
381+ client_config.connect();
382+ shutdown_server_process();
383+
384+ /*
385+ * While trying to create a surface the connection break will be detected
386+ * and the client should self-terminate.
387+ */
388+ client_config.create_surface_sync.signal_ready();
389+
390+ auto client_results = wait_for_shutdown_client_processes();
391+ ASSERT_EQ(1, client_results.size());
392+ EXPECT_EQ(mtf::TerminationReason::child_terminated_by_signal,
393+ client_results[0].reason);
394+ });
395+}
396
397=== modified file 'tests/acceptance-tests/test_server_shutdown.cpp'
398--- tests/acceptance-tests/test_server_shutdown.cpp 2014-07-21 03:35:31 +0000
399+++ tests/acceptance-tests/test_server_shutdown.cpp 2014-08-01 13:50:17 +0000
400@@ -327,6 +327,8 @@
401
402 /* Notify the clients that we are done (we only need to set the flag once) */
403 server_done.set();
404+
405+ wait_for_shutdown_client_processes();
406 });
407
408 /*
409
410=== modified file 'tests/acceptance-tests/test_stale_frames.cpp'
411--- tests/acceptance-tests/test_stale_frames.cpp 2014-07-25 10:02:18 +0000
412+++ tests/acceptance-tests/test_stale_frames.cpp 2014-08-01 13:50:17 +0000
413@@ -25,7 +25,6 @@
414 #include "mir/graphics/buffer.h"
415 #include "mir/graphics/buffer_id.h"
416
417-#include "mir_test_framework/using_stub_client_platform.h"
418 #include "mir_test_framework/stubbed_server_configuration.h"
419 #include "mir_test_framework/basic_client_server_fixture.h"
420 #include "mir_test_doubles/stub_renderer.h"
421@@ -180,7 +179,6 @@
422 }
423
424 MirSurface* surface;
425- mtf::UsingStubClientPlatform using_stub_client_platform;
426 };
427
428 }
429
430=== modified file 'tests/integration-tests/shell/test_session_lifecycle_event.cpp'
431--- tests/integration-tests/shell/test_session_lifecycle_event.cpp 2014-07-21 03:35:31 +0000
432+++ tests/integration-tests/shell/test_session_lifecycle_event.cpp 2014-08-01 13:50:17 +0000
433@@ -19,82 +19,71 @@
434 #include "mir/scene/null_session_listener.h"
435 #include "src/server/scene/application_session.h"
436
437-#include "mir_test_framework/display_server_test_fixture.h"
438+#include "mir_test_framework/stubbed_server_configuration.h"
439+#include "mir_test_framework/basic_client_server_fixture.h"
440+#include "mir_test_framework/in_process_server.h"
441
442 #include "mir_toolkit/mir_client_library.h"
443
444 #include <gtest/gtest.h>
445 #include <gmock/gmock.h>
446
447-#include <thread>
448-#include <unistd.h>
449-#include <fcntl.h>
450-
451 namespace ms = mir::scene;
452-namespace msh = mir::shell;
453 namespace mtf = mir_test_framework;
454
455 namespace
456 {
457-char const* const mir_test_socket = mtf::test_socket_file().c_str();
458
459 struct MockStateHandler
460 {
461 MOCK_METHOD1(state_changed, void (MirLifecycleState));
462 };
463
464+void lifecycle_callback(MirConnection* /*connection*/, MirLifecycleState state, void* context)
465+{
466+ auto handler = static_cast<MockStateHandler*>(context);
467+ handler->state_changed(state);
468+}
469+
470 class StubSessionListener : public ms::NullSessionListener
471 {
472 void stopping(std::shared_ptr<ms::Session> const& session)
473 {
474- std::shared_ptr<ms::ApplicationSession> app_session(
475- std::static_pointer_cast<ms::ApplicationSession>(session)
476- );
477+ auto const app_session = std::static_pointer_cast<ms::ApplicationSession>(session);
478
479 app_session->set_lifecycle_state(mir_lifecycle_state_will_suspend);
480 }
481 };
482
483-using LifecycleEventTest = BespokeDisplayServerTestFixture;
484+struct StubServerConfig : mtf::StubbedServerConfiguration
485+{
486+ std::shared_ptr<ms::SessionListener> the_session_listener() override
487+ {
488+ return std::make_shared<StubSessionListener>();
489+ }
490+};
491+
492+struct LifecycleEventTest : mtf::InProcessServer
493+{
494+ StubServerConfig server_configuration;
495+
496+ mir::DefaultServerConfiguration& server_config() override
497+ { return server_configuration; }
498+};
499+
500+}
501+
502 TEST_F(LifecycleEventTest, lifecycle_event_test)
503 {
504 using namespace ::testing;
505
506- struct ServerConfig : TestingServerConfiguration
507- {
508- std::shared_ptr<ms::SessionListener> the_session_listener() override
509- {
510- return std::make_shared<StubSessionListener>();
511- }
512- } server_config;
513-
514- launch_server_process(server_config);
515-
516- struct ClientConfig : TestingClientConfiguration
517- {
518- static void lifecycle_callback(MirConnection* /*connection*/, MirLifecycleState state, void* context)
519- {
520- auto config = static_cast<ClientConfig*>(context);
521- config->handler->state_changed(state);
522- }
523-
524- void exec()
525- {
526- handler = std::make_shared<MockStateHandler>();
527-
528- MirConnection* connection = mir_connect_sync(mir_test_socket, "testapp");
529- mir_connection_set_lifecycle_event_callback(connection, lifecycle_callback, this);
530-
531- EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_state_will_suspend))).Times(1);
532- EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_connection_lost))).Times(AtMost(1));
533- mir_connection_release(connection);
534-
535- handler.reset();
536- }
537-
538- std::shared_ptr<MockStateHandler> handler;
539- } client_config;
540-
541- launch_client_process(client_config);
542-}
543+ auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
544+
545+ auto const handler = std::make_shared<MockStateHandler>();
546+ mir_connection_set_lifecycle_event_callback(connection, lifecycle_callback, handler.get());
547+
548+ EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_state_will_suspend))).Times(1);
549+ EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_connection_lost))).Times(AtMost(1));
550+
551+ mir_connection_release(connection);
552 }
553
554=== modified file 'tests/mir_test_framework/display_server_test_fixture.cpp'
555--- tests/mir_test_framework/display_server_test_fixture.cpp 2014-04-10 22:23:27 +0000
556+++ tests/mir_test_framework/display_server_test_fixture.cpp 2014-08-01 13:50:17 +0000
557@@ -87,6 +87,11 @@
558 return process_manager.wait_for_shutdown_server_process();
559 }
560
561+std::vector<mtf::Result> BespokeDisplayServerTestFixture::wait_for_shutdown_client_processes()
562+{
563+ return process_manager.wait_for_shutdown_client_processes();
564+}
565+
566 void BespokeDisplayServerTestFixture::terminate_client_processes()
567 {
568 process_manager.terminate_client_processes();
569
570=== modified file 'tests/mir_test_framework/testing_process_manager.cpp'
571--- tests/mir_test_framework/testing_process_manager.cpp 2014-04-10 22:23:27 +0000
572+++ tests/mir_test_framework/testing_process_manager.cpp 2014-08-01 13:50:17 +0000
573@@ -203,6 +203,28 @@
574 return result;
575 }
576
577+std::vector<mtf::Result> mtf::TestingProcessManager::wait_for_shutdown_client_processes()
578+{
579+ std::vector<Result> results;
580+
581+ if (!clients.empty())
582+ {
583+ for (auto client : clients)
584+ results.push_back(client->wait_for_termination());
585+
586+ clients.clear();
587+ }
588+ else
589+ {
590+ Result result;
591+ result.reason = TerminationReason::child_terminated_normally;
592+ result.exit_code = EXIT_SUCCESS;
593+ results.push_back(result);
594+ }
595+
596+ return results;
597+}
598+
599 void mtf::TestingProcessManager::terminate_client_processes()
600 {
601 if (is_test_process)
602
603=== modified file 'tests/mir_test_framework/using_stub_client_platform.cpp'
604--- tests/mir_test_framework/using_stub_client_platform.cpp 2014-07-29 10:25:43 +0000
605+++ tests/mir_test_framework/using_stub_client_platform.cpp 2014-08-01 13:50:17 +0000
606@@ -27,6 +27,10 @@
607 namespace
608 {
609
610+void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*)
611+{
612+}
613+
614 MirWaitHandle* mir_connect_override(
615 char const *socket_file,
616 char const *app_name,
617@@ -42,6 +46,7 @@
618 {
619 try
620 {
621+ mir_connection_set_lifecycle_event_callback(connection, null_lifecycle_callback, nullptr);
622 auto wait_handle = connection->disconnect();
623 mir_wait_for(wait_handle);
624 }
625
626=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
627--- tests/unit-tests/client/test_client_mir_surface.cpp 2014-07-21 03:35:31 +0000
628+++ tests/unit-tests/client/test_client_mir_surface.cpp 2014-08-01 13:50:17 +0000
629@@ -392,6 +392,10 @@
630 {
631 }
632
633+void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*)
634+{
635+}
636+
637 MATCHER_P(BufferPackageMatches, package, "")
638 {
639 // Can't simply use memcmp() on the whole struct because age is not sent over the wire
640@@ -415,6 +419,13 @@
641 connect_to_test_server();
642 }
643
644+ ~MirClientSurfaceTest()
645+ {
646+ // Clear the lifecycle callback in order not to get SIGTERM by the default
647+ // lifecycle handler during connection teardown
648+ connection->register_lifecycle_event_callback(null_lifecycle_callback, nullptr);
649+ }
650+
651 void start_test_server()
652 {
653 // In case an earlier test left a stray file

Subscribers

People subscribed via source and target branches