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