| // 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 <stdint.h> |
| |
| #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_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() {} |
| |
| ~ChildProcessTaskTest() override {} |
| |
| // task_management::TaskProviderObserver: |
| void TaskAdded(Task* task) override { |
| DCHECK(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 { |
| DCHECK(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<base::ProcessHandle, Task*> 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_PPAPI_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 (const 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 |
| |