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