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