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

« back to all changes in this revision

Viewing changes to tests/acceptance-tests/throwback/test_client_library_errors.cpp

  • Committer: Package Import Robot
  • Author(s): Alexandros Frantzis
  • Date: 2015-10-08 16:12:19 UTC
  • mto: This revision was merged to the branch mainline in revision 109.
  • Revision ID: package-import@ubuntu.com-20151008161219-emk4a1ys51yy0wjb
Tags: upstream-0.17.0+15.10.20151008.2
ImportĀ upstreamĀ versionĀ 0.17.0+15.10.20151008.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright Ā© 2014 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
 
17
 */
 
18
 
 
19
#include "mir_toolkit/mir_client_library.h"
 
20
#include "mir_toolkit/debug/surface.h"
 
21
 
 
22
#include "src/include/client/mir/client_platform_factory.h"
 
23
#include "src/include/client/mir/client_platform.h"
 
24
#include "src/include/client/mir/client_buffer_factory.h"
 
25
 
 
26
#include "mir/test/validity_matchers.h"
 
27
 
 
28
#include "mir_test_framework/headless_in_process_server.h"
 
29
#include "mir_test_framework/using_client_platform.h"
 
30
#include "mir_test_framework/using_stub_client_platform.h"
 
31
#include "mir_test_framework/stub_client_connection_configuration.h"
 
32
#include "mir_test_framework/any_surface.h"
 
33
#include "mir/test/doubles/stub_client_buffer_factory.h"
 
34
 
 
35
#include <gtest/gtest.h>
 
36
#include <gmock/gmock.h>
 
37
 
 
38
#include <stdexcept>
 
39
#include <boost/throw_exception.hpp>
 
40
#include <cstring>
 
41
 
 
42
namespace mcl = mir::client;
 
43
namespace mtf = mir_test_framework;
 
44
namespace mtd = mir::test::doubles;
 
45
 
 
46
namespace
 
