Mir

Merge lp:~afrantzis/mir/fix-1353867-sigterm-dispatch into lp:mir

Proposed by Alexandros Frantzis
Status: Superseded
Proposed branch: lp:~afrantzis/mir/fix-1353867-sigterm-dispatch
Merge into: lp:mir
Diff against target: 850 lines (+191/-115)
23 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_cursor_api.cpp (+2/-0)
tests/acceptance-tests/test_client_input.cpp (+2/-0)
tests/acceptance-tests/test_client_library.cpp (+4/-1)
tests/acceptance-tests/test_client_screencast.cpp (+7/-43)
tests/acceptance-tests/test_client_surface_swap_buffers.cpp (+3/-15)
tests/acceptance-tests/test_large_messages.cpp (+3/-0)
tests/acceptance-tests/test_nested_mir.cpp (+2/-0)
tests/acceptance-tests/test_prompt_session_client_api.cpp (+2/-0)
tests/acceptance-tests/test_protobuf.cpp (+6/-3)
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/acceptance-tests/test_test_framework.cpp (+2/-0)
tests/integration-tests/client/test_client_render.cpp (+10/-0)
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 (+12/-0)
tests/mir_test_framework/using_stub_client_platform.cpp (+8/-0)
tests/unit-tests/client/test_client_mir_surface.cpp (+11/-0)
To merge this branch: bzr merge lp:~afrantzis/mir/fix-1353867-sigterm-dispatch
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Alan Griffiths Approve
Chris Halse Rogers Approve
Review via email: mp+230454@code.launchpad.net

This proposal has been superseded by a proposal from 2014-08-18.

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 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.

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
Daniel van Vugt (vanvugt) wrote :

Manual testing OK. Verified bug 1353867 is fixed.

I suggest SIGPIPE or SIGHUP would be more appropriate than SIGTERM though. SIGTERM means the user has explicitly asked for the app to be killed, and that's not true in this case. It's more appropriate to use SIGPIPE or SIGHUP indicating the user did not explicitly kill the app, but we still want a clean termination (no core file).

review: Approve
Revision history for this message
Chris Halse Rogers (raof) wrote :

Looks sensible to me

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Essentially Approved still. Just please consider using a more appropriate signal: SIGPIPE or SIGHUP.

review: Needs Information
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> Essentially Approved still. Just please consider using a more appropriate signal: SIGPIPE or SIGHUP.

I am not opposed to changing the signal, after some discussion about which one is best. A change to the signal needs to be followed by changes to signal handlers of our example clients so they can shut down properly. I'd rather we did all this in a separate MP and leave the current MP focused on just fixing the dispatch mechanism.

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

> > Essentially Approved still. Just please consider using a more appropriate
> signal: SIGPIPE or SIGHUP.
>
> I am not opposed to changing the signal, after some discussion about which one
> is best. A change to the signal needs to be followed by changes to signal
> handlers of our example clients so they can shut down properly. I'd rather we
> did all this in a separate MP and leave the current MP focused on just fixing
> the dispatch mechanism.

OK

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Happy to revisit the choice of signal later. One minor annoyance is stopping this from landing (per Jenkins):

Text conflict in tests/acceptance-tests/test_nested_mir.cpp
1 conflicts encountered.

