Mir

Merge lp:~kdub/mir/fix-1220443 into lp:~mir-team/mir/trunk

Proposed by Kevin DuBois
Status: Superseded
Proposed branch: lp:~kdub/mir/fix-1220443
Merge into: lp:~mir-team/mir/trunk
Diff against target: 491 lines (+301/-28)
9 files modified
include/test/mir_test_framework/display_server_test_fixture.h (+5/-0)
include/test/mir_test_framework/testing_client_configuration.h (+57/-0)
include/test/mir_test_framework/testing_process_manager.h (+1/-7)
src/client/mir_client_library.cpp (+39/-17)
tests/acceptance-tests/test_client_authorization.cpp (+3/-0)
tests/acceptance-tests/test_client_library.cpp (+6/-0)
tests/mir_test_framework/CMakeLists.txt (+1/-0)
tests/mir_test_framework/display_server_test_fixture.cpp (+8/-4)
tests/mir_test_framework/testing_client_options.cpp (+181/-0)
To merge this branch: bzr merge lp:~kdub/mir/fix-1220443
Reviewer Review Type Date Requested Status
Robert Carr (community) Abstain
Alan Griffiths Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Daniel van Vugt Approve
Review via email: mp+184159@code.launchpad.net

This proposal has been superseded by a proposal from 2013-09-24.

Commit message

fix: lp:1220443

let the test framework to inject stub graphics platforms on the client side during acceptance and integration tests

Description of the change

fix: lp:1220443

let the test framework to inject stub graphics platforms on the client side during acceptance and integration tests

see bug comment for what was happening: https://bugs.launchpad.net/mir/+bug/1220443/comments/3

