| // Copyright (c) 2012 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 "chrome/browser/task_manager/task_manager_browsertest_util.h" |
| |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/test_timeouts.h" |
| #include "base/timer/timer.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/task_manager/resource_provider.h" |
| #include "chrome/browser/task_manager/task_manager.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "extensions/strings/grit/extensions_strings.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace task_manager { |
| namespace browsertest_util { |
| |
| namespace { |
| |
| class ResourceChangeObserver : public TaskManagerModelObserver { |
| public: |
| ResourceChangeObserver(const TaskManagerModel* model, |
| int required_count, |
| const base::string16& title_pattern, |
| ColumnSpecifier column_specifier, |
| size_t min_column_value) |
| : model_(model), |
| required_count_(required_count), |
| title_pattern_(title_pattern), |
| column_specifier_(column_specifier), |
| min_column_value_(min_column_value) {} |
| |
| void OnModelChanged() override { OnResourceChange(); } |
| |
| void OnItemsChanged(int start, int length) override { OnResourceChange(); } |
| |
| void OnItemsAdded(int start, int length) override { OnResourceChange(); } |
| |
| void OnItemsRemoved(int start, int length) override { OnResourceChange(); } |
| |
| void RunUntilSatisfied() { |
| // See if the condition is satisfied without having to run the loop. This |
| // check has to be placed after the installation of the |
| // TaskManagerModelObserver, because resources may change before that. |
| if (IsSatisfied()) |
| return; |
| |
| timer_.Start(FROM_HERE, |
| TestTimeouts::action_timeout(), |
| this, |
| &ResourceChangeObserver::OnTimeout); |
| |
| run_loop_.Run(); |
| |
| // If we succeeded normally (no timeout), check our post condition again |
| // before returning control to the test. If it is no longer satisfied, the |
| // test is likely flaky: we were waiting for a state that was only achieved |
| // emphemerally), so treat this as a failure. |
| if (!IsSatisfied() && timer_.IsRunning()) { |
| FAIL() << "Wait condition satisfied only emphemerally. Likely test " |
| << "problem. Maybe wait instead for the state below?\n" |
| << DumpTaskManagerModel(); |
| } |
| |
| timer_.Stop(); |
| } |
| |
| private: |
| void OnResourceChange() { |
| if (!IsSatisfied()) |
| return; |
| |
| base::MessageLoop::current()->PostTask(FROM_HERE, run_loop_.QuitClosure()); |
| } |
| |
| bool IsSatisfied() { return CountMatches() == required_count_; } |
| |
| int CountMatches() { |
| int match_count = 0; |
| for (int i = 0; i < model_->ResourceCount(); i++) { |
| if (!MatchPattern(model_->GetResourceTitle(i), title_pattern_)) |
| continue; |
| |
| if (GetColumnValue(i) < min_column_value_) |
| continue; |
| |
| match_count++; |
| } |
| return match_count; |
| } |
| |
| size_t GetColumnValue(int index) { |
| size_t value = 0; |
| bool success = false; |
| switch (column_specifier_) { |
| case COLUMN_NONE: |
| break; |
| case V8_MEMORY: |
| success = model_->GetV8Memory(index, &value); |
| break; |
| case V8_MEMORY_USED: |
| success = model_->GetV8MemoryUsed(index, &value); |
| break; |
| case SQLITE_MEMORY_USED: |
| success = model_->GetSqliteMemoryUsedBytes(index, &value); |
| break; |
| } |
| if (!success) |
| return 0; |
| return value; |
| } |
| |
| const char* GetColumnName() { |
| switch (column_specifier_) { |
| case COLUMN_NONE: |
| return "N/A"; |
| case V8_MEMORY: |
| return "V8 Memory"; |
| case V8_MEMORY_USED: |
| return "V8 Memory Used"; |
| case SQLITE_MEMORY_USED: |
| return "SQLite Memory Used"; |
| } |
| return "N/A"; |
| } |
| |
| void OnTimeout() { |
| base::MessageLoop::current()->PostTask(FROM_HERE, run_loop_.QuitClosure()); |
| FAIL() << "Timed out.\n" << DumpTaskManagerModel(); |
| } |
| |
| testing::Message DumpTaskManagerModel() { |
| testing::Message task_manager_state_dump; |
| task_manager_state_dump << "Waiting for exactly " << required_count_ |
| << " matches of wildcard pattern \"" |
| << base::UTF16ToASCII(title_pattern_) << "\""; |
| if (min_column_value_ > 0) { |
| task_manager_state_dump << " && [" << GetColumnName() |
| << " >= " << min_column_value_ << "]"; |
| } |
| task_manager_state_dump << "\nCurrently there are " << CountMatches() |
| << " matches."; |
| task_manager_state_dump << "\nCurrent Task Manager Model is:"; |
| for (int i = 0; i < model_->ResourceCount(); i++) { |
| task_manager_state_dump |
| << "\n > " << std::setw(40) << std::left |
| << base::UTF16ToASCII(model_->GetResourceTitle(i)); |
| if (min_column_value_ > 0) { |
| task_manager_state_dump << " [" << GetColumnName() |
| << " == " << GetColumnValue(i) << "]"; |
| } |
| } |
| return task_manager_state_dump; |
| } |
| |
| const TaskManagerModel* model_; |
| const int required_count_; |
| const base::string16 title_pattern_; |
| const ColumnSpecifier column_specifier_; |
| const size_t min_column_value_; |
| base::RunLoop run_loop_; |
| base::OneShotTimer<ResourceChangeObserver> timer_; |
| }; |
| |
| } // namespace |
| |
| void WaitForTaskManagerRows(int required_count, |
| const base::string16& title_pattern) { |
| TaskManagerModel* model = TaskManager::GetInstance()->model(); |
| |
| const int column_value_dont_care = 0; |
| ResourceChangeObserver observer(model, required_count, title_pattern, |
| COLUMN_NONE, column_value_dont_care); |
| model->AddObserver(&observer); |
| observer.RunUntilSatisfied(); |
| model->RemoveObserver(&observer); |
| } |
| |
| void WaitForTaskManagerStatToExceed(const base::string16& title_pattern, |
| ColumnSpecifier column_getter, |
| size_t min_column_value) { |
| TaskManagerModel* model = TaskManager::GetInstance()->model(); |
| |
| const int wait_for_one_match = 1; |
| ResourceChangeObserver observer(model, wait_for_one_match, title_pattern, |
| column_getter, min_column_value); |
| model->AddObserver(&observer); |
| observer.RunUntilSatisfied(); |
| model->RemoveObserver(&observer); |
| } |
| |
| base::string16 MatchTab(const char* title) { |
| return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX, |
| base::ASCIIToUTF16(title)); |
| } |
| |
| base::string16 MatchAnyTab() { return MatchTab("*"); } |
| |
| base::string16 MatchAboutBlankTab() { return MatchTab("about:blank"); } |
| |
| base::string16 MatchExtension(const char* title) { |
| return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_EXTENSION_PREFIX, |
| base::ASCIIToUTF16(title)); |
| } |
| |
| base::string16 MatchAnyExtension() { return MatchExtension("*"); } |
| |
| base::string16 MatchApp(const char* title) { |
| return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_APP_PREFIX, |
| base::ASCIIToUTF16(title)); |
| } |
| |
| base::string16 MatchAnyApp() { return MatchApp("*"); } |
| |
| base::string16 MatchWebView(const char* title) { |
| return l10n_util::GetStringFUTF16( |
| IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX, |
| base::ASCIIToUTF16(title)); |
| } |
| |
| base::string16 MatchAnyWebView() { return MatchWebView("*"); } |
| |
| base::string16 MatchBackground(const char* title) { |
| return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX, |
| base::ASCIIToUTF16(title)); |
| } |
| |
| base::string16 MatchAnyBackground() { return MatchBackground("*"); } |
| |
| base::string16 MatchPrint(const char* title) { |
| return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRINT_PREFIX, |
| base::ASCIIToUTF16(title)); |
| } |
| |
| base::string16 MatchAnyPrint() { return MatchPrint("*"); } |
| |
| base::string16 MatchSubframe(const char* title) { |
| return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_SUBFRAME_PREFIX, |
| base::ASCIIToUTF16(title)); |
| } |
| |
| base::string16 MatchAnySubframe() { |
| return MatchSubframe("*"); |
| } |
| |
| base::string16 MatchUtility(const base::string16& title) { |
| return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX, title); |
| } |
| |
| base::string16 MatchAnyUtility() { |
| return MatchUtility(base::ASCIIToUTF16("*")); |
| } |
| |
| } // namespace browsertest_util |
| } // namespace task_manager |