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:
ResourceChangeObserver(const TaskManagerModel * model,int target_resource_count)39 ResourceChangeObserver(const TaskManagerModel* model,
40 int target_resource_count)
41 : model_(model),
42 target_resource_count_(target_resource_count) {
43 }
44
OnModelChanged()45 virtual void OnModelChanged() {
46 OnResourceChange();
47 }
48
OnItemsChanged(int start,int length)49 virtual void OnItemsChanged(int start, int length) {
50 OnResourceChange();
51 }
52
OnItemsAdded(int start,int length)53 virtual void OnItemsAdded(int start, int length) {
54 OnResourceChange();
55 }
56
OnItemsRemoved(int start,int length)57 virtual void OnItemsRemoved(int start, int length) {
58 OnResourceChange();
59 }
60
61 private:
OnResourceChange()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:
BackgroundContentsListener(Profile * profile)74 explicit BackgroundContentsListener(Profile* profile) {
75 registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
76 Source<Profile>(profile));
77 }
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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:
model() const93 TaskManagerModel* model() const {
94 return TaskManager::GetInstance()->model();
95 }
96
WaitForResourceChange(int target_count)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.
WaitForBackgroundContents()107 void WaitForBackgroundContents() {
108 BackgroundContentsListener listener(browser()->profile());
109 ui_test_utils::RunMessageLoop();
110 }
111 };
112
113 // Regression test for http://crbug.com/13361
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,ShutdownWhileOpen)114 IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) {
115 browser()->window()->ShowTaskManager();
116 }
117
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,NoticeTabContentsChanges)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
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,NoticeBGContentsChanges)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
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,KillBGContents)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
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,NoticeExtensionChanges)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
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,NoticeExtensionTabs)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
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,NoticeAppTabs)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
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,NoticeNotificationChanges)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
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,KillExtension)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.
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,DISABLED_KillExtensionAndReload)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.
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,DISABLED_ReloadExtension)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.
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,DISABLED_PopulateWebCacheFields)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