~ubuntu-branches/ubuntu/wily/mir/wily-proposed

« back to all changes in this revision

Viewing changes to tests/acceptance-tests/test_server_shutdown.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release
  • Date: 2014-10-10 14:01:26 UTC
  • mto: This revision was merged to the branch mainline in revision 84.
  • Revision ID: package-import@ubuntu.com-20141010140126-n1czko8na1kuz4ll
Tags: upstream-0.8.0+14.10.20141010
ImportĀ upstreamĀ versionĀ 0.8.0+14.10.20141010

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
17
17
 */
18
18
 
19
 
#include "mir_toolkit/mir_client_library.h"
20
 
#include "mir/compositor/renderer.h"
21
 
#include "mir/compositor/renderer_factory.h"
22
 
#include "mir/compositor/display_buffer_compositor.h"
23
 
#include "mir/compositor/display_buffer_compositor_factory.h"
24
 
#include "mir/input/composite_event_filter.h"
25
 
#include "mir/run_mir.h"
26
19
#include "mir/fatal.h"
27
20
 
28
21
#include "mir_test_framework/display_server_test_fixture.h"
29
 
#include "mir_test/fake_event_hub_input_configuration.h"
30
 
#include "mir_test/fake_event_hub.h"
31
 
#include "mir_test_framework/cross_process_sync.h"
32
 
#include "mir_test_doubles/stub_renderer.h"
33
22
 
34
23
#include <gtest/gtest.h>
35
24
 
36
 
#include <thread>
37
 
#include <cstdio>
38
 
#include <fcntl.h>
39
 
 
40
 
namespace mc = mir::compositor;
41
 
namespace mg = mir::graphics;
42
 
namespace mi = mir::input;
43
 
namespace mia = mir::input::android;
44
25
namespace mtf = mir_test_framework;
45
 
namespace mtd = mir::test::doubles;
46
 
namespace ms = mir::scene;
47
 
namespace geom = mir::geometry;
48
 
 
49
 
namespace
50
 
{
51
 
 
52
 
char const* const mir_test_socket = mtf::test_socket_file().c_str();
53
 
 
54
 
class StubRendererFactory : public mc::RendererFactory
55
 
{
56
 
public:
57
 
    std::unique_ptr<mc::Renderer> create_renderer_for(geom::Rectangle const&, mc::DestinationAlpha)
58
 
    {
59
 
        return std::unique_ptr<mc::Renderer>(new mtd::StubRenderer());
60
 
    }
61
 
};
62
 
 
63
 
class ExceptionThrowingDisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory
64
 
{
65
 
public:
66
 
    std::unique_ptr<mc::DisplayBufferCompositor>
67
 
        create_compositor_for(mg::DisplayBuffer&) override
68
 
    {
69
 
        struct ExceptionThrowingDisplayBufferCompositor : mc::DisplayBufferCompositor
70
 
        {
71
 
            void composite() override
72
 
            {
73
 
                throw std::runtime_error("ExceptionThrowingDisplayBufferCompositor");
74
 
            }
75
 
        };
76
 
 
77
 
        return std::unique_ptr<mc::DisplayBufferCompositor>(
78
 
            new ExceptionThrowingDisplayBufferCompositor{});
79
 
    }
80
 
};
81
 
 
82
 
void null_surface_callback(MirSurface*, void*)
83
 
{
84
 
}
85
 
 
86
 
class Flag
87
 
{
88
 
public:
89
 
    explicit Flag(std::string const& flag_file)
90
 
        : flag_file{flag_file}
91
 
    {
92
 
        std::remove(flag_file.c_str());
93
 
    }
94
 
 
95
 
    void set()
96
 
    {
97
 
        close(open(flag_file.c_str(), O_CREAT, S_IWUSR | S_IRUSR));
98
 
    }
99
 
 
100
 
    bool is_set()
101
 
    {
102
 
        int fd = -1;
103
 
        if ((fd = open(flag_file.c_str(), O_RDONLY, S_IWUSR | S_IRUSR)) != -1)
104
 
        {
105
 
            close(fd);
106
 
            return true;
107
 
        }
108
 
        return false;
109
 
    }
110
 
 
111
 
    void wait()
112
 
    {
113
 
        while (!is_set())
114
 
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
115
 
    }
116
 
 
117
 
private:
118
 
    std::string const flag_file;
119
 
};
120
 
 
121
 
struct FakeEventHubServerConfig : TestingServerConfiguration
122
 
{
123
 
    std::shared_ptr<mi::InputConfiguration> the_input_configuration() override
124
 
    {
125
 
        if (!input_configuration)
126
 
        {
127
 
            input_configuration =
128
 
                std::make_shared<mtd::FakeEventHubInputConfiguration>(
129
 
                    the_input_dispatcher(),
130
 
                    the_input_region(),
131
 
                    the_cursor_listener(),
132
 
                    the_touch_visualizer(),
133
 
                    the_input_report());
134
 
        }
135
 
 
136
 
        return input_configuration;
137
 
    }
138
 
 
139
 
    std::shared_ptr<mi::InputManager> the_input_manager() override
140
 
    {
141
 
        return DefaultServerConfiguration::the_input_manager();
142
 
    }
143
 
 
144
 
    std::shared_ptr<mir::shell::InputTargeter> the_input_targeter() override
145
 
    {
146
 
        return DefaultServerConfiguration::the_input_targeter();
147
 
    }
148
 
 
149
 
    std::shared_ptr<mir::input::InputDispatcher> the_input_dispatcher() override
150
 
    {
151
 
        return DefaultServerConfiguration::the_input_dispatcher();
152
 
    }
153
 
 
154
 
    mia::FakeEventHub* the_fake_event_hub()
155
 
    {
156
 
        the_input_configuration();
157
 
        return input_configuration->the_fake_event_hub();
158
 
    }
159
 
 
160
 
    std::shared_ptr<mtd::FakeEventHubInputConfiguration> input_configuration;
161
 
};
162
 
 
163
 
void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*)
164
 
