Make ApplicationImpl::args() be a std::vector<std::string>
[chromium-blink-merge.git] / mojo / application_manager / application_manager_unittest.cc
blobd33e5bec08114686f5dfcd949b0cbeb1d345ae2f
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.
5 #include "base/at_exit.h"
6 #include "base/bind.h"
7 #include "base/macros.h"
8 #include "base/message_loop/message_loop.h"
9 #include "mojo/application_manager/application_loader.h"
10 #include "mojo/application_manager/application_manager.h"
11 #include "mojo/application_manager/background_shell_application_loader.h"
12 #include "mojo/application_manager/test.mojom.h"
13 #include "mojo/public/cpp/application/application_connection.h"
14 #include "mojo/public/cpp/application/application_delegate.h"
15 #include "mojo/public/cpp/application/application_impl.h"
16 #include "mojo/public/cpp/application/interface_factory.h"
17 #include "mojo/public/interfaces/application/service_provider.mojom.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace mojo {
21 namespace {
23 const char kTestURLString[] = "test:testService";
24 const char kTestAURLString[] = "test:TestA";
25 const char kTestBURLString[] = "test:TestB";
27 struct TestContext {
28 TestContext() : num_impls(0), num_loader_deletes(0) {}
29 std::string last_test_string;
30 int num_impls;
31 int num_loader_deletes;
34 class QuitMessageLoopErrorHandler : public ErrorHandler {
35 public:
36 QuitMessageLoopErrorHandler() {}
37 virtual ~QuitMessageLoopErrorHandler() {}
39 // |ErrorHandler| implementation:
40 virtual void OnConnectionError() override {
41 base::MessageLoop::current()->QuitWhenIdle();
44 private:
45 DISALLOW_COPY_AND_ASSIGN(QuitMessageLoopErrorHandler);
48 class TestServiceImpl : public InterfaceImpl<TestService> {
49 public:
50 explicit TestServiceImpl(TestContext* context) : context_(context) {
51 ++context_->num_impls;
54 virtual ~TestServiceImpl() { --context_->num_impls; }
56 virtual void OnConnectionError() override {
57 if (!base::MessageLoop::current()->is_running())
58 return;
59 base::MessageLoop::current()->Quit();
62 // TestService implementation:
63 virtual void Test(const String& test_string) override {
64 context_->last_test_string = test_string;
65 client()->AckTest();
68 private:
69 TestContext* context_;
72 class TestClientImpl : public TestClient {
73 public:
74 explicit TestClientImpl(TestServicePtr service)
75 : service_(service.Pass()), quit_after_ack_(false) {
76 service_.set_client(this);
79 virtual ~TestClientImpl() { service_.reset(); }
81 virtual void AckTest() override {
82 if (quit_after_ack_)
83 base::MessageLoop::current()->Quit();
86 void Test(std::string test_string) {
87 quit_after_ack_ = true;
88 service_->Test(test_string);
91 private:
92 TestServicePtr service_;
93 bool quit_after_ack_;
94 DISALLOW_COPY_AND_ASSIGN(TestClientImpl);
97 class TestApplicationLoader : public ApplicationLoader,
98 public ApplicationDelegate,
99 public InterfaceFactory<TestService> {
100 public:
101 TestApplicationLoader() : context_(NULL), num_loads_(0) {}
103 virtual ~TestApplicationLoader() {
104 if (context_)
105 ++context_->num_loader_deletes;
106 test_app_.reset(NULL);
109 void set_context(TestContext* context) { context_ = context; }
110 int num_loads() const { return num_loads_; }
111 const std::vector<std::string>& GetArgs() { return test_app_->args(); }
113 private:
114 // ApplicationLoader implementation.
115 virtual void Load(ApplicationManager* manager,
116 const GURL& url,
117 scoped_refptr<LoadCallbacks> callbacks) override {
118 ++num_loads_;
119 test_app_.reset(
120 new ApplicationImpl(this, callbacks->RegisterApplication().Pass()));
123 virtual void OnApplicationError(ApplicationManager* manager,
124 const GURL& url) override {}
126 // ApplicationDelegate implementation.
127 virtual bool ConfigureIncomingConnection(
128 ApplicationConnection* connection) override {
129 connection->AddService(this);
130 return true;
133 // InterfaceFactory implementation.
134 virtual void Create(ApplicationConnection* connection,
135 InterfaceRequest<TestService> request) override {
136 BindToRequest(new TestServiceImpl(context_), &request);
139 scoped_ptr<ApplicationImpl> test_app_;
140 TestContext* context_;
141 int num_loads_;
142 DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader);
145 class TesterContext {
146 public:
147 explicit TesterContext(base::MessageLoop* loop)
148 : num_b_calls_(0),
149 num_c_calls_(0),
150 num_a_deletes_(0),
151 num_b_deletes_(0),
152 num_c_deletes_(0),
153 tester_called_quit_(false),
154 a_called_quit_(false),
155 loop_(loop) {}
157 void IncrementNumBCalls() {
158 base::AutoLock lock(lock_);
159 num_b_calls_++;
162 void IncrementNumCCalls() {
163 base::AutoLock lock(lock_);
164 num_c_calls_++;
167 void IncrementNumADeletes() {
168 base::AutoLock lock(lock_);
169 num_a_deletes_++;
172 void IncrementNumBDeletes() {
173 base::AutoLock lock(lock_);
174 num_b_deletes_++;
177 void IncrementNumCDeletes() {
178 base::AutoLock lock(lock_);
179 num_c_deletes_++;
182 void set_tester_called_quit() {
183 base::AutoLock lock(lock_);
184 tester_called_quit_ = true;
187 void set_a_called_quit() {
188 base::AutoLock lock(lock_);
189 a_called_quit_ = true;
192 int num_b_calls() {
193 base::AutoLock lock(lock_);
194 return num_b_calls_;
196 int num_c_calls() {
197 base::AutoLock lock(lock_);
198 return num_c_calls_;
200 int num_a_deletes() {
201 base::AutoLock lock(lock_);
202 return num_a_deletes_;
204 int num_b_deletes() {
205 base::AutoLock lock(lock_);
206 return num_b_deletes_;
208 int num_c_deletes() {
209 base::AutoLock lock(lock_);
210 return num_c_deletes_;
212 bool tester_called_quit() {
213 base::AutoLock lock(lock_);
214 return tester_called_quit_;
216 bool a_called_quit() {
217 base::AutoLock lock(lock_);
218 return a_called_quit_;
221 void QuitSoon() {
222 loop_->PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
225 private:
226 // lock_ protects all members except for loop_ which must be unchanged for the
227 // lifetime of this class.
228 base::Lock lock_;
229 int num_b_calls_;
230 int num_c_calls_;
231 int num_a_deletes_;
232 int num_b_deletes_;
233 int num_c_deletes_;
234 bool tester_called_quit_;
235 bool a_called_quit_;
237 base::MessageLoop* loop_;
240 // Used to test that the requestor url will be correctly passed.
241 class TestAImpl : public InterfaceImpl<TestA> {
242 public:
243 TestAImpl(ApplicationConnection* connection, TesterContext* test_context)
244 : test_context_(test_context) {
245 connection->ConnectToApplication(kTestBURLString)->ConnectToService(&b_);
247 virtual ~TestAImpl() {
248 test_context_->IncrementNumADeletes();
249 if (base::MessageLoop::current()->is_running())
250 Quit();
253 private:
254 virtual void CallB() override {
255 b_->B(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
258 virtual void CallCFromB() override {
259 b_->CallC(base::Bind(&TestAImpl::Quit, base::Unretained(this)));
262 void Quit() {
263 base::MessageLoop::current()->Quit();
264 test_context_->set_a_called_quit();
265 test_context_->QuitSoon();
268 TesterContext* test_context_;
269 TestBPtr b_;
272 class TestBImpl : public InterfaceImpl<TestB> {
273 public:
274 TestBImpl(ApplicationConnection* connection, TesterContext* test_context)
275 : test_context_(test_context) {
276 connection->ConnectToService(&c_);
279 virtual ~TestBImpl() {
280 test_context_->IncrementNumBDeletes();
281 if (base::MessageLoop::current()->is_running())
282 base::MessageLoop::current()->Quit();
283 test_context_->QuitSoon();
286 private:
287 virtual void B(const mojo::Callback<void()>& callback) override {
288 test_context_->IncrementNumBCalls();
289 callback.Run();
292 virtual void CallC(const mojo::Callback<void()>& callback) override {
293 test_context_->IncrementNumBCalls();
294 c_->C(callback);
297 TesterContext* test_context_;
298 TestCPtr c_;
301 class TestCImpl : public InterfaceImpl<TestC> {
302 public:
303 TestCImpl(ApplicationConnection* connection, TesterContext* test_context)
304 : test_context_(test_context) {}
306 virtual ~TestCImpl() { test_context_->IncrementNumCDeletes(); }
308 private:
309 virtual void C(const mojo::Callback<void()>& callback) override {
310 test_context_->IncrementNumCCalls();
311 callback.Run();
313 TesterContext* test_context_;
316 class Tester : public ApplicationDelegate,
317 public ApplicationLoader,
318 public InterfaceFactory<TestA>,
319 public InterfaceFactory<TestB>,
320 public InterfaceFactory<TestC> {
321 public:
322 Tester(TesterContext* context, const std::string& requestor_url)
323 : context_(context), requestor_url_(requestor_url) {}
324 virtual ~Tester() {}
326 private:
327 virtual void Load(ApplicationManager* manager,
328 const GURL& url,
329 scoped_refptr<LoadCallbacks> callbacks) override {
330 app_.reset(
331 new ApplicationImpl(this, callbacks->RegisterApplication().Pass()));
334 virtual void OnApplicationError(ApplicationManager* manager,
335 const GURL& url) override {}
337 virtual bool ConfigureIncomingConnection(
338 ApplicationConnection* connection) override {
339 if (!requestor_url_.empty() &&
340 requestor_url_ != connection->GetRemoteApplicationURL()) {
341 context_->set_tester_called_quit();
342 context_->QuitSoon();
343 base::MessageLoop::current()->Quit();
344 return false;
346 // If we're coming from A, then add B, otherwise A.
347 if (connection->GetRemoteApplicationURL() == kTestAURLString)
348 connection->AddService<TestB>(this);
349 else
350 connection->AddService<TestA>(this);
351 return true;
354 virtual bool ConfigureOutgoingConnection(
355 ApplicationConnection* connection) override {
356 // If we're connecting to B, then add C.
357 if (connection->GetRemoteApplicationURL() == kTestBURLString)
358 connection->AddService<TestC>(this);
359 return true;
362 virtual void Create(ApplicationConnection* connection,
363 InterfaceRequest<TestA> request) override {
364 BindToRequest(new TestAImpl(connection, context_), &request);
367 virtual void Create(ApplicationConnection* connection,
368 InterfaceRequest<TestB> request) override {
369 BindToRequest(new TestBImpl(connection, context_), &request);
372 virtual void Create(ApplicationConnection* connection,
373 InterfaceRequest<TestC> request) override {
374 BindToRequest(new TestCImpl(connection, context_), &request);
377 TesterContext* context_;
378 scoped_ptr<ApplicationImpl> app_;
379 std::string requestor_url_;
382 class TestServiceInterceptor : public ApplicationManager::Interceptor {
383 public:
384 TestServiceInterceptor() : call_count_(0) {}
386 virtual ServiceProviderPtr OnConnectToClient(
387 const GURL& url,
388 ServiceProviderPtr service_provider) override {
389 ++call_count_;
390 url_ = url;
391 return service_provider.Pass();
394 std::string url_spec() const {
395 if (!url_.is_valid())
396 return "invalid url";
397 return url_.spec();
400 int call_count() const { return call_count_; }
402 private:
403 int call_count_;
404 GURL url_;
405 DISALLOW_COPY_AND_ASSIGN(TestServiceInterceptor);
408 } // namespace
410 class ApplicationManagerTest : public testing::Test {
411 public:
412 ApplicationManagerTest() : tester_context_(&loop_) {}
414 virtual ~ApplicationManagerTest() {}
416 virtual void SetUp() override {
417 application_manager_.reset(new ApplicationManager);
418 TestApplicationLoader* default_loader = new TestApplicationLoader;
419 default_loader->set_context(&context_);
420 application_manager_->set_default_loader(
421 scoped_ptr<ApplicationLoader>(default_loader));
423 TestServicePtr service_proxy;
424 application_manager_->ConnectToService(GURL(kTestURLString),
425 &service_proxy);
426 test_client_.reset(new TestClientImpl(service_proxy.Pass()));
429 virtual void TearDown() override {
430 test_client_.reset(NULL);
431 application_manager_.reset(NULL);
434 scoped_ptr<BackgroundShellApplicationLoader> MakeLoader(
435 const std::string& requestor_url) {
436 scoped_ptr<ApplicationLoader> real_loader(
437 new Tester(&tester_context_, requestor_url));
438 scoped_ptr<BackgroundShellApplicationLoader> loader(
439 new BackgroundShellApplicationLoader(real_loader.Pass(),
440 std::string(),
441 base::MessageLoop::TYPE_DEFAULT));
442 return loader.Pass();
445 void AddLoaderForURL(const GURL& url, const std::string& requestor_url) {
446 application_manager_->SetLoaderForURL(MakeLoader(requestor_url), url);
449 bool HasFactoryForTestURL() {
450 ApplicationManager::TestAPI manager_test_api(application_manager_.get());
451 return manager_test_api.HasFactoryForURL(GURL(kTestURLString));
454 protected:
455 base::ShadowingAtExitManager at_exit_;
456 TesterContext tester_context_;
457 TestContext context_;
458 base::MessageLoop loop_;
459 scoped_ptr<TestClientImpl> test_client_;
460 scoped_ptr<ApplicationManager> application_manager_;
461 DISALLOW_COPY_AND_ASSIGN(ApplicationManagerTest);
464 TEST_F(ApplicationManagerTest, Basic) {
465 test_client_->Test("test");
466 loop_.Run();
467 EXPECT_EQ(std::string("test"), context_.last_test_string);
470 // Confirm that no arguments are sent to an application by default.
471 TEST_F(ApplicationManagerTest, NoArgs) {
472 ApplicationManager am;
473 GURL test_url("test:test");
474 TestContext context;
475 TestApplicationLoader* loader = new TestApplicationLoader;
476 loader->set_context(&context);
477 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url);
478 TestServicePtr test_service;
479 am.ConnectToService(test_url, &test_service);
480 TestClientImpl test_client(test_service.Pass());
481 test_client.Test("test");
482 loop_.Run();
483 std::vector<std::string> app_args = loader->GetArgs();
484 EXPECT_EQ(0U, app_args.size());
487 // Confirm that arguments are sent to an application.
488 TEST_F(ApplicationManagerTest, Args) {
489 ApplicationManager am;
490 GURL test_url("test:test");
491 std::vector<std::string> args;
492 args.push_back("test_arg1");
493 args.push_back("test_arg2");
494 am.SetArgsForURL(args, test_url);
495 TestContext context;
496 TestApplicationLoader* loader = new TestApplicationLoader;
497 loader->set_context(&context);
498 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(loader), test_url);
499 TestServicePtr test_service;
500 am.ConnectToService(test_url, &test_service);
501 TestClientImpl test_client(test_service.Pass());
502 test_client.Test("test");
503 loop_.Run();
504 std::vector<std::string> app_args = loader->GetArgs();
505 ASSERT_EQ(args.size(), app_args.size());
506 EXPECT_EQ(args[0], app_args[0]);
507 EXPECT_EQ(args[1], app_args[1]);
510 TEST_F(ApplicationManagerTest, ClientError) {
511 test_client_->Test("test");
512 EXPECT_TRUE(HasFactoryForTestURL());
513 loop_.Run();
514 EXPECT_EQ(1, context_.num_impls);
515 test_client_.reset(NULL);
516 loop_.Run();
517 EXPECT_EQ(0, context_.num_impls);
518 EXPECT_TRUE(HasFactoryForTestURL());
521 TEST_F(ApplicationManagerTest, Deletes) {
523 ApplicationManager am;
524 TestApplicationLoader* default_loader = new TestApplicationLoader;
525 default_loader->set_context(&context_);
526 TestApplicationLoader* url_loader1 = new TestApplicationLoader;
527 TestApplicationLoader* url_loader2 = new TestApplicationLoader;
528 url_loader1->set_context(&context_);
529 url_loader2->set_context(&context_);
530 TestApplicationLoader* scheme_loader1 = new TestApplicationLoader;
531 TestApplicationLoader* scheme_loader2 = new TestApplicationLoader;
532 scheme_loader1->set_context(&context_);
533 scheme_loader2->set_context(&context_);
534 am.set_default_loader(scoped_ptr<ApplicationLoader>(default_loader));
535 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader1),
536 GURL("test:test1"));
537 am.SetLoaderForURL(scoped_ptr<ApplicationLoader>(url_loader2),
538 GURL("test:test1"));
539 am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader1),
540 "test");
541 am.SetLoaderForScheme(scoped_ptr<ApplicationLoader>(scheme_loader2),
542 "test");
544 EXPECT_EQ(5, context_.num_loader_deletes);
547 // Confirm that both urls and schemes can have their loaders explicitly set.
548 TEST_F(ApplicationManagerTest, SetLoaders) {
549 TestApplicationLoader* default_loader = new TestApplicationLoader;
550 TestApplicationLoader* url_loader = new TestApplicationLoader;
551 TestApplicationLoader* scheme_loader = new TestApplicationLoader;
552 application_manager_->set_default_loader(
553 scoped_ptr<ApplicationLoader>(default_loader));
554 application_manager_->SetLoaderForURL(
555 scoped_ptr<ApplicationLoader>(url_loader), GURL("test:test1"));
556 application_manager_->SetLoaderForScheme(
557 scoped_ptr<ApplicationLoader>(scheme_loader), "test");
559 // test::test1 should go to url_loader.
560 TestServicePtr test_service;
561 application_manager_->ConnectToService(GURL("test:test1"), &test_service);
562 EXPECT_EQ(1, url_loader->num_loads());
563 EXPECT_EQ(0, scheme_loader->num_loads());
564 EXPECT_EQ(0, default_loader->num_loads());
566 // test::test2 should go to scheme loader.
567 application_manager_->ConnectToService(GURL("test:test2"), &test_service);
568 EXPECT_EQ(1, url_loader->num_loads());
569 EXPECT_EQ(1, scheme_loader->num_loads());
570 EXPECT_EQ(0, default_loader->num_loads());
572 // http::test1 should go to default loader.
573 application_manager_->ConnectToService(GURL("http:test1"), &test_service);
574 EXPECT_EQ(1, url_loader->num_loads());
575 EXPECT_EQ(1, scheme_loader->num_loads());
576 EXPECT_EQ(1, default_loader->num_loads());
579 // Confirm that the url of a service is correctly passed to another service that
580 // it loads.
581 TEST_F(ApplicationManagerTest, ACallB) {
582 // Any url can load a.
583 AddLoaderForURL(GURL(kTestAURLString), std::string());
585 // Only a can load b.
586 AddLoaderForURL(GURL(kTestBURLString), kTestAURLString);
588 TestAPtr a;
589 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
590 a->CallB();
591 loop_.Run();
592 EXPECT_EQ(1, tester_context_.num_b_calls());
593 EXPECT_TRUE(tester_context_.a_called_quit());
596 // A calls B which calls C.
597 TEST_F(ApplicationManagerTest, BCallC) {
598 // Any url can load a.
599 AddLoaderForURL(GURL(kTestAURLString), std::string());
601 // Only a can load b.
602 AddLoaderForURL(GURL(kTestBURLString), kTestAURLString);
604 TestAPtr a;
605 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
606 a->CallCFromB();
607 loop_.Run();
609 EXPECT_EQ(1, tester_context_.num_b_calls());
610 EXPECT_EQ(1, tester_context_.num_c_calls());
611 EXPECT_TRUE(tester_context_.a_called_quit());
614 // Confirm that a service impl will be deleted if the app that connected to
615 // it goes away.
616 TEST_F(ApplicationManagerTest, BDeleted) {
617 AddLoaderForURL(GURL(kTestAURLString), std::string());
618 AddLoaderForURL(GURL(kTestBURLString), std::string());
620 TestAPtr a;
621 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
623 a->CallB();
624 loop_.Run();
626 // Kills the a app.
627 application_manager_->SetLoaderForURL(scoped_ptr<ApplicationLoader>(),
628 GURL(kTestAURLString));
629 loop_.Run();
631 EXPECT_EQ(1, tester_context_.num_b_deletes());
634 // Confirm that the url of a service is correctly passed to another service that
635 // it loads, and that it can be rejected.
636 TEST_F(ApplicationManagerTest, ANoLoadB) {
637 // Any url can load a.
638 AddLoaderForURL(GURL(kTestAURLString), std::string());
640 // Only c can load b, so this will fail.
641 AddLoaderForURL(GURL(kTestBURLString), "test:TestC");
643 TestAPtr a;
644 application_manager_->ConnectToService(GURL(kTestAURLString), &a);
645 a->CallB();
646 loop_.Run();
647 EXPECT_EQ(0, tester_context_.num_b_calls());
649 EXPECT_FALSE(tester_context_.a_called_quit());
650 EXPECT_TRUE(tester_context_.tester_called_quit());
653 TEST_F(ApplicationManagerTest, NoServiceNoLoad) {
654 AddLoaderForURL(GURL(kTestAURLString), std::string());
656 // There is no TestC service implementation registered with
657 // ApplicationManager, so this cannot succeed (but also shouldn't crash).
658 TestCPtr c;
659 application_manager_->ConnectToService(GURL(kTestAURLString), &c);
660 QuitMessageLoopErrorHandler quitter;
661 c.set_error_handler(&quitter);
663 loop_.Run();
664 EXPECT_TRUE(c.encountered_error());
667 TEST_F(ApplicationManagerTest, Interceptor) {
668 TestServiceInterceptor interceptor;
669 TestApplicationLoader* default_loader = new TestApplicationLoader;
670 application_manager_->set_default_loader(
671 scoped_ptr<ApplicationLoader>(default_loader));
672 application_manager_->SetInterceptor(&interceptor);
674 std::string url("test:test3");
675 TestServicePtr test_service;
676 application_manager_->ConnectToService(GURL(url), &test_service);
678 EXPECT_EQ(1, interceptor.call_count());
679 EXPECT_EQ(url, interceptor.url_spec());
680 EXPECT_EQ(1, default_loader->num_loads());
683 } // namespace mojo