| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <memory> |
| 6 |
| 5 #include "base/bind.h" | 7 #include "base/bind.h" |
| 6 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 7 #include "base/macros.h" | 9 #include "base/macros.h" |
| 10 #include "base/memory/ptr_util.h" |
| 8 #include "base/process/process.h" | 11 #include "base/process/process.h" |
| 9 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
| 10 #include "services/shell/public/cpp/identity.h" | 13 #include "services/shell/public/cpp/identity.h" |
| 11 #include "services/shell/public/cpp/shell_test.h" | 14 #include "services/shell/public/cpp/shell_test.h" |
| 12 #include "services/shell/public/interfaces/shell.mojom.h" | 15 #include "services/shell/public/interfaces/shell.mojom.h" |
| 13 #include "services/shell/tests/lifecycle/lifecycle_unittest.mojom.h" | 16 #include "services/shell/tests/lifecycle/lifecycle_unittest.mojom.h" |
| 14 #include "services/shell/tests/util.h" | 17 #include "services/shell/tests/util.h" |
| 15 | 18 |
| 16 namespace mojo { | |
| 17 namespace shell { | 19 namespace shell { |
| 20 |
| 18 namespace { | 21 namespace { |
| 19 | 22 |
| 20 const char kTestAppName[] = "mojo:lifecycle_unittest_app"; | 23 const char kTestAppName[] = "mojo:lifecycle_unittest_app"; |
| 21 const char kTestParentName[] = "mojo:lifecycle_unittest_parent"; | 24 const char kTestParentName[] = "mojo:lifecycle_unittest_parent"; |
| 22 const char kTestExeName[] = "exe:lifecycle_unittest_exe"; | 25 const char kTestExeName[] = "exe:lifecycle_unittest_exe"; |
| 23 const char kTestPackageName[] = "mojo:lifecycle_unittest_package"; | 26 const char kTestPackageName[] = "mojo:lifecycle_unittest_package"; |
| 24 const char kTestPackageAppNameA[] = "mojo:lifecycle_unittest_package_app_a"; | 27 const char kTestPackageAppNameA[] = "mojo:lifecycle_unittest_package_app_a"; |
| 25 const char kTestPackageAppNameB[] = "mojo:lifecycle_unittest_package_app_b"; | 28 const char kTestPackageAppNameB[] = "mojo:lifecycle_unittest_package_app_b"; |
| 26 const char kTestName[] = "mojo:lifecycle_unittest"; | 29 const char kTestName[] = "mojo:lifecycle_unittest"; |
| 27 | 30 |
| 28 void QuitLoop(base::RunLoop* loop) { | 31 void QuitLoop(base::RunLoop* loop) { |
| 29 loop->Quit(); | 32 loop->Quit(); |
| 30 } | 33 } |
| 31 | 34 |
| 32 void DecrementCountAndQuitWhenZero(base::RunLoop* loop, size_t* count) { | 35 void DecrementCountAndQuitWhenZero(base::RunLoop* loop, size_t* count) { |
| 33 if (!--(*count)) | 36 if (!--(*count)) |
| 34 loop->Quit(); | 37 loop->Quit(); |
| 35 } | 38 } |
| 36 | 39 |
| 37 struct Instance { | 40 struct Instance { |
| 38 Instance() : id(shell::mojom::kInvalidInstanceID), pid(0) {} | 41 Instance() : id(mojom::kInvalidInstanceID), pid(0) {} |
| 39 Instance(const Identity& identity, uint32_t id, uint32_t pid) | 42 Instance(const Identity& identity, uint32_t id, uint32_t pid) |
| 40 : identity(identity), id(id), pid(pid) {} | 43 : identity(identity), id(id), pid(pid) {} |
| 41 | 44 |
| 42 Identity identity; | 45 Identity identity; |
| 43 uint32_t id; | 46 uint32_t id; |
| 44 uint32_t pid; | 47 uint32_t pid; |
| 45 }; | 48 }; |
| 46 | 49 |
| 47 class InstanceState : public mojom::InstanceListener { | 50 class InstanceState : public mojom::InstanceListener { |
| 48 public: | 51 public: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 59 void WaitForInstanceDestruction(base::RunLoop* loop) { | 62 void WaitForInstanceDestruction(base::RunLoop* loop) { |
| 60 DCHECK(!destruction_loop_); | 63 DCHECK(!destruction_loop_); |
| 61 destruction_loop_ = loop; | 64 destruction_loop_ = loop; |
| 62 // First of all check to see if we should be spinning this loop at all - | 65 // First of all check to see if we should be spinning this loop at all - |
| 63 // the app(s) we're waiting on quitting may already have quit. | 66 // the app(s) we're waiting on quitting may already have quit. |
| 64 TryToQuitDestructionLoop(); | 67 TryToQuitDestructionLoop(); |
| 65 } | 68 } |
| 66 | 69 |
| 67 private: | 70 private: |
| 68 // mojom::InstanceListener: | 71 // mojom::InstanceListener: |
| 69 void SetExistingInstances(Array<mojom::InstanceInfoPtr> instances) override { | 72 void SetExistingInstances( |
| 73 mojo::Array<mojom::InstanceInfoPtr> instances) override { |
| 70 for (const auto& instance : instances) { | 74 for (const auto& instance : instances) { |
| 71 Instance i(instance->identity.To<Identity>(), instance->id, | 75 Instance i(instance->identity.To<Identity>(), instance->id, |
| 72 instance->pid); | 76 instance->pid); |
| 73 initial_instances_[i.identity.name()] = i; | 77 initial_instances_[i.identity.name()] = i; |
| 74 instances_[i.identity.name()] = i; | 78 instances_[i.identity.name()] = i; |
| 75 } | 79 } |
| 76 loop_->Quit(); | 80 loop_->Quit(); |
| 77 } | 81 } |
| 78 void InstanceCreated(mojom::InstanceInfoPtr instance) override { | 82 void InstanceCreated(mojom::InstanceInfoPtr instance) override { |
| 79 instances_[instance->identity->name] = | 83 instances_[instance->identity->name] = |
| (...skipping 23 matching lines...) Expand all Loading... |
| 103 destruction_loop_->Quit(); | 107 destruction_loop_->Quit(); |
| 104 destruction_loop_ = nullptr; | 108 destruction_loop_ = nullptr; |
| 105 } | 109 } |
| 106 } | 110 } |
| 107 | 111 |
| 108 // All currently running instances. | 112 // All currently running instances. |
| 109 std::map<std::string, Instance> instances_; | 113 std::map<std::string, Instance> instances_; |
| 110 // The initial set of instances. | 114 // The initial set of instances. |
| 111 std::map<std::string, Instance> initial_instances_; | 115 std::map<std::string, Instance> initial_instances_; |
| 112 | 116 |
| 113 Binding<mojom::InstanceListener> binding_; | 117 mojo::Binding<mojom::InstanceListener> binding_; |
| 114 base::RunLoop* loop_; | 118 base::RunLoop* loop_; |
| 115 | 119 |
| 116 // Set when the client wants to wait for this object to track the destruction | 120 // Set when the client wants to wait for this object to track the destruction |
| 117 // of an instance before proceeding. | 121 // of an instance before proceeding. |
| 118 base::RunLoop* destruction_loop_ = nullptr; | 122 base::RunLoop* destruction_loop_ = nullptr; |
| 119 | 123 |
| 120 DISALLOW_COPY_AND_ASSIGN(InstanceState); | 124 DISALLOW_COPY_AND_ASSIGN(InstanceState); |
| 121 }; | 125 }; |
| 122 | 126 |
| 123 } | 127 } // namespace |
| 124 | 128 |
| 125 class LifecycleTest : public mojo::test::ShellTest { | 129 class LifecycleTest : public test::ShellTest { |
| 126 public: | 130 public: |
| 127 LifecycleTest() : ShellTest(kTestName) {} | 131 LifecycleTest() : ShellTest(kTestName) {} |
| 128 ~LifecycleTest() override {} | 132 ~LifecycleTest() override {} |
| 129 | 133 |
| 130 protected: | 134 protected: |
| 131 // mojo::test::ShellTest: | 135 // test::ShellTest: |
| 132 void SetUp() override { | 136 void SetUp() override { |
| 133 mojo::test::ShellTest::SetUp(); | 137 test::ShellTest::SetUp(); |
| 134 InitPackage(); | 138 InitPackage(); |
| 135 instances_ = TrackInstances(); | 139 instances_ = TrackInstances(); |
| 136 } | 140 } |
| 137 void TearDown() override { | 141 void TearDown() override { |
| 138 instances_.reset(); | 142 instances_.reset(); |
| 139 mojo::test::ShellTest::TearDown(); | 143 test::ShellTest::TearDown(); |
| 140 } | 144 } |
| 141 | 145 |
| 142 bool CanRunCrashTest() { | 146 bool CanRunCrashTest() { |
| 143 return !base::CommandLine::ForCurrentProcess()->HasSwitch("single-process"); | 147 return !base::CommandLine::ForCurrentProcess()->HasSwitch("single-process"); |
| 144 } | 148 } |
| 145 | 149 |
| 146 void InitPackage() { | 150 void InitPackage() { |
| 147 test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestPackageName); | 151 test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestPackageName); |
| 148 base::RunLoop loop; | 152 base::RunLoop loop; |
| 149 lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop)); | 153 lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop)); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 180 | 184 |
| 181 InstanceState* instances() { return instances_.get(); } | 185 InstanceState* instances() { return instances_.get(); } |
| 182 | 186 |
| 183 void WaitForInstanceDestruction() { | 187 void WaitForInstanceDestruction() { |
| 184 base::RunLoop loop; | 188 base::RunLoop loop; |
| 185 instances()->WaitForInstanceDestruction(&loop); | 189 instances()->WaitForInstanceDestruction(&loop); |
| 186 loop.Run(); | 190 loop.Run(); |
| 187 } | 191 } |
| 188 | 192 |
| 189 private: | 193 private: |
| 190 scoped_ptr<InstanceState> TrackInstances() { | 194 std::unique_ptr<InstanceState> TrackInstances() { |
| 191 mojom::ShellPtr shell; | 195 mojom::ShellPtr shell; |
| 192 connector()->ConnectToInterface("mojo:shell", &shell); | 196 connector()->ConnectToInterface("mojo:shell", &shell); |
| 193 mojom::InstanceListenerPtr listener; | 197 mojom::InstanceListenerPtr listener; |
| 194 base::RunLoop loop; | 198 base::RunLoop loop; |
| 195 InstanceState* state = new InstanceState(GetProxy(&listener), &loop); | 199 InstanceState* state = new InstanceState(GetProxy(&listener), &loop); |
| 196 shell->AddInstanceListener(std::move(listener)); | 200 shell->AddInstanceListener(std::move(listener)); |
| 197 loop.Run(); | 201 loop.Run(); |
| 198 return make_scoped_ptr(state); | 202 return base::WrapUnique(state); |
| 199 } | 203 } |
| 200 | 204 |
| 201 scoped_ptr<InstanceState> instances_; | 205 std::unique_ptr<InstanceState> instances_; |
| 202 | 206 |
| 203 DISALLOW_COPY_AND_ASSIGN(LifecycleTest); | 207 DISALLOW_COPY_AND_ASSIGN(LifecycleTest); |
| 204 }; | 208 }; |
| 205 | 209 |
| 206 TEST_F(LifecycleTest, Standalone_GracefulQuit) { | 210 TEST_F(LifecycleTest, Standalone_GracefulQuit) { |
| 207 test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestAppName); | 211 test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestAppName); |
| 208 | 212 |
| 209 EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName)); | 213 EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName)); |
| 210 EXPECT_EQ(1u, instances()->GetNewInstanceCount()); | 214 EXPECT_EQ(1u, instances()->GetNewInstanceCount()); |
| 211 | 215 |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 process.Terminate(9, true); | 438 process.Terminate(9, true); |
| 435 loop.Run(); | 439 loop.Run(); |
| 436 | 440 |
| 437 WaitForInstanceDestruction(); | 441 WaitForInstanceDestruction(); |
| 438 EXPECT_FALSE(instances()->HasInstanceForName(kTestExeName)); | 442 EXPECT_FALSE(instances()->HasInstanceForName(kTestExeName)); |
| 439 EXPECT_EQ(0u, instances()->GetNewInstanceCount()); | 443 EXPECT_EQ(0u, instances()->GetNewInstanceCount()); |
| 440 } | 444 } |
| 441 | 445 |
| 442 TEST_F(LifecycleTest, ShutdownTree) { | 446 TEST_F(LifecycleTest, ShutdownTree) { |
| 443 // Verifies that Instances are destroyed when their creator is. | 447 // Verifies that Instances are destroyed when their creator is. |
| 444 scoped_ptr<Connection> parent_connection = | 448 std::unique_ptr<Connection> parent_connection = |
| 445 connector()->Connect(kTestParentName); | 449 connector()->Connect(kTestParentName); |
| 446 test::mojom::ParentPtr parent; | 450 test::mojom::ParentPtr parent; |
| 447 parent_connection->GetInterface(&parent); | 451 parent_connection->GetInterface(&parent); |
| 448 | 452 |
| 449 // This asks kTestParentName to open a connection to kTestAppName and blocks | 453 // This asks kTestParentName to open a connection to kTestAppName and blocks |
| 450 // on a response from a Ping(). | 454 // on a response from a Ping(). |
| 451 { | 455 { |
| 452 base::RunLoop loop; | 456 base::RunLoop loop; |
| 453 parent->ConnectToChild(base::Bind(&QuitLoop, &loop)); | 457 parent->ConnectToChild(base::Bind(&QuitLoop, &loop)); |
| 454 loop.Run(); | 458 loop.Run(); |
| 455 } | 459 } |
| 456 | 460 |
| 457 // Should now have two new instances (parent and child). | 461 // Should now have two new instances (parent and child). |
| 458 EXPECT_EQ(2u, instances()->GetNewInstanceCount()); | 462 EXPECT_EQ(2u, instances()->GetNewInstanceCount()); |
| 459 EXPECT_TRUE(instances()->HasInstanceForName(kTestParentName)); | 463 EXPECT_TRUE(instances()->HasInstanceForName(kTestParentName)); |
| 460 EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName)); | 464 EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName)); |
| 461 | 465 |
| 462 parent->Quit(); | 466 parent->Quit(); |
| 463 | 467 |
| 464 // Quitting the parent should cascade-quit the child. | 468 // Quitting the parent should cascade-quit the child. |
| 465 WaitForInstanceDestruction(); | 469 WaitForInstanceDestruction(); |
| 466 EXPECT_EQ(0u, instances()->GetNewInstanceCount()); | 470 EXPECT_EQ(0u, instances()->GetNewInstanceCount()); |
| 467 EXPECT_FALSE(instances()->HasInstanceForName(kTestParentName)); | 471 EXPECT_FALSE(instances()->HasInstanceForName(kTestParentName)); |
| 468 EXPECT_FALSE(instances()->HasInstanceForName(kTestAppName)); | 472 EXPECT_FALSE(instances()->HasInstanceForName(kTestAppName)); |
| 469 } | 473 } |
| 470 | 474 |
| 471 } // namespace shell | 475 } // namespace shell |
| 472 } // namespace mojo | |
| OLD | NEW |