Merge lp:~alan-griffiths/mir/some-acceptance-tests-use-mir-Server-API into lp:mir
- some-acceptance-tests-use-mir-Server-API
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2009 |
Proposed branch: | lp:~alan-griffiths/mir/some-acceptance-tests-use-mir-Server-API |
Merge into: | lp:mir |
Prerequisite: | lp:~alan-griffiths/mir/Migrate-ServerConfigurationWrapping-to-Server-API |
Diff against target: |
678 lines (+387/-84) 12 files modified
include/server/mir/server.h (+21/-1) server-ABI-sha1sums (+1/-1) src/server/server.cpp (+63/-0) src/server/symbols.map (+1/-0) tests/acceptance-tests/server_configuration_wrapping.cpp (+3/-41) tests/acceptance-tests/test_client_library.cpp (+21/-6) tests/include/mir_test_framework/headless_test.h (+71/-0) tests/include/mir_test_framework/temporary_environment_value.h (+41/-0) tests/mir_test_framework/CMakeLists.txt (+2/-0) tests/mir_test_framework/headless_test.cpp (+113/-0) tests/mir_test_framework/temporary_environment_value.cpp (+42/-0) tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp (+8/-35) |
To merge this branch: | bzr merge lp:~alan-griffiths/mir/some-acceptance-tests-use-mir-Server-API |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Kevin DuBois (community) | Approve | ||
Alberto Aguirre (community) | Approve | ||
Andreas Pokorny (community) | Approve | ||
Alexandros Frantzis (community) | Needs Fixing | ||
Review via email: mp+239406@code.launchpad.net |
Commit message
test: Move another of the acceptance test suites [ClientLibrary.*] to the mir::Server based API
Description of the change
test: Move another of the acceptance test suites [ClientLibrary.*] to the mir::Server based API
It cleans up the "AcceptanceTest" fixture from the prerequisite branch and introduces "HeadlessTest".
There's a similar "debt" with a new HeadlessInProce
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2004
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alexandros Frantzis (afrantzis) wrote : | # |
> typedef std::function<
using ConnectHandler = ... , it's more consistent with other type definitions in the class.
> auto open_client_
Although testing is a valid driver of the API, I am a bit skeptical of exposing functionality for tests only, since doing so may occasionally compromise the focus of the API, expose internals etc. This particular change seems OK, though, and if we want to provide such functionality we should also provide the same stability guarantees as we do for the "normal" public API (and stability should be an important factor in deciding whether we want a test-only method appear in the public API).
Needs fixing for the typedef.
Alan Griffiths (alan-griffiths) wrote : | # |
> > typedef std::function<
> session)> ConnectHandler;
>
> using ConnectHandler = ... , it's more consistent with other type definitions
> in the class.
Fixed
> > auto open_client_
>
> Although testing is a valid driver of the API, I am a bit skeptical of
> exposing functionality for tests only, since doing so may occasionally
> compromise the focus of the API, expose internals etc.
I totally agree. Although in the case of acceptance tests these should ideally be written in terms of the API.
Where acceptance tests need something other than the API exposes there should a clear distinction in the way such features are invoked.
> This particular change
> seems OK, though, and if we want to provide such functionality we should also
> provide the same stability guarantees as we do for the "normal" public API
> (and stability should be an important factor in deciding whether we want a
> test-only method appear in the public API).
I gave some thought to this and concluded supporting the test this way gives a potentially useful API: we don't always want to expose an endpoint on the filesystem for clients to use (doing so is a long standing issue with unity-system-
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2005
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2006
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
27 + auto open_client_
Given the api, I'd assume that I own the returned fd after calling this function, but it would be a bit more clear if it returned a mir::Fd.
Otherwise, I'm persuaded that this can solve help solve the endpoint-
Andreas Pokorny (andreas-pokorny) wrote : | # |
+1 for mir::Fd
looks good otherwise
Andreas Pokorny (andreas-pokorny) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2007
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) wrote : | # |
The "needs fixing" items from the other 2 reviewers have been addressed so TA'ing.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Alan Griffiths (alan-griffiths) wrote : | # |
[ FAILED ] 17 tests, listed below:
[ FAILED ] AvailableSurfac
[ FAILED ] SurfaceFirstFra
[ FAILED ] SwapIntervalSig
[ FAILED ] ServerShutdown.
[ FAILED ] SessionMediator
[ FAILED ] SessionMediator
[ FAILED ] SessionMediator
[ FAILED ] SessionMediator
[ FAILED ] SessionMediator
[ FAILED ] SessionMediator
[ FAILED ] SessionMediator
[ FAILED ] SessionMediator
[ FAILED ] Process.
[ FAILED ] Process.
[ FAILED ] BespokeDisplayS
[ FAILED ] BespokeDisplayS
[ FAILED ] BespokeDisplayS
WOW! (Not related AFAICS - those are integration tests I've not touched)
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'include/server/mir/server.h' | |||
2 | --- include/server/mir/server.h 2014-10-24 13:39:38 +0000 | |||
3 | +++ include/server/mir/server.h 2014-10-28 09:41:16 +0000 | |||
4 | @@ -19,13 +19,15 @@ | |||
5 | 19 | #ifndef MIR_SERVER_H_ | 19 | #ifndef MIR_SERVER_H_ |
6 | 20 | #define MIR_SERVER_H_ | 20 | #define MIR_SERVER_H_ |
7 | 21 | 21 | ||
8 | 22 | #include "mir/fd.h" | ||
9 | 23 | |||
10 | 22 | #include <functional> | 24 | #include <functional> |
11 | 23 | #include <memory> | 25 | #include <memory> |
12 | 24 | 26 | ||
13 | 25 | namespace mir | 27 | namespace mir |
14 | 26 | { | 28 | { |
15 | 27 | namespace compositor { class Compositor; class DisplayBufferCompositorFactory; } | 29 | namespace compositor { class Compositor; class DisplayBufferCompositorFactory; } |
17 | 28 | namespace frontend { class SessionAuthorizer; } | 30 | namespace frontend { class SessionAuthorizer; class Session; } |
18 | 29 | namespace graphics { class Platform; class Display; class GLConfig; class DisplayConfigurationPolicy; } | 31 | namespace graphics { class Platform; class Display; class GLConfig; class DisplayConfigurationPolicy; } |
19 | 30 | namespace input { class CompositeEventFilter; class InputDispatcher; class CursorListener; } | 32 | namespace input { class CompositeEventFilter; class InputDispatcher; class CursorListener; } |
20 | 31 | namespace options { class Option; } | 33 | namespace options { class Option; } |
21 | @@ -234,6 +236,24 @@ | |||
22 | 234 | auto the_surface_coordinator() const -> std::shared_ptr<scene::SurfaceCoordinator>; | 236 | auto the_surface_coordinator() const -> std::shared_ptr<scene::SurfaceCoordinator>; |
23 | 235 | /** @} */ | 237 | /** @} */ |
24 | 236 | 238 | ||
25 | 239 | /** @name Client side support | ||
26 | 240 | * These facilitate use of the server through the client API. | ||
27 | 241 | * They should be called while the server is running (i.e. run() has been called and | ||
28 | 242 | * not exited) otherwise they throw a std::logic_error. | ||
29 | 243 | * @{ */ | ||
30 | 244 | using ConnectHandler = std::function<void(std::shared_ptr<frontend::Session> const& session)>; | ||
31 | 245 | |||
32 | 246 | /// Get a file descriptor that can be used to connect a client | ||
33 | 247 | /// It can be passed to another process, or used directly with mir_connect() | ||
34 | 248 | /// using the format "fd://%d". | ||
35 | 249 | auto open_client_socket() -> Fd; | ||
36 | 250 | |||
37 | 251 | /// Get a file descriptor that can be used to connect a client | ||
38 | 252 | /// It can be passed to another process, or used directly with mir_connect() | ||
39 | 253 | /// using the format "fd://%d". | ||
40 | 254 | /// \param connect_handler callback to be invoked when the client connects | ||
41 | 255 | auto open_client_socket(ConnectHandler const& connect_handler) -> Fd; | ||
42 | 256 | /** @} */ | ||
43 | 237 | private: | 257 | private: |
44 | 238 | void apply_settings() const; | 258 | void apply_settings() const; |
45 | 239 | struct ServerConfiguration; | 259 | struct ServerConfiguration; |
46 | 240 | 260 | ||
47 | === modified file 'server-ABI-sha1sums' | |||
48 | --- server-ABI-sha1sums 2014-10-27 22:31:16 +0000 | |||
49 | +++ server-ABI-sha1sums 2014-10-28 09:41:16 +0000 | |||
50 | @@ -98,7 +98,7 @@ | |||
51 | 98 | 993e9f458ffc4288d304413f3fa0b1dcc95a093d include/server/mir/scene/surface_observer.h | 98 | 993e9f458ffc4288d304413f3fa0b1dcc95a093d include/server/mir/scene/surface_observer.h |
52 | 99 | 7ef3e99901168cda296d74d05a979f47bf9c3ff1 include/server/mir/server_action_queue.h | 99 | 7ef3e99901168cda296d74d05a979f47bf9c3ff1 include/server/mir/server_action_queue.h |
53 | 100 | 8d83a51c278b8b71866d2178d9b6387c1f91a7d0 include/server/mir/server_configuration.h | 100 | 8d83a51c278b8b71866d2178d9b6387c1f91a7d0 include/server/mir/server_configuration.h |
55 | 101 | a42b26d4796c66706c65be963468645620024820 include/server/mir/server.h | 101 | 320c467bdd757c71d02a904cc6a30cba67e27030 include/server/mir/server.h |
56 | 102 | 86098b500339bfccd07a9bed8298f75a68b18f5c include/server/mir/server_status_listener.h | 102 | 86098b500339bfccd07a9bed8298f75a68b18f5c include/server/mir/server_status_listener.h |
57 | 103 | 860c04f32b60e680140148dc9dc2295de145b9c1 include/server/mir/shell/display_layout.h | 103 | 860c04f32b60e680140148dc9dc2295de145b9c1 include/server/mir/shell/display_layout.h |
58 | 104 | 6a2107b01feae13060d5c305804906e53c52e0be include/server/mir/shell/focus_controller.h | 104 | 6a2107b01feae13060d5c305804906e53c52e0be include/server/mir/shell/focus_controller.h |
59 | 105 | 105 | ||
60 | === modified file 'src/server/server.cpp' | |||
61 | --- src/server/server.cpp 2014-10-24 13:39:38 +0000 | |||
62 | +++ src/server/server.cpp 2014-10-28 09:41:16 +0000 | |||
63 | @@ -18,12 +18,18 @@ | |||
64 | 18 | 18 | ||
65 | 19 | #include "mir/server.h" | 19 | #include "mir/server.h" |
66 | 20 | 20 | ||
67 | 21 | #include "mir/frontend/connector.h" | ||
68 | 21 | #include "mir/options/default_configuration.h" | 22 | #include "mir/options/default_configuration.h" |
69 | 22 | #include "mir/default_server_configuration.h" | 23 | #include "mir/default_server_configuration.h" |
70 | 23 | #include "mir/main_loop.h" | 24 | #include "mir/main_loop.h" |
71 | 24 | #include "mir/report_exception.h" | 25 | #include "mir/report_exception.h" |
72 | 25 | #include "mir/run_mir.h" | 26 | #include "mir/run_mir.h" |
73 | 26 | 27 | ||
74 | 28 | // TODO these are used to frig a stub renderer when running headless | ||
75 | 29 | #include "mir/compositor/renderer.h" | ||
76 | 30 | #include "mir/graphics/renderable.h" | ||
77 | 31 | #include "mir/compositor/renderer_factory.h" | ||
78 | 32 | |||
79 | 27 | #include <iostream> | 33 | #include <iostream> |
80 | 28 | 34 | ||
81 | 29 | namespace mo = mir::options; | 35 | namespace mo = mir::options; |
82 | @@ -118,6 +124,36 @@ | |||
83 | 118 | return mir::DefaultServerConfiguration::wrap_##name(wrapped);\ | 124 | return mir::DefaultServerConfiguration::wrap_##name(wrapped);\ |
84 | 119 | } | 125 | } |
85 | 120 | 126 | ||
86 | 127 | // TODO these are used to frig a stub renderer when running headless | ||
87 | 128 | namespace | ||
88 | 129 | { | ||
89 | 130 | class StubRenderer : public mir::compositor::Renderer | ||
90 | 131 | { | ||
91 | 132 | public: | ||
92 | 133 | void set_viewport(mir::geometry::Rectangle const&) override {} | ||
93 | 134 | |||
94 | 135 | void set_rotation(float) override {} | ||
95 | 136 | |||
96 | 137 | void render(mir::graphics::RenderableList const& renderables) const override | ||
97 | 138 | { | ||
98 | 139 | for (auto const& r : renderables) | ||
99 | 140 | r->buffer(); // We need to consume a buffer to unblock client tests | ||
100 | 141 | } | ||
101 | 142 | |||
102 | 143 | void suspend() override {} | ||
103 | 144 | }; | ||
104 | 145 | |||
105 | 146 | class StubRendererFactory : public mir::compositor::RendererFactory | ||
106 | 147 | { | ||
107 | 148 | public: | ||
108 | 149 | auto create_renderer_for(mir::geometry::Rectangle const&, mir::compositor::DestinationAlpha) | ||
109 | 150 | -> std::unique_ptr<mir::compositor::Renderer> | ||
110 | 151 | { | ||
111 | 152 | return std::unique_ptr<mir::compositor::Renderer>(new StubRenderer()); | ||
112 | 153 | } | ||
113 | 154 | }; | ||
114 | 155 | } | ||
115 | 156 | |||
116 | 121 | struct mir::Server::ServerConfiguration : mir::DefaultServerConfiguration | 157 | struct mir::Server::ServerConfiguration : mir::DefaultServerConfiguration |
117 | 122 | { | 158 | { |
118 | 123 | ServerConfiguration( | 159 | ServerConfiguration( |
119 | @@ -128,6 +164,17 @@ | |||
120 | 128 | { | 164 | { |
121 | 129 | } | 165 | } |
122 | 130 | 166 | ||
123 | 167 | // TODO this is an ugly frig to avoid exposing the render factory to end users and tests running headless | ||
124 | 168 | auto the_renderer_factory() -> std::shared_ptr<compositor::RendererFactory> override | ||
125 | 169 | { | ||
126 | 170 | auto const graphics_lib = the_options()->get<std::string>(options::platform_graphics_lib); | ||
127 | 171 | |||
128 | 172 | if (graphics_lib != "libmirplatformstub.so") | ||
129 | 173 | return mir::DefaultServerConfiguration::the_renderer_factory(); | ||
130 | 174 | else | ||
131 | 175 | return std::make_shared<StubRendererFactory>(); | ||
132 | 176 | } | ||
133 | 177 | |||
134 | 131 | using mir::DefaultServerConfiguration::the_options; | 178 | using mir::DefaultServerConfiguration::the_options; |
135 | 132 | 179 | ||
136 | 133 | // TODO the MIR_SERVER_CONFIG_OVERRIDE macro expects a CachePtr named | 180 | // TODO the MIR_SERVER_CONFIG_OVERRIDE macro expects a CachePtr named |
137 | @@ -256,6 +303,22 @@ | |||
138 | 256 | return self->exit_status; | 303 | return self->exit_status; |
139 | 257 | } | 304 | } |
140 | 258 | 305 | ||
141 | 306 | auto mir::Server::open_client_socket() -> Fd | ||
142 | 307 | { | ||
143 | 308 | if (auto const config = self->server_config) | ||
144 | 309 | return Fd{config->the_connector()->client_socket_fd()}; | ||
145 | 310 | |||
146 | 311 | BOOST_THROW_EXCEPTION(std::logic_error("Cannot open connection when not running")); | ||
147 | 312 | } | ||
148 | 313 | |||
149 | 314 | auto mir::Server::open_client_socket(ConnectHandler const& connect_handler) -> Fd | ||
150 | 315 | { | ||
151 | 316 | if (auto const config = self->server_config) | ||
152 | 317 | return Fd{config->the_connector()->client_socket_fd(connect_handler)}; | ||
153 | 318 | |||
154 | 319 | BOOST_THROW_EXCEPTION(std::logic_error("Cannot open connection when not running")); | ||
155 | 320 | } | ||
156 | 321 | |||
157 | 259 | #define MIR_SERVER_ACCESSOR(name)\ | 322 | #define MIR_SERVER_ACCESSOR(name)\ |
158 | 260 | auto mir::Server::name() const -> decltype(self->server_config->name())\ | 323 | auto mir::Server::name() const -> decltype(self->server_config->name())\ |
159 | 261 | {\ | 324 | {\ |
160 | 262 | 325 | ||
161 | === modified file 'src/server/symbols.map' | |||
162 | --- src/server/symbols.map 2014-10-27 22:31:16 +0000 | |||
163 | +++ src/server/symbols.map 2014-10-28 09:41:16 +0000 | |||
164 | @@ -397,6 +397,7 @@ | |||
165 | 397 | mir::ServerConfiguration::the_server_status_listener*; | 397 | mir::ServerConfiguration::the_server_status_listener*; |
166 | 398 | mir::Server::exited_normally*; | 398 | mir::Server::exited_normally*; |
167 | 399 | mir::Server::get_options*; | 399 | mir::Server::get_options*; |
168 | 400 | mir::Server::open_client_socket*; | ||
169 | 400 | mir::Server::override_the_compositor*; | 401 | mir::Server::override_the_compositor*; |
170 | 401 | mir::Server::override_the_display_buffer_compositor_factory*; | 402 | mir::Server::override_the_display_buffer_compositor_factory*; |
171 | 402 | mir::Server::override_the_cursor_listener*; | 403 | mir::Server::override_the_cursor_listener*; |
172 | 403 | 404 | ||
173 | === modified file 'tests/acceptance-tests/server_configuration_wrapping.cpp' | |||
174 | --- tests/acceptance-tests/server_configuration_wrapping.cpp 2014-10-22 02:50:44 +0000 | |||
175 | +++ tests/acceptance-tests/server_configuration_wrapping.cpp 2014-10-28 09:41:16 +0000 | |||
176 | @@ -19,7 +19,7 @@ | |||
177 | 19 | #include "mir/shell/session_coordinator_wrapper.h" | 19 | #include "mir/shell/session_coordinator_wrapper.h" |
178 | 20 | #include "mir/shell/surface_coordinator_wrapper.h" | 20 | #include "mir/shell/surface_coordinator_wrapper.h" |
179 | 21 | 21 | ||
181 | 22 | #include "mir/server.h" | 22 | #include "mir_test_framework/headless_test.h" |
182 | 23 | 23 | ||
183 | 24 | #include <gtest/gtest.h> | 24 | #include <gtest/gtest.h> |
184 | 25 | #include <gmock/gmock.h> | 25 | #include <gmock/gmock.h> |
185 | @@ -44,46 +44,8 @@ | |||
186 | 44 | MOCK_METHOD0(focus_next, void()); | 44 | MOCK_METHOD0(focus_next, void()); |
187 | 45 | }; | 45 | }; |
188 | 46 | 46 | ||
229 | 47 | class TemporaryEnvironmentValue | 47 | struct ServerConfigurationWrapping : mir_test_framework::HeadlessTest |
230 | 48 | { | 48 | { |
191 | 49 | public: | ||
192 | 50 | TemporaryEnvironmentValue(char const* name, char const* value) | ||
193 | 51 | : name{name}, | ||
194 | 52 | has_old_value{getenv(name) != nullptr}, | ||
195 | 53 | old_value{has_old_value ? getenv(name) : ""} | ||
196 | 54 | { | ||
197 | 55 | if (value) | ||
198 | 56 | setenv(name, value, overwrite); | ||
199 | 57 | else | ||
200 | 58 | unsetenv(name); | ||
201 | 59 | } | ||
202 | 60 | |||
203 | 61 | ~TemporaryEnvironmentValue() | ||
204 | 62 | { | ||
205 | 63 | if (has_old_value) | ||
206 | 64 | setenv(name.c_str(), old_value.c_str(), overwrite); | ||
207 | 65 | else | ||
208 | 66 | unsetenv(name.c_str()); | ||
209 | 67 | } | ||
210 | 68 | |||
211 | 69 | private: | ||
212 | 70 | static int const overwrite = 1; | ||
213 | 71 | std::string const name; | ||
214 | 72 | bool const has_old_value; | ||
215 | 73 | std::string const old_value; | ||
216 | 74 | }; | ||
217 | 75 | |||
218 | 76 | struct AcceptanceTest : Test | ||
219 | 77 | { | ||
220 | 78 | AcceptanceTest() : platform("MIR_SERVER_PLATFORM_GRAPHICS_LIB", "libmirplatformstub.so") {} | ||
221 | 79 | |||
222 | 80 | TemporaryEnvironmentValue platform; | ||
223 | 81 | }; | ||
224 | 82 | |||
225 | 83 | struct ServerConfigurationWrapping : AcceptanceTest | ||
226 | 84 | { | ||
227 | 85 | mir::Server server; | ||
228 | 86 | |||
231 | 87 | void SetUp() override | 49 | void SetUp() override |
232 | 88 | { | 50 | { |
233 | 89 | server.wrap_surface_coordinator([] | 51 | server.wrap_surface_coordinator([] |
234 | 90 | 52 | ||
235 | === modified file 'tests/acceptance-tests/test_client_library.cpp' | |||
236 | --- tests/acceptance-tests/test_client_library.cpp 2014-10-27 22:31:16 +0000 | |||
237 | +++ tests/acceptance-tests/test_client_library.cpp 2014-10-28 09:41:16 +0000 | |||
238 | @@ -18,8 +18,7 @@ | |||
239 | 18 | 18 | ||
240 | 19 | #include "mir_toolkit/mir_client_library.h" | 19 | #include "mir_toolkit/mir_client_library.h" |
241 | 20 | 20 | ||
244 | 21 | #include "mir_test_framework/stubbed_server_configuration.h" | 21 | #include "mir_test_framework/headless_test.h" |
243 | 22 | #include "mir_test_framework/in_process_server.h" | ||
245 | 23 | #include "mir_test_framework/using_stub_client_platform.h" | 22 | #include "mir_test_framework/using_stub_client_platform.h" |
246 | 24 | 23 | ||
247 | 25 | #include "src/client/client_buffer.h" | 24 | #include "src/client/client_buffer.h" |
248 | @@ -53,10 +52,26 @@ | |||
249 | 53 | 52 | ||
250 | 54 | namespace | 53 | namespace |
251 | 55 | { | 54 | { |
256 | 56 | struct ClientLibrary : mir_test_framework::InProcessServer | 55 | struct HeadlessInProcessServer : mir_test_framework::HeadlessTest |
257 | 57 | { | 56 | { |
258 | 58 | mtf::StubbedServerConfiguration server_configuration; | 57 | HeadlessInProcessServer() |
259 | 59 | mir::DefaultServerConfiguration& server_config() override { return server_configuration; } | 58 | { |
260 | 59 | add_to_environment("MIR_SERVER_NO_FILE", ""); | ||
261 | 60 | } | ||
262 | 61 | |||
263 | 62 | void SetUp() override | ||
264 | 63 | { | ||
265 | 64 | start_server(); | ||
266 | 65 | } | ||
267 | 66 | |||
268 | 67 | void TearDown() override | ||
269 | 68 | { | ||
270 | 69 | stop_server(); | ||
271 | 70 | } | ||
272 | 71 | }; | ||
273 | 72 | |||
274 | 73 | struct ClientLibrary : HeadlessInProcessServer | ||
275 | 74 | { | ||
276 | 60 | mtf::UsingStubClientPlatform using_stub_client_platform; | 75 | mtf::UsingStubClientPlatform using_stub_client_platform; |
277 | 61 | 76 | ||
278 | 62 | std::set<MirSurface*> surfaces; | 77 | std::set<MirSurface*> surfaces; |
279 | 63 | 78 | ||
280 | === added file 'tests/include/mir_test_framework/headless_test.h' | |||
281 | --- tests/include/mir_test_framework/headless_test.h 1970-01-01 00:00:00 +0000 | |||
282 | +++ tests/include/mir_test_framework/headless_test.h 2014-10-28 09:41:16 +0000 | |||
283 | @@ -0,0 +1,71 @@ | |||
284 | 1 | /* | ||
285 | 2 | * Copyright © 2014 Canonical Ltd. | ||
286 | 3 | * | ||
287 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
288 | 5 | * under the terms of the GNU General Public License version 3, | ||
289 | 6 | * as published by the Free Software Foundation. | ||
290 | 7 | * | ||
291 | 8 | * This program is distributed in the hope that it will be useful, | ||
292 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
293 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
294 | 11 | * GNU General Public License for more details. | ||
295 | 12 | * | ||
296 | 13 | * You should have received a copy of the GNU General Public License | ||
297 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
298 | 15 | * | ||
299 | 16 | * Authored By: Alan Griffiths <alan@octopull.co.uk> | ||
300 | 17 | */ | ||
301 | 18 | |||
302 | 19 | #ifndef MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_ | ||
303 | 20 | #define MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_ | ||
304 | 21 | |||
305 | 22 | #include "mir_test_framework/temporary_environment_value.h" | ||
306 | 23 | |||
307 | 24 | #include "mir/server.h" | ||
308 | 25 | |||
309 | 26 | #include <gtest/gtest.h> | ||
310 | 27 | |||
311 | 28 | #include <condition_variable> | ||
312 | 29 | #include <list> | ||
313 | 30 | #include <mutex> | ||
314 | 31 | #include <thread> | ||
315 | 32 | |||
316 | 33 | namespace mir_test_framework | ||
317 | 34 | { | ||
318 | 35 | /** Basic fixture for tests that don't use graphics hardware. | ||
319 | 36 | * This provides a mechanism for temporarily setting environment variables. | ||
320 | 37 | * It automatically sets "MIR_SERVER_PLATFORM_GRAPHICS_LIB" to "libmirplatformstub.so" | ||
321 | 38 | * as the tests do not hit the graphics hardware. | ||
322 | 39 | */ | ||
323 | 40 | class HeadlessTest : public ::testing::Test | ||
324 | 41 | { | ||
325 | 42 | public: | ||
326 | 43 | HeadlessTest(); | ||
327 | 44 | ~HeadlessTest() noexcept; | ||
328 | 45 | |||
329 | 46 | void add_to_environment(char const* key, char const* value); | ||
330 | 47 | |||
331 | 48 | /// Starts the server on a new thread | ||
332 | 49 | void start_server(); | ||
333 | 50 | |||
334 | 51 | /// Stops the server and joins thread | ||
335 | 52 | void stop_server(); | ||
336 | 53 | |||
337 | 54 | /// \return a connection string for a new client to connect to the server | ||
338 | 55 | auto new_connection() -> std::string; | ||
339 | 56 | |||
340 | 57 | mir::Server server; | ||
341 | 58 | |||
342 | 59 | private: | ||
343 | 60 | std::list<TemporaryEnvironmentValue> env; | ||
344 | 61 | std::thread server_thread; | ||
345 | 62 | |||
346 | 63 | std::list<mir::Fd> connections; | ||
347 | 64 | |||
348 | 65 | std::mutex mutex; | ||
349 | 66 | std::condition_variable started; | ||
350 | 67 | bool server_running{false}; | ||
351 | 68 | }; | ||
352 | 69 | } | ||
353 | 70 | |||
354 | 71 | #endif /* MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_ */ | ||
355 | 0 | 72 | ||
356 | === added file 'tests/include/mir_test_framework/temporary_environment_value.h' | |||
357 | --- tests/include/mir_test_framework/temporary_environment_value.h 1970-01-01 00:00:00 +0000 | |||
358 | +++ tests/include/mir_test_framework/temporary_environment_value.h 2014-10-28 09:41:16 +0000 | |||
359 | @@ -0,0 +1,41 @@ | |||
360 | 1 | /* | ||
361 | 2 | * Copyright © 2014 Canonical Ltd. | ||
362 | 3 | * | ||
363 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
364 | 5 | * under the terms of the GNU General Public License version 3, | ||
365 | 6 | * as published by the Free Software Foundation. | ||
366 | 7 | * | ||
367 | 8 | * This program is distributed in the hope that it will be useful, | ||
368 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
369 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
370 | 11 | * GNU General Public License for more details. | ||
371 | 12 | * | ||
372 | 13 | * You should have received a copy of the GNU General Public License | ||
373 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
374 | 15 | * | ||
375 | 16 | * Authored By: Alan Griffiths <alan@octopull.co.uk> | ||
376 | 17 | */ | ||
377 | 18 | |||
378 | 19 | #ifndef MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_ | ||
379 | 20 | #define MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_ | ||
380 | 21 | |||
381 | 22 | #include <string> | ||
382 | 23 | |||
383 | 24 | namespace mir_test_framework | ||
384 | 25 | { | ||
385 | 26 | class TemporaryEnvironmentValue | ||
386 | 27 | { | ||
387 | 28 | public: | ||
388 | 29 | TemporaryEnvironmentValue(char const* name, char const* value); | ||
389 | 30 | |||
390 | 31 | ~TemporaryEnvironmentValue(); | ||
391 | 32 | |||
392 | 33 | private: | ||
393 | 34 | static int const overwrite = 1; | ||
394 | 35 | std::string const name; | ||
395 | 36 | bool const has_old_value; | ||
396 | 37 | std::string const old_value; | ||
397 | 38 | }; | ||
398 | 39 | } | ||
399 | 40 | |||
400 | 41 | #endif /* MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_ */ | ||
401 | 0 | 42 | ||
402 | === modified file 'tests/mir_test_framework/CMakeLists.txt' | |||
403 | --- tests/mir_test_framework/CMakeLists.txt 2014-10-23 02:30:50 +0000 | |||
404 | +++ tests/mir_test_framework/CMakeLists.txt 2014-10-28 09:41:16 +0000 | |||
405 | @@ -15,7 +15,9 @@ | |||
406 | 15 | executable_path.cpp | 15 | executable_path.cpp |
407 | 16 | command_line_server_configuration.cpp | 16 | command_line_server_configuration.cpp |
408 | 17 | cross_process_sync.cpp | 17 | cross_process_sync.cpp |
409 | 18 | headless_test.cpp | ||
410 | 18 | server_runner.cpp | 19 | server_runner.cpp |
411 | 20 | temporary_environment_value.cpp | ||
412 | 19 | testing_server_options.cpp | 21 | testing_server_options.cpp |
413 | 20 | input_testing_server_options.cpp | 22 | input_testing_server_options.cpp |
414 | 21 | stubbed_server_configuration.cpp | 23 | stubbed_server_configuration.cpp |
415 | 22 | 24 | ||
416 | === added file 'tests/mir_test_framework/headless_test.cpp' | |||
417 | --- tests/mir_test_framework/headless_test.cpp 1970-01-01 00:00:00 +0000 | |||
418 | +++ tests/mir_test_framework/headless_test.cpp 2014-10-28 09:41:16 +0000 | |||
419 | @@ -0,0 +1,113 @@ | |||
420 | 1 | /* | ||
421 | 2 | * Copyright © 2014 Canonical Ltd. | ||
422 | 3 | * | ||
423 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
424 | 5 | * under the terms of the GNU General Public License version 3, | ||
425 | 6 | * as published by the Free Software Foundation. | ||
426 | 7 | * | ||
427 | 8 | * This program is distributed in the hope that it will be useful, | ||
428 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
429 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
430 | 11 | * GNU General Public License for more details. | ||
431 | 12 | * | ||
432 | 13 | * You should have received a copy of the GNU General Public License | ||
433 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
434 | 15 | * | ||
435 | 16 | * Authored By: Alan Griffiths <alan@octopull.co.uk> | ||
436 | 17 | */ | ||
437 | 18 | |||
438 | 19 | #include "mir_test_framework/headless_test.h" | ||
439 | 20 | |||
440 | 21 | #include "mir/main_loop.h" | ||
441 | 22 | |||
442 | 23 | #include <boost/throw_exception.hpp> | ||
443 | 24 | |||
444 | 25 | namespace mtf = mir_test_framework; | ||
445 | 26 | |||
446 | 27 | namespace | ||
447 | 28 | { | ||
448 | 29 | std::chrono::seconds const timeout{10}; | ||
449 | 30 | } | ||
450 | 31 | |||
451 | 32 | mtf::HeadlessTest::HeadlessTest() | ||
452 | 33 | { | ||
453 | 34 | add_to_environment("MIR_SERVER_PLATFORM_GRAPHICS_LIB", "libmirplatformstub.so"); | ||
454 | 35 | } | ||
455 | 36 | |||
456 | 37 | void mtf::HeadlessTest::add_to_environment(char const* key, char const* value) | ||
457 | 38 | { | ||
458 | 39 | env.emplace_back(key, value); | ||
459 | 40 | } | ||
460 | 41 | |||
461 | 42 | void mtf::HeadlessTest::start_server() | ||
462 | 43 | { | ||
463 | 44 | server.add_init_callback([&] | ||
464 | 45 | { | ||
465 | 46 | auto const main_loop = server.the_main_loop(); | ||
466 | 47 | // By enqueuing the notification code in the main loop, we are | ||
467 | 48 | // ensuring that the server has really and fully started before | ||
468 | 49 | // leaving start_mir_server(). | ||
469 | 50 | main_loop->enqueue( | ||
470 | 51 | this, | ||
471 | 52 | [&] | ||
472 | 53 | { | ||
473 | 54 | std::lock_guard<std::mutex> lock(mutex); | ||
474 | 55 | server_running = true; | ||
475 | 56 | started.notify_one(); | ||
476 | 57 | }); | ||
477 | 58 | }); | ||
478 | 59 | |||
479 | 60 | server_thread = std::thread([&] | ||
480 | 61 | { | ||
481 | 62 | try | ||
482 | 63 | { | ||
483 | 64 | server.run(); | ||
484 | 65 | } | ||
485 | 66 | catch (std::exception const& e) | ||
486 | 67 | { | ||
487 | 68 | FAIL() << e.what(); | ||
488 | 69 | } | ||
489 | 70 | std::lock_guard<std::mutex> lock(mutex); | ||
490 | 71 | server_running = false; | ||
491 | 72 | started.notify_one(); | ||
492 | 73 | }); | ||
493 | 74 | |||
494 | 75 | std::unique_lock<std::mutex> lock(mutex); | ||
495 | 76 | started.wait_for(lock, timeout, [&] { return server_running; }); | ||
496 | 77 | |||
497 | 78 | if (!server_running) | ||
498 | 79 | { | ||
499 | 80 | BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to start server thread"}); | ||
500 | 81 | } | ||
501 | 82 | } | ||
502 | 83 | |||
503 | 84 | void mtf::HeadlessTest::stop_server() | ||
504 | 85 | { | ||
505 | 86 | connections.clear(); | ||
506 | 87 | |||
507 | 88 | std::unique_lock<std::mutex> lock(mutex); | ||
508 | 89 | if (server_running) | ||
509 | 90 | { | ||
510 | 91 | server.stop(); | ||
511 | 92 | started.wait_for(lock, timeout, [&] { return !server_running; }); | ||
512 | 93 | } | ||
513 | 94 | |||
514 | 95 | if (server_running) | ||
515 | 96 | { | ||
516 | 97 | BOOST_THROW_EXCEPTION(std::logic_error{"stop_server() failed to stop server"}); | ||
517 | 98 | } | ||
518 | 99 | } | ||
519 | 100 | |||
520 | 101 | mtf::HeadlessTest::~HeadlessTest() noexcept | ||
521 | 102 | { | ||
522 | 103 | if (server_thread.joinable()) server_thread.join(); | ||
523 | 104 | } | ||
524 | 105 | |||
525 | 106 | auto mtf::HeadlessTest::new_connection() -> std::string | ||
526 | 107 | { | ||
527 | 108 | char connect_string[64] = {0}; | ||
528 | 109 | auto const client_socket = server.open_client_socket(); | ||
529 | 110 | connections.push_back(client_socket); | ||
530 | 111 | sprintf(connect_string, "fd://%d", client_socket.operator int()); | ||
531 | 112 | return connect_string; | ||
532 | 113 | } | ||
533 | 0 | 114 | ||
534 | === added file 'tests/mir_test_framework/temporary_environment_value.cpp' | |||
535 | --- tests/mir_test_framework/temporary_environment_value.cpp 1970-01-01 00:00:00 +0000 | |||
536 | +++ tests/mir_test_framework/temporary_environment_value.cpp 2014-10-28 09:41:16 +0000 | |||
537 | @@ -0,0 +1,42 @@ | |||
538 | 1 | /* | ||
539 | 2 | * Copyright © 2014 Canonical Ltd. | ||
540 | 3 | * | ||
541 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
542 | 5 | * under the terms of the GNU General Public License version 3, | ||
543 | 6 | * as published by the Free Software Foundation. | ||
544 | 7 | * | ||
545 | 8 | * This program is distributed in the hope that it will be useful, | ||
546 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
547 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
548 | 11 | * GNU General Public License for more details. | ||
549 | 12 | * | ||
550 | 13 | * You should have received a copy of the GNU General Public License | ||
551 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
552 | 15 | * | ||
553 | 16 | * Authored By: Alan Griffiths <alan@octopull.co.uk> | ||
554 | 17 | */ | ||
555 | 18 | |||
556 | 19 | #include "mir_test_framework/temporary_environment_value.h" | ||
557 | 20 | |||
558 | 21 | #include <cstdlib> | ||
559 | 22 | |||
560 | 23 | namespace mtf = mir_test_framework; | ||
561 | 24 | |||
562 | 25 | mtf::TemporaryEnvironmentValue::TemporaryEnvironmentValue(char const* name, char const* value) : | ||
563 | 26 | name{name}, | ||
564 | 27 | has_old_value{getenv(name) != nullptr}, | ||
565 | 28 | old_value{has_old_value ? getenv(name) : ""} | ||
566 | 29 | { | ||
567 | 30 | if (value) | ||
568 | 31 | setenv(name, value, overwrite); | ||
569 | 32 | else | ||
570 | 33 | unsetenv(name); | ||
571 | 34 | } | ||
572 | 35 | |||
573 | 36 | mtf::TemporaryEnvironmentValue::~TemporaryEnvironmentValue() | ||
574 | 37 | { | ||
575 | 38 | if (has_old_value) | ||
576 | 39 | setenv(name.c_str(), old_value.c_str(), overwrite); | ||
577 | 40 | else | ||
578 | 41 | unsetenv(name.c_str()); | ||
579 | 42 | } | ||
580 | 0 | 43 | ||
581 | === modified file 'tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp' | |||
582 | --- tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp 2014-10-21 16:21:14 +0000 | |||
583 | +++ tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp 2014-10-28 09:41:16 +0000 | |||
584 | @@ -18,6 +18,8 @@ | |||
585 | 18 | 18 | ||
586 | 19 | #include "src/platform/graphics/mesa/anonymous_shm_file.h" | 19 | #include "src/platform/graphics/mesa/anonymous_shm_file.h" |
587 | 20 | 20 | ||
588 | 21 | #include "mir_test_framework/temporary_environment_value.h" | ||
589 | 22 | |||
590 | 21 | #include <gtest/gtest.h> | 23 | #include <gtest/gtest.h> |
591 | 22 | #include <gmock/gmock.h> | 24 | #include <gmock/gmock.h> |
592 | 23 | 25 | ||
593 | @@ -33,39 +35,10 @@ | |||
594 | 33 | 35 | ||
595 | 34 | namespace mg = mir::graphics; | 36 | namespace mg = mir::graphics; |
596 | 35 | namespace mgm = mir::graphics::mesa; | 37 | namespace mgm = mir::graphics::mesa; |
597 | 38 | namespace mtf = mir_test_framework; | ||
598 | 36 | 39 | ||
599 | 37 | namespace | 40 | namespace |
600 | 38 | { | 41 | { |
601 | 39 | |||
602 | 40 | class TemporaryEnvironmentValue | ||
603 | 41 | { | ||
604 | 42 | public: | ||
605 | 43 | TemporaryEnvironmentValue(char const* name, char const* value) | ||
606 | 44 | : name{name}, | ||
607 | 45 | has_old_value{getenv(name) != nullptr}, | ||
608 | 46 | old_value{has_old_value ? getenv(name) : ""} | ||
609 | 47 | { | ||
610 | 48 | if (value) | ||
611 | 49 | setenv(name, value, overwrite); | ||
612 | 50 | else | ||
613 | 51 | unsetenv(name); | ||
614 | 52 | } | ||
615 | 53 | |||
616 | 54 | ~TemporaryEnvironmentValue() | ||
617 | 55 | { | ||
618 | 56 | if (has_old_value) | ||
619 | 57 | setenv(name.c_str(), old_value.c_str(), overwrite); | ||
620 | 58 | else | ||
621 | 59 | unsetenv(name.c_str()); | ||
622 | 60 | } | ||
623 | 61 | |||
624 | 62 | private: | ||
625 | 63 | static int const overwrite = 1; | ||
626 | 64 | std::string const name; | ||
627 | 65 | bool const has_old_value; | ||
628 | 66 | std::string const old_value; | ||
629 | 67 | }; | ||
630 | 68 | |||
631 | 69 | class TemporaryDirectory | 42 | class TemporaryDirectory |
632 | 70 | { | 43 | { |
633 | 71 | public: | 44 | public: |
634 | @@ -185,7 +158,7 @@ | |||
635 | 185 | using namespace testing; | 158 | using namespace testing; |
636 | 186 | 159 | ||
637 | 187 | TemporaryDirectory const temp_dir; | 160 | TemporaryDirectory const temp_dir; |
639 | 188 | TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; | 161 | mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; |
640 | 189 | PathWatcher const path_watcher{temp_dir.path()}; | 162 | PathWatcher const path_watcher{temp_dir.path()}; |
641 | 190 | size_t const file_size{100}; | 163 | size_t const file_size{100}; |
642 | 191 | 164 | ||
643 | @@ -202,7 +175,7 @@ | |||
644 | 202 | { | 175 | { |
645 | 203 | using namespace testing; | 176 | using namespace testing; |
646 | 204 | 177 | ||
648 | 205 | TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", nullptr}; | 178 | mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", nullptr}; |
649 | 206 | PathWatcher const path_watcher{"/tmp"}; | 179 | PathWatcher const path_watcher{"/tmp"}; |
650 | 207 | size_t const file_size{100}; | 180 | size_t const file_size{100}; |
651 | 208 | 181 | ||
652 | @@ -219,7 +192,7 @@ | |||
653 | 219 | { | 192 | { |
654 | 220 | using namespace testing; | 193 | using namespace testing; |
655 | 221 | 194 | ||
657 | 222 | TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", "/non-existent-dir"}; | 195 | mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", "/non-existent-dir"}; |
658 | 223 | PathWatcher const path_watcher{"/tmp"}; | 196 | PathWatcher const path_watcher{"/tmp"}; |
659 | 224 | size_t const file_size{100}; | 197 | size_t const file_size{100}; |
660 | 225 | 198 | ||
661 | @@ -237,7 +210,7 @@ | |||
662 | 237 | using namespace testing; | 210 | using namespace testing; |
663 | 238 | 211 | ||
664 | 239 | TemporaryDirectory const temp_dir; | 212 | TemporaryDirectory const temp_dir; |
666 | 240 | TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; | 213 | mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; |
667 | 241 | size_t const file_size{100}; | 214 | size_t const file_size{100}; |
668 | 242 | 215 | ||
669 | 243 | mgm::AnonymousShmFile shm_file{file_size}; | 216 | mgm::AnonymousShmFile shm_file{file_size}; |
670 | @@ -253,7 +226,7 @@ | |||
671 | 253 | using namespace testing; | 226 | using namespace testing; |
672 | 254 | 227 | ||
673 | 255 | TemporaryDirectory const temp_dir; | 228 | TemporaryDirectory const temp_dir; |
675 | 256 | TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; | 229 | mtf::TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; |
676 | 257 | size_t const file_size{100}; | 230 | size_t const file_size{100}; |
677 | 258 | 231 | ||
678 | 259 | mgm::AnonymousShmFile shm_file{file_size}; | 232 | mgm::AnonymousShmFile shm_file{file_size}; |
PASSED: Continuous integration, rev:2003 jenkins. qa.ubuntu. com/job/ mir-ci/ 1900/ jenkins. qa.ubuntu. com/job/ mir-android- utopic- i386-build/ 2237 jenkins. qa.ubuntu. com/job/ mir-clang- utopic- amd64-build/ 2244 jenkins. qa.ubuntu. com/job/ mir-mediumtests -utopic- touch/2172 jenkins. qa.ubuntu. com/job/ mir-utopic- amd64-ci/ 240 jenkins. qa.ubuntu. com/job/ mir-utopic- amd64-ci/ 240/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- utopic- armhf/1109 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- utopic- armhf/1109/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/3156 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 15032
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/1900/ rebuild
http://