1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
|
// 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_browsertest_util.h"
#include <iomanip>
#include <string>
#include <string_view>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/test_timeouts.h"
#include "base/timer/timer.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/task_manager/task_manager_tester.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"
#include "ui/base/models/table_model_observer.h"
namespace task_manager {
namespace browsertest_util {
namespace {
// Helper class to run a message loop until a TaskManagerTester is in an
// expected state. If timeout occurs, an ASCII version of the task manager's
// contents, along with a summary of the expected state, are dumped to test
// output, to assist debugging.
class ResourceChangeObserver {
public:
ResourceChangeObserver(size_t required_count,
const std::u16string& title_pattern,
ColumnSpecifier column_specifier,
size_t min_column_value)
: required_count_(required_count),
title_pattern_(title_pattern),
column_specifier_(column_specifier),
min_column_value_(min_column_value) {
task_manager_tester_ = TaskManagerTester::Create(base::BindRepeating(
&ResourceChangeObserver::OnResourceChange, base::Unretained(this)));
}
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::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, run_loop_.QuitClosure());
}
bool IsSatisfied() { return CountMatches() == required_count_; }
size_t CountMatches() {
size_t match_count = 0;
for (size_t i = 0; i < task_manager_tester_->GetRowCount(); i++) {
if (!base::MatchPattern(task_manager_tester_->GetRowTitle(i),
title_pattern_))
continue;
if (GetColumnValue(i) < min_column_value_)
continue;
match_count++;
}
return match_count;
}
int64_t GetColumnValue(int index) {
return task_manager_tester_->GetColumnValue(column_specifier_, index);
}
const char* GetColumnName() {
switch (column_specifier_) {
case ColumnSpecifier::COLUMN_NONE:
return "N/A";
case ColumnSpecifier::PROCESS_ID:
return "Process ID";
case ColumnSpecifier::MEMORY_FOOTPRINT:
return "Memory Footprint";
case ColumnSpecifier::V8_MEMORY:
return "V8 Memory";
case ColumnSpecifier::V8_MEMORY_USED:
return "V8 Memory Used";
case ColumnSpecifier::SQLITE_MEMORY_USED:
return "SQLite Memory Used";
case ColumnSpecifier::IDLE_WAKEUPS:
return "Idle wake ups";
case ColumnSpecifier::NETWORK_USE:
return "Network";
case ColumnSpecifier::TOTAL_NETWORK_USE:
return "Total Network";
}
return "N/A";
}
void OnTimeout() {
base::SingleThreadTaskRunner::GetCurrentDefault()->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 (size_t i = 0; i < task_manager_tester_->GetRowCount(); i++) {
task_manager_state_dump
<< "\n > " << std::setw(40) << std::left
<< base::UTF16ToASCII(task_manager_tester_->GetRowTitle(i));
if (min_column_value_ > 0) {
task_manager_state_dump << " [" << GetColumnName()
<< " == " << GetColumnValue(i) << "]";
}
}
return task_manager_state_dump;
}
std::unique_ptr<TaskManagerTester> task_manager_tester_;
const size_t required_count_;
const std::u16string title_pattern_;
const ColumnSpecifier column_specifier_;
const int64_t min_column_value_;
base::RunLoop run_loop_;
base::OneShotTimer timer_;
};
} // namespace
void WaitForTaskManagerRows(size_t required_count,
const std::u16string& title_pattern) {
constexpr size_t kColumnValueDontCare = 0;
ResourceChangeObserver observer(required_count, title_pattern,
ColumnSpecifier::COLUMN_NONE,
kColumnValueDontCare);
observer.RunUntilSatisfied();
}
void WaitForTaskManagerStatToExceed(const std::u16string& title_pattern,
ColumnSpecifier column_getter,
size_t min_column_value) {
constexpr size_t kWaitForOneMatch = 1;
ResourceChangeObserver observer(kWaitForOneMatch, title_pattern,
column_getter, min_column_value);
observer.RunUntilSatisfied();
}
std::u16string MatchTab(std::string_view title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX,
base::UTF8ToUTF16(title));
}
std::u16string MatchAnyTab() {
return MatchTab("*");
}
std::u16string MatchAboutBlankTab() {
return MatchTab("about:blank");
}
std::u16string MatchIncognitoTab(std::string_view title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_INCOGNITO_PREFIX,
base::UTF8ToUTF16(title));
}
std::u16string MatchAnyIncognitoTab() {
return MatchIncognitoTab("*");
}
std::u16string MatchExtension(const char* title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_EXTENSION_PREFIX,
base::ASCIIToUTF16(title));
}
std::u16string MatchAnyExtension() {
return MatchExtension("*");
}
std::u16string MatchApp(const char* title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_APP_PREFIX,
base::ASCIIToUTF16(title));
}
std::u16string MatchAnyApp() {
return MatchApp("*");
}
std::u16string MatchWebView(const char* title) {
return l10n_util::GetStringFUTF16(
IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX, base::ASCIIToUTF16(title));
}
std::u16string MatchAnyWebView() {
return MatchWebView("*");
}
std::u16string MatchBackground(const char* title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX,
base::ASCIIToUTF16(title));
}
std::u16string MatchAnyBackground() {
return MatchBackground("*");
}
std::u16string MatchPrint(const char* title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRINT_PREFIX,
base::ASCIIToUTF16(title));
}
std::u16string MatchAnyPrint() {
return MatchPrint("*");
}
std::u16string MatchSubframe(const char* title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_SUBFRAME_PREFIX,
base::ASCIIToUTF16(title));
}
std::u16string MatchAnySubframe() {
return MatchSubframe("*");
}
std::u16string MatchUtility(const std::u16string& title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_UTILITY_PREFIX, title);
}
std::u16string MatchAnyUtility() {
return MatchUtility(u"*");
}
std::u16string MatchBFCache(std::string_view title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACK_FORWARD_CACHE_PREFIX,
base::UTF8ToUTF16(title));
}
std::u16string MatchAnyBFCache() {
return MatchBFCache("*");
}
std::u16string MatchPrerender(std::string_view title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRERENDER_PREFIX,
base::UTF8ToUTF16(title));
}
std::u16string MatchAnyPrerender() {
return MatchPrerender("*");
}
std::u16string MatchFencedFrame(std::string_view title) {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_FENCED_FRAME_PREFIX,
base::UTF8ToUTF16(title));
}
std::u16string MatchAnyFencedFrame() {
return MatchFencedFrame("*");
}
std::u16string MatchIncognitoFencedFrame(std::string_view title) {
return l10n_util::GetStringFUTF16(
IDS_TASK_MANAGER_FENCED_FRAME_INCOGNITO_PREFIX, base::UTF8ToUTF16(title));
}
std::u16string MatchAnyIncognitoFencedFrame() {
return MatchIncognitoFencedFrame("*");
}
} // namespace browsertest_util
} // namespace task_manager
|