{
165
 
}
166
 
 
167
 
}
168
26
 
169
27
using ServerShutdown = BespokeDisplayServerTestFixture;
170
28
 
171
 
TEST_F(ServerShutdown, server_can_shut_down_when_clients_are_blocked)
172
 
{
173
 
    Flag next_buffer_done1{"next_buffer_done1_c5d49978.tmp"};
174
 
    Flag next_buffer_done2{"next_buffer_done2_c5d49978.tmp"};
175
 
    Flag next_buffer_done3{"next_buffer_done3_c5d49978.tmp"};
176
 
    Flag server_done{"server_done_c5d49978.tmp"};
177
 
 
178
 
    struct ServerConfig : TestingServerConfiguration
179
 
    {
180
 
        std::shared_ptr<mc::RendererFactory> the_renderer_factory() override
181
 
        {
182
 
            return renderer_factory([] { return std::make_shared<StubRendererFactory>(); });
183
 
        }
184
 
    } server_config;
185
 
 
186
 
    launch_server_process(server_config);
187
 
 
188
 
    struct ClientConfig : TestingClientConfiguration
189
 
    {
190
 
        ClientConfig(Flag& next_buffer_done,
191
 
                     Flag& server_done)
192
 
            : next_buffer_done(next_buffer_done),
193
 
              server_done(server_done)
194
 
        {
195
 
        }
196
 
 
197
 
        void exec()
198
 
        {
199
 
            MirConnection* connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__);
200
 
 
201
 
            ASSERT_TRUE(connection != NULL);
202
 
 
203
 
            /* Default lifecycle handler terminates the process on disconnect, so override it */
204
 
            mir_connection_set_lifecycle_event_callback(connection, null_lifecycle_callback, nullptr);
205
 
 
206
 
            MirSurfaceParameters const request_params =
207
 
            {
208
 
                __PRETTY_FUNCTION__,
209
 
                640, 480,
210
 
                mir_pixel_format_abgr_8888,
211
 
                mir_buffer_usage_hardware,
212
 
                mir_display_output_id_invalid
213
 
            };
214
 
 
215
 
            MirSurface* surf = mir_connection_create_surface_sync(connection, &request_params);
216
 
 
217
 
            /* Ask for the first buffer (should succeed) */
218
 
            mir_surface_swap_buffers_sync(surf);
219
 
            /* Ask for the first second buffer (should block) */
220
 
            mir_surface_swap_buffers(surf, null_surface_callback, nullptr);
221
 
 
222
 
            next_buffer_done.set();
223
 
            server_done.wait();
224
 
 
225
 
            mir_connection_release(connection);
226
 
        }
227
 
 
228
 
 
229
 
        Flag& next_buffer_done;
230
 
        Flag& server_done;
231
 
    };
232
 
 
233
 
    ClientConfig client_config1{next_buffer_done1, server_done};
234
 
    ClientConfig client_config2{next_buffer_done2, server_done};
