Home | History | Annotate | Download | only in application_manager
      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 
     19 namespace mojo {
     20 namespace {
     21 
     22 const char kTestURLString[] = "test:testService";
     23 const char kTestAURLString[] = "test:TestA";
     24 const char kTestBURLString[] = "test:TestB";
     25 
     26 struct 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 
     33 class 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 
     47 class 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 
     71 class 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 
     96 class 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 
    146 class 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.
    242 class 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 
    273 class 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 
    302 class 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 
    317 class 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 
    383 class 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 
    411 class 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 
    466 TEST_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.
    473 TEST_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.
    490 TEST_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 
    512 TEST_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 
    523 TEST_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.
    550 TEST_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.
    583 TEST_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.
    599 TEST_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.
    618 TEST_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.
    638 TEST_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 
    655 TEST_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 
    669 TEST_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