Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(925)

Side by Side Diff: mojo/shell/tests/connect/connect_unittest.cc

Issue 1877753003: Move mojo\shell to services\shell (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@62scan
Patch Set: . Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/guid.h"
12 #include "base/macros.h"
13 #include "base/run_loop.h"
14 #include "base/test/test_suite.h"
15 #include "mojo/public/cpp/bindings/binding_set.h"
16 #include "mojo/shell/public/cpp/names.h"
17 #include "mojo/shell/public/cpp/shell_test.h"
18 #include "mojo/shell/public/interfaces/shell.mojom.h"
19 #include "mojo/shell/tests/connect/connect_test.mojom.h"
20
21 // Tests that multiple applications can be packaged in a single Mojo application
22 // implementing ShellClientFactory; that these applications can be specified by
23 // the package's manifest and are thus registered with the PackageManager.
24
25 namespace mojo {
26 namespace shell {
27 namespace {
28 const char kTestPackageName[] = "mojo:connect_test_package";
29 const char kTestAppName[] = "mojo:connect_test_app";
30 const char kTestAppAName[] = "mojo:connect_test_a";
31 const char kTestAppBName[] = "mojo:connect_test_b";
32 const char kTestClassAppName[] = "mojo:connect_test_class_app";
33 const char kTestSingletonAppName[] = "mojo:connect_test_singleton_app";
34 const char kTestDriverName[] = "exe:connect_test_driver";
35
36 void ReceiveOneString(std::string* out_string,
37 base::RunLoop* loop,
38 const String& in_string) {
39 *out_string = in_string;
40 loop->Quit();
41 }
42
43 void ReceiveTwoStrings(std::string* out_string_1, std::string* out_string_2,
44 base::RunLoop* loop,
45 const String& in_string_1, const String& in_string_2) {
46 *out_string_1 = in_string_1;
47 *out_string_2 = in_string_2;
48 loop->Quit();
49 }
50
51 void ReceiveConnectionResult(mojom::ConnectResult* out_result,
52 Identity* out_target,
53 base::RunLoop* loop,
54 int32_t in_result,
55 mojom::IdentityPtr in_identity) {
56 *out_result = static_cast<shell::mojom::ConnectResult>(in_result);
57 *out_target = in_identity.To<Identity>();
58 loop->Quit();
59 }
60
61 void QuitLoop(base::RunLoop* loop) {
62 loop->Quit();
63 }
64
65 } // namespace
66
67 class ConnectTest : public mojo::test::ShellTest,
68 public InterfaceFactory<test::mojom::ExposedInterface>,
69 public test::mojom::ExposedInterface {
70 public:
71 ConnectTest() : ShellTest("mojo:connect_unittests") {}
72 ~ConnectTest() override {}
73
74 protected:
75 scoped_ptr<Connection> ConnectTo(Connector::ConnectParams* params) {
76 scoped_ptr<Connection> connection = connector()->Connect(params);
77 base::RunLoop loop;
78 connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
79 loop.Run();
80 return connection;
81 }
82
83 void set_ping_callback(const base::Closure& callback) {
84 ping_callback_ = callback;
85 }
86
87 void CompareConnectionState(
88 const std::string& connection_local_name,
89 const std::string& connection_remote_name,
90 const std::string& connection_remote_userid,
91 uint32_t connection_remote_id,
92 const std::string& initialize_local_name,
93 const std::string& initialize_userid,
94 uint32_t initialize_id) {
95 EXPECT_EQ(connection_local_name, connection_state_->connection_local_name);
96 EXPECT_EQ(connection_remote_name,
97 connection_state_->connection_remote_name);
98 EXPECT_EQ(connection_remote_userid,
99 connection_state_->connection_remote_userid);
100 EXPECT_EQ(connection_remote_id, connection_state_->connection_remote_id);
101 EXPECT_EQ(initialize_local_name, connection_state_->initialize_local_name);
102 EXPECT_EQ(initialize_id, connection_state_->initialize_id);
103 EXPECT_EQ(initialize_userid, connection_state_->initialize_userid);
104 }
105
106 private:
107 // mojo::test::ShellTest:
108 void SetUp() override {
109 mojo::test::ShellTest::SetUp();
110 // We need to connect to the package first to force the shell to read the
111 // package app's manifest and register aliases for the applications it
112 // provides.
113 test::mojom::ConnectTestServicePtr root_service;
114 scoped_ptr<Connection> connection = connector()->Connect(kTestPackageName);
115 connection->GetInterface(&root_service);
116 base::RunLoop run_loop;
117 std::string root_name;
118 root_service->GetTitle(
119 base::Bind(&ReceiveOneString, &root_name, &run_loop));
120 run_loop.Run();
121 }
122
123 // InterfaceFactory<test::mojom::ExposedInterface>:
124 void Create(Connection* connection,
125 test::mojom::ExposedInterfaceRequest request) override {
126 bindings_.AddBinding(this, std::move(request));
127 }
128 void ConnectionAccepted(test::mojom::ConnectionStatePtr state) override {
129 connection_state_ = std::move(state);
130 ping_callback_.Run();
131 }
132
133 base::Closure ping_callback_;
134 test::mojom::ConnectionStatePtr connection_state_;
135
136 BindingSet<test::mojom::ExposedInterface> bindings_;
137
138 DISALLOW_COPY_AND_ASSIGN(ConnectTest);
139 };
140
141 // Ensure the connection was properly established and that a round trip
142 // method call/response is completed.
143 TEST_F(ConnectTest, Connect) {
144 scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
145 test::mojom::ConnectTestServicePtr service;
146 connection->GetInterface(&service);
147 base::RunLoop run_loop;
148 std::string title;
149 service->GetTitle(base::Bind(&ReceiveOneString, &title, &run_loop));
150 run_loop.Run();
151 EXPECT_EQ("APP", title);
152 EXPECT_FALSE(connection->IsPending());
153 EXPECT_NE(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
154 EXPECT_EQ(connection->GetRemoteIdentity().name(), kTestAppName);
155 }
156
157 TEST_F(ConnectTest, Instances) {
158 Connector::ConnectParams params_a(
159 Identity(kTestAppName, mojom::kInheritUserID, "A"));
160 scoped_ptr<Connection> connection_a1 = ConnectTo(&params_a);
161 scoped_ptr<Connection> connection_a2 = ConnectTo(&params_a);
162 std::string instance_a1, instance_a2;
163 test::mojom::ConnectTestServicePtr service_a1;
164 {
165 connection_a1->GetInterface(&service_a1);
166 base::RunLoop loop;
167 service_a1->GetInstance(base::Bind(&ReceiveOneString, &instance_a1, &loop));
168 loop.Run();
169 }
170 test::mojom::ConnectTestServicePtr service_a2;
171 {
172 connection_a2->GetInterface(&service_a2);
173 base::RunLoop loop;
174 service_a2->GetInstance(base::Bind(&ReceiveOneString, &instance_a2, &loop));
175 loop.Run();
176 }
177 EXPECT_EQ(instance_a1, instance_a2);
178
179 Connector::ConnectParams params_b(
180 Identity(kTestAppName, mojom::kInheritUserID, "B"));
181 scoped_ptr<Connection> connection_b = ConnectTo(&params_b);
182 std::string instance_b;
183 test::mojom::ConnectTestServicePtr service_b;
184 {
185 connection_b->GetInterface(&service_b);
186 base::RunLoop loop;
187 service_b->GetInstance(base::Bind(&ReceiveOneString, &instance_b, &loop));
188 loop.Run();
189 }
190
191 EXPECT_NE(instance_a1, instance_b);
192 }
193
194 // When both the unresolved and resolved instance names are their default
195 // values, the instance name from the unresolved name must be used.
196 // (The case where the instance names differ is covered by
197 // LifecycleTest.PackagedApp_CrashCrashesOtherProvidedApp).
198 TEST_F(ConnectTest, PreferUnresolvedDefaultInstanceName) {
199 // Connect to an app with no manifest-supplied instance name provided by a
200 // package, the instance name must be derived from the application instance
201 // name, not the package.
202 scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
203 {
204 base::RunLoop loop;
205 connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
206 loop.Run();
207 }
208
209 std::string instance;
210 {
211 test::mojom::ConnectTestServicePtr service;
212 connection->GetInterface(&service);
213 base::RunLoop loop;
214 service->GetInstance(base::Bind(&ReceiveOneString, &instance, &loop));
215 loop.Run();
216 }
217 EXPECT_EQ(GetNamePath(kTestAppName), instance);
218 }
219
220 // BlockedInterface should not be exposed to this application because it is not
221 // in our CapabilityFilter whitelist.
222 TEST_F(ConnectTest, BlockedInterface) {
223 scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
224 base::RunLoop run_loop;
225 test::mojom::BlockedInterfacePtr blocked;
226 connection->GetInterface(&blocked);
227 blocked.set_connection_error_handler(base::Bind(&QuitLoop, &run_loop));
228 std::string title = "unchanged";
229 blocked->GetTitleBlocked(base::Bind(&ReceiveOneString, &title, &run_loop));
230 run_loop.Run();
231 EXPECT_EQ("unchanged", title);
232 }
233
234 // Connects to an app provided by a package.
235 TEST_F(ConnectTest, PackagedApp) {
236 scoped_ptr<Connection> connection = connector()->Connect(kTestAppAName);
237 test::mojom::ConnectTestServicePtr service_a;
238 connection->GetInterface(&service_a);
239 base::RunLoop run_loop;
240 std::string a_name;
241 service_a->GetTitle(base::Bind(&ReceiveOneString, &a_name, &run_loop));
242 run_loop.Run();
243 EXPECT_EQ("A", a_name);
244 EXPECT_FALSE(connection->IsPending());
245 EXPECT_NE(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
246 EXPECT_EQ(connection->GetRemoteIdentity().name(), kTestAppAName);
247 }
248
249 // Ask the target application to attempt to connect to a third application
250 // provided by a package whose id is permitted by the primary target's
251 // CapabilityFilter but whose package is not. The connection should be
252 // blocked and the returned title should be "uninitialized".
253 TEST_F(ConnectTest, BlockedPackage) {
254 scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
255 test::mojom::StandaloneAppPtr standalone_app;
256 connection->GetInterface(&standalone_app);
257 base::RunLoop run_loop;
258 std::string title;
259 standalone_app->ConnectToAllowedAppInBlockedPackage(
260 base::Bind(&ReceiveOneString, &title, &run_loop));
261 run_loop.Run();
262 EXPECT_EQ("uninitialized", title);
263 }
264
265 // BlockedInterface should not be exposed to this application because it is not
266 // in our CapabilityFilter whitelist.
267 TEST_F(ConnectTest, PackagedApp_BlockedInterface) {
268 scoped_ptr<Connection> connection = connector()->Connect(kTestAppAName);
269 base::RunLoop run_loop;
270 test::mojom::BlockedInterfacePtr blocked;
271 connection->GetInterface(&blocked);
272 blocked.set_connection_error_handler(base::Bind(&QuitLoop, &run_loop));
273 run_loop.Run();
274 }
275
276 // Connection to another application provided by the same package, blocked
277 // because it's not in the capability filter whitelist.
278 TEST_F(ConnectTest, BlockedPackagedApplication) {
279 scoped_ptr<Connection> connection = connector()->Connect(kTestAppBName);
280 test::mojom::ConnectTestServicePtr service_b;
281 connection->GetInterface(&service_b);
282 base::RunLoop run_loop;
283 connection->SetConnectionLostClosure(base::Bind(&QuitLoop, &run_loop));
284 run_loop.Run();
285 EXPECT_FALSE(connection->IsPending());
286 EXPECT_EQ(mojom::ConnectResult::ACCESS_DENIED, connection->GetResult());
287 EXPECT_EQ(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
288 }
289
290 TEST_F(ConnectTest, CapabilityClasses) {
291 scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
292 test::mojom::StandaloneAppPtr standalone_app;
293 connection->GetInterface(&standalone_app);
294 std::string string1, string2;
295 base::RunLoop loop;
296 standalone_app->ConnectToClassInterface(
297 base::Bind(&ReceiveTwoStrings, &string1, &string2, &loop));
298 loop.Run();
299 EXPECT_EQ("PONG", string1);
300 EXPECT_EQ("CLASS APP", string2);
301 }
302
303 TEST_F(ConnectTest, ConnectAsDifferentUser_Allowed) {
304 scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
305 test::mojom::UserIdTestPtr user_id_test;
306 connection->GetInterface(&user_id_test);
307 shell::mojom::ConnectResult result;
308 Identity target(kTestClassAppName, base::GenerateGUID());
309 Identity result_identity;
310 {
311 base::RunLoop loop;
312 user_id_test->ConnectToClassAppAsDifferentUser(
313 mojom::Identity::From(target),
314 base::Bind(&ReceiveConnectionResult, &result, &result_identity, &loop));
315 loop.Run();
316 }
317 EXPECT_EQ(result, shell::mojom::ConnectResult::SUCCEEDED);
318 EXPECT_EQ(target, result_identity);
319 }
320
321 TEST_F(ConnectTest, ConnectAsDifferentUser_Blocked) {
322 scoped_ptr<Connection> connection = connector()->Connect(kTestAppAName);
323 test::mojom::UserIdTestPtr user_id_test;
324 connection->GetInterface(&user_id_test);
325 shell::mojom::ConnectResult result;
326 Identity target(kTestClassAppName, base::GenerateGUID());
327 Identity result_identity;
328 {
329 base::RunLoop loop;
330 user_id_test->ConnectToClassAppAsDifferentUser(
331 mojom::Identity::From(target),
332 base::Bind(&ReceiveConnectionResult, &result, &result_identity, &loop));
333 loop.Run();
334 }
335 EXPECT_EQ(shell::mojom::ConnectResult::ACCESS_DENIED, result);
336 EXPECT_FALSE(target == result_identity);
337 }
338
339 // There are various other tests (shell, lifecycle) that test valid client
340 // process specifications. This is the only one for blocking.
341 TEST_F(ConnectTest, ConnectToClientProcess_Blocked) {
342 scoped_ptr<Connection> connection = connector()->Connect(kTestDriverName);
343 test::mojom::ClientProcessTestPtr client_process_test;
344 connection->GetInterface(&client_process_test);
345 shell::mojom::ConnectResult result;
346 Identity result_identity;
347 {
348 base::RunLoop loop;
349 client_process_test->LaunchAndConnectToProcess(
350 base::Bind(&ReceiveConnectionResult, &result, &result_identity, &loop));
351 loop.Run();
352 }
353 EXPECT_EQ(shell::mojom::ConnectResult::ACCESS_DENIED, result);
354 }
355
356 // Verifies that a client with the "all_users" capability class can receive
357 // connections from clients run as other users.
358 TEST_F(ConnectTest, AllUsersSingleton) {
359 // Connect to an instance with an explicitly different user_id. This supplied
360 // user id should be ignored by the shell (which will generate its own
361 // synthetic user id for all-user singleton instances).
362 const std::string singleton_userid = base::GenerateGUID();
363 Connector::ConnectParams params(
364 Identity(kTestSingletonAppName, singleton_userid));
365 scoped_ptr<Connection> connection = connector()->Connect(&params);
366 {
367 base::RunLoop loop;
368 connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
369 loop.Run();
370 EXPECT_NE(connection->GetRemoteIdentity().user_id(), singleton_userid);
371 }
372 // This connects using the current client's user_id. It should be bound to the
373 // same service started above, with the same shell-generated user id.
374 scoped_ptr<Connection> inherit_connection =
375 connector()->Connect(kTestSingletonAppName);
376 {
377 base::RunLoop loop;
378 inherit_connection->AddConnectionCompletedClosure(
379 base::Bind(&QuitLoop, &loop));
380 loop.Run();
381 EXPECT_EQ(inherit_connection->GetRemoteIdentity().user_id(),
382 connection->GetRemoteIdentity().user_id());
383 }
384 }
385
386 // Tests that we can expose an interface to targets on outbound connections.
387 TEST_F(ConnectTest, LocalInterface) {
388 // Connect to a standalone application.
389 {
390 test::mojom::ConnectTestServicePtr service;
391 scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
392 connection->GetInterface(&service);
393 connection->AddInterface<test::mojom::ExposedInterface>(this);
394
395 uint32_t remote_id = shell::mojom::kInvalidInstanceID;
396 {
397 base::RunLoop run_loop;
398 EXPECT_TRUE(connection->IsPending());
399 EXPECT_EQ(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
400 connection->AddConnectionCompletedClosure(
401 base::Bind(&QuitLoop, &run_loop));
402 run_loop.Run();
403 EXPECT_FALSE(connection->IsPending());
404 remote_id = connection->GetRemoteInstanceID();
405 EXPECT_NE(mojom::kInvalidInstanceID, remote_id);
406 }
407
408 {
409 base::RunLoop run_loop;
410 set_ping_callback(base::Bind(&QuitLoop, &run_loop));
411 run_loop.Run();
412 CompareConnectionState(
413 kTestAppName, test_name(), test_userid(), test_instance_id(),
414 kTestAppName, connection->GetRemoteIdentity().user_id(), remote_id);
415 }
416 }
417
418 // Connect to an application provided by a package.
419 {
420 test::mojom::ConnectTestServicePtr service_a;
421 scoped_ptr<Connection> connection = connector()->Connect(kTestAppAName);
422 connection->GetInterface(&service_a);
423 connection->AddInterface<test::mojom::ExposedInterface>(this);
424
425 uint32_t remote_id = shell::mojom::kInvalidInstanceID;
426 {
427 base::RunLoop run_loop;
428 EXPECT_TRUE(connection->IsPending());
429 EXPECT_EQ(mojom::kInvalidInstanceID, connection->GetRemoteInstanceID());
430 connection->AddConnectionCompletedClosure(
431 base::Bind(&QuitLoop, &run_loop));
432 run_loop.Run();
433 EXPECT_FALSE(connection->IsPending());
434 remote_id = connection->GetRemoteInstanceID();
435 EXPECT_NE(mojom::kInvalidInstanceID, remote_id);
436 }
437
438 {
439 base::RunLoop run_loop;
440 set_ping_callback(base::Bind(&QuitLoop, &run_loop));
441 run_loop.Run();
442 CompareConnectionState(
443 kTestAppAName, test_name(), test_userid(), test_instance_id(),
444 kTestAppAName, connection->GetRemoteIdentity().user_id(), remote_id);
445 }
446
447 }
448 }
449
450 } // namespace shell
451 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698