47
{
 
48
enum Method : uint64_t
 
49
{
 
50
    none = 0,
 
51
    the_client_platform_factory = 1<<0,
 
52
    create_client_platform      = 1<<1,
 
53
    create_egl_native_window    = 1<<2,
 
54
    create_buffer_factory       = 1<<3
 
55
};
 
56
 
 
57
std::string const exception_text{"Ducks!"};
 
58
 
 
59
template<Method name, Method failure_set>
 
60
bool should_fail()
 
61
{
 
62
    return (name & failure_set);
 
63
}
 
64
 
 
65
template<Method failure_set>
 
66
class ConfigurableFailurePlatform : public mir::client::ClientPlatform
 
67
{
 
68
    std::shared_ptr<EGLNativeWindowType> create_egl_native_window(mir::client::EGLNativeSurface *)
 
69
    {
 
70
        if (should_fail<Method::create_egl_native_window, failure_set>())
 
71
        {
 
72
            BOOST_THROW_EXCEPTION(std::runtime_error{exception_text});
 
73
        }
 
74
        return std::shared_ptr<EGLNativeWindowType>{};
 
75
    }
 
76
 
 
77
    void populate(MirPlatformPackage&) const override
 
78
    {
 
79
    }
 
80
 
 
81
    MirPlatformMessage* platform_operation(MirPlatformMessage const*) override
 
82
    {
 
83
        return nullptr;
 
84
    }
 
85
 
 
86
    MirPlatformType platform_type() const
 
87
    {
 
88
        BOOST_THROW_EXCEPTION(std::runtime_error{exception_text});
 
89
        return MirPlatformType::mir_platform_type_gbm;
 
90
    }
 
91
    std::shared_ptr<mir::client::ClientBufferFactory> create_buffer_factory()
 
92
    {
 
93
        if (should_fail<Method::create_buffer_factory, failure_set>())
 
94
        {
 
95
            BOOST_THROW_EXCEPTION(std::runtime_error{exception_text});
 
96
        }
 
97
        return std::make_shared<mtd::StubClientBufferFactory>();
 
98
    }
 
99
    std::shared_ptr<EGLNativeDisplayType> create_egl_native_display()
 
100
    {
 
101
        return std::shared_ptr<EGLNativeDisplayType>{};
 
102
    }
 
103
    MirNativeBuffer *convert_native_buffer(mir::graphics::NativeBuffer*) const
 
104
    {
 
105
        BOOST_THROW_EXCEPTION(std::runtime_error{exception_text});
 
106
        return nullptr;
 
107
    }
 
108
    MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override
 
109
    {
 
110
        return mir_pixel_format_invalid;
 
111
    }
 
112
};
 
113
 
 
114
template<Method failure_set>
 
115
class ConfigurableFailureFactory: public mir::client::ClientPlatformFactory
 
116
{
 
117
    std::shared_ptr<mir::client::ClientPlatform>
 
118
    create_client_platform(mir::client::ClientContext* /*context*/) override
 
119
    {
 
120
        if (should_fail<Method::create_client_platform, failure_set>())
 
121
        {
 
122
            BOOST_THROW_EXCEPTION(std::runtime_error{exception_text});
 
123
        }
 
124
        return std::make_shared<ConfigurableFailurePlatform<failure_set>>();
 
125
    }
 
126
};
 
127
 
 
128
template<Method failure_set>
 
129
class ConfigurableFailureConfiguration : public mtf::StubConnectionConfiguration
 
130
{
 
131
    using mtf::StubConnectionConfiguration::StubConnectionConfiguration;
 
132
 
 
133
    std::shared_ptr<mir::client::ClientPlatformFactory> the_client_platform_factory() override
 
134
    {
 
135
        if (should_fail<Method::the_client_platform_factory, failure_set>())
 
136
        {
 
137
            BOOST_THROW_EXCEPTION(std::runtime_error{exception_text});
 
138
        }
 
139
        return std::make_shared<ConfigurableFailureFactory<failure_set>>();
 
140
    }
 
141
};
 
142
 
 
143
struct ClientLibraryErrors : mtf::HeadlessInProcessServer
 
144
{
 
145
    ClientLibraryErrors() { add_to_environment("MIR_SERVER_ENABLE_INPUT","off"); }
 
146
};
 
147
}
 
148
 
 
149
 
 
150
TEST_F(ClientLibraryErrors, exception_in_client_configuration_constructor_generates_error)
 
151
{
 
152
    mtf::UsingClientPlatform<ConfigurableFailureConfiguration<Method::the_client_platform_factory>> stubby;
 
153
 
 
154
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
155
 
 
156
    EXPECT_FALSE(mir_connection_is_valid(connection));
 
157
    EXPECT_THAT(mir_connection_get_error_message(connection), testing::HasSubstr(exception_text));
 
158
    mir_connection_release(connection);
 
159
}
 
160
 
 
161
TEST_F(ClientLibraryErrors, exception_in_platform_construction_generates_error)
 
162
{
 
163
    mtf::UsingClientPlatform<ConfigurableFailureConfiguration<Method::create_client_platform>> stubby;
 
164
 
 
165
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
166
 
 
167
    EXPECT_FALSE(mir_connection_is_valid(connection));
 
168
    EXPECT_THAT(mir_connection_get_error_message(connection), testing::HasSubstr(exception_text));
 
169
    mir_connection_release(connection);
 
170
}
 
171
 
 
172
TEST_F(ClientLibraryErrors, connecting_to_garbage_socket_returns_appropriate_error)
 
173
{
 
174
    using namespace testing;
 
175
    mtf::UsingStubClientPlatform stubby;
 
176
 
 
177
    auto connection = mir_connect_sync("garbage", __PRETTY_FUNCTION__);
 
178
    ASSERT_THAT(connection, NotNull());
 
179
 
 
180
    char const* error = mir_connection_get_error_message(connection);
 
181
 
 
182
    if (std::strcmp("connect: No such file or directory", error) &&
 
183
        std::strcmp("Can't find MIR server", error) &&
 
184
        !std::strstr(error, "Failed to connect to server socket"))
 
185
    {
 
186
        FAIL() << error;
 
187
    }
 
188
    mir_connection_release(connection);
 
189
}
 
