Merge lp:~raof/mir/xserver-spawner into lp:mir
- xserver-spawner
- Merge into development-branch
Status: | Work in progress |
---|---|
Proposed branch: | lp:~raof/mir/xserver-spawner |
Merge into: | lp:mir |
Prerequisite: | lp:~raof/mir/process-wrapper |
Diff against target: |
725 lines (+566/-2) 16 files modified
.clang-format (+1/-1) include/server/mir/default_server_configuration.h (+11/-0) include/server/mir/xserver/null_server_spawner.h (+25/-0) include/server/mir/xserver/xserver_launcher.h (+59/-0) src/server/CMakeLists.txt (+3/-1) src/server/default_server_configuration.cpp (+6/-0) src/server/xserver/CMakeLists.txt (+12/-0) src/server/xserver/global_socket_listening_server_spawner.cpp (+71/-0) src/server/xserver/global_socket_listening_server_spawner.h (+52/-0) src/server/xserver/null_server_spawner.cpp (+34/-0) tests/CMakeLists.txt (+1/-0) tests/acceptance-tests/CMakeLists.txt (+2/-0) tests/acceptance-tests/test_xserver_spawner.cpp (+73/-0) tests/unit-tests/CMakeLists.txt (+2/-0) tests/unit-tests/xserver/CMakeLists.txt (+8/-0) tests/unit-tests/xserver/test_xserver_spawner.cpp (+206/-0) |
To merge this branch: | bzr merge lp:~raof/mir/xserver-spawner |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andreas Pokorny (community) | Needs Fixing | ||
Daniel van Vugt | Needs Fixing | ||
Alan Griffiths | Needs Information | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Review via email: mp+203475@code.launchpad.net |
This proposal supersedes a proposal from 2014-01-28.
Commit message
Description of the change
A first cut at the infrastructure required for seamless nesting of X11 clients.
In order to do this we need to be able to spawn an Xorg server, wait until it's
ready to accept connections, connect a Mir X11 client to act as a bridging WM,
and *then* offer the X11 socket to clients.
This branch accomplishes the first two requirements.
I'm proposing it now because it's a reasonable checkpoint and I need to go and work on something else.
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1349
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
How much should Mir know about launching xservers?
Is it essential to all the uses we envisage: unity8? system compositor? Other (hypothetical at this time) shells?
Kevin DuBois (kdub) wrote : | # |
could
+const char* mir::X:
return a string instead of a const char*?
Kevin DuBois (kdub) wrote : | # |
> How much should Mir know about launching xservers?
>
> Is it essential to all the uses we envisage: unity8? system compositor? Other
> (hypothetical at this time) shells?
Last I heard from the architectural-level view is that lightdm was going to negotiate starting mir and friends and hooking up the FD's between them appropriately. That was something I heard a (relatively) long time ago though.
Chris Halse Rogers (raof) wrote : | # |
@Alan:
I think most non-trivial shells are going to want to support running X11 apps. It's not interesting for system-compositor usage, true.
As to why Mir should know about launching xservers - the process of tying together foreign X11 windows needs Mir support. Mir will need to include an X11 window manager in order to proxy between X11 EWMH window management and Mir - this could be in U8, but any shell that wants to support X11 apps will need identical code.
Ideally you want to start the X11 WM before any app connects to the server to avoid unexpected behaviours; the easiest way to do this is to start the X server, wait for it to come up, connect the WM proxy, and only then consider the server to be started (that's the next part of X11 integration).
I (obviously) think it makes sense to have Mir know how to start the X server.
@kdub:
This is somewhat of a circular dependency - the X server needs Mir running in order to be started (it needs the mir socket), and Mir's X11 WM needs the X server to be running. You can't easily start both from LightDM, as it would need to start Mir, it to be ready to accept connections, then start the X server.
Also, U8 wants to (a) start an X server only when an app needs it, and (b) start one-Xserver-
re: client_
Daniel van Vugt (vanvugt) wrote : | # |
(1) "er" issues as described above.
(2) I'm concerned about mentioning "X"-anything in the Mir source too. It feels like we're preventing Mir from being a success in its own right if it even has to mention X in its source. Even if the coupling is weak, we should strive for a better answer. Generalize, move it out-of-project, etc. We almost certainly don't want an "X" namespace. That's a reasonable indication that we're going in the wrong direction.
(3) You've introduced a build-dep on libx11-dev:
+#include <X11/Xlib.h>
Definitely don't do that, at least :)
Chris Halse Rogers (raof) wrote : | # |
On Wed, 2014-01-29 at 03:09 +0000, Daniel van Vugt wrote:
> Review: Needs Fixing
>
> (1) "er" issues as described above.
Would you prefer XServerFactory?
> (2) I'm concerned about mentioning "X"-anything in the Mir source too. It feels like we're preventing Mir from being a success in its own right if it even has to mention X in its source. Even if the coupling is weak, we should strive for a better answer. Generalize, move it out-of-project, etc. We almost certainly don't want an "X" namespace. That's a reasonable indication that we're going in the wrong direction.
We're going to have to support running X11 apps for the foreseeable
future. Certainly for the life of 14.04, probably for the life of 16.04.
I don't think it's unreasonable for the Mir codebase to reflect the
importance of legacy X11 support.
Indeed, the actual implementations should be in a separate opt-in
libmirserverX11
depend on X11 libraries.
>
> (3) You've introduced a build-dep on libx11-dev:
> +#include <X11/Xlib.h>
> Definitely don't do that, at least :)
>
Ah, yeah. This is currently only for the (disabled) acceptance test.
Once there's mirserver code that depends on X11 libs it'll be optional
and in a separate library.
Andreas Pokorny (andreas-pokorny) wrote : | # |
@er:
I still dont get the argument about "er" - If RAOF renames "XServerSpawner" into "XServerFactory" and people are satisfied then there is something wrong with that rule (of thumb?).
We then switched from a noun that was derived from a verb that meant something like: "creates and launches a process or activity" to something that only means: "creates something". So from a clearer specific term to a generic one. A specific term that describes what should be in this class and what not - A term that suggest that this is actually a very specific functor that launches an XServer.
So I would prefer XServerSpawner:
@library: I do believe that this functionality is something a current linux compositor framework needs to provide, but probably as a separate library. -> Needs Fixing
@clang-format: thanks for fixing!
Unmerged revisions
- 1349. By Chris Halse Rogers
-
clang-format: We always split constructor initialisers on new lines
- 1348. By Chris Halse Rogers
-
Disable X11ClientConnects acceptance test.
This needs a bit more fiddling - it all roughly works, but in the acceptance
test framework we don't have a real graphics card, so XMir currently fails.Needs at least an xorg.conf specifying the dummy graphics driver
- 1347. By Chris Halse Rogers
-
Get the Xserver to connect to a Mir socket
- 1346. By Chris Halse Rogers
-
Update for process::Spawner API change
- 1345. By Chris Halse Rogers
-
Merged subprocess-wrapper into xserver-spawner.
- 1344. By Chris Halse Rogers
-
X::ServerSpawne
r::create_ server must take a shared_ ptr<process: :Spawner> create_server does things asynchronously, so it has to take shared ownership
of the process::Spawner it's using - 1343. By Chris Halse Rogers
-
Rejigger X::ServerSpawner API.
spawn_server() now returns a future<
ServerHandle> that will become a present ServerHandle once
the server is ready, rather than returning a ServerHandle now that has methods that will only
work in the future. - 1342. By Chris Halse Rogers
-
Implement -displayfd handling for GlobalSocketLis
teningServerSpa wner. client_
connection_ string now returns a string that should be associated with an Xorg server that's ready to accept connections - 1341. By Chris Halse Rogers
-
Merge process::Spawner work required to do Xserver startup properly
- 1340. By Chris Halse Rogers
-
More basic unittests for GlobalSocketLis
teningServerSpa wner
Preview Diff
1 | === modified file '.clang-format' | |||
2 | --- .clang-format 2014-01-10 15:48:08 +0000 | |||
3 | +++ .clang-format 2014-01-28 06:35:36 +0000 | |||
4 | @@ -14,7 +14,7 @@ | |||
5 | 14 | BreakConstructorInitializersBeforeComma: false | 14 | BreakConstructorInitializersBeforeComma: false |
6 | 15 | BinPackParameters: true | 15 | BinPackParameters: true |
7 | 16 | ColumnLimit: 120 | 16 | ColumnLimit: 120 |
9 | 17 | ConstructorInitializerAllOnOneLineOrOnePerLine: false | 17 | ConstructorInitializerAllOnOneLineOrOnePerLine: true |
10 | 18 | DerivePointerBinding: true | 18 | DerivePointerBinding: true |
11 | 19 | ExperimentalAutoDetectBinPacking: true | 19 | ExperimentalAutoDetectBinPacking: true |
12 | 20 | IndentCaseLabels: false | 20 | IndentCaseLabels: false |
13 | 21 | 21 | ||
14 | === modified file 'include/server/mir/default_server_configuration.h' | |||
15 | --- include/server/mir/default_server_configuration.h 2014-01-21 15:29:52 +0000 | |||
16 | +++ include/server/mir/default_server_configuration.h 2014-01-28 06:35:36 +0000 | |||
17 | @@ -113,6 +113,11 @@ | |||
18 | 113 | class Logger; | 113 | class Logger; |
19 | 114 | } | 114 | } |
20 | 115 | 115 | ||
21 | 116 | namespace X | ||
22 | 117 | { | ||
23 | 118 | class ServerSpawner; | ||
24 | 119 | } | ||
25 | 120 | |||
26 | 116 | class DefaultServerConfiguration : public virtual ServerConfiguration, DefaultConfigurationOptions | 121 | class DefaultServerConfiguration : public virtual ServerConfiguration, DefaultConfigurationOptions |
27 | 117 | { | 122 | { |
28 | 118 | public: | 123 | public: |
29 | @@ -232,6 +237,12 @@ | |||
30 | 232 | 237 | ||
31 | 233 | virtual std::shared_ptr<time::Clock> the_clock(); | 238 | virtual std::shared_ptr<time::Clock> the_clock(); |
32 | 234 | 239 | ||
33 | 240 | /** @name X11 server integration - customization | ||
34 | 241 | * configurable interfaces for integration with legacy X11 apps | ||
35 | 242 | * @{ */ | ||
36 | 243 | virtual std::shared_ptr<X::ServerSpawner> the_xserver_spawner(); | ||
37 | 244 | /** @} */ | ||
38 | 245 | |||
39 | 235 | protected: | 246 | protected: |
40 | 236 | using DefaultConfigurationOptions::the_options; | 247 | using DefaultConfigurationOptions::the_options; |
41 | 237 | using DefaultConfigurationOptions::add_options; | 248 | using DefaultConfigurationOptions::add_options; |
42 | 238 | 249 | ||
43 | === added directory 'include/server/mir/xserver' | |||
44 | === added file 'include/server/mir/xserver/null_server_spawner.h' | |||
45 | --- include/server/mir/xserver/null_server_spawner.h 1970-01-01 00:00:00 +0000 | |||
46 | +++ include/server/mir/xserver/null_server_spawner.h 2014-01-28 06:35:36 +0000 | |||
47 | @@ -0,0 +1,25 @@ | |||
48 | 1 | #ifndef MIR_X_NULL_SERVER_SPAWNER_H_ | ||
49 | 2 | #define MIR_X_NULL_SERVER_SPAWNER_H_ | ||
50 | 3 | |||
51 | 4 | #include <mir/xserver/xserver_launcher.h> | ||
52 | 5 | |||
53 | 6 | namespace mir | ||
54 | 7 | { | ||
55 | 8 | namespace X | ||
56 | 9 | { | ||
57 | 10 | class NullServerContext : public ServerContext | ||
58 | 11 | { | ||
59 | 12 | public: | ||
60 | 13 | char const* client_connection_string() override; | ||
61 | 14 | }; | ||
62 | 15 | |||
63 | 16 | class NullServerSpawner : public ServerSpawner | ||
64 | 17 | { | ||
65 | 18 | public: | ||
66 | 19 | std::future<std::unique_ptr<ServerContext>> create_server(std::shared_ptr<process::Spawner> const& spawner, std::shared_ptr<mir::frontend::Connector> const& connector) override; | ||
67 | 20 | }; | ||
68 | 21 | |||
69 | 22 | } | ||
70 | 23 | } | ||
71 | 24 | |||
72 | 25 | #endif // MIR_X_NULL_SERVER_SPAWNER_H_ | ||
73 | 0 | 26 | ||
74 | === added file 'include/server/mir/xserver/xserver_launcher.h' | |||
75 | --- include/server/mir/xserver/xserver_launcher.h 1970-01-01 00:00:00 +0000 | |||
76 | +++ include/server/mir/xserver/xserver_launcher.h 2014-01-28 06:35:36 +0000 | |||
77 | @@ -0,0 +1,59 @@ | |||
78 | 1 | /* | ||
79 | 2 | * Copyright © 2014 Canonical Ltd. | ||
80 | 3 | * | ||
81 | 4 | * This program is free software: you can redistribute it and/or modify | ||
82 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
83 | 6 | * published by the Free Software Foundation. | ||
84 | 7 | * | ||
85 | 8 | * This program is distributed in the hope that it will be useful, | ||
86 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
87 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
88 | 11 | * GNU General Public License for more details. | ||
89 | 12 | * | ||
90 | 13 | * You should have received a copy of the GNU General Public License | ||
91 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
92 | 15 | * | ||
93 | 16 | * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> | ||
94 | 17 | */ | ||
95 | 18 | |||
96 | 19 | #ifndef MIR_X_XSERVER_LAUNCHER_H_ | ||
97 | 20 | #define MIR_X_XSERVER_LAUNCHER_H_ | ||
98 | 21 | |||
99 | 22 | #include <future> | ||
100 | 23 | #include <memory> | ||
101 | 24 | |||
102 | 25 | #include "mir/process/spawner.h" | ||
103 | 26 | #include "mir/frontend/connector.h" | ||
104 | 27 | |||
105 | 28 | namespace mir | ||
106 | 29 | { | ||
107 | 30 | namespace X | ||
108 | 31 | { | ||
109 | 32 | |||
110 | 33 | class ServerContext | ||
111 | 34 | { | ||
112 | 35 | public: | ||
113 | 36 | virtual ~ServerContext() = default; | ||
114 | 37 | |||
115 | 38 | /** | ||
116 | 39 | * \brief Get the XLib connection string to connect to this server | ||
117 | 40 | * | ||
118 | 41 | * This string can be passed by the client to XOpenDisplay to connect | ||
119 | 42 | * to this server instance, or set in the DISPLAY environment variable | ||
120 | 43 | * to be used as the default display. | ||
121 | 44 | */ | ||
122 | 45 | virtual char const* client_connection_string() = 0; | ||
123 | 46 | }; | ||
124 | 47 | |||
125 | 48 | class ServerSpawner | ||
126 | 49 | { | ||
127 | 50 | public: | ||
128 | 51 | virtual ~ServerSpawner() = default; | ||
129 | 52 | |||
130 | 53 | virtual std::future<std::unique_ptr<ServerContext>> create_server(std::shared_ptr<mir::process::Spawner> const& spawner, | ||
131 | 54 | std::shared_ptr<mir::frontend::Connector> const& connector) = 0; | ||
132 | 55 | }; | ||
133 | 56 | } | ||
134 | 57 | } | ||
135 | 58 | |||
136 | 59 | #endif // MIR_X_XSERVER_LAUNCHER_H_ | ||
137 | 0 | 60 | ||
138 | === modified file 'src/server/CMakeLists.txt' | |||
139 | --- src/server/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
140 | +++ src/server/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
141 | @@ -13,6 +13,7 @@ | |||
142 | 13 | add_subdirectory(shell/) | 13 | add_subdirectory(shell/) |
143 | 14 | add_subdirectory(time/) | 14 | add_subdirectory(time/) |
144 | 15 | add_subdirectory(process/) | 15 | add_subdirectory(process/) |
145 | 16 | add_subdirectory(xserver/) | ||
146 | 16 | 17 | ||
147 | 17 | set(PREFIX "${CMAKE_INSTALL_PREFIX}") | 18 | set(PREFIX "${CMAKE_INSTALL_PREFIX}") |
148 | 18 | set(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") | 19 | set(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") |
149 | @@ -57,8 +58,9 @@ | |||
150 | 57 | mirlttng | 58 | mirlttng |
151 | 58 | mirnestedgraphics | 59 | mirnestedgraphics |
152 | 59 | miroffscreengraphics | 60 | miroffscreengraphics |
153 | 61 | mirsharedpipe | ||
154 | 60 | mirprocess | 62 | mirprocess |
156 | 61 | mirsharedpipe | 63 | mirxserverintegration |
157 | 62 | ) | 64 | ) |
158 | 63 | 65 | ||
159 | 64 | list(APPEND MIRSERVER_LINKS | 66 | list(APPEND MIRSERVER_LINKS |
160 | 65 | 67 | ||
161 | === modified file 'src/server/default_server_configuration.cpp' | |||
162 | --- src/server/default_server_configuration.cpp 2014-01-13 06:12:33 +0000 | |||
163 | +++ src/server/default_server_configuration.cpp 2014-01-28 06:35:36 +0000 | |||
164 | @@ -42,6 +42,7 @@ | |||
165 | 42 | #include "mir/time/high_resolution_clock.h" | 42 | #include "mir/time/high_resolution_clock.h" |
166 | 43 | #include "mir/geometry/rectangles.h" | 43 | #include "mir/geometry/rectangles.h" |
167 | 44 | #include "mir/default_configuration.h" | 44 | #include "mir/default_configuration.h" |
168 | 45 | #include "mir/xserver/null_server_spawner.h" | ||
169 | 45 | 46 | ||
170 | 46 | #include <map> | 47 | #include <map> |
171 | 47 | 48 | ||
172 | @@ -249,3 +250,8 @@ | |||
173 | 249 | return std::make_shared<mir::DefaultServerStatusListener>(); | 250 | return std::make_shared<mir::DefaultServerStatusListener>(); |
174 | 250 | }); | 251 | }); |
175 | 251 | } | 252 | } |
176 | 253 | |||
177 | 254 | std::shared_ptr<mir::X::ServerSpawner> mir::DefaultServerConfiguration::the_xserver_spawner() | ||
178 | 255 | { | ||
179 | 256 | return std::make_shared<mir::X::NullServerSpawner>(); | ||
180 | 257 | } | ||
181 | 252 | 258 | ||
182 | === added directory 'src/server/xserver' | |||
183 | === added file 'src/server/xserver/CMakeLists.txt' | |||
184 | --- src/server/xserver/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
185 | +++ src/server/xserver/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
186 | @@ -0,0 +1,12 @@ | |||
187 | 1 | set( | ||
188 | 2 | MIR_XSERVER_SRCS | ||
189 | 3 | |||
190 | 4 | global_socket_listening_server_spawner.cpp | ||
191 | 5 | null_server_spawner.cpp | ||
192 | 6 | ) | ||
193 | 7 | |||
194 | 8 | ADD_LIBRARY( | ||
195 | 9 | mirxserverintegration STATIC | ||
196 | 10 | |||
197 | 11 | ${MIR_XSERVER_SRCS} | ||
198 | 12 | ) | ||
199 | 0 | 13 | ||
200 | === added file 'src/server/xserver/global_socket_listening_server_spawner.cpp' | |||
201 | --- src/server/xserver/global_socket_listening_server_spawner.cpp 1970-01-01 00:00:00 +0000 | |||
202 | +++ src/server/xserver/global_socket_listening_server_spawner.cpp 2014-01-28 06:35:36 +0000 | |||
203 | @@ -0,0 +1,71 @@ | |||
204 | 1 | /* | ||
205 | 2 | * Copyright © 2014 Canonical Ltd. | ||
206 | 3 | * | ||
207 | 4 | * This program is free software: you can redistribute it and/or modify | ||
208 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
209 | 6 | * published by the Free Software Foundation. | ||
210 | 7 | * | ||
211 | 8 | * This program is distributed in the hope that it will be useful, | ||
212 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
213 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
214 | 11 | * GNU General Public License for more details. | ||
215 | 12 | * | ||
216 | 13 | * You should have received a copy of the GNU General Public License | ||
217 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
218 | 15 | * | ||
219 | 16 | * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> | ||
220 | 17 | */ | ||
221 | 18 | |||
222 | 19 | #include <unistd.h> | ||
223 | 20 | #include <errno.h> | ||
224 | 21 | |||
225 | 22 | #include <boost/throw_exception.hpp> | ||
226 | 23 | #include <boost/exception/errinfo_errno.hpp> | ||
227 | 24 | |||
228 | 25 | #include "global_socket_listening_server_spawner.h" | ||
229 | 26 | #include "mir/process/handle.h" | ||
230 | 27 | |||
231 | 28 | namespace mx = mir::X; | ||
232 | 29 | |||
233 | 30 | mx::GlobalSocketListeningServerContext::GlobalSocketListeningServerContext(std::unique_ptr<mir::process::Handle> server_handle, std::string connection_string) | ||
234 | 31 | : server_handle(std::move(server_handle)), | ||
235 | 32 | connection_string(connection_string) | ||
236 | 33 | { | ||
237 | 34 | } | ||
238 | 35 | |||
239 | 36 | char const* mx::GlobalSocketListeningServerContext::client_connection_string() | ||
240 | 37 | { | ||
241 | 38 | return connection_string.c_str(); | ||
242 | 39 | } | ||
243 | 40 | |||
244 | 41 | std::future<std::unique_ptr<mx::ServerContext>> mx::GlobalSocketListeningServerSpawner::create_server(std::shared_ptr<mir::process::Spawner> const& spawner, std::shared_ptr<mir::frontend::Connector> const& connector) | ||
245 | 42 | { | ||
246 | 43 | return std::async(std::launch::async, [spawner, connector]() | ||
247 | 44 | { | ||
248 | 45 | mir::pipe::Pipe displayfd_pipe; | ||
249 | 46 | auto displayfd = std::to_string(displayfd_pipe.write_fd()); | ||
250 | 47 | int mir_fd = connector->client_socket_fd(); | ||
251 | 48 | auto mir_fd_arg = std::string("fd://") + std::to_string(mir_fd); | ||
252 | 49 | |||
253 | 50 | auto future_handle = spawner->run_from_path("Xorg", | ||
254 | 51 | {"-displayfd", displayfd.c_str(), | ||
255 | 52 | "-mir", "xserver", | ||
256 | 53 | "-mirSocket", mir_fd_arg.c_str()}, | ||
257 | 54 | {displayfd_pipe.write_fd(), mir_fd}); | ||
258 | 55 | |||
259 | 56 | char display_number[10]; | ||
260 | 57 | errno = 0; | ||
261 | 58 | int bytes_read = read(displayfd_pipe.read_fd(), display_number, sizeof display_number); | ||
262 | 59 | |||
263 | 60 | while (bytes_read == -1 && errno == EINTR) | ||
264 | 61 | bytes_read = read(displayfd_pipe.read_fd(), display_number, sizeof display_number);; | ||
265 | 62 | |||
266 | 63 | if (errno != 0) | ||
267 | 64 | BOOST_THROW_EXCEPTION(boost::enable_error_info(std::runtime_error("Failed to receive display number from Xserver")) | ||
268 | 65 | << boost::errinfo_errno(errno)); | ||
269 | 66 | |||
270 | 67 | display_number[bytes_read] = '\0'; | ||
271 | 68 | |||
272 | 69 | return std::unique_ptr<mx::ServerContext>(new mx::GlobalSocketListeningServerContext(future_handle.get(), std::string(":") + display_number)); | ||
273 | 70 | }); | ||
274 | 71 | } | ||
275 | 0 | 72 | ||
276 | === added file 'src/server/xserver/global_socket_listening_server_spawner.h' | |||
277 | --- src/server/xserver/global_socket_listening_server_spawner.h 1970-01-01 00:00:00 +0000 | |||
278 | +++ src/server/xserver/global_socket_listening_server_spawner.h 2014-01-28 06:35:36 +0000 | |||
279 | @@ -0,0 +1,52 @@ | |||
280 | 1 | /* | ||
281 | 2 | * Copyright © 2014 Canonical Ltd. | ||
282 | 3 | * | ||
283 | 4 | * This program is free software: you can redistribute it and/or modify | ||
284 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
285 | 6 | * published by the Free Software Foundation. | ||
286 | 7 | * | ||
287 | 8 | * This program is distributed in the hope that it will be useful, | ||
288 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
289 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
290 | 11 | * GNU General Public License for more details. | ||
291 | 12 | * | ||
292 | 13 | * You should have received a copy of the GNU General Public License | ||
293 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
294 | 15 | * | ||
295 | 16 | * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> | ||
296 | 17 | */ | ||
297 | 18 | |||
298 | 19 | #ifndef MIR_X_GLOBAL_SOCKET_LISTENING_SERVER_SPAWNER_H_ | ||
299 | 20 | #define MIR_X_GLOBAL_SOCKET_LISTENING_SERVER_SPAWNER_H_ | ||
300 | 21 | |||
301 | 22 | #include "mir/xserver/xserver_launcher.h" | ||
302 | 23 | #include "mir/process/spawner.h" | ||
303 | 24 | #include "mir/pipe.h" | ||
304 | 25 | |||
305 | 26 | #include <memory> | ||
306 | 27 | |||
307 | 28 | namespace mir | ||
308 | 29 | { | ||
309 | 30 | namespace X | ||
310 | 31 | { | ||
311 | 32 | class GlobalSocketListeningServerContext : public ServerContext | ||
312 | 33 | { | ||
313 | 34 | public: | ||
314 | 35 | GlobalSocketListeningServerContext(std::unique_ptr<mir::process::Handle> server_handle, std::string connection_string); | ||
315 | 36 | char const* client_connection_string() override; | ||
316 | 37 | |||
317 | 38 | private: | ||
318 | 39 | std::unique_ptr<mir::process::Handle> server_handle; | ||
319 | 40 | std::string connection_string; | ||
320 | 41 | }; | ||
321 | 42 | |||
322 | 43 | class GlobalSocketListeningServerSpawner : public ServerSpawner | ||
323 | 44 | { | ||
324 | 45 | public: | ||
325 | 46 | std::future<std::unique_ptr<ServerContext>> create_server(std::shared_ptr<mir::process::Spawner> const& spawner, std::shared_ptr<mir::frontend::Connector> const& connector) override; | ||
326 | 47 | }; | ||
327 | 48 | |||
328 | 49 | } | ||
329 | 50 | } | ||
330 | 51 | |||
331 | 52 | #endif // MIR_X_GLOBAL_SOCKET_LISTENING_SERVER_SPAWNER_H_ | ||
332 | 0 | 53 | ||
333 | === added file 'src/server/xserver/null_server_spawner.cpp' | |||
334 | --- src/server/xserver/null_server_spawner.cpp 1970-01-01 00:00:00 +0000 | |||
335 | +++ src/server/xserver/null_server_spawner.cpp 2014-01-28 06:35:36 +0000 | |||
336 | @@ -0,0 +1,34 @@ | |||
337 | 1 | /* | ||
338 | 2 | * Copyright © 2014 Canonical Ltd. | ||
339 | 3 | * | ||
340 | 4 | * This program is free software: you can redistribute it and/or modify | ||
341 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
342 | 6 | * published by the Free Software Foundation. | ||
343 | 7 | * | ||
344 | 8 | * This program is distributed in the hope that it will be useful, | ||
345 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
346 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
347 | 11 | * GNU General Public License for more details. | ||
348 | 12 | * | ||
349 | 13 | * You should have received a copy of the GNU General Public License | ||
350 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
351 | 15 | * | ||
352 | 16 | * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> | ||
353 | 17 | */ | ||
354 | 18 | |||
355 | 19 | #include "mir/xserver/null_server_spawner.h" | ||
356 | 20 | |||
357 | 21 | const char* mir::X::NullServerContext::client_connection_string() | ||
358 | 22 | { | ||
359 | 23 | return ""; | ||
360 | 24 | } | ||
361 | 25 | |||
362 | 26 | std::future<std::unique_ptr<mir::X::ServerContext>> mir::X::NullServerSpawner::create_server( | ||
363 | 27 | std::shared_ptr<mir::process::Spawner> const& unused, std::shared_ptr<mir::frontend::Connector> const& unuseder) | ||
364 | 28 | { | ||
365 | 29 | static_cast<void>(unused); | ||
366 | 30 | static_cast<void>(unuseder); | ||
367 | 31 | std::promise<std::unique_ptr<mir::X::ServerContext>> boring_promise; | ||
368 | 32 | boring_promise.set_value(std::unique_ptr<mir::X::ServerContext>(new mir::X::NullServerContext)); | ||
369 | 33 | return boring_promise.get_future(); | ||
370 | 34 | } | ||
371 | 0 | 35 | ||
372 | === modified file 'tests/CMakeLists.txt' | |||
373 | --- tests/CMakeLists.txt 2014-01-23 08:06:05 +0000 | |||
374 | +++ tests/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
375 | @@ -36,6 +36,7 @@ | |||
376 | 36 | 36 | ||
377 | 37 | if (MIR_BUILD_ACCEPTANCE_TESTS) | 37 | if (MIR_BUILD_ACCEPTANCE_TESTS) |
378 | 38 | add_subdirectory(acceptance-tests/) | 38 | add_subdirectory(acceptance-tests/) |
379 | 39 | pkg_check_modules(X11 REQUIRED x11) | ||
380 | 39 | endif (MIR_BUILD_ACCEPTANCE_TESTS) | 40 | endif (MIR_BUILD_ACCEPTANCE_TESTS) |
381 | 40 | 41 | ||
382 | 41 | if (MIR_BUILD_INTEGRATION_TESTS) | 42 | if (MIR_BUILD_INTEGRATION_TESTS) |
383 | 42 | 43 | ||
384 | === modified file 'tests/acceptance-tests/CMakeLists.txt' | |||
385 | --- tests/acceptance-tests/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
386 | +++ tests/acceptance-tests/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
387 | @@ -28,6 +28,7 @@ | |||
388 | 28 | test_client_library_drm.cpp | 28 | test_client_library_drm.cpp |
389 | 29 | test_protobuf.cpp | 29 | test_protobuf.cpp |
390 | 30 | test_subprocess.cpp | 30 | test_subprocess.cpp |
391 | 31 | test_xserver_spawner.cpp | ||
392 | 31 | ${GENERATED_PROTOBUF_SRCS} | 32 | ${GENERATED_PROTOBUF_SRCS} |
393 | 32 | ${GENERATED_PROTOBUF_HDRS} | 33 | ${GENERATED_PROTOBUF_HDRS} |
394 | 33 | ) | 34 | ) |
395 | @@ -66,6 +67,7 @@ | |||
396 | 66 | ${GMOCK_LIBRARY} | 67 | ${GMOCK_LIBRARY} |
397 | 67 | ${GMOCK_MAIN_LIBRARY} | 68 | ${GMOCK_MAIN_LIBRARY} |
398 | 68 | ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. | 69 | ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. |
399 | 70 | ${X11_LDFLAGS} | ||
400 | 69 | ) | 71 | ) |
401 | 70 | 72 | ||
402 | 71 | CMAKE_DEPENDENT_OPTION( | 73 | CMAKE_DEPENDENT_OPTION( |
403 | 72 | 74 | ||
404 | === added file 'tests/acceptance-tests/test_xserver_spawner.cpp' | |||
405 | --- tests/acceptance-tests/test_xserver_spawner.cpp 1970-01-01 00:00:00 +0000 | |||
406 | +++ tests/acceptance-tests/test_xserver_spawner.cpp 2014-01-28 06:35:36 +0000 | |||
407 | @@ -0,0 +1,73 @@ | |||
408 | 1 | /* | ||
409 | 2 | * Copyright © 2014 Canonical Ltd. | ||
410 | 3 | * | ||
411 | 4 | * This program is free software: you can redistribute it and/or modify | ||
412 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
413 | 6 | * published by the Free Software Foundation. | ||
414 | 7 | * | ||
415 | 8 | * This program is distributed in the hope that it will be useful, | ||
416 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
417 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
418 | 11 | * GNU General Public License for more details. | ||
419 | 12 | * | ||
420 | 13 | * You should have received a copy of the GNU General Public License | ||
421 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
422 | 15 | * | ||
423 | 16 | * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> | ||
424 | 17 | */ | ||
425 | 18 | |||
426 | 19 | #include "src/server/xserver/global_socket_listening_server_spawner.h" | ||
427 | 20 | #include "mir_test_framework/testing_server_configuration.h" | ||
428 | 21 | #include "mir_test_framework/in_process_server.h" | ||
429 | 22 | #include "mir/xserver/xserver_launcher.h" | ||
430 | 23 | #include "src/server/process/fork_spawner.h" | ||
431 | 24 | |||
432 | 25 | #include <X11/Xlib.h> | ||
433 | 26 | #include <stdlib.h> | ||
434 | 27 | |||
435 | 28 | #include <gtest/gtest.h> | ||
436 | 29 | |||
437 | 30 | namespace mtf = mir_test_framework; | ||
438 | 31 | namespace mx = mir::X; | ||
439 | 32 | |||
440 | 33 | namespace | ||
441 | 34 | { | ||
442 | 35 | struct XserverSpawningServer : public mtf::InProcessServer | ||
443 | 36 | { | ||
444 | 37 | public: | ||
445 | 38 | std::shared_ptr<mx::ServerSpawner> the_xserver_spawner() | ||
446 | 39 | { | ||
447 | 40 | return config.the_xserver_spawner(); | ||
448 | 41 | } | ||
449 | 42 | |||
450 | 43 | mir::DefaultServerConfiguration& server_config() override | ||
451 | 44 | { | ||
452 | 45 | return config; | ||
453 | 46 | } | ||
454 | 47 | |||
455 | 48 | class SocketListeningXServerConfig : public mtf::StubbedServerConfiguration | ||
456 | 49 | { | ||
457 | 50 | public: | ||
458 | 51 | std::shared_ptr<mx::ServerSpawner> the_xserver_spawner() override | ||
459 | 52 | { | ||
460 | 53 | return std::make_shared<mx::GlobalSocketListeningServerSpawner> (); | ||
461 | 54 | } | ||
462 | 55 | } config; | ||
463 | 56 | }; | ||
464 | 57 | } | ||
465 | 58 | |||
466 | 59 | // This requires a bit more fiddling before it will work. | ||
467 | 60 | // Particularly, it needs an xorg.conf that specifies dummy | ||
468 | 61 | // devices, so the real devices don't fail to load. | ||
469 | 62 | TEST_F(XserverSpawningServer, DISABLED_X11ClientConnects) | ||
470 | 63 | { | ||
471 | 64 | // Ensure the surrounding environment doesn't mess with the test | ||
472 | 65 | unsetenv("DISPLAY"); | ||
473 | 66 | |||
474 | 67 | auto xserver = the_xserver_spawner()->create_server(std::make_shared<mir::process::ForkSpawner>(), config.the_connector()); | ||
475 | 68 | Display* disp = XOpenDisplay(xserver.get()->client_connection_string()); | ||
476 | 69 | |||
477 | 70 | ASSERT_TRUE(disp != NULL); | ||
478 | 71 | |||
479 | 72 | XCloseDisplay(disp); | ||
480 | 73 | } | ||
481 | 0 | 74 | ||
482 | === modified file 'tests/unit-tests/CMakeLists.txt' | |||
483 | --- tests/unit-tests/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
484 | +++ tests/unit-tests/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
485 | @@ -30,6 +30,7 @@ | |||
486 | 30 | add_subdirectory(android_input/) | 30 | add_subdirectory(android_input/) |
487 | 31 | add_subdirectory(scene/) | 31 | add_subdirectory(scene/) |
488 | 32 | add_subdirectory(draw/) | 32 | add_subdirectory(draw/) |
489 | 33 | add_subdirectory(xserver/) | ||
490 | 33 | 34 | ||
491 | 34 | add_executable(mir_unit_tests ${UNIT_TEST_SOURCES}) | 35 | add_executable(mir_unit_tests ${UNIT_TEST_SOURCES}) |
492 | 35 | uses_android_input(mir_unit_tests) | 36 | uses_android_input(mir_unit_tests) |
493 | @@ -43,6 +44,7 @@ | |||
494 | 43 | mirdraw | 44 | mirdraw |
495 | 44 | mirtestdraw | 45 | mirtestdraw |
496 | 45 | mirlogging | 46 | mirlogging |
497 | 47 | mirxserverintegration | ||
498 | 46 | 48 | ||
499 | 47 | mir-test | 49 | mir-test |
500 | 48 | mir-test-doubles | 50 | mir-test-doubles |
501 | 49 | 51 | ||
502 | === added directory 'tests/unit-tests/xserver' | |||
503 | === added file 'tests/unit-tests/xserver/CMakeLists.txt' | |||
504 | --- tests/unit-tests/xserver/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
505 | +++ tests/unit-tests/xserver/CMakeLists.txt 2014-01-28 06:35:36 +0000 | |||
506 | @@ -0,0 +1,8 @@ | |||
507 | 1 | list(APPEND UNIT_TEST_SOURCES | ||
508 | 2 | ${CMAKE_CURRENT_SOURCE_DIR}/test_xserver_spawner.cpp | ||
509 | 3 | ) | ||
510 | 4 | |||
511 | 5 | set( | ||
512 | 6 | UNIT_TEST_SOURCES | ||
513 | 7 | ${UNIT_TEST_SOURCES} | ||
514 | 8 | PARENT_SCOPE) | ||
515 | 0 | 9 | ||
516 | === added file 'tests/unit-tests/xserver/test_xserver_spawner.cpp' | |||
517 | --- tests/unit-tests/xserver/test_xserver_spawner.cpp 1970-01-01 00:00:00 +0000 | |||
518 | +++ tests/unit-tests/xserver/test_xserver_spawner.cpp 2014-01-28 06:35:36 +0000 | |||
519 | @@ -0,0 +1,206 @@ | |||
520 | 1 | /* | ||
521 | 2 | * Copyright © 2014 Canonical Ltd. | ||
522 | 3 | * | ||
523 | 4 | * This program is free software: you can redistribute it and/or modify | ||
524 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
525 | 6 | * published by the Free Software Foundation. | ||
526 | 7 | * | ||
527 | 8 | * This program is distributed in the hope that it will be useful, | ||
528 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
529 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
530 | 11 | * GNU General Public License for more details. | ||
531 | 12 | * | ||
532 | 13 | * You should have received a copy of the GNU General Public License | ||
533 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
534 | 15 | * | ||
535 | 16 | * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com> | ||
536 | 17 | */ | ||
537 | 18 | |||
538 | 19 | #include <future> | ||
539 | 20 | #include <vector> | ||
540 | 21 | #include <thread> | ||
541 | 22 | #include <condition_variable> | ||
542 | 23 | |||
543 | 24 | #include <gtest/gtest.h> | ||
544 | 25 | #include <gmock/gmock.h> | ||
545 | 26 | |||
546 | 27 | #include "mir/process/spawner.h" | ||
547 | 28 | #include "mir/process/handle.h" | ||
548 | 29 | |||
549 | 30 | #include "src/server/xserver/global_socket_listening_server_spawner.h" | ||
550 | 31 | |||
551 | 32 | using namespace ::testing; | ||
552 | 33 | |||
553 | 34 | namespace | ||
554 | 35 | { | ||
555 | 36 | struct MockConnector : public mir::frontend::Connector | ||
556 | 37 | { | ||
557 | 38 | MOCK_METHOD0(start, void(void)); | ||
558 | 39 | MOCK_METHOD0(stop, void(void)); | ||
559 | 40 | MOCK_CONST_METHOD0(client_socket_fd, int(void)); | ||
560 | 41 | MOCK_CONST_METHOD0(remove_endpoint, void(void)); | ||
561 | 42 | }; | ||
562 | 43 | |||
563 | 44 | struct MockProcessSpawner : public mir::process::Spawner | ||
564 | 45 | { | ||
565 | 46 | MOCK_CONST_METHOD3(run, mir::process::Handle*(std::string, std::vector<char const*>, std::vector<int>)); | ||
566 | 47 | |||
567 | 48 | std::future<std::unique_ptr<mir::process::Handle>> run_from_path(char const* binary) const override | ||
568 | 49 | { | ||
569 | 50 | std::promise<std::unique_ptr<mir::process::Handle>> dummy_promise; | ||
570 | 51 | dummy_promise.set_value(std::unique_ptr<mir::process::Handle>( | ||
571 | 52 | run(binary, std::initializer_list<char const*>(), std::initializer_list<int>()))); | ||
572 | 53 | return dummy_promise.get_future(); | ||
573 | 54 | } | ||
574 | 55 | std::future<std::unique_ptr<mir::process::Handle>> run_from_path(char const* binary, | ||
575 | 56 | std::initializer_list<char const*> args) const | ||
576 | 57 | override | ||
577 | 58 | { | ||
578 | 59 | std::promise<std::unique_ptr<mir::process::Handle>> dummy_promise; | ||
579 | 60 | dummy_promise.set_value(std::unique_ptr<mir::process::Handle>(run(binary, args, std::initializer_list<int>()))); | ||
580 | 61 | return dummy_promise.get_future(); | ||
581 | 62 | } | ||
582 | 63 | |||
583 | 64 | std::future<std::unique_ptr<mir::process::Handle>> run_from_path(char const* binary, | ||
584 | 65 | std::initializer_list<char const*> args, | ||
585 | 66 | std::initializer_list<int> fds) const override | ||
586 | 67 | { | ||
587 | 68 | std::promise<std::unique_ptr<mir::process::Handle>> dummy_promise; | ||
588 | 69 | dummy_promise.set_value(std::unique_ptr<mir::process::Handle>(run(binary, args, fds))); | ||
589 | 70 | return dummy_promise.get_future(); | ||
590 | 71 | } | ||
591 | 72 | }; | ||
592 | 73 | |||
593 | 74 | struct SocketListeningServerTest : public testing::Test | ||
594 | 75 | { | ||
595 | 76 | SocketListeningServerTest() | ||
596 | 77 | : default_server_number("100"), | ||
597 | 78 | spawner(std::make_shared<NiceMock<MockProcessSpawner>>()), | ||
598 | 79 | connector(std::make_shared<NiceMock<MockConnector>>()) | ||
599 | 80 | { | ||
600 | 81 | ON_CALL(*spawner, run(_, _, _)) | ||
601 | 82 | .WillByDefault(DoAll(SaveArg<0>(&binary), | ||
602 | 83 | SaveArg<1>(&args), | ||
603 | 84 | SaveArg<2>(&fds), | ||
604 | 85 | InvokeWithoutArgs([this]() | ||
605 | 86 | { write_server_string(default_server_number); }), | ||
606 | 87 | Return(nullptr))); | ||
607 | 88 | ON_CALL(*connector, client_socket_fd()) | ||
608 | 89 | .WillByDefault(Return(22)); | ||
609 | 90 | } | ||
610 | 91 | |||
611 | 92 | void write_server_string(std::string server_number) | ||
612 | 93 | { | ||
613 | 94 | auto location = std::find_if(args.begin(), args.end(), [](char const* a) | ||
614 | 95 | { return strcmp(a, "-displayfd") == 0; }); | ||
615 | 96 | ASSERT_NE(location, args.end()); | ||
616 | 97 | ASSERT_NE(++location, args.end()); | ||
617 | 98 | int server_fd = atoi(*location); | ||
618 | 99 | write(server_fd, server_number.data(), server_number.length()); | ||
619 | 100 | close(server_fd); | ||
620 | 101 | } | ||
621 | 102 | |||
622 | 103 | std::string default_server_number; | ||
623 | 104 | std::string binary; | ||
624 | 105 | std::vector<char const*> args; | ||
625 | 106 | std::vector<int> fds; | ||
626 | 107 | std::shared_ptr<NiceMock<MockProcessSpawner>> spawner; | ||
627 | 108 | std::shared_ptr<NiceMock<MockConnector>> connector; | ||
628 | 109 | }; | ||
629 | 110 | } | ||
630 | 111 | |||
631 | 112 | TEST_F(SocketListeningServerTest, CreateServerAlwaysValid) | ||
632 | 113 | { | ||
633 | 114 | mir::X::GlobalSocketListeningServerSpawner factory; | ||
634 | 115 | |||
635 | 116 | auto server_context = factory.create_server(spawner, connector); | ||
636 | 117 | ASSERT_NE(server_context.get(), nullptr); | ||
637 | 118 | } | ||
638 | 119 | |||
639 | 120 | TEST_F(SocketListeningServerTest, SpawnsCorrectExecutable) | ||
640 | 121 | { | ||
641 | 122 | mir::X::GlobalSocketListeningServerSpawner factory; | ||
642 | 123 | |||
643 | 124 | auto server_context = factory.create_server(spawner, connector); | ||
644 | 125 | server_context.get(); | ||
645 | 126 | |||
646 | 127 | EXPECT_EQ(binary, "Xorg"); | ||
647 | 128 | } | ||
648 | 129 | |||
649 | 130 | namespace | ||
650 | 131 | { | ||
651 | 132 | MATCHER_P(ContainsSubsequence, subsequence, "") | ||
652 | 133 | { | ||
653 | 134 | auto location = | ||
654 | 135 | std::search(arg.begin(), arg.end(), subsequence.begin(), subsequence.end(), [](char const* a, std::string b) | ||
655 | 136 | { return strcmp(a, b.c_str()) == 0; }); | ||
656 | 137 | return location != arg.end(); | ||
657 | 138 | } | ||
658 | 139 | } | ||
659 | 140 | |||
660 | 141 | TEST_F(SocketListeningServerTest, SpawnsWithDisplayFDSet) | ||
661 | 142 | { | ||
662 | 143 | mir::X::GlobalSocketListeningServerSpawner factory; | ||
663 | 144 | |||
664 | 145 | auto server_context = factory.create_server(spawner, connector); | ||
665 | 146 | server_context.get(); | ||
666 | 147 | |||
667 | 148 | ASSERT_THAT(args, Not(IsEmpty())); | ||
668 | 149 | ASSERT_THAT(fds, Not(IsEmpty())); | ||
669 | 150 | |||
670 | 151 | Matcher<std::vector<char const*>> fd_matcher = Not(_); | ||
671 | 152 | for (auto fd : fds) | ||
672 | 153 | { | ||
673 | 154 | fd_matcher = AnyOf(fd_matcher, ContainsSubsequence(std::vector<std::string>{"-displayfd", std::to_string(fd)})); | ||
674 | 155 | } | ||
675 | 156 | EXPECT_THAT(args, fd_matcher); | ||
676 | 157 | } | ||
677 | 158 | |||
678 | 159 | TEST_F(SocketListeningServerTest, ReturnsCorrectDisplayString) | ||
679 | 160 | { | ||
680 | 161 | mir::X::GlobalSocketListeningServerSpawner factory; | ||
681 | 162 | |||
682 | 163 | default_server_number = "20"; | ||
683 | 164 | auto server_context = factory.create_server(spawner, connector); | ||
684 | 165 | |||
685 | 166 | EXPECT_STREQ(":20", server_context.get()->client_connection_string()); | ||
686 | 167 | } | ||
687 | 168 | |||
688 | 169 | TEST_F(SocketListeningServerTest, HandlesSpawnerLifecycleCorrectly) | ||
689 | 170 | { | ||
690 | 171 | mir::X::GlobalSocketListeningServerSpawner factory; | ||
691 | 172 | |||
692 | 173 | std::future<std::unique_ptr<mir::X::ServerContext>> server_context; | ||
693 | 174 | |||
694 | 175 | { | ||
695 | 176 | auto tmp_spawner = std::make_shared<MockProcessSpawner>(); | ||
696 | 177 | ON_CALL(*tmp_spawner, run(_, _, _)) | ||
697 | 178 | .WillByDefault(DoAll(SaveArg<0>(&binary), | ||
698 | 179 | SaveArg<1>(&args), | ||
699 | 180 | SaveArg<2>(&fds), | ||
700 | 181 | InvokeWithoutArgs([this]() | ||
701 | 182 | { write_server_string(default_server_number); }), | ||
702 | 183 | Return(nullptr))); | ||
703 | 184 | EXPECT_CALL(*tmp_spawner, run(_, _, _)); | ||
704 | 185 | server_context = factory.create_server(tmp_spawner, connector); | ||
705 | 186 | } | ||
706 | 187 | |||
707 | 188 | ASSERT_NE(server_context.get(), nullptr); | ||
708 | 189 | } | ||
709 | 190 | |||
710 | 191 | TEST_F(SocketListeningServerTest, PassesMirSocketCorrectly) | ||
711 | 192 | { | ||
712 | 193 | mir::X::GlobalSocketListeningServerSpawner factory; | ||
713 | 194 | |||
714 | 195 | int const mir_fd{32}; | ||
715 | 196 | std::string const mir_connect_str{std::string("fd://") + std::to_string(mir_fd)}; | ||
716 | 197 | EXPECT_CALL(*connector, client_socket_fd()) | ||
717 | 198 | .WillOnce(Return(mir_fd)); | ||
718 | 199 | |||
719 | 200 | auto server_context = factory.create_server(spawner, connector); | ||
720 | 201 | |||
721 | 202 | server_context.get(); | ||
722 | 203 | |||
723 | 204 | EXPECT_THAT(args, ContainsSubsequence(std::vector<std::string>{"-mirSocket", mir_connect_str})); | ||
724 | 205 | EXPECT_THAT(fds, Contains(Eq(mir_fd))); | ||
725 | 206 | } |
Please rethink class names ending in "er". That's almost always a bad decision, and an indication that a different cleaner design is possible...
http:// www.benhallbenh all.com/ 2013/01/ naming- objects- er-object- names/