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

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

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

Powered by Google App Engine
This is Rietveld 408576698