| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/task_manager/task_manager_tester.h" |
| |
| #include <memory> |
| #include <string_view> |
| |
| #include "base/byte_count.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/task_manager/task_manager_interface.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/models/table_model_observer.h" |
| |
| namespace task_manager { |
| |
| // Temporarily intercepts the calls between a TableModel and its Observer, |
| // running |callback| whenever anything happens. |
| class ScopedInterceptTableModelObserver : public ui::TableModelObserver { |
| public: |
| ScopedInterceptTableModelObserver( |
| ui::TableModel* model_to_intercept, |
| ui::TableModelObserver* real_table_model_observer, |
| const base::RepeatingClosure& callback) |
| : model_to_intercept_(model_to_intercept), |
| real_table_model_observer_(real_table_model_observer), |
| callback_(callback) { |
| model_to_intercept_->SetObserver(this); |
| } |
| |
| ~ScopedInterceptTableModelObserver() override { |
| model_to_intercept_->SetObserver(real_table_model_observer_); |
| } |
| |
| // ui::TableModelObserver: |
| void OnModelChanged() override { |
| real_table_model_observer_->OnModelChanged(); |
| callback_.Run(); |
| } |
| void OnItemsChanged(size_t start, size_t length) override { |
| real_table_model_observer_->OnItemsChanged(start, length); |
| callback_.Run(); |
| } |
| void OnItemsAdded(size_t start, size_t length) override { |
| real_table_model_observer_->OnItemsAdded(start, length); |
| callback_.Run(); |
| } |
| void OnItemsRemoved(size_t start, size_t length) override { |
| real_table_model_observer_->OnItemsRemoved(start, length); |
| callback_.Run(); |
| } |
| |
| private: |
| raw_ptr<ui::TableModel> model_to_intercept_; |
| raw_ptr<ui::TableModelObserver> real_table_model_observer_; |
| base::RepeatingClosure callback_; |
| }; |
| |
| namespace { |
| |
| // Returns the TaskManagerTableModel for the the visible NewTaskManagerView. |
| TaskManagerTableModel* GetRealModel() { |
| return chrome::ShowTaskManager(nullptr); |
| } |
| |
| } // namespace |
| |
| TaskManagerTester::TaskManagerTester( |
| const base::RepeatingClosure& on_resource_change) |
| : model_(GetRealModel()) { |
| // Eavesdrop the model->view conversation, since the model only supports |
| // single observation. |
| if (!on_resource_change.is_null()) { |
| interceptor_ = std::make_unique<ScopedInterceptTableModelObserver>( |
| model_, model_->table_model_observer_, on_resource_change); |
| } |
| } |
| |
| TaskManagerTester::~TaskManagerTester() { |
| CHECK_EQ(GetRealModel(), model_) << "Task Manager should not be hidden " |
| "while TaskManagerTester is alive. " |
| "This indicates a test bug."; |
| } |
| |
| // TaskManagerTester: |
| size_t TaskManagerTester::GetRowCount() { |
| return model_->RowCount(); |
| } |
| |
| std::u16string TaskManagerTester::GetRowTitle(size_t row) { |
| return model_->GetText(row, IDS_TASK_MANAGER_TASK_COLUMN); |
| } |
| |
| void TaskManagerTester::ToggleColumnVisibility(ColumnSpecifier column) { |
| int column_id = 0; |
| switch (column) { |
| case ColumnSpecifier::COLUMN_NONE: |
| return; |
| case ColumnSpecifier::PROCESS_ID: |
| column_id = IDS_TASK_MANAGER_PROCESS_ID_COLUMN; |
| break; |
| case ColumnSpecifier::MEMORY_FOOTPRINT: |
| column_id = IDS_TASK_MANAGER_MEM_FOOTPRINT_COLUMN; |
| break; |
| case ColumnSpecifier::SQLITE_MEMORY_USED: |
| column_id = IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN; |
| break; |
| case ColumnSpecifier::V8_MEMORY_USED: |
| case ColumnSpecifier::V8_MEMORY: |
| column_id = IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN; |
| break; |
| case ColumnSpecifier::IDLE_WAKEUPS: |
| column_id = IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN; |
| break; |
| case ColumnSpecifier::TOTAL_NETWORK_USE: |
| case ColumnSpecifier::NETWORK_USE: |
| column_id = IDS_TASK_MANAGER_NET_COLUMN; |
| break; |
| } |
| model_->ToggleColumnVisibility(column_id); |
| } |
| |
| int64_t TaskManagerTester::GetColumnValue(ColumnSpecifier column, size_t row) { |
| TaskId task_id = model_->tasks_[row]; |
| switch (column) { |
| case ColumnSpecifier::COLUMN_NONE: |
| return 0; |
| case ColumnSpecifier::MEMORY_FOOTPRINT: |
| return task_manager()->GetMemoryFootprintUsage(task_id).InBytes(); |
| case ColumnSpecifier::PROCESS_ID: |
| return task_manager()->GetProcessId(task_id); |
| case ColumnSpecifier::V8_MEMORY: |
| case ColumnSpecifier::V8_MEMORY_USED: { |
| base::ByteCount allocated; |
| base::ByteCount used; |
| bool success = task_manager()->GetV8Memory(task_id, &allocated, &used); |
| if (!success) { |
| return 0; |
| } |
| return column == ColumnSpecifier::V8_MEMORY ? allocated.InBytes() |
| : used.InBytes(); |
| } |
| case ColumnSpecifier::SQLITE_MEMORY_USED: |
| return task_manager()->GetSqliteMemoryUsed(task_id).InBytes(); |
| case ColumnSpecifier::IDLE_WAKEUPS: |
| return task_manager()->GetIdleWakeupsPerSecond(task_id); |
| case ColumnSpecifier::NETWORK_USE: |
| return task_manager()->GetNetworkUsage(task_id).InBytes(); |
| case ColumnSpecifier::TOTAL_NETWORK_USE: |
| return task_manager()->GetCumulativeNetworkUsage(task_id).InBytes(); |
| } |
| } |
| |
| SessionID TaskManagerTester::GetTabId(size_t row) { |
| TaskId task_id = model_->tasks_[row]; |
| return task_manager()->GetTabId(task_id); |
| } |
| |
| void TaskManagerTester::Kill(size_t row) { |
| model_->KillTask(row); |
| } |
| |
| void TaskManagerTester::Activate(size_t row) { |
| model_->ActivateTask(row); |
| } |
| |
| void TaskManagerTester::GetRowsGroupRange(size_t row, |
| size_t* out_start, |
| size_t* out_length) { |
| return model_->GetRowsGroupRange(row, out_start, out_length); |
| } |
| |
| std::vector<std::u16string> TaskManagerTester::GetWebContentsTaskTitles() { |
| std::vector<std::u16string> titles; |
| titles.reserve(GetRowCount()); |
| for (size_t row = 0; row < GetRowCount(); row++) { |
| // Exclude tasks which are not associated with a WebContents. |
| if (GetTabId(row) != SessionID::InvalidValue()) |
| titles.push_back(GetRowTitle(row)); |
| } |
| return titles; |
| } |
| |
| bool TaskManagerTester::UpdateModel(const DisplayCategory display_category, |
| std::u16string_view search_term) { |
| return model_->UpdateModel(display_category, search_term); |
| } |
| |
| TaskManagerInterface* TaskManagerTester::task_manager() { |
| return model_->observed_task_manager(); |
| } |
| |
| // static |
| std::unique_ptr<TaskManagerTester> TaskManagerTester::Create( |
| const base::RepeatingClosure& callback) { |
| return base::WrapUnique(new TaskManagerTester(callback)); |
| } |
| |
| } // namespace task_manager |