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

Side by Side Diff: mojo/shell/tests/loader_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
« no previous file with comments | « mojo/shell/tests/lifecycle/parent_manifest.json ('k') | mojo/shell/tests/shell/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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 <utility>
6
7 #include "base/at_exit.h"
8 #include "base/bind.h"
9 #include "base/macros.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "mojo/public/cpp/bindings/strong_binding.h"
14 #include "mojo/services/catalog/factory.h"
15 #include "mojo/services/catalog/store.h"
16 #include "mojo/shell/connect_util.h"
17 #include "mojo/shell/loader.h"
18 #include "mojo/shell/public/cpp/connector.h"
19 #include "mojo/shell/public/cpp/interface_factory.h"
20 #include "mojo/shell/public/cpp/shell_client.h"
21 #include "mojo/shell/public/cpp/shell_connection.h"
22 #include "mojo/shell/public/interfaces/interface_provider.mojom.h"
23 #include "mojo/shell/shell.h"
24 #include "mojo/shell/tests/test.mojom.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace mojo {
28 namespace shell {
29 namespace test {
30
31 const char kTestURLString[] = "test:testService";
32 const char kTestAURLString[] = "test:TestA";
33 const char kTestBURLString[] = "test:TestB";
34
35 struct TestContext {
36 TestContext() : num_impls(0), num_loader_deletes(0) {}
37 std::string last_test_string;
38 int num_impls;
39 int num_loader_deletes;
40 };
41
42 void QuitClosure(const Identity& expected,
43 bool* value,
44 const Identity& actual) {
45 if (expected == actual) {
46 *value = true;
47 base::MessageLoop::current()->QuitWhenIdle();
48 }
49 }
50
51 class TestServiceImpl : public TestService {
52 public:
53 TestServiceImpl(TestContext* context, InterfaceRequest<TestService> request)
54 : context_(context), binding_(this, std::move(request)) {
55 ++context_->num_impls;
56 }
57
58 ~TestServiceImpl() override {
59 --context_->num_impls;
60 if (!base::MessageLoop::current()->is_running())
61 return;
62 base::MessageLoop::current()->QuitWhenIdle();
63 }
64
65 // TestService implementation:
66 void Test(const String& test_string,
67 const Callback<void()>& callback) override {
68 context_->last_test_string = test_string;
69 callback.Run();
70 }
71
72 private:
73 TestContext* context_;
74 StrongBinding<TestService> binding_;
75 };
76
77 class TestClient {
78 public:
79 explicit TestClient(TestServicePtr service)
80 : service_(std::move(service)), quit_after_ack_(false) {}
81
82 void AckTest() {
83 if (quit_after_ack_)
84 base::MessageLoop::current()->QuitWhenIdle();
85 }
86
87 void Test(const std::string& test_string) {
88 quit_after_ack_ = true;
89 service_->Test(test_string,
90 base::Bind(&TestClient::AckTest, base::Unretained(this)));
91 }
92
93 private:
94 TestServicePtr service_;
95 bool quit_after_ack_;
96 DISALLOW_COPY_AND_ASSIGN(TestClient);
97 };
98
99 class TestLoader : public Loader,
100 public ShellClient,
101 public InterfaceFactory<TestService> {
102 public:
103 explicit TestLoader(TestContext* context)
104 : context_(context), num_loads_(0) {}
105
106 ~TestLoader() override {
107 ++context_->num_loader_deletes;
108 shell_connection_.reset();
109 }
110
111 int num_loads() const { return num_loads_; }
112 const std::string& last_requestor_name() const {
113 return last_requestor_name_;
114 }
115
116 private:
117 // Loader implementation.
118 void Load(const std::string& name,
119 mojom::ShellClientRequest request) override {
120 ++num_loads_;
121 shell_connection_.reset(new ShellConnection(this, std::move(request)));
122 }
123
124 // mojo::ShellClient implementation.
125 bool AcceptConnection(Connection* connection) override {
126 connection->AddInterface<TestService>(this);
127 last_requestor_name_ = connection->GetRemoteIdentity().name();
128 return true;
129 }
130
131 // InterfaceFactory<TestService> implementation.
132 void Create(Connection* connection,
133 InterfaceRequest<TestService> request) override {
134 new TestServiceImpl(context_, std::move(request));
135 }
136
137 scoped_ptr<ShellConnection> shell_connection_;
138 TestContext* context_;
139 int num_loads_;
140 std::string last_requestor_name_;
141
142 DISALLOW_COPY_AND_ASSIGN(TestLoader);
143 };
144
145 class ClosingLoader : public Loader {
146 private:
147 // Loader implementation.
148 void Load(const std::string& name,
149 mojom::ShellClientRequest request) override {
150 }
151 };
152
153 class TesterContext {
154 public:
155 explicit TesterContext(base::MessageLoop* loop)
156 : num_b_calls_(0),
157 num_c_calls_(0),
158 num_a_deletes_(0),
159 num_b_deletes_(0),
160 num_c_deletes_(0),
161 tester_called_quit_(false),
162 a_called_quit_(false),
163 loop_(loop) {}
164
165 void IncrementNumBCalls() {
166 base::AutoLock lock(lock_);
167 num_b_calls_++;
168 }
169
170 void IncrementNumCCalls() {
171 base::AutoLock lock(lock_);
172 num_c_calls_++;
173 }
174
175 void IncrementNumADeletes() {
176 base::AutoLock lock(lock_);
177 num_a_deletes_++;
178 }
179
180 void IncrementNumBDeletes() {
181 base::AutoLock lock(lock_);
182 num_b_deletes_++;
183 }
184
185 void IncrementNumCDeletes() {
186 base::AutoLock lock(lock_);
187 num_c_deletes_++;
188 }
189
190 void set_tester_called_quit() {
191 base::AutoLock lock(lock_);
192 tester_called_quit_ = true;
193 }
194
195 void set_a_called_quit() {
196 base::AutoLock lock(lock_);
197 a_called_quit_ = true;
198 }
199
200 int num_b_calls() {
201 base::AutoLock lock(lock_);
202 return num_b_calls_;
203 }
204 int num_c_calls() {
205 base::AutoLock lock(lock_);
206 return num_c_calls_;
207 }
208 int num_a_deletes() {
209 base::AutoLock lock(lock_);
210 return num_a_deletes_;
211 }
212 int num_b_deletes() {
213 base::AutoLock lock(lock_);
214 return num_b_deletes_;
215 }
216 int num_c_deletes() {
217 base::AutoLock lock(lock_);
218 return num_c_deletes_;
219 }
220 bool tester_called_quit() {
221 base::AutoLock lock(lock_);
222 return tester_called_quit_;
223 }
224 bool a_called_quit() {
225 base::AutoLock lock(lock_);
226 return a_called_quit_;
227 }
228
229 void QuitSoon() {
230 loop_->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
231 }
232
233 private:
234 // lock_ protects all members except for loop_ which must be unchanged for the
235 // lifetime of this class.
236 base::Lock lock_;
237 int num_b_calls_;
238 int num_c_calls_;
239 int num_a_deletes_;
240 int num_b_deletes_;
241 int num_c_deletes_;
242 bool tester_called_quit_;
243 bool a_called_quit_;
244
245 base::MessageLoop* loop_;
246 };
247
248 // Used to test that the requestor name will be correctly passed.
249 class TestAImpl : public TestA {
250 public:
251 TestAImpl(Connector* connector,
252 TesterContext* test_context,
253 InterfaceRequest<TestA> request,
254 InterfaceFactory<TestC>* factory)
255 : test_context_(test_context), binding_(this, std::move(request)) {
256 connection_ = connector->Connect(kTestBURLString);
257 connection_->AddInterface<TestC>(factory);
258 connection_->GetInterface(&b_);
259 }
260
261 ~TestAImpl() override {
262 test_context_->IncrementNumADeletes();
263 if (base::MessageLoop::current()->is_running())
264 Quit();
265 }
266
267 private:
268 void CallB() override {
269 b_->B(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
270 }
271
272 void CallCFromB() override {
273 b_->CallC(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
274 }
275
276 void Quit() {
277 base::MessageLoop::current()->QuitWhenIdle();
278 test_context_->set_a_called_quit();
279 test_context_->QuitSoon();
280 }
281
282 scoped_ptr<Connection> connection_;
283 TesterContext* test_context_;
284 TestBPtr b_;
285 StrongBinding<TestA> binding_;
286 };
287
288 class TestBImpl : public TestB {
289 public:
290 TestBImpl(Connection* connection,
291 TesterContext* test_context,
292 InterfaceRequest<TestB> request)
293 : test_context_(test_context), binding_(this, std::move(request)) {
294 connection->GetInterface(&c_);
295 }
296
297 ~TestBImpl() override {
298 test_context_->IncrementNumBDeletes();
299 if (base::MessageLoop::current()->is_running())
300 base::MessageLoop::current()->QuitWhenIdle();
301 test_context_->QuitSoon();
302 }
303
304 private:
305 void B(const Callback<void()>& callback) override {
306 test_context_->IncrementNumBCalls();
307 callback.Run();
308 }
309
310 void CallC(const Callback<void()>& callback) override {
311 test_context_->IncrementNumBCalls();
312 c_->C(callback);
313 }
314
315 TesterContext* test_context_;
316 TestCPtr c_;
317 StrongBinding<TestB> binding_;
318 };
319
320 class TestCImpl : public TestC {
321 public:
322 TestCImpl(Connection* connection,
323 TesterContext* test_context,
324 InterfaceRequest<TestC> request)
325 : test_context_(test_context), binding_(this, std::move(request)) {}
326
327 ~TestCImpl() override { test_context_->IncrementNumCDeletes(); }
328
329 private:
330 void C(const Callback<void()>& callback) override {
331 test_context_->IncrementNumCCalls();
332 callback.Run();
333 }
334
335 TesterContext* test_context_;
336 StrongBinding<TestC> binding_;
337 };
338
339 class Tester : public ShellClient,
340 public Loader,
341 public InterfaceFactory<TestA>,
342 public InterfaceFactory<TestB>,
343 public InterfaceFactory<TestC> {
344 public:
345 Tester(TesterContext* context, const std::string& requestor_name)
346 : context_(context), requestor_name_(requestor_name) {}
347 ~Tester() override {}
348
349 private:
350 void Load(const std::string& name,
351 InterfaceRequest<mojom::ShellClient> request) override {
352 app_.reset(new ShellConnection(this, std::move(request)));
353 }
354
355 bool AcceptConnection(Connection* connection) override {
356 if (!requestor_name_.empty() &&
357 requestor_name_ != connection->GetRemoteIdentity().name()) {
358 context_->set_tester_called_quit();
359 context_->QuitSoon();
360 base::MessageLoop::current()->QuitWhenIdle();
361 return false;
362 }
363 // If we're coming from A, then add B, otherwise A.
364 if (connection->GetRemoteIdentity().name() == kTestAURLString)
365 connection->AddInterface<TestB>(this);
366 else
367 connection->AddInterface<TestA>(this);
368 return true;
369 }
370
371 void Create(Connection* connection,
372 InterfaceRequest<TestA> request) override {
373 a_bindings_.push_back(
374 new TestAImpl(app_->connector(), context_, std::move(request), this));
375 }
376
377 void Create(Connection* connection,
378 InterfaceRequest<TestB> request) override {
379 new TestBImpl(connection, context_, std::move(request));
380 }
381
382 void Create(Connection* connection,
383 InterfaceRequest<TestC> request) override {
384 new TestCImpl(connection, context_, std::move(request));
385 }
386
387 TesterContext* context_;
388 scoped_ptr<ShellConnection> app_;
389 std::string requestor_name_;
390 ScopedVector<TestAImpl> a_bindings_;
391 };
392
393 void OnConnect(base::RunLoop* loop, mojom::ConnectResult result,
394 const String& user_id, uint32_t instance_id) {
395 loop->Quit();
396 }
397
398 class LoaderTest : public testing::Test {
399 public:
400 LoaderTest() : tester_context_(&loop_) {}
401 ~LoaderTest() override {}
402
403 void SetUp() override {
404 blocking_pool_ = new base::SequencedWorkerPool(3, "blocking_pool");
405 catalog_.reset(
406 new catalog::Factory(blocking_pool_.get(), nullptr, nullptr));
407 shell_.reset(new Shell(nullptr, catalog_->TakeShellClient()));
408 test_loader_ = new TestLoader(&context_);
409 shell_->set_default_loader(scoped_ptr<Loader>(test_loader_));
410
411 TestServicePtr service_proxy;
412 ConnectToInterface(kTestURLString, &service_proxy);
413 test_client_.reset(new TestClient(std::move(service_proxy)));
414 }
415
416 void TearDown() override {
417 test_client_.reset();
418 shell_.reset();
419 blocking_pool_->Shutdown();
420 }
421
422 void AddLoaderForName(const std::string& name,
423 const std::string& requestor_name) {
424 shell_->SetLoaderForName(
425 make_scoped_ptr(new Tester(&tester_context_, requestor_name)), name);
426 }
427
428 bool HasRunningInstanceForName(const std::string& name) {
429 Shell::TestAPI test_api(shell_.get());
430 return test_api.HasRunningInstanceForName(name);
431 }
432
433 protected:
434 template <typename Interface>
435 void ConnectToInterface(const std::string& name,
436 InterfacePtr<Interface>* ptr) {
437 base::RunLoop loop;
438 mojom::InterfaceProviderPtr remote_interfaces;
439 scoped_ptr<ConnectParams> params(new ConnectParams);
440 params->set_source(CreateShellIdentity());
441 params->set_target(Identity(name, mojom::kRootUserID));
442 params->set_remote_interfaces(GetProxy(&remote_interfaces));
443 params->set_connect_callback(
444 base::Bind(&OnConnect, base::Unretained(&loop)));
445 shell_->Connect(std::move(params));
446 loop.Run();
447
448 mojo::GetInterface(remote_interfaces.get(), ptr);
449 }
450
451 base::ShadowingAtExitManager at_exit_;
452 TestLoader* test_loader_;
453 TesterContext tester_context_;
454 TestContext context_;
455 base::MessageLoop loop_;
456 scoped_ptr<TestClient> test_client_;
457 scoped_ptr<catalog::Factory> catalog_;
458 scoped_refptr<base::SequencedWorkerPool> blocking_pool_;
459 scoped_ptr<Shell> shell_;
460 DISALLOW_COPY_AND_ASSIGN(LoaderTest);
461 };
462
463 TEST_F(LoaderTest, Basic) {
464 test_client_->Test("test");
465 loop_.Run();
466 EXPECT_EQ(std::string("test"), context_.last_test_string);
467 }
468
469 TEST_F(LoaderTest, ClientError) {
470 test_client_->Test("test");
471 EXPECT_TRUE(HasRunningInstanceForName(kTestURLString));
472 loop_.Run();
473 EXPECT_EQ(1, context_.num_impls);
474 test_client_.reset();
475 loop_.Run();
476 EXPECT_EQ(0, context_.num_impls);
477 EXPECT_TRUE(HasRunningInstanceForName(kTestURLString));
478 }
479
480 TEST_F(LoaderTest, Deletes) {
481 {
482 catalog::Factory catalog(blocking_pool_.get(), nullptr, nullptr);
483 Shell shell(nullptr, catalog.TakeShellClient());
484 TestLoader* default_loader = new TestLoader(&context_);
485 TestLoader* name_loader1 = new TestLoader(&context_);
486 TestLoader* name_loader2 = new TestLoader(&context_);
487 shell.set_default_loader(scoped_ptr<Loader>(default_loader));
488 shell.SetLoaderForName(scoped_ptr<Loader>(name_loader1), "test:test1");
489 shell.SetLoaderForName(scoped_ptr<Loader>(name_loader2), "test:test1");
490 }
491 EXPECT_EQ(3, context_.num_loader_deletes);
492 }
493
494 // Test for SetLoaderForName() & set_default_loader().
495 TEST_F(LoaderTest, SetLoaders) {
496 TestLoader* default_loader = new TestLoader(&context_);
497 TestLoader* name_loader = new TestLoader(&context_);
498 shell_->set_default_loader(scoped_ptr<Loader>(default_loader));
499 shell_->SetLoaderForName(scoped_ptr<Loader>(name_loader), "test:test1");
500
501 // test::test1 should go to name_loader.
502 TestServicePtr test_service;
503 ConnectToInterface("test:test1", &test_service);
504 EXPECT_EQ(1, name_loader->num_loads());
505 EXPECT_EQ(0, default_loader->num_loads());
506
507 // http::test1 should go to default loader.
508 ConnectToInterface("http:test1", &test_service);
509 EXPECT_EQ(1, name_loader->num_loads());
510 EXPECT_EQ(1, default_loader->num_loads());
511 }
512
513 TEST_F(LoaderTest, NoServiceNoLoad) {
514 AddLoaderForName(kTestAURLString, std::string());
515
516 // There is no TestC service implementation registered with the Shell, so this
517 // cannot succeed (but also shouldn't crash).
518 TestCPtr c;
519 ConnectToInterface(kTestAURLString, &c);
520 c.set_connection_error_handler(
521 []() { base::MessageLoop::current()->QuitWhenIdle(); });
522
523 loop_.Run();
524 EXPECT_TRUE(c.encountered_error());
525 }
526
527 TEST_F(LoaderTest, TestEndApplicationClosure) {
528 ClosingLoader* loader = new ClosingLoader();
529 shell_->SetLoaderForName(scoped_ptr<Loader>(loader), "test:test");
530
531 bool called = false;
532 scoped_ptr<ConnectParams> params(new ConnectParams);
533 params->set_source(CreateShellIdentity());
534 params->set_target(Identity("test:test", mojom::kRootUserID));
535 shell_->SetInstanceQuitCallback(
536 base::Bind(&QuitClosure, params->target(), &called));
537 shell_->Connect(std::move(params));
538 loop_.Run();
539 EXPECT_TRUE(called);
540 }
541
542 TEST_F(LoaderTest, SameIdentityShouldNotCauseDuplicateLoad) {
543 // 1 because LoaderTest connects once at startup.
544 EXPECT_EQ(1, test_loader_->num_loads());
545
546 TestServicePtr test_service;
547 ConnectToInterface("test:foo", &test_service);
548 EXPECT_EQ(2, test_loader_->num_loads());
549
550 // Exactly the same name as above.
551 ConnectToInterface("test:foo", &test_service);
552 EXPECT_EQ(2, test_loader_->num_loads());
553
554 // A different identity because the domain is different.
555 ConnectToInterface("test:bar", &test_service);
556 EXPECT_EQ(3, test_loader_->num_loads());
557 }
558
559 } // namespace test
560 } // namespace shell
561 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/tests/lifecycle/parent_manifest.json ('k') | mojo/shell/tests/shell/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698