235
 
    ClientConfig client_config3{next_buffer_done3, server_done};
236
 
 
237
 
    launch_client_process(client_config1);
238
 
    launch_client_process(client_config2);
239
 
    launch_client_process(client_config3);
240
 
 
241
 
    run_in_test_process([&]
242
 
    {
243
 
        /* Wait until the clients are blocked on getting the second buffer */
244
 
        next_buffer_done1.wait();
245
 
        next_buffer_done2.wait();
246
 
        next_buffer_done3.wait();
247
 
 
248
 
        /* Shutting down the server should not block */
249
 
        shutdown_server_process();
250
 
 
251
 
        /* Notify the clients that we are done (we only need to set the flag once) */
252
 
        server_done.set();
253
 
    });
254
 
}
255
 
 
256
 
TEST_F(ServerShutdown, server_releases_resources_on_shutdown_with_connected_clients)
257
 
{
258
 
    Flag surface_created1{"surface_created1_7e9c69fc.tmp"};
259
 
    Flag surface_created2{"surface_created2_7e9c69fc.tmp"};
260
 
    Flag surface_created3{"surface_created3_7e9c69fc.tmp"};
261
 
    Flag server_done{"server_done_7e9c69fc.tmp"};
262
 
    Flag resources_freed_success{"resources_free_success_7e9c69fc.tmp"};
263
 
    Flag resources_freed_failure{"resources_free_failure_7e9c69fc.tmp"};
264
 
 
265
 
    auto server_config = std::make_shared<FakeEventHubServerConfig>();
266
 
    launch_server_process(*server_config);
267
 
 
268
 
    struct ClientConfig : TestingClientConfiguration
269
 
    {
270
 
        ClientConfig(Flag& surface_created,
271
 
                     Flag& server_done)
272
 
            : surface_created(surface_created),
273
 
              server_done(server_done)
274
 
        {
275
 
        }
276
 
 
277
 
        void exec()
278
 
        {
279
 
            MirConnection* connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__);
280
 
 
281
 
            ASSERT_TRUE(connection != NULL);
282
 
 
283
 
            MirSurfaceParameters const request_params =
284
 
            {
285
 
                __PRETTY_FUNCTION__,
286
 
                640, 480,
287
 
                mir_pixel_format_abgr_8888,
288
 
                mir_buffer_usage_hardware,
289
 
                mir_display_output_id_invalid
290
 
            };
291
 
 
292
 
            mir_connection_create_surface_sync(connection, &request_params);
293
 
 
294
 
            surface_created.set();
295
 
            server_done.wait();
296
 
 
297
 
            mir_connection_release(connection);
298
 
        }
299
 
 
300
 
        Flag& surface_created;
301
 
        Flag& server_done;
302
 
    };
303
 
 
304
 
    ClientConfig client_config1{surface_created1, server_done};
305
 
    ClientConfig client_config2{surface_created2, server_done};
306
 
    ClientConfig client_config3{surface_created3, server_done};
307
 
 
308
 
    launch_client_process(client_config1);
309
 
    launch_client_process(client_config2);
310
 
    launch_client_process(client_config3);
311
 
 
312
 
    run_in_test_process([&]
313
 
    {
314
 
        /* Wait until the clients have created a surface */
315
 
        surface_created1.wait();
316
 
        surface_created2.wait();
317
 
        surface_created3.wait();
318
 
 
319
 
        /* Shut down the server */
320
 
        shutdown_server_process();
321
 
 
322
 
        /* Wait until we have checked the resources in the server process */
323
 
        while (!resources_freed_failure.is_set() && !resources_freed_success.is_set())
324
 
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
325
 
 
326
 
        /* Fail if the resources have not been freed */
327
 
        if (resources_freed_failure.is_set())
328
 
            ADD_FAILURE();
329
 
 
330
 
        /* Notify the clients that we are done (we only need to set the flag once) */
331
 
        server_done.set();
332
 
 
333
 
        wait_for_shutdown_client_processes();
334
 
    });
335
 
 
336
 
    /*
337
 
     * Check that all resources are freed after destroying the server config.
338
 
     * Note that these checks are run multiple times: in the server process,
339
 
     * in each of the client processes and in the test process. We only care about
340
 
     * the results in the server process (in the other cases the checks will
341
 
     * succeed anyway, since we are not using the config object).
342
 
     */
343
 
    std::weak_ptr<mir::graphics::Display> display = server_config->the_display();
