// Copyright 2015 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 #include "base/macros.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/task_management/providers/child_process_task.h" #include "chrome/browser/task_management/providers/child_process_task_provider.h" #include "chrome/browser/task_management/task_manager_observer.h" #include "chrome/grit/generated_resources.h" #include "components/nacl/common/nacl_process_type.h" #include "content/public/browser/child_process_data.h" #include "content/public/common/process_type.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" using content::ChildProcessData; namespace task_management { namespace { // Will be used to test the translation from |content::ProcessType| to // |task_management::Task::Type|. struct ProcessTypeTaskTypePair { int process_type_; Task::Type expected_task_type_; } process_task_types_pairs[] = { { content::PROCESS_TYPE_PLUGIN, Task::PLUGIN }, { content::PROCESS_TYPE_PPAPI_PLUGIN, Task::PLUGIN }, { content::PROCESS_TYPE_PPAPI_BROKER, Task::PLUGIN }, { content::PROCESS_TYPE_UTILITY, Task::UTILITY }, { content::PROCESS_TYPE_ZYGOTE, Task::ZYGOTE }, { content::PROCESS_TYPE_SANDBOX_HELPER, Task::SANDBOX_HELPER }, { content::PROCESS_TYPE_GPU, Task::GPU }, { PROCESS_TYPE_NACL_LOADER, Task::NACL }, { PROCESS_TYPE_NACL_BROKER, Task::NACL }, }; } // namespace // Defines a test for the child process task provider and the child process // tasks themselves. class ChildProcessTaskTest : public testing::Test, public TaskProviderObserver { public: ChildProcessTaskTest() : provided_tasks_(), thread_bundle_() { } ~ChildProcessTaskTest() override {} // task_management::TaskProviderObserver: void TaskAdded(Task* task) override { CHECK(task); if (provided_tasks_.find(task->process_handle()) != provided_tasks_.end()) FAIL() << "ChildProcessTaskProvider must never provide duplicate tasks"; provided_tasks_[task->process_handle()] = task; } void TaskRemoved(Task* task) override { CHECK(task); provided_tasks_.erase(task->process_handle()); } bool AreProviderContainersEmpty( const ChildProcessTaskProvider& provider) const { return provider.tasks_by_handle_.empty() && provider.tasks_by_pid_.empty(); } protected: std::map provided_tasks_; private: content::TestBrowserThreadBundle thread_bundle_; DISALLOW_COPY_AND_ASSIGN(ChildProcessTaskTest); }; // Perfoms a basic test. TEST_F(ChildProcessTaskTest, BasicTest) { ChildProcessTaskProvider provider; EXPECT_TRUE(provided_tasks_.empty()); provider.SetObserver(this); content::RunAllPendingInMessageLoop(); ASSERT_TRUE(provided_tasks_.empty()) << "unit tests don't have any browser child processes"; provider.ClearObserver(); EXPECT_TRUE(provided_tasks_.empty()); EXPECT_TRUE(AreProviderContainersEmpty(provider)); } // Tests everything related to child process task providing. TEST_F(ChildProcessTaskTest, TestAll) { ChildProcessTaskProvider provider; EXPECT_TRUE(provided_tasks_.empty()); provider.SetObserver(this); content::RunAllPendingInMessageLoop(); ASSERT_TRUE(provided_tasks_.empty()); // The following process which has handle = base::kNullProcessHandle, won't be // added. ChildProcessData data1(0); ASSERT_EQ(base::kNullProcessHandle, data1.handle); provider.BrowserChildProcessLaunchedAndConnected(data1); EXPECT_TRUE(provided_tasks_.empty()); const int unique_id = 245; const base::string16 name(base::UTF8ToUTF16("Test Task")); const base::string16 expected_name(l10n_util::GetStringFUTF16( IDS_TASK_MANAGER_PLUGIN_PREFIX, name)); ChildProcessData data2(content::PROCESS_TYPE_PLUGIN); data2.handle = base::GetCurrentProcessHandle(); data2.name = name; data2.id = unique_id; provider.BrowserChildProcessLaunchedAndConnected(data2); ASSERT_EQ(1U, provided_tasks_.size()); Task* task = provided_tasks_.begin()->second; EXPECT_EQ(base::GetCurrentProcessHandle(), task->process_handle()); EXPECT_EQ(base::GetCurrentProcId(), task->process_id()); EXPECT_EQ(expected_name, task->title()); EXPECT_EQ(Task::PLUGIN, task->GetType()); EXPECT_EQ(unique_id, task->GetChildProcessUniqueID()); EXPECT_EQ(base::string16(), task->GetProfileName()); EXPECT_FALSE(task->ReportsSqliteMemory()); EXPECT_FALSE(task->ReportsV8Memory()); EXPECT_FALSE(task->ReportsWebCacheStats()); EXPECT_FALSE(task->ReportsNetworkUsage()); // Make sure that the conversion from PID to Handle inside // |GetTaskOfUrlRequest()| is working properly. Task* found_task = provider.GetTaskOfUrlRequest(base::GetCurrentProcId(), 0, 0); ASSERT_EQ(task, found_task); const int64_t bytes_read = 1024; found_task->OnNetworkBytesRead(bytes_read); found_task->Refresh(base::TimeDelta::FromSeconds(1), REFRESH_TYPE_NETWORK_USAGE); EXPECT_TRUE(task->ReportsNetworkUsage()); EXPECT_EQ(bytes_read, task->network_usage()); // Clearing the observer won't notify us of any tasks removals even though // tasks will be actually deleted. provider.ClearObserver(); EXPECT_FALSE(provided_tasks_.empty()); EXPECT_TRUE(AreProviderContainersEmpty(provider)); } // Tests the translation of |content::ProcessType| to // |task_management::Task::Type|. TEST_F(ChildProcessTaskTest, ProcessTypeToTaskType) { ChildProcessTaskProvider provider; EXPECT_TRUE(provided_tasks_.empty()); provider.SetObserver(this); content::RunAllPendingInMessageLoop(); ASSERT_TRUE(provided_tasks_.empty()); for (auto& types_pair : process_task_types_pairs) { // Add the task. ChildProcessData data(types_pair.process_type_); data.handle = base::GetCurrentProcessHandle(); provider.BrowserChildProcessLaunchedAndConnected(data); ASSERT_EQ(1U, provided_tasks_.size()); Task* task = provided_tasks_.begin()->second; EXPECT_EQ(base::GetCurrentProcessHandle(), task->process_handle()); EXPECT_EQ(types_pair.expected_task_type_, task->GetType()); // Remove the task. provider.BrowserChildProcessHostDisconnected(data); EXPECT_TRUE(provided_tasks_.empty()); } provider.ClearObserver(); EXPECT_TRUE(AreProviderContainersEmpty(provider)); } } // namespace task_management