review: Approve

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-07-02 06:29:24 +0000
3+++ include/test/mir_test_framework/basic_client_server_fixture.h 2014-08-12 10:44:30 +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-12 10:44:30 +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-12 10:44:30 +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-30 15:25:54 +0000
72+++ src/client/mir_connection.cpp 2014-08-12 10:44:30 +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_cursor_api.cpp'
89--- tests/acceptance-tests/test_client_cursor_api.cpp 2014-07-10 03:45:37 +0000
90+++ tests/acceptance-tests/test_client_cursor_api.cpp 2014-08-12 10:44:30 +0000
91@@ -34,6 +34,7 @@
92 #include "mir_test_framework/testing_client_configuration.h"
93 #include "mir_test_framework/declarative_placement_strategy.h"
94 #include "mir_test_framework/deferred_in_process_server.h"
95+#include "mir_test_framework/using_stub_client_platform.h"
96
97 #include <gtest/gtest.h>
98 #include <gmock/gmock.h>
99@@ -234,6 +235,7 @@
100
101 ServerConfiguration server_configuration{cursor_configured_fence, client_may_exit_fence};
102 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
103+ mtf::UsingStubClientPlatform using_stub_client_platform;
104
105 ClientConfig client_config_1{client_name_1, cursor_configured_fence, client_may_exit_fence};
106 ClientConfig client_config_2{client_name_2, cursor_configured_fence, client_may_exit_fence};
107
108=== modified file 'tests/acceptance-tests/test_client_input.cpp'
109--- tests/acceptance-tests/test_client_input.cpp 2014-08-06 01:40:20 +0000
110+++ tests/acceptance-tests/test_client_input.cpp 2014-08-12 10:44:30 +0000
111@@ -32,6 +32,7 @@
112 #include "mir_test_framework/input_testing_server_configuration.h"
113 #include "mir_test_framework/input_testing_client_configuration.h"
114 #include "mir_test_framework/declarative_placement_strategy.h"
115+#include "mir_test_framework/using_stub_client_platform.h"
116
117 #include <gtest/gtest.h>
118 #include <gmock/gmock.h>
119@@ -120,6 +121,7 @@
120 mt::Barrier fence{2};
121 mt::WaitCondition second_client_done;
122 ServerConfiguration server_configuration{fence};
123+ mtf::UsingStubClientPlatform using_stub_client_platform;
124
125 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
126
127
128=== modified file 'tests/acceptance-tests/test_client_library.cpp'
129--- tests/acceptance-tests/test_client_library.cpp 2014-07-21 03:35:31 +0000
130+++ tests/acceptance-tests/test_client_library.cpp 2014-08-12 10:44:30 +0000
131@@ -21,6 +21,7 @@
132
133 #include "mir_test_framework/stubbed_server_configuration.h"
134 #include "mir_test_framework/in_process_server.h"
135+#include "mir_test_framework/using_stub_client_platform.h"
136
137 #include "src/client/client_buffer.h"
138
139@@ -51,13 +52,15 @@
140 namespace mf = mir::frontend;
141 namespace mc = mir::compositor;
142 namespace mcl = mir::client;
143+namespace mtf = mir_test_framework;
144
145 namespace
146 {
147 struct ClientLibrary : mir_test_framework::InProcessServer
148 {
149- mir_test_framework::StubbedServerConfiguration server_configuration;
150+ mtf::StubbedServerConfiguration server_configuration;
151 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
152+ mtf::UsingStubClientPlatform using_stub_client_platform;
153
154 std::set<MirSurface*> surfaces;
155 MirConnection* connection = nullptr;
156
157=== modified file 'tests/acceptance-tests/test_client_screencast.cpp'
158--- tests/acceptance-tests/test_client_screencast.cpp 2014-07-02 06:29:24 +0000
159+++ tests/acceptance-tests/test_client_screencast.cpp 2014-08-12 10:44:30 +0000
160@@ -22,8 +22,7 @@
161 #include "mir_toolkit/mir_client_library.h"
162
163 #include "mir_test_framework/stubbed_server_configuration.h"
164-#include "mir_test_framework/in_process_server.h"
165-#include "mir_test_framework/using_stub_client_platform.h"
166+#include "mir_test_framework/basic_client_server_fixture.h"
167
168 #include "mir_test_doubles/null_display_changer.h"
169 #include "mir_test_doubles/stub_display_configuration.h"
170@@ -84,15 +83,10 @@
171 mtd::MockScreencast mock_screencast;
172 };
173
174-class MirScreencastTest : public mir_test_framework::InProcessServer
175+struct MirScreencastTest : mtf::BasicClientServerFixture<StubServerConfig>
176 {
177-public:
178- mir::DefaultServerConfiguration& server_config() override { return server_config_; }
179-
180- mtd::MockScreencast& mock_screencast() { return server_config_.mock_screencast; }
181-
182- StubServerConfig server_config_;
183- mtf::UsingStubClientPlatform using_stub_client_platform;
184+ mtd::MockScreencast& mock_screencast() { return server_configuration.mock_screencast; }
185+
186 MirScreencastParameters default_screencast_params {
187 {0, 0, 1, 1}, 1, 1, mir_pixel_format_abgr_8888};
188 };
189@@ -111,9 +105,6 @@
190 {
191 using namespace testing;
192
193- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
194- ASSERT_TRUE(mir_connection_is_valid(connection));
195-
196 mf::ScreencastSessionId const screencast_session_id{99};
197
198 InSequence seq;
199@@ -130,17 +121,12 @@
200 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
201 ASSERT_NE(nullptr, screencast);
202 mir_screencast_release_sync(screencast);
203-
204- mir_connection_release(connection);
205 }
206
207 TEST_F(MirScreencastTest, contacts_server_screencast_with_provided_params)
208 {
209 using namespace testing;
210
211- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
212- ASSERT_TRUE(mir_connection_is_valid(connection));
213-
214 mf::ScreencastSessionId const screencast_session_id{99};
215
216 geom::Size const size{default_screencast_params.width, default_screencast_params.height};
217@@ -164,17 +150,12 @@
218 ASSERT_NE(nullptr, screencast);
219
220 mir_screencast_release_sync(screencast);
221-
222- mir_connection_release(connection);
223 }
224
225 TEST_F(MirScreencastTest, creation_with_invalid_params_fails)
226 {
227 using namespace testing;
228
229- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
230- ASSERT_TRUE(mir_connection_is_valid(connection));
231-
232 MirScreencastParameters params = default_screencast_params;
233 params.width = params.height = 0;
234 auto screencast = mir_connection_create_screencast_sync(connection, &params);
235@@ -190,17 +171,12 @@
236
237 screencast = mir_connection_create_screencast_sync(connection, &params);
238 ASSERT_EQ(nullptr, screencast);
239-
240- mir_connection_release(connection);
241 }
242
243 TEST_F(MirScreencastTest, gets_valid_egl_native_window)
244 {
245 using namespace testing;
246
247- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
248- ASSERT_TRUE(mir_connection_is_valid(connection));
249-
250 mf::ScreencastSessionId const screencast_session_id{99};
251
252 InSequence seq;
253@@ -217,24 +193,17 @@
254 EXPECT_NE(MirEGLNativeWindowType(), egl_native_window);
255
256 mir_screencast_release_sync(screencast);
257-
258- mir_connection_release(connection);
259 }
260
261 TEST_F(MirScreencastTest, fails_on_client_when_server_request_fails)
262 {
263 using namespace testing;
264
265- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
266- ASSERT_TRUE(mir_connection_is_valid(connection));
267-
268 EXPECT_CALL(mock_screencast(), create_session(_, _, _))
269 .WillOnce(Throw(std::runtime_error("")));
270
271 auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params);
272 ASSERT_EQ(nullptr, screencast);
273-
274- mir_connection_release(connection);
275 }
276
277 namespace
278@@ -255,15 +224,10 @@
279 MockSessionAuthorizer mock_authorizer;
280 };
281
282-class UnauthorizedMirScreencastTest : public mir_test_framework::InProcessServer
283+struct UnauthorizedMirScreencastTest : mtf::BasicClientServerFixture<MockAuthorizerServerConfig>
284 {
285-public:
286- mir::DefaultServerConfiguration& server_config() override { return server_config_; }
287-
288- MockSessionAuthorizer& mock_authorizer() { return server_config_.mock_authorizer; }
289-
290- MockAuthorizerServerConfig server_config_;
291- mtf::UsingStubClientPlatform using_stub_client_platform;
292+ MockSessionAuthorizer& mock_authorizer() { return server_configuration.mock_authorizer; }
293+
294 MirScreencastParameters default_screencast_params {
295 {0, 0, 1, 1}, 1, 1, mir_pixel_format_abgr_8888};
296 };
297
298=== modified file 'tests/acceptance-tests/test_client_surface_swap_buffers.cpp'
299--- tests/acceptance-tests/test_client_surface_swap_buffers.cpp 2014-08-05 11:34:22 +0000
300+++ tests/acceptance-tests/test_client_surface_swap_buffers.cpp 2014-08-12 10:44:30 +0000
301@@ -19,8 +19,7 @@
302 #include "mir_toolkit/mir_client_library.h"
303
304 #include "mir_test_framework/stubbed_server_configuration.h"
305-#include "mir_test_framework/in_process_server.h"
306-#include "mir_test_framework/using_stub_client_platform.h"
307+#include "mir_test_framework/basic_client_server_fixture.h"
308 #include "mir_test_doubles/null_display_buffer_compositor_factory.h"
309 #include "mir_test/signal.h"
310
311@@ -43,30 +42,20 @@
312 }
313 };
314
315-class MirSurfaceSwapBuffersTest : public mir_test_framework::InProcessServer
316-{
317-public:
318- mir::DefaultServerConfiguration& server_config() override { return server_config_; }
319-
320- StubServerConfig server_config_;
321- mtf::UsingStubClientPlatform using_stub_client_platform;
322-};
323-
324 void swap_buffers_callback(MirSurface*, void* ctx)
325 {
326 auto buffers_swapped = static_cast<mt::Signal*>(ctx);
327 buffers_swapped->raise();
328 }
329
330+using MirSurfaceSwapBuffersTest = mtf::BasicClientServerFixture<StubServerConfig>;
331+
332 }
333
334 TEST_F(MirSurfaceSwapBuffersTest, swap_buffers_does_not_block_when_surface_is_not_composited)
335 {
336 using namespace testing;
337
338- auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
339- ASSERT_TRUE(mir_connection_is_valid(connection));
340-
341 MirSurfaceParameters request_params =
342 {
343 __PRETTY_FUNCTION__,
344@@ -93,5 +82,4 @@
345 }
346
347 mir_surface_release_sync(surface);
348- mir_connection_release(connection);
349 }
350
351=== modified file 'tests/acceptance-tests/test_large_messages.cpp'
352--- tests/acceptance-tests/test_large_messages.cpp 2014-05-19 10:30:17 +0000
353+++ tests/acceptance-tests/test_large_messages.cpp 2014-08-12 10:44:30 +0000
354@@ -18,6 +18,7 @@
355
356 #include "mir_test_framework/in_process_server.h"
357 #include "mir_test_framework/stubbed_server_configuration.h"
358+#include "mir_test_framework/using_stub_client_platform.h"
359 #include "mir_test/wait_object.h"
360 #include "mir_test/fake_shared.h"
361 #include "mir_test_doubles/stub_display_configuration.h"
362@@ -66,6 +67,8 @@
363 {
364 return large_messages_server_config;
365 }
366+
367+ mir_test_framework::UsingStubClientPlatform using_stub_client_platform;
368 };
369
370 struct ConnectionContext
371
372=== modified file 'tests/acceptance-tests/test_nested_mir.cpp'
373--- tests/acceptance-tests/test_nested_mir.cpp 2014-08-06 15:15:35 +0000
374+++ tests/acceptance-tests/test_nested_mir.cpp 2014-08-12 10:44:30 +0000
375@@ -28,6 +28,7 @@
376
377 #include "mir_test_framework/in_process_server.h"
378 #include "mir_test_framework/stubbed_server_configuration.h"
379+#include "mir_test_framework/using_stub_client_platform.h"
380
381 #include "mir_test_doubles/mock_egl.h"
382
383@@ -267,6 +268,7 @@
384 NestedServer() : HostServerConfiguration(display_geometry) {}
385
386 NestedMockEGL mock_egl;
387+ mtf::UsingStubClientPlatform using_stub_client_platform;
388
389 virtual mir::DefaultServerConfiguration& server_config()
390 {
391
392=== modified file 'tests/acceptance-tests/test_prompt_session_client_api.cpp'
393--- tests/acceptance-tests/test_prompt_session_client_api.cpp 2014-07-30 15:25:54 +0000
394+++ tests/acceptance-tests/test_prompt_session_client_api.cpp 2014-08-12 10:44:30 +0000
395@@ -27,6 +27,7 @@
396 #include "mir_test_doubles/stub_session_authorizer.h"
397 #include "mir_test_framework/stubbed_server_configuration.h"
398 #include "mir_test_framework/in_process_server.h"
399+#include "mir_test_framework/using_stub_client_platform.h"
400 #include "mir_test/popen.h"
401
402 #include <gtest/gtest.h>
403@@ -140,6 +141,7 @@
404 std::shared_ptr<mf::Session> application_session;
405
406 std::shared_ptr<ms::PromptSession> server_prompt_session;
407+ mtf::UsingStubClientPlatform using_stub_client_platform;
408
409 void SetUp() override
410 {
411
412=== modified file 'tests/acceptance-tests/test_protobuf.cpp'
413--- tests/acceptance-tests/test_protobuf.cpp 2014-07-10 03:45:37 +0000
414+++ tests/acceptance-tests/test_protobuf.cpp 2014-08-12 10:44:30 +0000
415@@ -26,6 +26,7 @@
416
417 #include "mir_test_framework/stubbed_server_configuration.h"
418 #include "mir_test_framework/in_process_server.h"
419+#include "mir_test_framework/using_stub_client_platform.h"
420
421 #include <gtest/gtest.h>
422 #include <gmock/gmock.h>
423@@ -34,6 +35,7 @@
424
425 namespace mf = mir::frontend;
426 namespace mfd = mir::frontend::detail;
427+namespace mtf = mir_test_framework;
428
429 /*************************************************************************/
430 /*************************************************************************/
431@@ -136,7 +138,7 @@
432 }
433 };
434
435-struct DemoServerConfiguration : mir_test_framework::StubbedServerConfiguration
436+struct DemoServerConfiguration : mtf::StubbedServerConfiguration
437 {
438 std::shared_ptr<mf::ConnectionCreator> the_connection_creator() override
439 {
440@@ -151,11 +153,12 @@
441
442 };
443
444-struct DemoPrivateProtobuf : mir_test_framework::InProcessServer
445+struct DemoPrivateProtobuf : mtf::InProcessServer
446 {
447 mir::DefaultServerConfiguration& server_config() override { return my_server_config; }
448
449 DemoServerConfiguration my_server_config;
450+ mtf::UsingStubClientPlatform using_stub_client_platform;
451
452 std::shared_ptr<DemoConnectionCreator> demo_connection_creator;
453
454@@ -163,7 +166,7 @@
455 {
456 ::demo_mir_server = &demo_mir_server;
457
458- mir_test_framework::InProcessServer::SetUp();
459+ mtf::InProcessServer::SetUp();
460 demo_connection_creator = std::dynamic_pointer_cast<DemoConnectionCreator>(my_server_config.the_connection_creator());
461
462 using namespace testing;
463
464=== modified file 'tests/acceptance-tests/test_server_disconnect.cpp'
465--- tests/acceptance-tests/test_server_disconnect.cpp 2014-03-26 05:48:59 +0000
466+++ tests/acceptance-tests/test_server_disconnect.cpp 2014-08-12 10:44:30 +0000
467@@ -130,6 +130,40 @@
468 mt::CrossProcessAction configure_display;
469 mt::CrossProcessAction disconnect;
470 };
471+
472+/*
473+ * This client will self-terminate on server connection break (through the default
474+ * lifecycle handler).
475+ */
476+struct TerminatingTestingClientConfiguration : mtf::TestingClientConfiguration
477+{
478+ void exec() override
479+ {
480+ MirConnection* connection{nullptr};
481+
482+ connect.exec([&] {
483+ connection = mir_connect_sync(mtf::test_socket_file().c_str() , __PRETTY_FUNCTION__);
484+ EXPECT_TRUE(mir_connection_is_valid(connection));
485+ });
486+
487+ create_surface_sync.wait_for_signal_ready_for();
488+
489+ MirSurfaceParameters const parameters =
490+ {
491+ __PRETTY_FUNCTION__,
492+ 1, 1,
493+ mir_pixel_format_abgr_8888,
494+ mir_buffer_usage_hardware,
495+ mir_display_output_id_invalid
496+ };
497+ mir_connection_create_surface_sync(connection, &parameters);
498+
499+ mir_connection_release(connection);
500+ }
501+
502+ mt::CrossProcessAction connect;
503+ mtf::CrossProcessSync create_surface_sync;
504+};
505 }
506
507 TEST_F(ServerDisconnect, client_detects_server_shutdown)
508@@ -168,3 +202,29 @@
509 client_config.disconnect();
510 });
511 }
512+
513+TEST_F(ServerDisconnect, causes_client_to_terminate_by_default)
514+{
515+ TestingServerConfiguration server_config;
516+ launch_server_process(server_config);
517+
518+ TerminatingTestingClientConfiguration client_config;
519+ launch_client_process(client_config);
520+
521+ run_in_test_process([this, &client_config]
522+ {
523+ client_config.connect();
524+ shutdown_server_process();
525+
526+ /*
527+ * While trying to create a surface the connection break will be detected
528+ * and the client should self-terminate.
529+ */
530+ client_config.create_surface_sync.signal_ready();
531+
532+ auto const client_results = wait_for_shutdown_client_processes();
533+ ASSERT_EQ(1, client_results.size());
534+ EXPECT_EQ(mtf::TerminationReason::child_terminated_by_signal,
535+ client_results[0].reason);
536+ });
537+}
538
539=== modified file 'tests/acceptance-tests/test_server_shutdown.cpp'
540--- tests/acceptance-tests/test_server_shutdown.cpp 2014-08-07 10:27:18 +0000
541+++ tests/acceptance-tests/test_server_shutdown.cpp 2014-08-12 10:44:30 +0000
542@@ -329,6 +329,8 @@
543
544 /* Notify the clients that we are done (we only need to set the flag once) */
545 server_done.set();
546+
547+ wait_for_shutdown_client_processes();
548 });
549
550 /*
551
552=== modified file 'tests/acceptance-tests/test_stale_frames.cpp'
553--- tests/acceptance-tests/test_stale_frames.cpp 2014-07-25 10:02:18 +0000
554+++ tests/acceptance-tests/test_stale_frames.cpp 2014-08-12 10:44:30 +0000
555@@ -25,7 +25,6 @@
556 #include "mir/graphics/buffer.h"
557 #include "mir/graphics/buffer_id.h"
558
559-#include "mir_test_framework/using_stub_client_platform.h"
560 #include "mir_test_framework/stubbed_server_configuration.h"
561 #include "mir_test_framework/basic_client_server_fixture.h"
562 #include "mir_test_doubles/stub_renderer.h"
563@@ -180,7 +179,6 @@
564 }
565
566 MirSurface* surface;
567- mtf::UsingStubClientPlatform using_stub_client_platform;
568 };
569
570 }
571
572=== modified file 'tests/acceptance-tests/test_test_framework.cpp'
573--- tests/acceptance-tests/test_test_framework.cpp 2014-03-06 06:05:17 +0000
574+++ tests/acceptance-tests/test_test_framework.cpp 2014-08-12 10:44:30 +0000
575@@ -19,6 +19,7 @@
576 #include "mir_test_framework/display_server_test_fixture.h"
577 #include "mir_test_framework/testing_server_configuration.h"
578 #include "mir_test_framework/in_process_server.h"
579+#include "mir_test_framework/using_stub_client_platform.h"
580
581 #include "mir_toolkit/mir_client_library.h"
582
583@@ -74,6 +75,7 @@
584 virtual mir::DefaultServerConfiguration& server_config() { return server_config_; }
585
586 mir_test_framework::StubbedServerConfiguration server_config_;
587+ mir_test_framework::UsingStubClientPlatform using_stub_client_platform;
588 };
589 }
590
591
592=== modified file 'tests/integration-tests/client/test_client_render.cpp'
593--- tests/integration-tests/client/test_client_render.cpp 2014-07-30 15:25:54 +0000
594+++ tests/integration-tests/client/test_client_render.cpp 2014-08-12 10:44:30 +0000
595@@ -57,6 +57,10 @@
596 static mtd::DrawPatternCheckered<2,2> draw_pattern1(pattern1);
597 static const char socket_file[] = "./test_client_ipc_render_socket";
598
599+void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*)
600+{
601+}
602+
603 struct TestClient
604 {
605 static MirPixelFormat select_format_for_visual_id(int visual_id)
606@@ -110,6 +114,9 @@
607 }
608
609 mir_surface_release_sync(surface);
610+ // Clear the lifecycle callback in order not to get SIGTERM by the default
611+ // lifecycle handler during connection teardown
612+ mir_connection_set_lifecycle_event_callback(connection, null_lifecycle_callback, nullptr);
613 mir_connection_release(connection);
614 return 0;
615 }
616@@ -167,6 +174,9 @@
617 }
618
619 mir_surface_release_sync(mir_surface);
620+ // Clear the lifecycle callback in order not to get SIGTERM by the default
621+ // lifecycle handler during connection teardown
622+ mir_connection_set_lifecycle_event_callback(connection, null_lifecycle_callback, nullptr);
623 mir_connection_release(connection);
624 return 0;
625 }
626
627=== modified file 'tests/integration-tests/shell/test_session_lifecycle_event.cpp'
628--- tests/integration-tests/shell/test_session_lifecycle_event.cpp 2014-07-21 03:35:31 +0000
629+++ tests/integration-tests/shell/test_session_lifecycle_event.cpp 2014-08-12 10:44:30 +0000
630@@ -19,82 +19,71 @@
631 #include "mir/scene/null_session_listener.h"
632 #include "src/server/scene/application_session.h"
633
634-#include "mir_test_framework/display_server_test_fixture.h"
635+#include "mir_test_framework/stubbed_server_configuration.h"
636+#include "mir_test_framework/basic_client_server_fixture.h"
637+#include "mir_test_framework/in_process_server.h"
638
639 #include "mir_toolkit/mir_client_library.h"
640
641 #include <gtest/gtest.h>
642 #include <gmock/gmock.h>
643
644-#include <thread>
645-#include <unistd.h>
646-#include <fcntl.h>
647-
648 namespace ms = mir::scene;
649-namespace msh = mir::shell;
650 namespace mtf = mir_test_framework;
651
652 namespace
653 {
654-char const* const mir_test_socket = mtf::test_socket_file().c_str();
655
656 struct MockStateHandler
657 {
658 MOCK_METHOD1(state_changed, void (MirLifecycleState));
659 };
660
661+void lifecycle_callback(MirConnection* /*connection*/, MirLifecycleState state, void* context)
662+{
663+ auto const handler = static_cast<MockStateHandler*>(context);
664+ handler->state_changed(state);
665+}
666+
667 class StubSessionListener : public ms::NullSessionListener
668 {
669 void stopping(std::shared_ptr<ms::Session> const& session)
670 {
671- std::shared_ptr<ms::ApplicationSession> app_session(
672- std::static_pointer_cast<ms::ApplicationSession>(session)
673- );
674+ auto const app_session = std::static_pointer_cast<ms::ApplicationSession>(session);
675
676 app_session->set_lifecycle_state(mir_lifecycle_state_will_suspend);
677 }
678 };
679
680-using LifecycleEventTest = BespokeDisplayServerTestFixture;
681+struct StubServerConfig : mtf::StubbedServerConfiguration
682+{
683+ std::shared_ptr<ms::SessionListener> the_session_listener() override
684+ {
685+ return std::make_shared<StubSessionListener>();
686+ }
687+};
688+
689+struct LifecycleEventTest : mtf::InProcessServer
690+{
691+ StubServerConfig server_configuration;
692+
693+ mir::DefaultServerConfiguration& server_config() override
694+ { return server_configuration; }
695+};
696+
697+}
698+
699 TEST_F(LifecycleEventTest, lifecycle_event_test)
700 {
701 using namespace ::testing;
702
703- struct ServerConfig : TestingServerConfiguration
704- {
705- std::shared_ptr<ms::SessionListener> the_session_listener() override
706- {
707- return std::make_shared<StubSessionListener>();
708- }
709- } server_config;
710-
711- launch_server_process(server_config);
712-
713- struct ClientConfig : TestingClientConfiguration
714- {
715- static void lifecycle_callback(MirConnection* /*connection*/, MirLifecycleState state, void* context)
716- {
717- auto config = static_cast<ClientConfig*>(context);
718- config->handler->state_changed(state);
719- }
720-
721- void exec()
722- {
723- handler = std::make_shared<MockStateHandler>();
724-
725- MirConnection* connection = mir_connect_sync(mir_test_socket, "testapp");
726- mir_connection_set_lifecycle_event_callback(connection, lifecycle_callback, this);
727-
728- EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_state_will_suspend))).Times(1);
729- EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_connection_lost))).Times(AtMost(1));
730- mir_connection_release(connection);
731-
732- handler.reset();
733- }
734-
735- std::shared_ptr<MockStateHandler> handler;
736- } client_config;
737-
738- launch_client_process(client_config);
739-}
740+ auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
741+
742+ auto const handler = std::make_shared<MockStateHandler>();
743+ mir_connection_set_lifecycle_event_callback(connection, lifecycle_callback, handler.get());
744+
745+ EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_state_will_suspend))).Times(1);
746+ EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_connection_lost))).Times(AtMost(1));
747+
748+ mir_connection_release(connection);
749 }
750
751=== modified file 'tests/mir_test_framework/display_server_test_fixture.cpp'
752--- tests/mir_test_framework/display_server_test_fixture.cpp 2014-04-10 22:23:27 +0000
753+++ tests/mir_test_framework/display_server_test_fixture.cpp 2014-08-12 10:44:30 +0000
754@@ -87,6 +87,11 @@
755 return process_manager.wait_for_shutdown_server_process();
756 }
757
758+std::vector<mtf::Result> BespokeDisplayServerTestFixture::wait_for_shutdown_client_processes()
759+{
760+ return process_manager.wait_for_shutdown_client_processes();
761+}
762+
763 void BespokeDisplayServerTestFixture::terminate_client_processes()
764 {
765 process_manager.terminate_client_processes();
766
767=== modified file 'tests/mir_test_framework/testing_process_manager.cpp'
768--- tests/mir_test_framework/testing_process_manager.cpp 2014-04-10 22:23:27 +0000
769+++ tests/mir_test_framework/testing_process_manager.cpp 2014-08-12 10:44:30 +0000
770@@ -203,6 +203,18 @@
771 return result;
772 }
773
774+std::vector<mtf::Result> mtf::TestingProcessManager::wait_for_shutdown_client_processes()
775+{
776+ std::vector<Result> results;
777+
778+ for (auto const& client : clients)
779+ results.push_back(client->wait_for_termination());
780+
781+ clients.clear();
782+
783+ return results;
784+}
785+
786 void mtf::TestingProcessManager::terminate_client_processes()
787 {
788 if (is_test_process)
789
790=== modified file 'tests/mir_test_framework/using_stub_client_platform.cpp'
791--- tests/mir_test_framework/using_stub_client_platform.cpp 2014-08-05 10:18:13 +0000
792+++ tests/mir_test_framework/using_stub_client_platform.cpp 2014-08-12 10:44:30 +0000
793@@ -18,6 +18,7 @@
794
795 #include "mir_test_framework/using_stub_client_platform.h"
796 #include "mir_test_framework/stub_client_connection_configuration.h"
797+#include "mir_toolkit/mir_client_library.h"
798 #include "src/client/mir_connection_api.h"
799
800 namespace mtf = mir_test_framework;
801@@ -26,6 +27,10 @@
802 namespace
803 {
804
805+void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*)
806+{
807+}
808+
809 class StubMirConnectionAPI : public mcl::MirConnectionAPI
810 {
811 public:
812@@ -45,6 +50,9 @@
813
814 void release(MirConnection* connection) override
815 {
816+ // Clear the lifecycle callback in order not to get SIGTERM by the default
817+ // lifecycle handler during connection teardown
818+ mir_connection_set_lifecycle_event_callback(connection, null_lifecycle_callback, nullptr);
819 return prev_api->release(connection);
820 }
821
822
823=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
824--- tests/unit-tests/client/test_client_mir_surface.cpp 2014-07-30 15:25:54 +0000
825+++ tests/unit-tests/client/test_client_mir_surface.cpp 2014-08-12 10:44:30 +0000
826@@ -392,6 +392,10 @@
827 {
828 }
829
830+void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*)
831+{
832+}
833+
834 MATCHER_P(BufferPackageMatches, package, "")
835 {
836 // Can't simply use memcmp() on the whole struct because age is not sent over the wire
837@@ -415,6 +419,13 @@
838 connect_to_test_server();
839 }
840
841+ ~MirClientSurfaceTest()
842+ {
843+ // Clear the lifecycle callback in order not to get SIGTERM by the default
844+ // lifecycle handler during connection teardown
845+ connection->register_lifecycle_event_callback(null_lifecycle_callback, nullptr);
846+ }
847+
848 void start_test_server()
849 {
850 // In case an earlier test left a stray file

Subscribers

People subscribed via source and target branches