Merge lp:~afrantzis/mir/better-client-api-override into lp:mir
- better-client-api-override
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alexandros Frantzis |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1834 |
Proposed branch: | lp:~afrantzis/mir/better-client-api-override |
Merge into: | lp:mir |
Diff against target: |
447 lines (+180/-163) 6 files modified
include/test/mir_test_framework/using_stub_client_platform.h (+11/-3) src/client/api_impl.h (+0/-27) src/client/api_impl_types.h (+0/-32) src/client/mir_connection_api.cpp (+73/-66) src/client/mir_connection_api.h (+59/-0) tests/mir_test_framework/using_stub_client_platform.cpp (+37/-35) |
To merge this branch: | bzr merge lp:~afrantzis/mir/better-client-api-override |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Chris Halse Rogers | Approve | ||
Kevin DuBois (community) | Approve | ||
Alan Griffiths | Approve | ||
Review via email: mp+229479@code.launchpad.net |
Commit message
client: Rework mechanism to override Mir client functions
Description of the change
client: Rework mechanism to override Mir client functions
In addition to being more versatile and powerful in general, the proposed approach is needed so that we can fix the tests for [1] (which is currently WIP) in a more sane way. I have provided override points only for connect, release (which existed before) and a new one (the ConnectionConfi
IMPORTANT UPDATE: it turns out that because of recent changes in how we build unit and integration tests, client global code is executed twice: once from the client code that was compiled in mir_unit_
and destructors of global objects are run twice, causing issues. I have worked around this issue in r1814, but this problem may come back to bite us at later time, so it's worth some further consideration (not as part of this MP please, unless the proposed workaround is not acceptable).
[1] https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1814
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
I've no objection to this step (the direction is sane), but I've a feeling that this and the [Default]
Kevin DuBois (kdub) wrote : | # |
hah, I was just staring at this today when writing an integration test, and thought that this should be done. looks good to me.
Chris Halse Rogers (raof) wrote : | # |
Looks sensible to me.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Alexandros Frantzis (afrantzis) wrote : | # |
Oh, no...
Setting up libmirplatform1
dpkg: dependency problems prevent configuration of libmirplatform-
libmirplatform
Package libboost-
dpkg: error processing package libmirplatform-
dependency problems - leaving unconfigured
dpkg: libmirplatform:
libmirplatform
Version of libmirplatform:
Setting up libmirplatform:
Setting up libmirplatformg
Setting up libmirplatformg
dpkg: dependency problems prevent configuration of libmirserver-
libmirserver-
Package libmirplatform-
dpkg: error processing package libmirserver-
dependency problems - leaving unconfigured
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
FAILURE: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Alexandros Frantzis (afrantzis) wrote : | # |
Started by upstream project "mir-mediumtest
Building remotely on cyclops-node07 in workspace /home/ubuntu/
java.io.
at hudson.
at hudson.
at hudson.
at jenkins.
at hudson.
at hudson.
at hudson.
at hudson.
at hudson.
Archiving artifacts
Build was marked for publishing on https:/
Finished: FAILURE
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'include/test/mir_test_framework/using_stub_client_platform.h' |
2 | --- include/test/mir_test_framework/using_stub_client_platform.h 2014-01-29 13:06:25 +0000 |
3 | +++ include/test/mir_test_framework/using_stub_client_platform.h 2014-08-05 10:18:32 +0000 |
4 | @@ -19,7 +19,15 @@ |
5 | #ifndef MIR_TEST_FRAMEWORK_USING_STUB_CLIENT_PLATFORM_H_ |
6 | #define MIR_TEST_FRAMEWORK_USING_STUB_CLIENT_PLATFORM_H_ |
7 | |
8 | -#include "src/client/api_impl_types.h" |
9 | +#include <memory> |
10 | + |
11 | +namespace mir |
12 | +{ |
13 | +namespace client |
14 | +{ |
15 | +class MirConnectionAPI; |
16 | +} |
17 | +} |
18 | |
19 | namespace mir_test_framework |
20 | { |
21 | @@ -34,8 +42,8 @@ |
22 | UsingStubClientPlatform(UsingStubClientPlatform const&) = delete; |
23 | UsingStubClientPlatform operator=(UsingStubClientPlatform const&) = delete; |
24 | |
25 | - mir_connect_impl_func const prev_mir_connect_impl; |
26 | - mir_connection_release_impl_func const prev_mir_connection_release_impl; |
27 | + mir::client::MirConnectionAPI* prev_api; |
28 | + std::unique_ptr<mir::client::MirConnectionAPI> stub_api; |
29 | }; |
30 | |
31 | } |
32 | |
33 | === removed file 'src/client/api_impl.h' |
34 | --- src/client/api_impl.h 2014-01-28 18:21:14 +0000 |
35 | +++ src/client/api_impl.h 1970-01-01 00:00:00 +0000 |
36 | @@ -1,27 +0,0 @@ |
37 | -/* |
38 | - * Copyright © 2014 Canonical Ltd. |
39 | - * |
40 | - * This program is free software: you can redistribute it and/or modify it |
41 | - * under the terms of the GNU Lesser General Public License version 3, |
42 | - * as published by the Free Software Foundation. |
43 | - * |
44 | - * This program is distributed in the hope that it will be useful, |
45 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
46 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
47 | - * GNU Lesser General Public License for more details. |
48 | - * |
49 | - * You should have received a copy of the GNU Lesser General Public License |
50 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
51 | - * |
52 | - * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
53 | - */ |
54 | - |
55 | -#ifndef MIR_CLIENT_API_IMPL_H_ |
56 | -#define MIR_CLIENT_API_IMPL_H_ |
57 | - |
58 | -#include "api_impl_types.h" |
59 | - |
60 | -extern mir_connect_impl_func mir_connect_impl; |
61 | -extern mir_connection_release_impl_func mir_connection_release_impl; |
62 | - |
63 | -#endif /* MIR_CLIENT_API_IMPL_H_ */ |
64 | |
65 | === removed file 'src/client/api_impl_types.h' |
66 | --- src/client/api_impl_types.h 2014-01-28 18:21:14 +0000 |
67 | +++ src/client/api_impl_types.h 1970-01-01 00:00:00 +0000 |
68 | @@ -1,32 +0,0 @@ |
69 | -/* |
70 | - * Copyright © 2014 Canonical Ltd. |
71 | - * |
72 | - * This program is free software: you can redistribute it and/or modify it |
73 | - * under the terms of the GNU Lesser General Public License version 3, |
74 | - * as published by the Free Software Foundation. |
75 | - * |
76 | - * This program is distributed in the hope that it will be useful, |
77 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
78 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
79 | - * GNU Lesser General Public License for more details. |
80 | - * |
81 | - * You should have received a copy of the GNU Lesser General Public License |
82 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
83 | - * |
84 | - * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
85 | - */ |
86 | - |
87 | -#ifndef MIR_CLIENT_API_IMPL_TYPES_H_ |
88 | -#define MIR_CLIENT_API_IMPL_TYPES_H_ |
89 | - |
90 | -#include "mir_toolkit/client_types.h" |
91 | - |
92 | -typedef MirWaitHandle* (*mir_connect_impl_func)( |
93 | - char const *server, |
94 | - char const *app_name, |
95 | - mir_connected_callback callback, |
96 | - void *context); |
97 | - |
98 | -typedef void (*mir_connection_release_impl_func)(MirConnection *connection); |
99 | - |
100 | -#endif /* MIR_CLIENT_API_IMPL_TYPES_H_ */ |
101 | |
102 | === modified file 'src/client/mir_connection_api.cpp' |
103 | --- src/client/mir_connection_api.cpp 2014-06-09 13:48:18 +0000 |
104 | +++ src/client/mir_connection_api.cpp 2014-08-05 10:18:32 +0000 |
105 | @@ -16,6 +16,7 @@ |
106 | * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
107 | */ |
108 | |
109 | +#include "mir_connection_api.h" |
110 | #include "mir_toolkit/mir_connection.h" |
111 | #include "mir_toolkit/mir_client_library_drm.h" |
112 | #include "mir/default_configuration.h" |
113 | @@ -25,7 +26,6 @@ |
114 | //#include "egl_native_display_container.h" |
115 | #include "default_connection_configuration.h" |
116 | #include "display_configuration.h" |
117 | -#include "api_impl_types.h" |
118 | #include "error_connections.h" |
119 | |
120 | |
121 | @@ -49,78 +49,85 @@ |
122 | return ((a - 1) / b) + 1; |
123 | } |
124 | |
125 | - |
126 | -MirWaitHandle* mir_default_connect( |
127 | - char const* socket_file, |
128 | - char const* name, |
129 | - mir_connected_callback callback, |
130 | - void* context) |
131 | +class DefaultMirConnectionAPI : public mcl::MirConnectionAPI |
132 | { |
133 | - |
134 | - try |
135 | - { |
136 | - std::string sock; |
137 | - if (socket_file) |
138 | - sock = socket_file; |
139 | +public: |
140 | + MirWaitHandle* connect( |
141 | + char const* socket_file, |
142 | + char const* name, |
143 | + mir_connected_callback callback, |
144 | + void* context) override |
145 | + { |
146 | + try |
147 | + { |
148 | + std::string sock; |
149 | + if (socket_file) |
150 | + sock = socket_file; |
151 | + else |
152 | + { |
153 | + auto socket_env = getenv("MIR_SOCKET"); |
154 | + if (socket_env) |
155 | + sock = socket_env; |
156 | + else |
157 | + sock = mir::default_server_socket; |
158 | + } |
159 | + |
160 | + auto const conf = configuration(sock); |
161 | + |
162 | + std::unique_ptr<MirConnection> connection{new MirConnection(*conf)}; |
163 | + auto const result = connection->connect(name, callback, context); |
164 | + connection.release(); |
165 | + return result; |
166 | + } |
167 | + catch (std::exception const& x) |
168 | + { |
169 | + MirConnection* error_connection = new MirConnection(x.what()); |
170 | + mcl::ErrorConnections::instance().insert(error_connection); |
171 | + callback(error_connection, context); |
172 | + return nullptr; |
173 | + } |
174 | + } |
175 | + |
176 | + void release(MirConnection* connection) override |
177 | + { |
178 | + if (!mcl::ErrorConnections::instance().contains(connection)) |
179 | + { |
180 | + try |
181 | + { |
182 | + auto wait_handle = connection->disconnect(); |
183 | + wait_handle->wait_for_all(); |
184 | + } |
185 | + catch (std::exception const&) |
186 | + { |
187 | + // We're implementing a C API so no exceptions are to be |
188 | + // propagated. And that's OK because if disconnect() fails, |
189 | + // we don't care why. We're finished with the connection anyway. |
190 | + } |
191 | + } |
192 | else |
193 | { |
194 | - auto socket_env = getenv("MIR_SOCKET"); |
195 | - if (socket_env) |
196 | - sock = socket_env; |
197 | - else |
198 | - sock = mir::default_server_socket; |
199 | + mcl::ErrorConnections::instance().remove(connection); |
200 | } |
201 | |
202 | - mcl::DefaultConnectionConfiguration conf{sock}; |
203 | - |
204 | - std::unique_ptr<MirConnection> connection{new MirConnection(conf)}; |
205 | - auto const result = connection->connect(name, callback, context); |
206 | - connection.release(); |
207 | - return result; |
208 | + delete connection; |
209 | } |
210 | - catch (std::exception const& x) |
211 | + |
212 | + std::unique_ptr<mcl::ConnectionConfiguration> configuration(std::string const& socket) override |
213 | { |
214 | - MirConnection* error_connection = new MirConnection(x.what()); |
215 | - mcl::ErrorConnections::instance().insert(error_connection); |
216 | - callback(error_connection, context); |
217 | - return nullptr; |
218 | + return std::unique_ptr<mcl::ConnectionConfiguration>{ |
219 | + new mcl::DefaultConnectionConfiguration{socket}}; |
220 | } |
221 | -} |
222 | - |
223 | - |
224 | -void mir_default_connection_release(MirConnection* connection) |
225 | +}; |
226 | + |
227 | +mcl::MirConnectionAPI* mir_connection_api_impl_default() |
228 | { |
229 | - if (!mcl::ErrorConnections::instance().contains(connection)) |
230 | - { |
231 | - try |
232 | - { |
233 | - auto wait_handle = connection->disconnect(); |
234 | - wait_handle->wait_for_all(); |
235 | - } |
236 | - catch (std::exception const&) |
237 | - { |
238 | - // We're implementing a C API so no exceptions are to be |
239 | - // propagated. And that's OK because if disconnect() fails, |
240 | - // we don't care why. We're finished with the connection anyway. |
241 | - } |
242 | - } |
243 | - else |
244 | - { |
245 | - mcl::ErrorConnections::instance().remove(connection); |
246 | - } |
247 | - |
248 | - delete connection; |
249 | -} |
250 | - |
251 | -} |
252 | - |
253 | -//mir_connect and mir_connection_release can be overridden by test code that sets these function |
254 | -//pointers to do things like stub out the graphics drivers or change the connection configuration. |
255 | - |
256 | -//TODO: we could have a more comprehensive solution that allows us to substitute any of the functions |
257 | -//for test purposes, not just the connect functions |
258 | -mir_connect_impl_func mir_connect_impl = mir_default_connect; |
259 | -mir_connection_release_impl_func mir_connection_release_impl = mir_default_connection_release; |
260 | + static DefaultMirConnectionAPI default_api; |
261 | + return &default_api; |
262 | +} |
263 | + |
264 | +} |
265 | + |
266 | +mcl::MirConnectionAPI* mir_connection_api_impl{mir_connection_api_impl_default()}; |
267 | |
268 | MirWaitHandle* mir_connect( |
269 | char const* socket_file, |
270 | @@ -130,7 +137,7 @@ |
271 | { |
272 | try |
273 | { |
274 | - return mir_connect_impl(socket_file, name, callback, context); |
275 | + return mir_connection_api_impl->connect(socket_file, name, callback, context); |
276 | } |
277 | catch (std::exception const&) |
278 | { |
279 | @@ -164,7 +171,7 @@ |
280 | { |
281 | try |
282 | { |
283 | - return mir_connection_release_impl(connection); |
284 | + return mir_connection_api_impl->release(connection); |
285 | } |
286 | catch (std::exception const&) |
287 | { |
288 | |
289 | === added file 'src/client/mir_connection_api.h' |
290 | --- src/client/mir_connection_api.h 1970-01-01 00:00:00 +0000 |
291 | +++ src/client/mir_connection_api.h 2014-08-05 10:18:32 +0000 |
292 | @@ -0,0 +1,59 @@ |
293 | +/* |
294 | + * Copyright © 2014 Canonical Ltd. |
295 | + * |
296 | + * This program is free software: you can redistribute it and/or modify it |
297 | + * under the terms of the GNU Lesser General Public License version 3, |
298 | + * as published by the Free Software Foundation. |
299 | + * |
300 | + * This program is distributed in the hope that it will be useful, |
301 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
302 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
303 | + * GNU Lesser General Public License for more details. |
304 | + * |
305 | + * You should have received a copy of the GNU Lesser General Public License |
306 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
307 | + * |
308 | + * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com> |
309 | + */ |
310 | + |
311 | +#ifndef MIR_CLIENT_MIR_CONNECTION_API_H_ |
312 | +#define MIR_CLIENT_MIR_CONNECTION_API_H_ |
313 | + |
314 | +#include "mir_toolkit/mir_wait.h" |
315 | + |
316 | +#include <string> |
317 | +#include <memory> |
318 | + |
319 | +namespace mir |
320 | +{ |
321 | +namespace client |
322 | +{ |
323 | +class ConnectionConfiguration; |
324 | + |
325 | +class MirConnectionAPI |
326 | +{ |
327 | +public: |
328 | + virtual ~MirConnectionAPI() = default; |
329 | + |
330 | + virtual MirWaitHandle* connect( |
331 | + char const* socket_file, |
332 | + char const* name, |
333 | + mir_connected_callback callback, |
334 | + void* context) = 0; |
335 | + |
336 | + virtual void release(MirConnection* connection) = 0; |
337 | + |
338 | + virtual std::unique_ptr<ConnectionConfiguration> configuration(std::string const& socket) = 0; |
339 | + |
340 | +protected: |
341 | + MirConnectionAPI() = default; |
342 | + MirConnectionAPI(MirConnectionAPI const&) = default; |
343 | + MirConnectionAPI& operator=(MirConnectionAPI const&) = default; |
344 | +}; |
345 | + |
346 | +} |
347 | +} |
348 | + |
349 | +extern "C" mir::client::MirConnectionAPI* mir_connection_api_impl; |
350 | + |
351 | +#endif |
352 | |
353 | === modified file 'tests/mir_test_framework/using_stub_client_platform.cpp' |
354 | --- tests/mir_test_framework/using_stub_client_platform.cpp 2014-07-29 10:25:43 +0000 |
355 | +++ tests/mir_test_framework/using_stub_client_platform.cpp 2014-08-05 10:18:32 +0000 |
356 | @@ -18,54 +18,56 @@ |
357 | |
358 | #include "mir_test_framework/using_stub_client_platform.h" |
359 | #include "mir_test_framework/stub_client_connection_configuration.h" |
360 | -#include "src/client/mir_wait_handle.h" |
361 | -#include "src/client/mir_connection.h" |
362 | -#include "src/client/api_impl.h" |
363 | +#include "src/client/mir_connection_api.h" |
364 | |
365 | namespace mtf = mir_test_framework; |
366 | +namespace mcl = mir::client; |
367 | |
368 | namespace |
369 | { |
370 | |
371 | -MirWaitHandle* mir_connect_override( |
372 | - char const *socket_file, |
373 | - char const *app_name, |
374 | - mir_connected_callback callback, |
375 | - void *context) |
376 | -{ |
377 | - mtf::StubConnectionConfiguration conf(socket_file); |
378 | - auto connection = new MirConnection(conf); |
379 | - return connection->connect(app_name, callback, context); |
380 | -} |
381 | - |
382 | -void mir_connection_release_override(MirConnection *connection) |
383 | -{ |
384 | - try |
385 | - { |
386 | - auto wait_handle = connection->disconnect(); |
387 | - mir_wait_for(wait_handle); |
388 | - } |
389 | - catch (std::exception const&) |
390 | - { |
391 | - // Really, we want try/finally, but that's not C++11 |
392 | - delete connection; |
393 | - throw; |
394 | - } |
395 | - delete connection; |
396 | -} |
397 | +class StubMirConnectionAPI : public mcl::MirConnectionAPI |
398 | +{ |
399 | +public: |
400 | + StubMirConnectionAPI(mcl::MirConnectionAPI* prev_api) |
401 | + : prev_api{prev_api} |
402 | + { |
403 | + } |
404 | + |
405 | + MirWaitHandle* connect( |
406 | + char const* socket_file, |
407 | + char const* name, |
408 | + mir_connected_callback callback, |
409 | + void* context) override |
410 | + { |
411 | + return prev_api->connect(socket_file, name, callback, context); |
412 | + } |
413 | + |
414 | + void release(MirConnection* connection) override |
415 | + { |
416 | + return prev_api->release(connection); |
417 | + } |
418 | + |
419 | + std::unique_ptr<mcl::ConnectionConfiguration> configuration(std::string const& socket) override |
420 | + { |
421 | + return std::unique_ptr<mcl::ConnectionConfiguration>{ |
422 | + new mtf::StubConnectionConfiguration{socket}}; |
423 | + } |
424 | + |
425 | +private: |
426 | + mcl::MirConnectionAPI* const prev_api; |
427 | +}; |
428 | |
429 | } |
430 | |
431 | mtf::UsingStubClientPlatform::UsingStubClientPlatform() |
432 | - : prev_mir_connect_impl{mir_connect_impl}, |
433 | - prev_mir_connection_release_impl{mir_connection_release_impl} |
434 | + : prev_api{mir_connection_api_impl}, |
435 | + stub_api{new StubMirConnectionAPI{prev_api}} |
436 | { |
437 | - mir_connect_impl = mir_connect_override; |
438 | - mir_connection_release_impl = mir_connection_release_override; |
439 | + mir_connection_api_impl = stub_api.get(); |
440 | } |
441 | |
442 | mtf::UsingStubClientPlatform::~UsingStubClientPlatform() |
443 | { |
444 | - mir_connect_impl = prev_mir_connect_impl; |
445 | - mir_connection_release_impl = prev_mir_connection_release_impl; |
446 | + mir_connection_api_impl = prev_api; |
447 | } |
FAILED: Continuous integration, rev:1813 jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- ci/2303/ jenkins. qa.ubuntu. com/job/ mir-android- utopic- i386-build/ 1184 jenkins. qa.ubuntu. com/job/ mir-clang- utopic- amd64-build/ 1190 jenkins. qa.ubuntu. com/job/ mir-mediumtests -utopic- touch/1172/ console jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- utopic- amd64-ci/ 825/console jenkins. qa.ubuntu. com/job/ mir-team- mir-development -branch- utopic- armhf-ci/ 826/console jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- utopic- armhf/107/ console
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- team-mir- development- branch- ci/2303/ rebuild
http://