nb. fix addresses 1220443, but tests-use-real-graphics is still problematic when turned on (https://bugs.launchpad.net/mir/+bug/1221373)

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

mir_client_library_debug.h: Incorrect capitalization and punctuation.

mir_connection_factory.h: Incorrect date.

They're not blockers, but should be fixed. I haven't stopped long enough to consider the overall approach however, so abstain for now.

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

Defining MirConnectionFactory in a private header makes publishing mir_global_connection_factory via the debug API pointless - it is unusable.

Initializing mir_global_connection_factory to point to a default would avoid tests for NULL (should be nullptr).

But a better approach would be to publish a function pointer with the same signature as mir_connect() and have mir_connect() forward to whatever it points at. This pointer should default to a renamed copy of the current implementation.

This would allow clients to intercept the call and optionally call the default implementation (or, in test cases, restore the pointer to use).

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
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 :

I'm not sure that exposing the client API as something a client can *modify* is a good idea...

11 +extern MirWaitHandle* (*mir_connect_impl)(
12 + char const *server,
13 + char const *app_name,
14 + mir_connected_callback callback,
15 + void *context);

If nothing else, it's inconsistent to only allow this on one function. Normally you would use LD_PRELOAD (man ld.so) to achieve this.

Also, still... mir_client_library_debug.h: Incorrect capitalization and punctuation.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> I'm not sure that exposing the client API as something a client can *modify*
> is a good idea...

The key question is: is this needed as part of the debug API, or is it a facility for test code that should be internal to the implementation?

If the former, then we should probably providing a mechanism for intercepting the whole API atomically, not a single functions.

*Needs discussion*

review: Needs Information
Revision history for this message
Kevin DuBois (kdub) wrote :

I think its more of a test code facility, so perhaps it should be moved out of the debug header.
Since running with stubbed drivers is the default, I'm not a fan of recommending the use of LD_PRELOAD to anyone who wants to run the android test suite.

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

You should be able to do the equivalent of LD_PRELOAD without using the environment variable, maybe? The linker should allow you to, somehow. But I don't have an answer to hand so won't block on it.

Regarding test vs debug code, yeah... Maybe it would be a good idea to not mention the trampoline pointer (mir_connect_impl) in any header at all. Just extern it manually when you need it. That would be better hidden.

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

Verified bug 1220443 is fixed.

We can argue over the details later.

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

switched to a more hidden extern (was a good idea) so no public-facing headers mention the override. Added a TODO to make a more comprehensive solution to stubbing client functions out

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

I don't like adding implementation to the TestingClientConfiguration interface. The test framework still only uses the exec() function.

Rather than having the tests call functions to change use of connect functions I'd rather see them using an alternative DefaultTestingClientConfiguration/DummyGraphicsTestingClientConfiguration.

I'm not sure that sharing a single TestingServerConfiguration across all tests is a good idea. It shouldn't be a problem (as it is only used in the separate server processes) but it introduces potential for state to leak from one test to another.

review: Needs Fixing
Revision history for this message
Robert Carr (robertcarr) wrote :

It looks ok. I think overriding mir_connect is pretty counterintuitive to me though. I wonder if this calls for a 'mir_init' type function which can handle command line arguments, environment, etc, in order to set up client configuration.

Revision history for this message
Robert Carr (robertcarr) :
review: Abstain

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/display_server_test_fixture.h'
2--- include/test/mir_test_framework/display_server_test_fixture.h 2013-08-28 03:41:48 +0000
3+++ include/test/mir_test_framework/display_server_test_fixture.h 2013-09-11 21:25:43 +0000
4@@ -22,11 +22,14 @@
5 #include "mir_test_framework/process.h"
6
7 #include "mir_test_framework/testing_process_manager.h"
8+#include "mir_test_framework/testing_client_configuration.h"
9 #include <gtest/gtest.h>
10
11 #include <memory>
12 #include <functional>
13
14+#include "mir_toolkit/mir_client_library_debug.h"
15+
16 namespace mir_test_framework
17 {
18 using namespace ::mir;
19@@ -46,6 +49,7 @@
20
21 private:
22 static TestingProcessManager process_manager;
23+ static TestingServerConfiguration default_parameters;
24
25 virtual void TearDown();
26 };
27@@ -73,6 +77,7 @@
28 virtual void TearDown();
29
30 private:
31+ std::shared_ptr<mir::options::Option> server_options;
32 TestingProcessManager process_manager;
33 };
34
35
36=== added file 'include/test/mir_test_framework/testing_client_configuration.h'
37--- include/test/mir_test_framework/testing_client_configuration.h 1970-01-01 00:00:00 +0000
38+++ include/test/mir_test_framework/testing_client_configuration.h 2013-09-11 21:25:43 +0000
39@@ -0,0 +1,57 @@
40+/*
41+ * Copyright © 2013 Canonical Ltd.
42+ *
43+ * This program is free software: you can redistribute it and/or modify it
44+ * under the terms of the GNU General Public License version 3,
45+ * as published by the Free Software Foundation.
46+ *
47+ * This program is distributed in the hope that it will be useful,
48+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
49+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50+ * GNU General Public License for more details.
51+ *
52+ * You should have received a copy of the GNU General Public License
53+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
54+ *
55+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
56+ */
57+
58+#ifndef MIR_TESTING_CLIENT_CONFIGURATION
59+#define MIR_TESTING_CLIENT_CONFIGURATION
60+
61+#include "mir_toolkit/mir_client_library_debug.h"
62+#include <memory>
63+
64+namespace mir
65+{
66+namespace options
67+{
68+class Option;
69+}
70+}
71+
72+namespace mir_test_framework
73+{
74+
75+struct TestingClientConfiguration
76+{
77+ TestingClientConfiguration();
78+ virtual ~TestingClientConfiguration();
79+
80+ // Code to run in client process
81+ virtual void exec() = 0;
82+
83+ void set_client_configuration(std::shared_ptr<mir::options::Option> const& options);
84+
85+ //force client configuration to use default connect and disconnect functions
86+ void use_default_connect_functions();
87+
88+private:
89+ MirWaitHandle* (*default_mir_connect_impl)
90+ (char const *server, char const *app_name, mir_connected_callback callback, void *context);
91+
92+ void (*default_mir_connection_release_impl) (MirConnection *connection);
93+};
94+
95+}
96+#endif /* MIR_TESTING_CLIENT_CONFIGURATION */
97
98=== modified file 'include/test/mir_test_framework/testing_process_manager.h'
99--- include/test/mir_test_framework/testing_process_manager.h 2013-08-28 03:41:48 +0000
100+++ include/test/mir_test_framework/testing_process_manager.h 2013-09-11 21:25:43 +0000
101@@ -24,6 +24,7 @@
102 #include "mir_test_framework/process.h"
103
104 #include "mir_test_framework/testing_server_configuration.h"
105+#include "mir_test_framework/testing_client_configuration.h"
106
107 #include <memory>
108 #include <list>
109@@ -38,13 +39,6 @@
110 {
111 using namespace mir;
112
113-struct TestingClientConfiguration
114-{
115- virtual ~TestingClientConfiguration() = default;
116- // Code to run in client process
117- virtual void exec() = 0;
118-};
119-
120
121 class TestingProcessManager
122 {
123
124=== modified file 'src/client/mir_client_library.cpp'
125--- src/client/mir_client_library.cpp 2013-08-28 03:41:48 +0000
126+++ src/client/mir_client_library.cpp 2013-09-11 21:25:43 +0000
127@@ -77,7 +77,8 @@
128
129 }
130
131-MirWaitHandle* mir_connect(char const* socket_file, char const* name, mir_connected_callback callback, void * context)
132+MirWaitHandle* mir_default_connect(
133+ char const* socket_file, char const* name, mir_connected_callback callback, void * context)
134 {
135
136 try
137@@ -93,7 +94,7 @@
138 else
139 sock = mir::default_server_socket;
140 }
141-
142+
143 mcl::DefaultConnectionConfiguration conf{sock};
144
145 MirConnection* connection = new MirConnection(conf);
146@@ -110,6 +111,42 @@
147 }
148 }
149
150+
151+void mir_default_connection_release(MirConnection * connection)
152+{
153+ if (!error_connections.contains(connection))
154+ {
155+ auto wait_handle = connection->disconnect();
156+ wait_handle->wait_for_all();
157+ }
158+ else
159+ {
160+ error_connections.remove(connection);
161+ }
162+
163+ delete connection;
164+}
165+
166+//mir_connect and mir_connection_release can be overridden by test code that sets these function
167+//pointers to do things like stub out the graphics drivers or change the connection configuration.
168+
169+//TODO: we could have a more comprehensive solution that allows us to substitute any of the functions
170+//for test purposes, not just the connect functions
171+MirWaitHandle* (*mir_connect_impl)(
172+ char const *server, char const *app_name,
173+ mir_connected_callback callback, void *context) = mir_default_connect;
174+void (*mir_connection_release_impl) (MirConnection *connection) = mir_default_connection_release;
175+
176+MirWaitHandle* mir_connect(char const* socket_file, char const* name, mir_connected_callback callback, void * context)
177+{
178+ return mir_connect_impl(socket_file, name, callback, context);
179+}
180+
181+void mir_connection_release(MirConnection *connection)
182+{
183+ return mir_connection_release_impl(connection);
184+}
185+
186 MirConnection *mir_connect_sync(char const *server,
187 char const *app_name)
188 {
189@@ -131,21 +168,6 @@
190 return connection->get_error_message();
191 }
192
193-void mir_connection_release(MirConnection * connection)
194-{
195- if (!error_connections.contains(connection))
196- {
197- auto wait_handle = connection->disconnect();
198- wait_handle->wait_for_all();
199- }
200- else
201- {
202- error_connections.remove(connection);
203- }
204-
205- delete connection;
206-}
207-
208 MirEGLNativeDisplayType mir_connection_get_egl_native_display(MirConnection *connection)
209 {
210 return connection->egl_native_display();
211
212=== modified file 'tests/acceptance-tests/test_client_authorization.cpp'
213--- tests/acceptance-tests/test_client_authorization.cpp 2013-08-28 03:41:48 +0000
214+++ tests/acceptance-tests/test_client_authorization.cpp 2013-09-11 21:25:43 +0000
215@@ -232,6 +232,9 @@
216
217 void exec() override
218 {
219+ //we are testing the connect function itself, so force using default
220+ use_default_connect_functions();
221+
222 pid_t client_pid = getpid();
223 shared_region->post_client_process_pid(client_pid);
224
225
226=== modified file 'tests/acceptance-tests/test_client_library.cpp'
227--- tests/acceptance-tests/test_client_library.cpp 2013-09-02 09:54:31 +0000
228+++ tests/acceptance-tests/test_client_library.cpp 2013-09-11 21:25:43 +0000
229@@ -748,6 +748,9 @@
230 {
231 void exec()
232 {
233+ //we are testing the connect function itself, so force using default
234+ use_default_connect_functions();
235+
236 mir_wait_for(mir_connect("garbage", __PRETTY_FUNCTION__, connection_callback, this));
237 ASSERT_TRUE(connection != NULL);
238
239@@ -771,6 +774,9 @@
240 {
241 void exec()
242 {
243+ //we are testing the connect function itself, so force using default
244+ use_default_connect_functions();
245+
246 mir_wait_for(mir_connect("garbage", __PRETTY_FUNCTION__, connection_callback, this));
247
248 MirSurfaceParameters const request_params =
249
250=== modified file 'tests/mir_test_framework/CMakeLists.txt'
251--- tests/mir_test_framework/CMakeLists.txt 2013-08-28 03:41:48 +0000
252+++ tests/mir_test_framework/CMakeLists.txt 2013-09-11 21:25:43 +0000
253@@ -13,6 +13,7 @@
254 testing_server_options.cpp
255 input_testing_server_options.cpp
256 testing_process_manager.cpp
257+ testing_client_options.cpp
258 display_server_test_fixture.cpp
259 process.cpp
260 )
261
262=== modified file 'tests/mir_test_framework/display_server_test_fixture.cpp'
263--- tests/mir_test_framework/display_server_test_fixture.cpp 2013-08-28 03:41:48 +0000
264+++ tests/mir_test_framework/display_server_test_fixture.cpp 2013-09-11 21:25:43 +0000
265@@ -17,20 +17,22 @@
266 */
267
268 #include "mir_test_framework/display_server_test_fixture.h"
269+#include "mir_test_framework/testing_client_configuration.h"
270
271 namespace mc = mir::compositor;
272-
273-mir_test_framework::TestingProcessManager mir_test_framework::DefaultDisplayServerTestFixture::process_manager;
274-
275+namespace mtf = mir_test_framework;
276+
277+mtf::TestingProcessManager mir_test_framework::DefaultDisplayServerTestFixture::process_manager;
278+mtf::TestingServerConfiguration mir_test_framework::DefaultDisplayServerTestFixture::default_parameters;
279
280 void DefaultDisplayServerTestFixture::launch_client_process(TestingClientConfiguration& config)
281 {
282+ config.set_client_configuration(default_parameters.the_options());
283 process_manager.launch_client_process(config);
284 }
285
286 void DefaultDisplayServerTestFixture::SetUpTestCase()
287 {
288- TestingServerConfiguration default_parameters;
289 process_manager.launch_server_process(default_parameters);
290 }
291
292@@ -54,11 +56,13 @@
293
294 void BespokeDisplayServerTestFixture::launch_server_process(TestingServerConfiguration& functor)
295 {
296+ server_options = functor.the_options();
297 process_manager.launch_server_process(functor);
298 }
299
300 void BespokeDisplayServerTestFixture::launch_client_process(TestingClientConfiguration& config)
301 {
302+ config.set_client_configuration(server_options);
303 process_manager.launch_client_process(config);
304 }
305
306
307=== added file 'tests/mir_test_framework/testing_client_options.cpp'
308--- tests/mir_test_framework/testing_client_options.cpp 1970-01-01 00:00:00 +0000
309+++ tests/mir_test_framework/testing_client_options.cpp 2013-09-11 21:25:43 +0000
310@@ -0,0 +1,181 @@
311+/*
312+ * Copyright © 2013 Canonical Ltd.
313+ *
314+ * This program is free software: you can redistribute it and/or modify it
315+ * under the terms of the GNU General Public License version 3,
316+ * as published by the Free Software Foundation.
317+ *
318+ * This program is distributed in the hope that it will be useful,
319+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
320+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
321+ * GNU General Public License for more details.
322+ *
323+ * You should have received a copy of the GNU General Public License
324+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
325+ *
326+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
327+ */
328+
329+#include "mir_test_framework/testing_client_configuration.h"
330+#include "mir/options/program_option.h"
331+#include "src/client/default_connection_configuration.h"
332+#include "src/client/client_platform_factory.h"
333+#include "src/client/client_buffer_factory.h"
334+#include "src/client/client_buffer.h"
335+#include "src/client/client_platform.h"
336+#include "src/client/mir_connection.h"
337+
338+namespace mcl = mir::client;
339+namespace mtf=mir_test_framework;
340+namespace geom = mir::geometry;
341+
342+/* if set before any calls to the api functions, assigning to this pointer will allow user to
343+ * override calls to mir_connect() and mir_connection_release(). This is mostly useful in test scenarios
344+ */
345+extern MirWaitHandle* (*mir_connect_impl)(
346+ char const *server,
347+ char const *app_name,
348+ mir_connected_callback callback,
349+ void *context);
350+extern void (*mir_connection_release_impl) (MirConnection *connection);
351+
352+namespace
353+{
354+class StubClientBuffer : public mcl::ClientBuffer
355+{
356+ std::shared_ptr<mcl::MemoryRegion> secure_for_cpu_write()
357+ {
358+ return nullptr;
359+ }
360+
361+ geom::Size size() const
362+ {
363+ return geom::Size{};
364+ }
365+
366+ geom::Stride stride() const
367+ {
368+ return geom::Stride{};
369+ }
370+
371+ geom::PixelFormat pixel_format() const
372+ {
373+ return geom::PixelFormat::abgr_8888;
374+ }
375+
376+ uint32_t age() const
377+ {
378+ return 0;
379+ }
380+ void increment_age()
381+ {
382+ }
383+ void mark_as_submitted()
384+ {
385+ }
386+ std::shared_ptr<MirNativeBuffer> native_buffer_handle() const
387+ {
388+ return nullptr;
389+ }
390+};
391+
392+struct StubClientBufferFactory : public mcl::ClientBufferFactory
393+{
394+ std::shared_ptr<mcl::ClientBuffer> create_buffer(std::shared_ptr<MirBufferPackage> const&,
395+ geom::Size, geom::PixelFormat)
396+ {
397+ return std::make_shared<StubClientBuffer>();
398+ }
399+};
400+
401+struct StubClientPlatform : public mcl::ClientPlatform
402+{
403+ MirPlatformType platform_type() const
404+ {
405+ return mir_platform_type_gbm;
406+ }
407+
408+ std::shared_ptr<mcl::ClientBufferFactory> create_buffer_factory()
409+ {
410+ return std::make_shared<StubClientBufferFactory>();
411+ }
412+
413+ std::shared_ptr<EGLNativeWindowType> create_egl_native_window(mcl::ClientSurface*)
414+ {
415+ auto fake_window = reinterpret_cast<EGLNativeWindowType>(0x12345678);
416+ return std::make_shared<EGLNativeWindowType>(fake_window);
417+ }
418+
419+ std::shared_ptr<EGLNativeDisplayType> create_egl_native_display()
420+ {
421+ auto fake_display = reinterpret_cast<EGLNativeDisplayType>(0x12345678);
422+ return std::make_shared<EGLNativeDisplayType>(fake_display);
423+ }
424+};
425+
426+struct StubClientPlatformFactory : public mcl::ClientPlatformFactory
427+{
428+ std::shared_ptr<mcl::ClientPlatform> create_client_platform(mcl::ClientContext*)
429+ {
430+ return std::make_shared<StubClientPlatform>();
431+ }
432+};
433+
434+struct StubConnectionConfiguration : public mcl::DefaultConnectionConfiguration
435+{
436+ StubConnectionConfiguration(std::string const& socket_file)
437+ : DefaultConnectionConfiguration(socket_file)
438+ {
439+ }
440+
441+ std::shared_ptr<mcl::ClientPlatformFactory> the_client_platform_factory() override
442+ {
443+ return std::make_shared<StubClientPlatformFactory>();
444+ }
445+};
446+
447+MirWaitHandle* mir_connect_test_override(
448+ char const *socket_file,
449+ char const *app_name,
450+ mir_connected_callback callback,
451+ void *context)
452+{
453+ StubConnectionConfiguration conf(socket_file);
454+ auto connection = new MirConnection(conf);
455+ return connection->connect(app_name, callback, context);
456+}
457+
458+void mir_connection_release_override(MirConnection *connection)
459+{
460+ auto wait_handle = connection->disconnect();
461+ wait_handle->wait_for_all();
462+ delete connection;
463+}
464+
465+}
466+
467+mtf::TestingClientConfiguration::TestingClientConfiguration()
468+ : default_mir_connect_impl(mir_connect_impl),
469+ default_mir_connection_release_impl(mir_connection_release_impl)
470+{
471+}
472+
473+void mtf::TestingClientConfiguration::use_default_connect_functions()
474+{
475+ mir_connect_impl = default_mir_connect_impl;
476+ mir_connection_release_impl = default_mir_connection_release_impl;
477+}
478+
479+void mtf::TestingClientConfiguration::set_client_configuration(std::shared_ptr<mir::options::Option> const& options)
480+{
481+ if (!options->get("tests-use-real-graphics", false))
482+ {
483+ mir_connect_impl = mir_connect_test_override;
484+ mir_connection_release_impl = mir_connection_release_override;
485+ }
486+}
487+
488+mtf::TestingClientConfiguration::~TestingClientConfiguration()
489+{
490+ use_default_connect_functions();
491+}

Subscribers

People subscribed via source and target branches