| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/task_manager/task_manager_browsertest_util.h" | |
| 6 | |
| 7 #include "base/bind_helpers.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/location.h" | |
| 10 #include "base/run_loop.h" | |
| 11 #include "base/single_thread_task_runner.h" | |
| 12 #include "base/strings/pattern.h" | |
| 13 #include "base/strings/string16.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 #include "base/strings/utf_string_conversions.h" | |
| 16 #include "base/test/test_timeouts.h" | |
| 17 #include "base/thread_task_runner_handle.h" | |
| 18 #include "base/timer/timer.h" | |
| 19 #include "chrome/browser/browser_process.h" | |
| 20 #include "chrome/browser/task_management/task_manager_tester.h" | |
| 21 #include "chrome/grit/generated_resources.h" | |
| 22 #include "extensions/strings/grit/extensions_strings.h" | |
| 23 #include "testing/gtest/include/gtest/gtest.h" | |
| 24 #include "ui/base/l10n/l10n_util.h" | |
| 25 #include "ui/base/models/table_model_observer.h" | |
| 26 | |
| 27 namespace task_manager { | |
| 28 namespace browsertest_util { | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 using TaskManagerTester = task_management::TaskManagerTester; | |
| 33 | |
| 34 // Helper class to run a message loop until a TaskManagerTester is in an | |
| 35 // expected state. If timeout occurs, an ASCII version of the task manager's | |
| 36 // contents, along with a summary of the expected state, are dumped to test | |
| 37 // output, to assist debugging. | |
| 38 class ResourceChangeObserver { | |
| 39 public: | |
| 40 ResourceChangeObserver(int required_count, | |
| 41 const base::string16& title_pattern, | |
| 42 ColumnSpecifier column_specifier, | |
| 43 size_t min_column_value) | |
| 44 : required_count_(required_count), | |
| 45 title_pattern_(title_pattern), | |
| 46 column_specifier_(column_specifier), | |
| 47 min_column_value_(min_column_value) { | |
| 48 task_manager_tester_ = TaskManagerTester::Create(base::Bind( | |
| 49 &ResourceChangeObserver::OnResourceChange, base::Unretained(this))); | |
| 50 } | |
| 51 | |
| 52 void RunUntilSatisfied() { | |
| 53 // See if the condition is satisfied without having to run the loop. This | |
| 54 // check has to be placed after the installation of the | |
| 55 // TaskManagerModelObserver, because resources may change before that. | |
| 56 if (IsSatisfied()) | |
| 57 return; | |
| 58 | |
| 59 timer_.Start(FROM_HERE, TestTimeouts::action_timeout(), this, | |
| 60 &ResourceChangeObserver::OnTimeout); | |
| 61 | |
| 62 run_loop_.Run(); | |
| 63 | |
| 64 // If we succeeded normally (no timeout), check our post condition again | |
| 65 // before returning control to the test. If it is no longer satisfied, the | |
| 66 // test is likely flaky: we were waiting for a state that was only achieved | |
| 67 // emphemerally), so treat this as a failure. | |
| 68 if (!IsSatisfied() && timer_.IsRunning()) { | |
| 69 FAIL() << "Wait condition satisfied only emphemerally. Likely test " | |
| 70 << "problem. Maybe wait instead for the state below?\n" | |
| 71 << DumpTaskManagerModel(); | |
| 72 } | |
| 73 | |
| 74 timer_.Stop(); | |
| 75 } | |
| 76 | |
| 77 private: | |
| 78 void OnResourceChange() { | |
| 79 if (!IsSatisfied()) | |
| 80 return; | |
| 81 | |
| 82 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | |
| 83 run_loop_.QuitClosure()); | |
| 84 } | |
| 85 | |
| 86 bool IsSatisfied() { return CountMatches() == required_count_; } | |
| 87 | |
| 88 int CountMatches() { | |
| 89 int match_count = 0; | |
| 90 for (int i = 0; i < task_manager_tester_->GetRowCount(); i++) { | |
| 91 if (!base::MatchPattern(task_manager_tester_->GetRowTitle(i), | |
| 92 title_pattern_)) | |
| 93 continue; | |
| 94 | |
| 95 if (GetColumnValue(i) < min_column_value_) | |
| 96 continue; | |
| 97 | |
| 98 match_count++; | |
| 99 } | |
| 100 return match_count; | |
| 101 } | |
| 102 | |
| 103 int64_t GetColumnValue(int index) { | |
| 104 return task_manager_tester_->GetColumnValue(column_specifier_, index); | |
| 105 } | |
| 106 | |
| 107 const char* GetColumnName() { | |
| 108 switch (column_specifier_) { | |
| 109 case ColumnSpecifier::COLUMN_NONE: | |
| 110 return "N/A"; | |
| 111 case ColumnSpecifier::V8_MEMORY: | |
| 112 return "V8 Memory"; | |
| 113 case ColumnSpecifier::V8_MEMORY_USED: | |
| 114 return "V8 Memory Used"; | |
| 115 case ColumnSpecifier::SQLITE_MEMORY_USED: | |
| 116 return "SQLite Memory Used"; | |
| 117 } | |
| 118 return "N/A"; | |
| 119 } | |
| 120 | |
| 121 void OnTimeout() { | |
| 122 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, | |
| 123 run_loop_.QuitClosure()); | |
| 124 FAIL() << "Timed out.\n" << DumpTaskManagerModel(); | |
| 125 } | |
| 126 | |
| 127 testing::Message DumpTaskManagerModel() { | |
| 128 testing::Message task_manager_state_dump; | |
| 129 task_manager_state_dump << "Waiting for exactly " << required_count_ | |
| 130 << " matches of wildcard pattern \"" | |
| 131 << base::UTF16ToASCII(title_pattern_) << "\""; | |
| 132 if (min_column_value_ > 0) { | |
| 133 task_manager_state_dump << " && [" << GetColumnName() | |
| 134 << " >= " << min_column_value_ << "]"; | |
| 135 } | |
| 136 task_manager_state_dump << "\nCurrently there are " << CountMatches() | |
| 137 << " matches."; | |
| 138 task_manager_state_dump << "\nCurrent Task Manager Model is:"; | |
| 139 for (int i = 0; i < task_manager_tester_->GetRowCount(); i++) { | |
| 140 task_manager_state_dump | |
| 141 << "\n > " << std::setw(40) << std::left | |
| 142 << base::UTF16ToASCII(task_manager_tester_->GetRowTitle(i)); | |
| 143 if (min_column_value_ > 0) { | |
| 144 task_manager_state_dump << " [" << GetColumnName() | |
| 145 << " == " << GetColumnValue(i) << "]"; | |
| 146 } | |
| 147 } | |
| 148 return task_manager_state_dump; | |
| 149 } | |
| 150 | |
| 151 std::unique_ptr<TaskManagerTester> task_manager_tester_; | |
| 152 const int required_count_; | |
| 153 const base::string16 title_pattern_; | |
| 154 const ColumnSpecifier column_specifier_; | |
| 155 const int64_t min_column_value_; | |
| 156 base::RunLoop run_loop_; | |
| 157 base::OneShotTimer timer_; | |
| 158 }; | |
| 159 | |
| 160 } // namespace | |
| 161 | |
| 162 void WaitForTaskManagerRows(int required_count, | |
| 163 const base::string16& title_pattern) { | |
| 164 const int column_value_dont_care = 0; | |
| 165 ResourceChangeObserver observer(required_count, title_pattern, | |
| 166 ColumnSpecifier::COLUMN_NONE, | |
| 167 column_value_dont_care); | |
| 168 observer.RunUntilSatisfied(); | |
| 169 } | |
| 170 | |
| 171 void WaitForTaskManagerStatToExceed(const base::string16& title_pattern, | |
| 172 ColumnSpecifier column_getter, | |
| 173 size_t min_column_value) { | |
| 174 const int wait_for_one_match = 1; | |
| 175 ResourceChangeObserver observer(wait_for_one_match, title_pattern, | |
| 176 column_getter, min_column_value); | |
| 177 observer.RunUntilSatisfied(); | |
| 178 } | |
| 179 | |
| 180 base::string16 MatchTab(const char* title) { | |
| 181 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX, | |
| 182 base::ASCIIToUTF16(title)); | |
| 183 } | |
| 184 | |
| 185 base::string16 MatchAnyTab() { | |
| 186 return MatchTab("*"); | |
| 187 } | |
| 188 | |
| 189 base::string16 MatchAboutBlankTab() { | |
| 190 return MatchTab("about:blank"); | |
| 191 } | |
| 192 | |
| 193 base::string16 MatchExtension(const char* title) { | |
| 194 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_EXTENSION_PREFIX, | |
| 195 base::ASCIIToUTF16(title)); | |
| 196 } | |
| 197 | |
| 198 base::string16 MatchAnyExtension() { | |
| 199 return MatchExtension("*"); | |
| 200 } | |
| 201 | |
| 202 base::string16 MatchApp(const char* title) { | |
| 203 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_APP_PREFIX, | |
| 204 base::ASCIIToUTF16(title)); | |
| 205 } | |
| 206 | |
| 207 base::string16 MatchAnyApp() { | |
| 208 return MatchApp("*"); | |
| 209 } | |
| 210 | |
| 211 base::string16 MatchWebView(const char* title) { | |
| 212 return l10n_util::GetStringFUTF16( | |
| 213 IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX, base::ASCIIToUTF16(title)); | |
| 214 } | |
| 215 | |
| 216 base::string16 MatchAnyWebView() { | |
| 217 return MatchWebView("*"); | |
| 218 } | |
| 219 | |
| 220 base::string16 MatchBackground(const char* title) { | |
| 221 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX, | |
| 222 base::ASCIIToUTF16(title)); | |
| 223 } | |
| 224 | |
| 225 base::string16 MatchAnyBackground() { | |
| 226 return MatchBackground("*"); | |
| 227 } | |
| 228 | |
| 229 base::string16 MatchPrint(const char* title) { | |
| 230 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRINT_PREFIX, | |
| 231 base::ASCIIToUTF16(title)); | |
| 232 } | |
| 233 | |
| 234 base::string16 MatchAnyPrint() { | |
| 235 return MatchPrint("*"); | |
| 236 } | |
| 237 | |
| 238 base::string16 MatchSubframe(const char* title) { | |
| 239 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_SUBFRAME_PREFIX, | |
| 240 base::ASCIIToUTF16(title)); | |
| 241 } | |
| 242 | |
| 243 base::string16 MatchAnySubframe() { | |
| 244 return MatchSubframe("*"); | |
| 245 } | |
| 246 | |
| 247 base::string16 MatchUtility(const base::string16& title) { | |
| 248 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX, title); | |
| 249 } | |
| 250 | |
| 251 base::string16 MatchAnyUtility() { | |
| 252 return MatchUtility(base::ASCIIToUTF16("*")); | |
| 253 } | |
| 254 | |
| 255 } // namespace browsertest_util | |
| 256 } // namespace task_manager | |
| OLD | NEW |