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/message_loop/message_loop.h" 8 #include "base/run_loop.h" 9 #include "base/strings/string16.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/test/test_timeouts.h" 13 #include "base/timer/timer.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/task_manager/resource_provider.h" 17 #include "chrome/browser/task_manager/task_manager.h" 18 #include "chrome/grit/generated_resources.h" 19 #include "extensions/strings/grit/extensions_strings.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 #include "ui/base/l10n/l10n_util.h" 22 23 namespace task_manager { 24 namespace browsertest_util { 25 26 namespace { 27 28 class ResourceChangeObserver : public TaskManagerModelObserver { 29 public: 30 ResourceChangeObserver(const TaskManagerModel* model, 31 int required_count, 32 const base::string16& title_pattern) 33 : model_(model), 34 required_count_(required_count), 35 title_pattern_(title_pattern) {} 36 37 virtual void OnModelChanged() OVERRIDE { 38 OnResourceChange(); 39 } 40 41 virtual void OnItemsChanged(int start, int length) OVERRIDE { 42 OnResourceChange(); 43 } 44 45 virtual void OnItemsAdded(int start, int length) OVERRIDE { 46 OnResourceChange(); 47 } 48 49 virtual void OnItemsRemoved(int start, int length) OVERRIDE { 50 OnResourceChange(); 51 } 52 53 void RunUntilSatisfied() { 54 // See if the condition is satisfied without having to run the loop. This 55 // check has to be placed after the installation of the 56 // TaskManagerModelObserver, because resources may change before that. 57 if (IsSatisfied()) 58 return; 59 60 timer_.Start(FROM_HERE, 61 TestTimeouts::action_timeout(), 62 this, 63 &ResourceChangeObserver::OnTimeout); 64 65 run_loop_.Run(); 66 67 // If we succeeded normally (no timeout), check our post condition again 68 // before returning control to the test. If it is no longer satisfied, the 69 // test is likely flaky: we were waiting for a state that was only achieved 70 // emphemerally), so treat this as a failure. 71 if (!IsSatisfied() && timer_.IsRunning()) { 72 FAIL() << "Wait condition satisfied only emphemerally. Likely test " 73 << "problem. Maybe wait instead for the state below?\n" 74 << DumpTaskManagerModel(); 75 } 76 77 timer_.Stop(); 78 } 79 80 private: 81 void OnResourceChange() { 82 if (!IsSatisfied()) 83 return; 84 85 base::MessageLoop::current()->PostTask(FROM_HERE, run_loop_.QuitClosure()); 86 } 87 88 bool IsSatisfied() { return CountMatches() == required_count_; } 89 90 int CountMatches() { 91 int match_count = 0; 92 for (int i = 0; i < model_->ResourceCount(); i++) { 93 task_manager::Resource::Type type = model_->GetResourceType(i); 94 // Skip system infrastructure resources. 95 if (type == task_manager::Resource::BROWSER || 96 type == task_manager::Resource::NACL || 97 type == task_manager::Resource::GPU || 98 type == task_manager::Resource::UTILITY || 99 type == task_manager::Resource::ZYGOTE || 100 type == task_manager::Resource::SANDBOX_HELPER) { 101 continue; 102 } 103 104 if (MatchPattern(model_->GetResourceTitle(i), title_pattern_)) { 105 match_count++; 106 } 107 } 108 return match_count; 109 } 110 111 void OnTimeout() { 112 base::MessageLoop::current()->PostTask(FROM_HERE, run_loop_.QuitClosure()); 113 FAIL() << "Timed out.\n" << DumpTaskManagerModel(); 114 } 115 116 testing::Message DumpTaskManagerModel() { 117 testing::Message task_manager_state_dump; 118 task_manager_state_dump << "Waiting for exactly " << required_count_ 119 << " matches of wildcard pattern \"" 120 << base::UTF16ToASCII(title_pattern_) << "\"\n"; 121 task_manager_state_dump << "Currently there are " << CountMatches() 122 << " matches.\n"; 123 task_manager_state_dump << "Current Task Manager Model is:\n"; 124 for (int i = 0; i < model_->ResourceCount(); i++) { 125 task_manager_state_dump 126 << " > " << base::UTF16ToASCII(model_->GetResourceTitle(i)) << "\n"; 127 } 128 return task_manager_state_dump; 129 } 130 131 const TaskManagerModel* model_; 132 const int required_count_; 133 const base::string16 title_pattern_; 134 base::RunLoop run_loop_; 135 base::OneShotTimer<ResourceChangeObserver> timer_; 136 }; 137 138 } // namespace 139 140 void WaitForTaskManagerRows(int required_count, 141 const base::string16& title_pattern) { 142 TaskManagerModel* model = TaskManager::GetInstance()->model(); 143 144 ResourceChangeObserver observer(model, required_count, title_pattern); 145 model->AddObserver(&observer); 146 observer.RunUntilSatisfied(); 147 model->RemoveObserver(&observer); 148 } 149 150 base::string16 MatchTab(const char* title) { 151 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX, 152 base::ASCIIToUTF16(title)); 153 } 154 155 base::string16 MatchAnyTab() { return MatchTab("*"); } 156 157 base::string16 MatchAboutBlankTab() { return MatchTab("about:blank"); } 158 159 base::string16 MatchExtension(const char* title) { 160 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_EXTENSION_PREFIX, 161 base::ASCIIToUTF16(title)); 162 } 163 164 base::string16 MatchAnyExtension() { return MatchExtension("*"); } 165 166 base::string16 MatchApp(const char* title) { 167 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_APP_PREFIX, 168 base::ASCIIToUTF16(title)); 169 } 170 171 base::string16 MatchAnyApp() { return MatchApp("*"); } 172 173 base::string16 MatchWebView(const char* title) { 174 return l10n_util::GetStringFUTF16( 175 IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX, 176 base::ASCIIToUTF16(title)); 177 } 178 179 base::string16 MatchAnyWebView() { return MatchWebView("*"); } 180 181 base::string16 MatchBackground(const char* title) { 182 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX, 183 base::ASCIIToUTF16(title)); 184 } 185 186 base::string16 MatchAnyBackground() { return MatchBackground("*"); } 187 188 base::string16 MatchPrint(const char* title) { 189 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PRINT_PREFIX, 190 base::ASCIIToUTF16(title)); 191 } 192 193 base::string16 MatchAnyPrint() { return MatchPrint("*"); } 194 195 } // namespace browsertest_util 196 } // namespace task_manager 197