344
 
    std::weak_ptr<mir::compositor::Compositor> compositor = server_config->the_compositor();
345
 
    std::weak_ptr<mir::frontend::Connector> connector = server_config->the_connector();
346
 
    std::weak_ptr<mir::input::InputManager> input_manager = server_config->the_input_manager();
347
 
 
348
 
    server_config.reset();
349
 
 
350
 
    EXPECT_EQ(0, display.use_count());
351
 
    EXPECT_EQ(0, compositor.use_count());
352
 
    EXPECT_EQ(0, connector.use_count());
353
 
    EXPECT_EQ(0, input_manager.use_count());
354
 
 
355
 
    if (display.use_count() != 0 ||
356
 
        compositor.use_count() != 0 ||
357
 
        connector.use_count() != 0 ||
358
 
        input_manager.use_count() != 0)
359
 
    {
360
 
        resources_freed_failure.set();
361
 
    }
362
 
    else
363
 
    {
364
 
        resources_freed_success.set();
365
 
    }
366
 
}
367
 
 
368
29
namespace
369
30
{
370
31
bool file_exists(std::string const& filename)
590
251
    OnSignal,
591
252
    ::testing::Values(SIGQUIT, SIGABRT, SIGFPE, SIGSEGV, SIGBUS));
592
253
 
593
 
TEST(ServerShutdownWithThreadException,
594
 
     server_releases_resources_on_abnormal_input_thread_termination)
595
 
{
596
 
    auto server_config = std::make_shared<FakeEventHubServerConfig>();
597
 
    auto fake_event_hub = server_config->the_fake_event_hub();
598
 
 
599
 
    std::thread server{
600
 
        [&]
601
 
        {
602
 
            EXPECT_THROW(
603
 
                mir::run_mir(*server_config, [](mir::DisplayServer&){}),
604
 
                std::runtime_error);
605
 
        }};
606
 
 
607
 
    fake_event_hub->throw_exception_in_next_get_events();
608
 
    server.join();
609
 
 
610
 
    std::weak_ptr<mir::graphics::Display> display = server_config->the_display();
611
 
    std::weak_ptr<mir::compositor::Compositor> compositor = server_config->the_compositor();
612
 
    std::weak_ptr<mir::frontend::Connector> connector = server_config->the_connector();
613
 
    std::weak_ptr<mir::input::InputManager> input_manager = server_config->the_input_manager();
614
 
 
615
 
    server_config.reset();
616
 
 
617
 
    EXPECT_EQ(0, display.use_count());
618
 
    EXPECT_EQ(0, compositor.use_count());
619
 
    EXPECT_EQ(0, connector.use_count());
620
 
    EXPECT_EQ(0, input_manager.use_count());
621
 
}
622
 
 
623
 
TEST(ServerShutdownWithThreadException,
624
 
     server_releases_resources_on_abnormal_compositor_thread_termination)
625
 
{
626
 
    struct ServerConfig : TestingServerConfiguration
627
 
    {
628
 
        std::shared_ptr<mc::DisplayBufferCompositorFactory>
629
 
            the_display_buffer_compositor_factory() override
630
 
        {
631
 
            return display_buffer_compositor_factory(
632
 
                [this]()
633
 
                {
634
 
                    return std::make_shared<ExceptionThrowingDisplayBufferCompositorFactory>();
635
 
                });
636
 
        }
637
 
    };
638
 
 
639
 
    auto server_config = std::make_shared<ServerConfig>();
640
 
 
641
 
    std::thread server{
642
 
        [&]
643
 
        {
644
 
            EXPECT_THROW(
645
 
                mir::run_mir(*server_config, [](mir::DisplayServer&){}),
646
 
                std::runtime_error);
647
 
        }};
648
 
 
649
 
    server.join();
650
 
 
651
 
    std::weak_ptr<mir::graphics::Display> display = server_config->the_display();
652
 
    std::weak_ptr<mir::compositor::Compositor> compositor = server_config->the_compositor();
653
 
    std::weak_ptr<mir::frontend::Connector> connector = server_config->the_connector();
654
 
    std::weak_ptr<mir::input::InputManager> input_manager = server_config->the_input_manager();
655
 
 
656
 
    server_config.reset();
657
 
 
658
 
    EXPECT_EQ(0, display.use_count());
659
 
    EXPECT_EQ(0, compositor.use_count());
660
 
    EXPECT_EQ(0, connector.use_count());
661
 
    EXPECT_EQ(0, input_manager.use_count());
662
 
}