190
 
 
191
TEST_F(ClientLibraryErrors, create_surface_returns_error_object_on_failure)
 
192
{
 
193
    mtf::UsingClientPlatform<ConfigurableFailureConfiguration<Method::create_buffer_factory>> stubby;
 
194
 
 
195
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
196
 
 
197
    ASSERT_THAT(connection, IsValid());
 
198
 
 
199
    auto surface = mtf::make_any_surface(connection);
 
200
    ASSERT_NE(surface, nullptr);
 
201
    EXPECT_FALSE(mir_surface_is_valid(surface));
 
202
    EXPECT_THAT(mir_surface_get_error_message(surface), testing::HasSubstr(exception_text));
 
203
 
 
204
    mir_surface_release_sync(surface);
 
205
    mir_connection_release(connection);
 
206
}
 
207
 
 
208
namespace
 
209
{
 
210
void recording_surface_callback(MirSurface*, void* ctx)
 
211
{
 
212
    auto called = static_cast<bool*>(ctx);
 
213
    *called = true;
 
214
}
 
215
}
 
216
 
 
217
TEST_F(ClientLibraryErrors, surface_release_on_error_object_still_calls_callback)
 
218
{
 
219
    mtf::UsingClientPlatform<ConfigurableFailureConfiguration<Method::create_buffer_factory>> stubby;
 
220
 
 
221
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
222
 
 
223
    ASSERT_THAT(connection, IsValid());
 
224
 
 
225
    auto surface = mtf::make_any_surface(connection);
 
226
 
 
227
    ASSERT_NE(surface, nullptr);
 
228
    EXPECT_FALSE(mir_surface_is_valid(surface));
 
229
    EXPECT_THAT(mir_surface_get_error_message(surface), testing::HasSubstr(exception_text));
 
230
 
 
231
    bool callback_called{false};
 
232
    mir_surface_release(surface, &recording_surface_callback, &callback_called);
 
233
    EXPECT_TRUE(callback_called);
 
234
    mir_connection_release(connection);
 
235
}
 
236
 
 
237
 
 
238
TEST_F(ClientLibraryErrors, create_surface_returns_error_object_on_failure_in_reply_processing)
 
239
{
 
240
    mtf::UsingClientPlatform<ConfigurableFailureConfiguration<Method::create_egl_native_window>> stubby;
 
241
 
 
242
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
243
 
 
244
    ASSERT_THAT(connection, IsValid());
 
245
 
 
246
    auto surface = mtf::make_any_surface(connection);
 
247
    ASSERT_NE(surface, nullptr);
 
248
    EXPECT_FALSE(mir_surface_is_valid(surface));
 
249
    EXPECT_THAT(mir_surface_get_error_message(surface), testing::HasSubstr(exception_text));
 
250
 
 
251
    mir_surface_release_sync(surface);
 
252
    mir_connection_release(connection);
 
253
}
 
254
 
 
255
TEST_F(ClientLibraryErrors, passing_invalid_parent_id_to_surface_create)
 
256
{
 
257
    using namespace testing;
 
258
 
 
259
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
260
 
 
261
    ASSERT_THAT(connection, IsValid());
 
262
 
 
263
    // An ID that parses as valid, but doesn't correspond to any
 
264
    auto invalid_id = mir_persistent_id_from_string("05f223a2-39e5-48b9-9416-b0ce837351b6");
 
265
 
 
266
    auto spec = mir_connection_create_spec_for_input_method(connection,
 
267
                                                            200, 200,
 
268
                                                            mir_pixel_format_argb_8888);
 
269
    MirRectangle rect{
 
270
        100,
 
271
        100,
 
272
        10,
 
273
        10
 
274
    };
 
275
    mir_surface_spec_attach_to_foreign_parent(spec, invalid_id, &rect, mir_edge_attachment_any);
 
276
 
 
277
    auto surface = mir_surface_create_sync(spec);
 
278
    EXPECT_THAT(surface, Not(IsValid()));
 
279
    EXPECT_THAT(mir_surface_get_error_message(surface), MatchesRegex(".*Lookup.*failed.*"));
 
280
 
 
281
    mir_persistent_id_release(invalid_id);
 
282
    mir_surface_spec_release(spec);
 
283
    mir_surface_release_sync(surface);
 
284
    mir_connection_release(connection);
 
285
}
 
