| Index: mojo/shell/tests/lifecycle/lifecycle_unittest.cc
|
| diff --git a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc b/mojo/shell/tests/lifecycle/lifecycle_unittest.cc
|
| deleted file mode 100644
|
| index 27e068f5635c59b45e4e4f92288f4b543308fbb4..0000000000000000000000000000000000000000
|
| --- a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc
|
| +++ /dev/null
|
| @@ -1,472 +0,0 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/command_line.h"
|
| -#include "base/macros.h"
|
| -#include "base/process/process.h"
|
| -#include "base/run_loop.h"
|
| -#include "mojo/shell/public/cpp/identity.h"
|
| -#include "mojo/shell/public/cpp/shell_test.h"
|
| -#include "mojo/shell/public/interfaces/shell.mojom.h"
|
| -#include "mojo/shell/tests/lifecycle/lifecycle_unittest.mojom.h"
|
| -#include "mojo/shell/tests/util.h"
|
| -
|
| -namespace mojo {
|
| -namespace shell {
|
| -namespace {
|
| -
|
| -const char kTestAppName[] = "mojo:lifecycle_unittest_app";
|
| -const char kTestParentName[] = "mojo:lifecycle_unittest_parent";
|
| -const char kTestExeName[] = "exe:lifecycle_unittest_exe";
|
| -const char kTestPackageName[] = "mojo:lifecycle_unittest_package";
|
| -const char kTestPackageAppNameA[] = "mojo:lifecycle_unittest_package_app_a";
|
| -const char kTestPackageAppNameB[] = "mojo:lifecycle_unittest_package_app_b";
|
| -const char kTestName[] = "mojo:lifecycle_unittest";
|
| -
|
| -void QuitLoop(base::RunLoop* loop) {
|
| - loop->Quit();
|
| -}
|
| -
|
| -void DecrementCountAndQuitWhenZero(base::RunLoop* loop, size_t* count) {
|
| - if (!--(*count))
|
| - loop->Quit();
|
| -}
|
| -
|
| -struct Instance {
|
| - Instance() : id(shell::mojom::kInvalidInstanceID), pid(0) {}
|
| - Instance(const Identity& identity, uint32_t id, uint32_t pid)
|
| - : identity(identity), id(id), pid(pid) {}
|
| -
|
| - Identity identity;
|
| - uint32_t id;
|
| - uint32_t pid;
|
| -};
|
| -
|
| -class InstanceState : public mojom::InstanceListener {
|
| - public:
|
| - InstanceState(mojom::InstanceListenerRequest request, base::RunLoop* loop)
|
| - : binding_(this, std::move(request)), loop_(loop) {}
|
| - ~InstanceState() override {}
|
| -
|
| - bool HasInstanceForName(const std::string& name) const {
|
| - return instances_.find(name) != instances_.end();
|
| - }
|
| - size_t GetNewInstanceCount() const {
|
| - return instances_.size() - initial_instances_.size();
|
| - }
|
| - void WaitForInstanceDestruction(base::RunLoop* loop) {
|
| - DCHECK(!destruction_loop_);
|
| - destruction_loop_ = loop;
|
| - // First of all check to see if we should be spinning this loop at all -
|
| - // the app(s) we're waiting on quitting may already have quit.
|
| - TryToQuitDestructionLoop();
|
| - }
|
| -
|
| - private:
|
| - // mojom::InstanceListener:
|
| - void SetExistingInstances(Array<mojom::InstanceInfoPtr> instances) override {
|
| - for (const auto& instance : instances) {
|
| - Instance i(instance->identity.To<Identity>(), instance->id,
|
| - instance->pid);
|
| - initial_instances_[i.identity.name()] = i;
|
| - instances_[i.identity.name()] = i;
|
| - }
|
| - loop_->Quit();
|
| - }
|
| - void InstanceCreated(mojom::InstanceInfoPtr instance) override {
|
| - instances_[instance->identity->name] =
|
| - Instance(instance->identity.To<Identity>(), instance->id,
|
| - instance->pid);
|
| - }
|
| - void InstanceDestroyed(uint32_t id) override {
|
| - for (auto it = instances_.begin(); it != instances_.end(); ++it) {
|
| - if (it->second.id == id) {
|
| - instances_.erase(it);
|
| - break;
|
| - }
|
| - }
|
| - TryToQuitDestructionLoop();
|
| - }
|
| - void InstancePIDAvailable(uint32_t id, uint32_t pid) override {
|
| - for (auto& instance : instances_) {
|
| - if (instance.second.id == id) {
|
| - instance.second.pid = pid;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - void TryToQuitDestructionLoop() {
|
| - if (!GetNewInstanceCount() && destruction_loop_) {
|
| - destruction_loop_->Quit();
|
| - destruction_loop_ = nullptr;
|
| - }
|
| - }
|
| -
|
| - // All currently running instances.
|
| - std::map<std::string, Instance> instances_;
|
| - // The initial set of instances.
|
| - std::map<std::string, Instance> initial_instances_;
|
| -
|
| - Binding<mojom::InstanceListener> binding_;
|
| - base::RunLoop* loop_;
|
| -
|
| - // Set when the client wants to wait for this object to track the destruction
|
| - // of an instance before proceeding.
|
| - base::RunLoop* destruction_loop_ = nullptr;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(InstanceState);
|
| -};
|
| -
|
| -}
|
| -
|
| -class LifecycleTest : public mojo::test::ShellTest {
|
| - public:
|
| - LifecycleTest() : ShellTest(kTestName) {}
|
| - ~LifecycleTest() override {}
|
| -
|
| - protected:
|
| - // mojo::test::ShellTest:
|
| - void SetUp() override {
|
| - mojo::test::ShellTest::SetUp();
|
| - InitPackage();
|
| - instances_ = TrackInstances();
|
| - }
|
| - void TearDown() override {
|
| - instances_.reset();
|
| - mojo::test::ShellTest::TearDown();
|
| - }
|
| -
|
| - bool CanRunCrashTest() {
|
| - return !base::CommandLine::ForCurrentProcess()->HasSwitch("single-process");
|
| - }
|
| -
|
| - void InitPackage() {
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestPackageName);
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->GracefulQuit();
|
| - loop.Run();
|
| - }
|
| -
|
| - test::mojom::LifecycleControlPtr ConnectTo(const std::string& name) {
|
| - test::mojom::LifecycleControlPtr lifecycle;
|
| - connector()->ConnectToInterface(name, &lifecycle);
|
| - PingPong(lifecycle.get());
|
| - return lifecycle;
|
| - }
|
| -
|
| - base::Process LaunchProcess() {
|
| - base::Process process;
|
| - test::LaunchAndConnectToProcess(
|
| -#if defined(OS_WIN)
|
| - "lifecycle_unittest_exe.exe",
|
| -#else
|
| - "lifecycle_unittest_exe",
|
| -#endif
|
| - Identity(kTestExeName, mojom::kInheritUserID),
|
| - connector(),
|
| - &process);
|
| - return process;
|
| - }
|
| -
|
| - void PingPong(test::mojom::LifecycleControl* lifecycle) {
|
| - base::RunLoop loop;
|
| - lifecycle->Ping(base::Bind(&QuitLoop, &loop));
|
| - loop.Run();
|
| - }
|
| -
|
| - InstanceState* instances() { return instances_.get(); }
|
| -
|
| - void WaitForInstanceDestruction() {
|
| - base::RunLoop loop;
|
| - instances()->WaitForInstanceDestruction(&loop);
|
| - loop.Run();
|
| - }
|
| -
|
| - private:
|
| - scoped_ptr<InstanceState> TrackInstances() {
|
| - mojom::ShellPtr shell;
|
| - connector()->ConnectToInterface("mojo:shell", &shell);
|
| - mojom::InstanceListenerPtr listener;
|
| - base::RunLoop loop;
|
| - InstanceState* state = new InstanceState(GetProxy(&listener), &loop);
|
| - shell->AddInstanceListener(std::move(listener));
|
| - loop.Run();
|
| - return make_scoped_ptr(state);
|
| - }
|
| -
|
| - scoped_ptr<InstanceState> instances_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(LifecycleTest);
|
| -};
|
| -
|
| -TEST_F(LifecycleTest, Standalone_GracefulQuit) {
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestAppName);
|
| -
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName));
|
| - EXPECT_EQ(1u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->GracefulQuit();
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestAppName));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, Standalone_Crash) {
|
| - if (!CanRunCrashTest()) {
|
| - LOG(INFO) << "Skipping Standalone_Crash test in --single-process mode.";
|
| - return;
|
| - }
|
| -
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestAppName);
|
| -
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName));
|
| - EXPECT_EQ(1u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->Crash();
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestAppName));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, Standalone_CloseShellConnection) {
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestAppName);
|
| -
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName));
|
| - EXPECT_EQ(1u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->CloseShellConnection();
|
| -
|
| - WaitForInstanceDestruction();
|
| -
|
| - // |lifecycle| pipe should still be valid.
|
| - PingPong(lifecycle.get());
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, PackagedApp_GracefulQuit) {
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestPackageAppNameA);
|
| -
|
| - // There should be two new instances - one for the app and one for the package
|
| - // that vended it.
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_EQ(2u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->GracefulQuit();
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestAppName));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, PackagedApp_Crash) {
|
| - if (!CanRunCrashTest()) {
|
| - LOG(INFO) << "Skipping Standalone_Crash test in --single-process mode.";
|
| - return;
|
| - }
|
| -
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestPackageAppNameA);
|
| -
|
| - // There should be two new instances - one for the app and one for the package
|
| - // that vended it.
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_EQ(2u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->Crash();
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, PackagedApp_CloseShellConnection) {
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestPackageAppNameA);
|
| -
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_EQ(2u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->CloseShellConnection();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -
|
| - // |lifecycle| pipe should still be valid.
|
| - PingPong(lifecycle.get());
|
| -}
|
| -
|
| -
|
| -// When a single package provides multiple apps out of one process, crashing one
|
| -// app crashes all.
|
| -TEST_F(LifecycleTest, PackagedApp_CrashCrashesOtherProvidedApp) {
|
| - if (!CanRunCrashTest()) {
|
| - LOG(INFO) << "Skipping Standalone_Crash test in --single-process mode.";
|
| - return;
|
| - }
|
| -
|
| - test::mojom::LifecycleControlPtr lifecycle_a =
|
| - ConnectTo(kTestPackageAppNameA);
|
| - test::mojom::LifecycleControlPtr lifecycle_b =
|
| - ConnectTo(kTestPackageAppNameB);
|
| - test::mojom::LifecycleControlPtr lifecycle_package =
|
| - ConnectTo(kTestPackageName);
|
| -
|
| - // There should be three instances, one for each packaged app and the package
|
| - // itself.
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageAppNameB));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageName));
|
| - size_t instance_count = instances()->GetNewInstanceCount();
|
| - EXPECT_EQ(3u, instance_count);
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle_a.set_connection_error_handler(
|
| - base::Bind(&DecrementCountAndQuitWhenZero, &loop, &instance_count));
|
| - lifecycle_b.set_connection_error_handler(
|
| - base::Bind(&DecrementCountAndQuitWhenZero, &loop, &instance_count));
|
| - lifecycle_package.set_connection_error_handler(
|
| - base::Bind(&DecrementCountAndQuitWhenZero, &loop, &instance_count));
|
| -
|
| - // Now crash one of the packaged apps.
|
| - lifecycle_a->Crash();
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageAppNameB));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -}
|
| -
|
| -// When a single package provides multiple apps out of one process, crashing one
|
| -// app crashes all.
|
| -TEST_F(LifecycleTest, PackagedApp_GracefulQuitPackageQuitsAll) {
|
| - test::mojom::LifecycleControlPtr lifecycle_a =
|
| - ConnectTo(kTestPackageAppNameA);
|
| - test::mojom::LifecycleControlPtr lifecycle_b =
|
| - ConnectTo(kTestPackageAppNameB);
|
| - test::mojom::LifecycleControlPtr lifecycle_package =
|
| - ConnectTo(kTestPackageName);
|
| -
|
| - // There should be three instances, one for each packaged app and the package
|
| - // itself.
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageAppNameB));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestPackageName));
|
| - size_t instance_count = instances()->GetNewInstanceCount();
|
| - EXPECT_EQ(3u, instance_count);
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle_a.set_connection_error_handler(
|
| - base::Bind(&DecrementCountAndQuitWhenZero, &loop, &instance_count));
|
| - lifecycle_b.set_connection_error_handler(
|
| - base::Bind(&DecrementCountAndQuitWhenZero, &loop, &instance_count));
|
| - lifecycle_package.set_connection_error_handler(
|
| - base::Bind(&DecrementCountAndQuitWhenZero, &loop, &instance_count));
|
| -
|
| - // Now quit the package. All the packaged apps should close.
|
| - lifecycle_package->GracefulQuit();
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageName));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageAppNameA));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestPackageAppNameB));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, Exe_GracefulQuit) {
|
| - base::Process process = LaunchProcess();
|
| -
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestExeName);
|
| -
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestExeName));
|
| - EXPECT_EQ(1u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - lifecycle->GracefulQuit();
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestExeName));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -
|
| - process.Terminate(9, true);
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, Exe_TerminateProcess) {
|
| - base::Process process = LaunchProcess();
|
| -
|
| - test::mojom::LifecycleControlPtr lifecycle = ConnectTo(kTestExeName);
|
| -
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestExeName));
|
| - EXPECT_EQ(1u, instances()->GetNewInstanceCount());
|
| -
|
| - base::RunLoop loop;
|
| - lifecycle.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
|
| - process.Terminate(9, true);
|
| - loop.Run();
|
| -
|
| - WaitForInstanceDestruction();
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestExeName));
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| -}
|
| -
|
| -TEST_F(LifecycleTest, ShutdownTree) {
|
| - // Verifies that Instances are destroyed when their creator is.
|
| - scoped_ptr<Connection> parent_connection =
|
| - connector()->Connect(kTestParentName);
|
| - test::mojom::ParentPtr parent;
|
| - parent_connection->GetInterface(&parent);
|
| -
|
| - // This asks kTestParentName to open a connection to kTestAppName and blocks
|
| - // on a response from a Ping().
|
| - {
|
| - base::RunLoop loop;
|
| - parent->ConnectToChild(base::Bind(&QuitLoop, &loop));
|
| - loop.Run();
|
| - }
|
| -
|
| - // Should now have two new instances (parent and child).
|
| - EXPECT_EQ(2u, instances()->GetNewInstanceCount());
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestParentName));
|
| - EXPECT_TRUE(instances()->HasInstanceForName(kTestAppName));
|
| -
|
| - parent->Quit();
|
| -
|
| - // Quitting the parent should cascade-quit the child.
|
| - WaitForInstanceDestruction();
|
| - EXPECT_EQ(0u, instances()->GetNewInstanceCount());
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestParentName));
|
| - EXPECT_FALSE(instances()->HasInstanceForName(kTestAppName));
|
| -}
|
| -
|
| -} // namespace shell
|
| -} // namespace mojo
|
|
|