| OLD | NEW | 
|---|
|  | (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 |  | 
| OLD | NEW | 
|---|