1 // Copyright (c) 2011 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.h" 6 7 #include "base/file_path.h" 8 #include "base/utf_string_conversions.h" 9 #include "chrome/browser/background_contents_service.h" 10 #include "chrome/browser/background_contents_service_factory.h" 11 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/extensions/extension_browsertest.h" 13 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/notifications/desktop_notification_service.h" 15 #include "chrome/browser/notifications/notification.h" 16 #include "chrome/browser/notifications/notification_test_util.h" 17 #include "chrome/browser/notifications/notification_ui_manager.h" 18 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h" 20 #include "chrome/browser/tabs/tab_strip_model.h" 21 #include "chrome/browser/ui/browser.h" 22 #include "chrome/browser/ui/browser_navigator.h" 23 #include "chrome/browser/ui/browser_window.h" 24 #include "chrome/common/extensions/extension.h" 25 #include "chrome/test/in_process_browser_test.h" 26 #include "chrome/test/ui_test_utils.h" 27 #include "content/browser/tab_contents/tab_contents.h" 28 #include "content/common/page_transition_types.h" 29 #include "grit/generated_resources.h" 30 #include "testing/gtest/include/gtest/gtest.h" 31 #include "ui/base/l10n/l10n_util.h" 32 33 namespace { 34 35 const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html"); 36 37 class ResourceChangeObserver : public TaskManagerModelObserver { 38 public: 39 ResourceChangeObserver(const TaskManagerModel* model, 40 int target_resource_count) 41 : model_(model), 42 target_resource_count_(target_resource_count) { 43 } 44 45 virtual void OnModelChanged() { 46 OnResourceChange(); 47 } 48 49 virtual void OnItemsChanged(int start, int length) { 50 OnResourceChange(); 51 } 52 53 virtual void OnItemsAdded(int start, int length) { 54 OnResourceChange(); 55 } 56 57 virtual void OnItemsRemoved(int start, int length) { 58 OnResourceChange(); 59 } 60 61 private: 62 void OnResourceChange() { 63 if (model_->ResourceCount() == target_resource_count_) 64 MessageLoopForUI::current()->Quit(); 65 } 66 67 const TaskManagerModel* model_; 68 const int target_resource_count_; 69 }; 70 71 // Helper class used to wait for a BackgroundContents to finish loading. 72 class BackgroundContentsListener : public NotificationObserver { 73 public: 74 explicit BackgroundContentsListener(Profile* profile) { 75 registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED, 76 Source<Profile>(profile)); 77 } 78 virtual void Observe(NotificationType type, 79 const NotificationSource& source, 80 const NotificationDetails& details) { 81 // Quit once the BackgroundContents has been loaded. 82 if (type.value == NotificationType::BACKGROUND_CONTENTS_NAVIGATED) 83 MessageLoopForUI::current()->Quit(); 84 } 85 private: 86 NotificationRegistrar registrar_; 87 }; 88 89 } // namespace 90 91 class TaskManagerBrowserTest : public ExtensionBrowserTest { 92 public: 93 TaskManagerModel* model() const { 94 return TaskManager::GetInstance()->model(); 95 } 96 97 void WaitForResourceChange(int target_count) { 98 if (model()->ResourceCount() == target_count) 99 return; 100 ResourceChangeObserver observer(model(), target_count); 101 model()->AddObserver(&observer); 102 ui_test_utils::RunMessageLoop(); 103 model()->RemoveObserver(&observer); 104 } 105 106 // Wait for any pending BackgroundContents to finish starting up. 107 void WaitForBackgroundContents() { 108 BackgroundContentsListener listener(browser()->profile()); 109 ui_test_utils::RunMessageLoop(); 110 } 111 }; 112 113 // Regression test for http://crbug.com/13361 114 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) { 115 browser()->window()->ShowTaskManager(); 116 } 117 118 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeTabContentsChanges) { 119 EXPECT_EQ(0, model()->ResourceCount()); 120 121 // Show the task manager. This populates the model, and helps with debugging 122 // (you see the task manager). 123 browser()->window()->ShowTaskManager(); 124 125 // Browser and the New Tab Page. 126 WaitForResourceChange(2); 127 128 // Open a new tab and make sure we notice that. 129 GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 130 FilePath(kTitle1File))); 131 AddTabAtIndex(0, url, PageTransition::TYPED); 132 WaitForResourceChange(3); 133 134 // Check that the third entry is a tab contents resource whose title starts 135 // starts with "Tab:". 136 ASSERT_TRUE(model()->GetResourceTabContents(2) != NULL); 137 string16 prefix = l10n_util::GetStringFUTF16( 138 IDS_TASK_MANAGER_TAB_PREFIX, string16()); 139 ASSERT_TRUE(StartsWith(model()->GetResourceTitle(2), prefix, true)); 140 141 // Close the tab and verify that we notice. 142 TabContents* first_tab = browser()->GetTabContentsAt(0); 143 ASSERT_TRUE(first_tab); 144 browser()->CloseTabContents(first_tab); 145 WaitForResourceChange(2); 146 } 147 148 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeBGContentsChanges) { 149 EXPECT_EQ(0, model()->ResourceCount()); 150 151 // Show the task manager. This populates the model, and helps with debugging 152 // (you see the task manager). 153 browser()->window()->ShowTaskManager(); 154 155 // Browser and the New Tab Page. 156 WaitForResourceChange(2); 157 158 // Open a new background contents and make sure we notice that. 159 GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 160 FilePath(kTitle1File))); 161 162 BackgroundContentsService* service = 163 BackgroundContentsServiceFactory::GetForProfile(browser()->profile()); 164 string16 application_id(ASCIIToUTF16("test_app_id")); 165 service->LoadBackgroundContents(browser()->profile(), 166 url, 167 ASCIIToUTF16("background_page"), 168 application_id); 169 WaitForResourceChange(3); 170 171 // Close the background contents and verify that we notice. 172 service->ShutdownAssociatedBackgroundContents(application_id); 173 WaitForResourceChange(2); 174 } 175 176 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillBGContents) { 177 EXPECT_EQ(0, model()->ResourceCount()); 178 179 // Show the task manager. This populates the model, and helps with debugging 180 // (you see the task manager). 181 browser()->window()->ShowTaskManager(); 182 183 // Browser and the New Tab Page. 184 WaitForResourceChange(2); 185 186 // Open a new background contents and make sure we notice that. 187 GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 188 FilePath(kTitle1File))); 189 190 BackgroundContentsService* service = 191 BackgroundContentsServiceFactory::GetForProfile(browser()->profile()); 192 string16 application_id(ASCIIToUTF16("test_app_id")); 193 service->LoadBackgroundContents(browser()->profile(), 194 url, 195 ASCIIToUTF16("background_page"), 196 application_id); 197 // Wait for the background contents process to finish loading. 198 WaitForBackgroundContents(); 199 EXPECT_EQ(3, model()->ResourceCount()); 200 201 // Kill the background contents process and verify that it disappears from the 202 // model. 203 bool found = false; 204 for (int i = 0; i < model()->ResourceCount(); ++i) { 205 if (model()->IsBackgroundResource(i)) { 206 TaskManager::GetInstance()->KillProcess(i); 207 found = true; 208 break; 209 } 210 } 211 ASSERT_TRUE(found); 212 WaitForResourceChange(2); 213 } 214 215 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionChanges) { 216 EXPECT_EQ(0, model()->ResourceCount()); 217 218 // Show the task manager. This populates the model, and helps with debugging 219 // (you see the task manager). 220 browser()->window()->ShowTaskManager(); 221 222 // Browser and the New Tab Page. 223 WaitForResourceChange(2); 224 225 // Loading an extension with a background page should result in a new 226 // resource being created for it. 227 ASSERT_TRUE(LoadExtension( 228 test_data_dir_.AppendASCII("common").AppendASCII("background_page"))); 229 WaitForResourceChange(3); 230 231 // Unload extension to avoid crash on Windows (see http://crbug.com/31663). 232 UnloadExtension(last_loaded_extension_id_); 233 WaitForResourceChange(2); 234 } 235 236 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionTabs) { 237 // Show the task manager. This populates the model, and helps with debugging 238 // (you see the task manager). 239 browser()->window()->ShowTaskManager(); 240 241 ASSERT_TRUE(LoadExtension( 242 test_data_dir_.AppendASCII("good").AppendASCII("Extensions") 243 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 244 .AppendASCII("1.0.0.0"))); 245 246 // Browser, Extension background page, and the New Tab Page. 247 WaitForResourceChange(3); 248 249 // Open a new tab to an extension URL and make sure we notice that. 250 GURL url("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/page.html"); 251 AddTabAtIndex(0, url, PageTransition::TYPED); 252 WaitForResourceChange(4); 253 254 // Check that the third entry (background) is an extension resource whose 255 // title starts with "Extension:". 256 ASSERT_EQ(TaskManager::Resource::EXTENSION, model()->GetResourceType(2)); 257 ASSERT_TRUE(model()->GetResourceTabContents(2) == NULL); 258 ASSERT_TRUE(model()->GetResourceExtension(2) != NULL); 259 string16 prefix = l10n_util::GetStringFUTF16( 260 IDS_TASK_MANAGER_EXTENSION_PREFIX, string16()); 261 ASSERT_TRUE(StartsWith(model()->GetResourceTitle(2), prefix, true)); 262 263 // Check that the fourth entry (page.html) is of type extension and has both 264 // a tab contents and an extension. The title should start with "Extension:". 265 ASSERT_EQ(TaskManager::Resource::EXTENSION, model()->GetResourceType(3)); 266 ASSERT_TRUE(model()->GetResourceTabContents(3) != NULL); 267 ASSERT_TRUE(model()->GetResourceExtension(3) != NULL); 268 ASSERT_TRUE(StartsWith(model()->GetResourceTitle(3), prefix, true)); 269 270 // Unload extension to avoid crash on Windows. 271 UnloadExtension(last_loaded_extension_id_); 272 WaitForResourceChange(2); 273 } 274 275 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeAppTabs) { 276 // Show the task manager. This populates the model, and helps with debugging 277 // (you see the task manager). 278 browser()->window()->ShowTaskManager(); 279 280 ASSERT_TRUE(LoadExtension( 281 test_data_dir_.AppendASCII("packaged_app"))); 282 ExtensionService* service = browser()->profile()->GetExtensionService(); 283 const Extension* extension = 284 service->GetExtensionById(last_loaded_extension_id_, false); 285 286 // Browser and the New Tab Page. 287 WaitForResourceChange(2); 288 289 // Open a new tab to the app's launch URL and make sure we notice that. 290 GURL url(extension->GetResourceURL("main.html")); 291 AddTabAtIndex(0, url, PageTransition::TYPED); 292 WaitForResourceChange(3); 293 294 // Check that the third entry (main.html) is of type extension and has both 295 // a tab contents and an extension. The title should start with "App:". 296 ASSERT_EQ(TaskManager::Resource::EXTENSION, model()->GetResourceType(2)); 297 ASSERT_TRUE(model()->GetResourceTabContents(2) != NULL); 298 ASSERT_TRUE(model()->GetResourceExtension(2) != NULL); 299 string16 prefix = l10n_util::GetStringFUTF16( 300 IDS_TASK_MANAGER_APP_PREFIX, string16()); 301 ASSERT_TRUE(StartsWith(model()->GetResourceTitle(2), prefix, true)); 302 303 // Unload extension to avoid crash on Windows. 304 UnloadExtension(last_loaded_extension_id_); 305 WaitForResourceChange(2); 306 } 307 308 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeNotificationChanges) { 309 EXPECT_EQ(0, model()->ResourceCount()); 310 311 // Show the task manager. 312 browser()->window()->ShowTaskManager(); 313 // Expect to see the browser and the New Tab Page renderer. 314 WaitForResourceChange(2); 315 316 // Show a notification. 317 NotificationUIManager* notifications = 318 g_browser_process->notification_ui_manager(); 319 320 string16 content = DesktopNotificationService::CreateDataUrl( 321 GURL(), ASCIIToUTF16("Hello World!"), string16(), 322 WebKit::WebTextDirectionDefault); 323 324 scoped_refptr<NotificationDelegate> del1(new MockNotificationDelegate("n1")); 325 Notification n1( 326 GURL(), GURL(content), ASCIIToUTF16("Test 1"), string16(), del1.get()); 327 scoped_refptr<NotificationDelegate> del2(new MockNotificationDelegate("n2")); 328 Notification n2( 329 GURL(), GURL(content), ASCIIToUTF16("Test 2"), string16(), del2.get()); 330 331 notifications->Add(n1, browser()->profile()); 332 WaitForResourceChange(3); 333 notifications->Add(n2, browser()->profile()); 334 WaitForResourceChange(4); 335 notifications->CancelById(n1.notification_id()); 336 WaitForResourceChange(3); 337 notifications->CancelById(n2.notification_id()); 338 WaitForResourceChange(2); 339 } 340 341 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtension) { 342 // Show the task manager. This populates the model, and helps with debugging 343 // (you see the task manager). 344 browser()->window()->ShowTaskManager(); 345 346 ASSERT_TRUE(LoadExtension( 347 test_data_dir_.AppendASCII("common").AppendASCII("background_page"))); 348 349 // Wait until we see the loaded extension in the task manager (the three 350 // resources are: the browser process, New Tab Page, and the extension). 351 WaitForResourceChange(3); 352 353 EXPECT_TRUE(model()->GetResourceExtension(0) == NULL); 354 EXPECT_TRUE(model()->GetResourceExtension(1) == NULL); 355 ASSERT_TRUE(model()->GetResourceExtension(2) != NULL); 356 357 // Kill the extension process and make sure we notice it. 358 TaskManager::GetInstance()->KillProcess(2); 359 WaitForResourceChange(2); 360 } 361 362 // Disabled, http://crbug.com/66957. 363 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, 364 DISABLED_KillExtensionAndReload) { 365 // Show the task manager. This populates the model, and helps with debugging 366 // (you see the task manager). 367 browser()->window()->ShowTaskManager(); 368 369 ASSERT_TRUE(LoadExtension( 370 test_data_dir_.AppendASCII("common").AppendASCII("background_page"))); 371 372 // Wait until we see the loaded extension in the task manager (the three 373 // resources are: the browser process, New Tab Page, and the extension). 374 WaitForResourceChange(3); 375 376 EXPECT_TRUE(model()->GetResourceExtension(0) == NULL); 377 EXPECT_TRUE(model()->GetResourceExtension(1) == NULL); 378 ASSERT_TRUE(model()->GetResourceExtension(2) != NULL); 379 380 // Kill the extension process and make sure we notice it. 381 TaskManager::GetInstance()->KillProcess(2); 382 WaitForResourceChange(2); 383 384 // Reload the extension using the "crashed extension" infobar while the task 385 // manager is still visible. Make sure we don't crash and the extension 386 // gets reloaded and noticed in the task manager. 387 TabContents* current_tab = browser()->GetSelectedTabContents(); 388 ASSERT_EQ(1U, current_tab->infobar_count()); 389 ConfirmInfoBarDelegate* delegate = 390 current_tab->GetInfoBarDelegateAt(0)->AsConfirmInfoBarDelegate(); 391 ASSERT_TRUE(delegate); 392 delegate->Accept(); 393 WaitForResourceChange(3); 394 } 395 396 // Regression test for http://crbug.com/18693. 397 // 398 // This test is crashy. See http://crbug.com/42315. 399 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, DISABLED_ReloadExtension) { 400 // Show the task manager. This populates the model, and helps with debugging 401 // (you see the task manager). 402 browser()->window()->ShowTaskManager(); 403 404 LOG(INFO) << "loading extension"; 405 ASSERT_TRUE(LoadExtension( 406 test_data_dir_.AppendASCII("common").AppendASCII("background_page"))); 407 408 // Wait until we see the loaded extension in the task manager (the three 409 // resources are: the browser process, New Tab Page, and the extension). 410 LOG(INFO) << "waiting for resource change"; 411 WaitForResourceChange(3); 412 413 EXPECT_TRUE(model()->GetResourceExtension(0) == NULL); 414 EXPECT_TRUE(model()->GetResourceExtension(1) == NULL); 415 ASSERT_TRUE(model()->GetResourceExtension(2) != NULL); 416 417 const Extension* extension = model()->GetResourceExtension(2); 418 ASSERT_TRUE(extension != NULL); 419 420 // Reload the extension a few times and make sure our resource count 421 // doesn't increase. 422 LOG(INFO) << "First extension reload"; 423 ReloadExtension(extension->id()); 424 WaitForResourceChange(3); 425 extension = model()->GetResourceExtension(2); 426 ASSERT_TRUE(extension != NULL); 427 428 LOG(INFO) << "Second extension reload"; 429 ReloadExtension(extension->id()); 430 WaitForResourceChange(3); 431 extension = model()->GetResourceExtension(2); 432 ASSERT_TRUE(extension != NULL); 433 434 LOG(INFO) << "Third extension reload"; 435 ReloadExtension(extension->id()); 436 WaitForResourceChange(3); 437 } 438 439 // Crashy, http://crbug.com/42301. 440 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, 441 DISABLED_PopulateWebCacheFields) { 442 EXPECT_EQ(0, model()->ResourceCount()); 443 444 // Show the task manager. This populates the model, and helps with debugging 445 // (you see the task manager). 446 browser()->window()->ShowTaskManager(); 447 448 // Browser and the New Tab Page. 449 WaitForResourceChange(2); 450 451 // Open a new tab and make sure we notice that. 452 GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory), 453 FilePath(kTitle1File))); 454 AddTabAtIndex(0, url, PageTransition::TYPED); 455 WaitForResourceChange(3); 456 457 // Check that we get some value for the cache columns. 458 DCHECK_NE(model()->GetResourceWebCoreImageCacheSize(2), 459 l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT)); 460 DCHECK_NE(model()->GetResourceWebCoreScriptsCacheSize(2), 461 l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT)); 462 DCHECK_NE(model()->GetResourceWebCoreCSSCacheSize(2), 463 l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT)); 464 } 465