286
 
 
287
using ClientLibraryErrorsDeathTest = ClientLibraryErrors;
 
288
 
 
289
 
 
290
TEST_F(ClientLibraryErrorsDeathTest, creating_surface_on_garbage_connection_is_fatal)
 
291
{
 
292
    mtf::UsingStubClientPlatform stubby;
 
293
 
 
294
    auto connection = mir_connect_sync("garbage", __PRETTY_FUNCTION__);
 
295
 
 
296
    ASSERT_FALSE(mir_connection_is_valid(connection));
 
297
    EXPECT_DEATH(
 
298
        mtf::make_any_surface(connection), "");
 
299
 
 
300
    mir_connection_release(connection);
 
301
}
 
302
 
 
303
 
 
304
TEST_F(ClientLibraryErrorsDeathTest, creating_surface_synchronosly_on_malconstructed_connection_is_fatal)
 
305
{
 
306
    mtf::UsingClientPlatform<ConfigurableFailureConfiguration<Method::the_client_platform_factory>> stubby;
 
307
 
 
308
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
309
 
 
310
    ASSERT_FALSE(mir_connection_is_valid(connection));
 
311
    EXPECT_DEATH(mtf::make_any_surface(connection), "");
 
312
 
 
313
    mir_connection_release(connection);
 
314
}
 
315
 
 
316
TEST_F(ClientLibraryErrorsDeathTest, creating_surface_synchronosly_on_invalid_connection_is_fatal)
 
317
{
 
318
    mtf::UsingClientPlatform<ConfigurableFailureConfiguration<Method::create_client_platform>> stubby;
 
319
 
 
320
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
321
 
 
322
    ASSERT_FALSE(mir_connection_is_valid(connection));
 
323
    EXPECT_DEATH(mtf::make_any_surface(connection), "");
 
324
 
 
325
    mir_connection_release(connection);
 
326
}
 
327
 
 
328
TEST_F(ClientLibraryErrorsDeathTest, surface_spec_attaching_invalid_parent_id)
 
329
{
 
330
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
331
 
 
332
    auto spec = mir_connection_create_spec_for_input_method(connection, 100, 100, mir_pixel_format_argb_8888);
 
333
 
 
334
    MirRectangle rect{
 
335
        100,
 
336
        100,
 
337
        10,
 
338
        10
 
339
    };
 
340
    EXPECT_DEATH(mir_surface_spec_attach_to_foreign_parent(spec, nullptr, &rect, mir_edge_attachment_any), "");
 
341
 
 
342
    mir_connection_release(connection);
 
343
}
 
344
 
 
345
TEST_F(ClientLibraryErrorsDeathTest, surface_spec_attaching_invalid_rectangle)
 
346
{
 
347
    auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
 
348
 
 
349
    auto spec = mir_connection_create_spec_for_input_method(connection, 100, 100, mir_pixel_format_argb_8888);
 
350
 
 
351
    auto id = mir_persistent_id_from_string("fa69b2e9-d507-4005-be61-5068f40a5aec");
 
352
 
 
353
    EXPECT_DEATH(mir_surface_spec_attach_to_foreign_parent(spec, id, nullptr, mir_edge_attachment_any), "");
 
354
 
 
355
    mir_persistent_id_release(id);
 
356
    mir_connection_release(connection);
 
357
}