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.
5 #include "chrome/browser/browser_process.h"
6 #include "chrome/browser/extensions/extension_browsertest.h"
7 #include "chrome/browser/extensions/extension_service.h"
8 #include "chrome/browser/notifications/notification.h"
9 #include "chrome/browser/notifications/notification_delegate.h"
10 #include "chrome/browser/notifications/notification_ui_manager.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/test/base/ui_test_utils.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/common/result_codes.h"
21 #include "extensions/browser/extension_host.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/browser/process_manager.h"
25 #include "extensions/browser/process_map.h"
26 #include "ui/message_center/message_center.h"
27 #include "ui/message_center/notification_list.h"
29 using content::NavigationController
;
30 using content::WebContents
;
31 using extensions::Extension
;
32 using extensions::ExtensionRegistry
;
34 // Tests are timing out waiting for extension to crash.
35 // http://crbug.com/174705
36 #if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_LINUX)
37 #define MAYBE_ExtensionCrashRecoveryTest DISABLED_ExtensionCrashRecoveryTest
39 #define MAYBE_ExtensionCrashRecoveryTest ExtensionCrashRecoveryTest
40 #endif // defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_LINUX)
42 class ExtensionCrashRecoveryTestBase
: public ExtensionBrowserTest
{
44 virtual void AcceptNotification(size_t index
) = 0;
45 virtual void CancelNotification(size_t index
) = 0;
46 virtual size_t CountBalloons() = 0;
48 ExtensionService
* GetExtensionService() {
49 return browser()->profile()->GetExtensionService();
52 extensions::ProcessManager
* GetProcessManager() {
53 return extensions::ExtensionSystem::Get(browser()->profile())->
57 ExtensionRegistry
* GetExtensionRegistry() {
58 return ExtensionRegistry::Get(browser()->profile());
61 size_t GetEnabledExtensionCount() {
62 return GetExtensionRegistry()->enabled_extensions().size();
65 size_t GetTerminatedExtensionCount() {
66 return GetExtensionRegistry()->terminated_extensions().size();
69 void CrashExtension(const std::string
& extension_id
) {
70 const Extension
* extension
= GetExtensionRegistry()->GetExtensionById(
71 extension_id
, ExtensionRegistry::ENABLED
);
72 ASSERT_TRUE(extension
);
73 extensions::ExtensionHost
* extension_host
= GetProcessManager()->
74 GetBackgroundHostForExtension(extension_id
);
75 ASSERT_TRUE(extension_host
);
77 base::KillProcess(extension_host
->render_process_host()->GetHandle(),
78 content::RESULT_CODE_KILLED
, false);
79 ASSERT_TRUE(WaitForExtensionCrash(extension_id
));
80 ASSERT_FALSE(GetProcessManager()->
81 GetBackgroundHostForExtension(extension_id
));
83 // Wait for extension crash balloon to appear.
84 base::MessageLoop::current()->RunUntilIdle();
87 void CheckExtensionConsistency(const std::string
& extension_id
) {
88 const Extension
* extension
= GetExtensionRegistry()->GetExtensionById(
89 extension_id
, ExtensionRegistry::ENABLED
);
90 ASSERT_TRUE(extension
);
91 extensions::ExtensionHost
* extension_host
= GetProcessManager()->
92 GetBackgroundHostForExtension(extension_id
);
93 ASSERT_TRUE(extension_host
);
94 extensions::ProcessManager::ViewSet all_views
=
95 GetProcessManager()->GetAllViews();
96 extensions::ProcessManager::ViewSet::const_iterator it
=
97 all_views
.find(extension_host
->host_contents()->GetRenderViewHost());
98 ASSERT_FALSE(it
== all_views
.end());
99 ASSERT_TRUE(extension_host
->IsRenderViewLive());
100 extensions::ProcessMap
* process_map
=
101 extensions::ProcessMap::Get(browser()->profile());
102 ASSERT_TRUE(process_map
->Contains(
104 extension_host
->render_view_host()->GetProcess()->GetID()));
107 void LoadTestExtension() {
108 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
109 const Extension
* extension
= LoadExtension(
110 test_data_dir_
.AppendASCII("common").AppendASCII("background_page"));
111 ASSERT_TRUE(extension
);
112 first_extension_id_
= extension
->id();
113 CheckExtensionConsistency(first_extension_id_
);
116 void LoadSecondExtension() {
117 const Extension
* extension
= LoadExtension(
118 test_data_dir_
.AppendASCII("install").AppendASCII("install"));
119 ASSERT_TRUE(extension
);
120 second_extension_id_
= extension
->id();
121 CheckExtensionConsistency(second_extension_id_
);
124 std::string first_extension_id_
;
125 std::string second_extension_id_
;
128 class MAYBE_ExtensionCrashRecoveryTest
129 : public ExtensionCrashRecoveryTestBase
{
131 virtual void AcceptNotification(size_t index
) OVERRIDE
{
132 message_center::MessageCenter
* message_center
=
133 message_center::MessageCenter::Get();
134 ASSERT_GT(message_center
->NotificationCount(), index
);
135 message_center::NotificationList::Notifications::reverse_iterator it
=
136 message_center
->GetVisibleNotifications().rbegin();
137 for (size_t i
=0; i
< index
; ++i
)
139 std::string id
= (*it
)->id();
140 message_center
->ClickOnNotification(id
);
141 WaitForExtensionLoad();
144 virtual void CancelNotification(size_t index
) OVERRIDE
{
145 message_center::MessageCenter
* message_center
=
146 message_center::MessageCenter::Get();
147 ASSERT_GT(message_center
->NotificationCount(), index
);
148 message_center::NotificationList::Notifications::reverse_iterator it
=
149 message_center
->GetVisibleNotifications().rbegin();
150 for (size_t i
=0; i
< index
; i
++) { it
++; }
151 ASSERT_TRUE(g_browser_process
->notification_ui_manager()->
152 CancelById((*it
)->id()));
155 virtual size_t CountBalloons() OVERRIDE
{
156 return message_center::MessageCenter::Get()->NotificationCount();
160 // Flaky: http://crbug.com/242167.
161 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
, DISABLED_Basic
) {
162 const size_t count_before
= GetEnabledExtensionCount();
163 const size_t crash_count_before
= GetTerminatedExtensionCount();
165 CrashExtension(first_extension_id_
);
166 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
167 ASSERT_EQ(crash_count_before
+ 1, GetTerminatedExtensionCount());
168 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
170 SCOPED_TRACE("after clicking the balloon");
171 CheckExtensionConsistency(first_extension_id_
);
172 ASSERT_EQ(crash_count_before
, GetTerminatedExtensionCount());
175 // Flaky, http://crbug.com/241191.
176 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
177 DISABLED_CloseAndReload
) {
178 const size_t count_before
= GetEnabledExtensionCount();
179 const size_t crash_count_before
= GetTerminatedExtensionCount();
181 CrashExtension(first_extension_id_
);
183 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
184 ASSERT_EQ(crash_count_before
+ 1, GetTerminatedExtensionCount());
186 ASSERT_NO_FATAL_FAILURE(CancelNotification(0));
187 ReloadExtension(first_extension_id_
);
189 SCOPED_TRACE("after reloading");
190 CheckExtensionConsistency(first_extension_id_
);
191 ASSERT_EQ(crash_count_before
, GetTerminatedExtensionCount());
194 // Test is timing out on Windows http://crbug.com/174705.
196 #define MAYBE_ReloadIndependently DISABLED_ReloadIndependently
198 #define MAYBE_ReloadIndependently ReloadIndependently
199 #endif // defined(OS_WIN)
200 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
201 MAYBE_ReloadIndependently
) {
202 const size_t count_before
= GetEnabledExtensionCount();
204 CrashExtension(first_extension_id_
);
205 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
207 ReloadExtension(first_extension_id_
);
209 SCOPED_TRACE("after reloading");
210 CheckExtensionConsistency(first_extension_id_
);
212 WebContents
* current_tab
=
213 browser()->tab_strip_model()->GetActiveWebContents();
214 ASSERT_TRUE(current_tab
);
216 // The balloon should automatically hide after the extension is successfully
218 ASSERT_EQ(0U, CountBalloons());
221 // Test is timing out on Windows http://crbug.com/174705.
223 #define MAYBE_ReloadIndependentlyChangeTabs DISABLED_ReloadIndependentlyChangeTabs
225 #define MAYBE_ReloadIndependentlyChangeTabs ReloadIndependentlyChangeTabs
226 #endif // defined(OS_WIN)
228 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
229 MAYBE_ReloadIndependentlyChangeTabs
) {
230 const size_t count_before
= GetEnabledExtensionCount();
232 CrashExtension(first_extension_id_
);
233 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
235 WebContents
* original_tab
=
236 browser()->tab_strip_model()->GetActiveWebContents();
237 ASSERT_TRUE(original_tab
);
238 ASSERT_EQ(1U, CountBalloons());
240 // Open a new tab, but the balloon will still be there.
241 chrome::NewTab(browser());
242 WebContents
* new_current_tab
=
243 browser()->tab_strip_model()->GetActiveWebContents();
244 ASSERT_TRUE(new_current_tab
);
245 ASSERT_NE(new_current_tab
, original_tab
);
246 ASSERT_EQ(1U, CountBalloons());
248 ReloadExtension(first_extension_id_
);
250 SCOPED_TRACE("after reloading");
251 CheckExtensionConsistency(first_extension_id_
);
253 // The balloon should automatically hide after the extension is successfully
255 ASSERT_EQ(0U, CountBalloons());
258 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
259 DISABLED_ReloadIndependentlyNavigatePage
) {
260 const size_t count_before
= GetEnabledExtensionCount();
262 CrashExtension(first_extension_id_
);
263 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
265 WebContents
* current_tab
=
266 browser()->tab_strip_model()->GetActiveWebContents();
267 ASSERT_TRUE(current_tab
);
268 ASSERT_EQ(1U, CountBalloons());
270 // Navigate to another page.
271 ui_test_utils::NavigateToURL(
272 browser(), ui_test_utils::GetTestUrl(
273 base::FilePath(base::FilePath::kCurrentDirectory
),
274 base::FilePath(FILE_PATH_LITERAL("title1.html"))));
275 ASSERT_EQ(1U, CountBalloons());
277 ReloadExtension(first_extension_id_
);
279 SCOPED_TRACE("after reloading");
280 CheckExtensionConsistency(first_extension_id_
);
282 // The balloon should automatically hide after the extension is successfully
284 ASSERT_EQ(0U, CountBalloons());
287 // Make sure that when we don't do anything about the crashed extension
288 // and close the browser, it doesn't crash. The browser is closed implicitly
289 // at the end of each browser test.
291 // http://crbug.com/84719
292 #if defined(OS_LINUX)
293 #define MAYBE_ShutdownWhileCrashed DISABLED_ShutdownWhileCrashed
295 #define MAYBE_ShutdownWhileCrashed ShutdownWhileCrashed
296 #endif // defined(OS_LINUX)
298 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
299 MAYBE_ShutdownWhileCrashed
) {
300 const size_t count_before
= GetEnabledExtensionCount();
302 CrashExtension(first_extension_id_
);
303 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
306 // Flaky, http://crbug.com/241245.
307 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
308 DISABLED_TwoExtensionsCrashFirst
) {
309 const size_t count_before
= GetEnabledExtensionCount();
311 LoadSecondExtension();
312 CrashExtension(first_extension_id_
);
313 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
314 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
316 SCOPED_TRACE("after clicking the balloon");
317 CheckExtensionConsistency(first_extension_id_
);
318 CheckExtensionConsistency(second_extension_id_
);
321 // Flaky: http://crbug.com/242196
322 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
323 DISABLED_TwoExtensionsCrashSecond
) {
324 const size_t count_before
= GetEnabledExtensionCount();
326 LoadSecondExtension();
327 CrashExtension(second_extension_id_
);
328 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
329 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
331 SCOPED_TRACE("after clicking the balloon");
332 CheckExtensionConsistency(first_extension_id_
);
333 CheckExtensionConsistency(second_extension_id_
);
336 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
337 TwoExtensionsCrashBothAtOnce
) {
338 const size_t count_before
= GetEnabledExtensionCount();
339 const size_t crash_count_before
= GetTerminatedExtensionCount();
341 LoadSecondExtension();
342 CrashExtension(first_extension_id_
);
343 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
344 ASSERT_EQ(crash_count_before
+ 1, GetTerminatedExtensionCount());
345 CrashExtension(second_extension_id_
);
346 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
347 ASSERT_EQ(crash_count_before
+ 2, GetTerminatedExtensionCount());
350 SCOPED_TRACE("first balloon");
351 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
352 CheckExtensionConsistency(first_extension_id_
);
356 SCOPED_TRACE("second balloon");
357 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
358 CheckExtensionConsistency(first_extension_id_
);
359 CheckExtensionConsistency(second_extension_id_
);
363 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
364 TwoExtensionsOneByOne
) {
365 const size_t count_before
= GetEnabledExtensionCount();
367 CrashExtension(first_extension_id_
);
368 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
369 LoadSecondExtension();
370 CrashExtension(second_extension_id_
);
371 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
374 SCOPED_TRACE("first balloon");
375 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
376 CheckExtensionConsistency(first_extension_id_
);
380 SCOPED_TRACE("second balloon");
381 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
382 CheckExtensionConsistency(first_extension_id_
);
383 CheckExtensionConsistency(second_extension_id_
);
387 // http://crbug.com/84719
388 #if defined(OS_LINUX)
389 #define MAYBE_TwoExtensionsShutdownWhileCrashed \
390 DISABLED_TwoExtensionsShutdownWhileCrashed
392 #define MAYBE_TwoExtensionsShutdownWhileCrashed \
393 TwoExtensionsShutdownWhileCrashed
394 #endif // defined(OS_LINUX)
396 // Make sure that when we don't do anything about the crashed extensions
397 // and close the browser, it doesn't crash. The browser is closed implicitly
398 // at the end of each browser test.
399 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
400 MAYBE_TwoExtensionsShutdownWhileCrashed
) {
401 const size_t count_before
= GetEnabledExtensionCount();
403 CrashExtension(first_extension_id_
);
404 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
405 LoadSecondExtension();
406 CrashExtension(second_extension_id_
);
407 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
410 // Flaky, http://crbug.com/241573.
411 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
412 DISABLED_TwoExtensionsIgnoreFirst
) {
413 const size_t count_before
= GetEnabledExtensionCount();
415 LoadSecondExtension();
416 CrashExtension(first_extension_id_
);
417 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
418 CrashExtension(second_extension_id_
);
419 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
421 // Accept notification 1 before canceling notification 0.
422 // Otherwise, on Linux and Windows, there is a race here, in which
423 // canceled notifications do not immediately go away.
424 ASSERT_NO_FATAL_FAILURE(AcceptNotification(1));
425 ASSERT_NO_FATAL_FAILURE(CancelNotification(0));
427 SCOPED_TRACE("balloons done");
428 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
429 CheckExtensionConsistency(second_extension_id_
);
432 // Flaky, http://crbug.com/241164.
433 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
434 DISABLED_TwoExtensionsReloadIndependently
) {
435 const size_t count_before
= GetEnabledExtensionCount();
437 LoadSecondExtension();
438 CrashExtension(first_extension_id_
);
439 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
440 CrashExtension(second_extension_id_
);
441 ASSERT_EQ(count_before
, GetEnabledExtensionCount());
444 SCOPED_TRACE("first: reload");
445 WebContents
* current_tab
=
446 browser()->tab_strip_model()->GetActiveWebContents();
447 ASSERT_TRUE(current_tab
);
448 // At the beginning we should have one balloon displayed for each extension.
449 ASSERT_EQ(2U, CountBalloons());
450 ReloadExtension(first_extension_id_
);
451 // One of the balloons should hide after the extension is reloaded.
452 ASSERT_EQ(1U, CountBalloons());
453 CheckExtensionConsistency(first_extension_id_
);
457 SCOPED_TRACE("second: balloon");
458 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
459 CheckExtensionConsistency(first_extension_id_
);
460 CheckExtensionConsistency(second_extension_id_
);
464 // http://crbug.com/243648
466 #define MAYBE_CrashAndUninstall DISABLED_CrashAndUninstall
468 #define MAYBE_CrashAndUninstall CrashAndUninstall
470 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
471 MAYBE_CrashAndUninstall
) {
472 const size_t count_before
= GetEnabledExtensionCount();
473 const size_t crash_count_before
= GetTerminatedExtensionCount();
475 LoadSecondExtension();
476 CrashExtension(first_extension_id_
);
477 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
478 ASSERT_EQ(crash_count_before
+ 1, GetTerminatedExtensionCount());
480 ASSERT_EQ(1U, CountBalloons());
481 UninstallExtension(first_extension_id_
);
482 base::MessageLoop::current()->RunUntilIdle();
484 SCOPED_TRACE("after uninstalling");
485 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
486 ASSERT_EQ(crash_count_before
, GetTerminatedExtensionCount());
487 ASSERT_EQ(0U, CountBalloons());
490 // http://crbug.com/84719
491 #if defined(OS_LINUX)
492 #define MAYBE_CrashAndUnloadAll DISABLED_CrashAndUnloadAll
494 #define MAYBE_CrashAndUnloadAll CrashAndUnloadAll
495 #endif // defined(OS_LINUX)
497 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
498 MAYBE_CrashAndUnloadAll
) {
499 const size_t count_before
= GetEnabledExtensionCount();
500 const size_t crash_count_before
= GetTerminatedExtensionCount();
502 LoadSecondExtension();
503 CrashExtension(first_extension_id_
);
504 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
505 ASSERT_EQ(crash_count_before
+ 1, GetTerminatedExtensionCount());
507 GetExtensionService()->UnloadAllExtensionsForTest();
508 ASSERT_EQ(crash_count_before
, GetTerminatedExtensionCount());
511 // Fails a DCHECK on Aura and Linux: http://crbug.com/169622
512 // Failing on Windows: http://crbug.com/232340
513 #if defined(USE_AURA)
514 #define MAYBE_ReloadTabsWithBackgroundPage DISABLED_ReloadTabsWithBackgroundPage
516 #define MAYBE_ReloadTabsWithBackgroundPage ReloadTabsWithBackgroundPage
519 // Test that when an extension with a background page that has a tab open
520 // crashes, the tab stays open, and reloading it reloads the extension.
521 // Regression test for issue 71629.
522 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest
,
523 MAYBE_ReloadTabsWithBackgroundPage
) {
524 TabStripModel
* tab_strip
= browser()->tab_strip_model();
525 const size_t count_before
= GetEnabledExtensionCount();
526 const size_t crash_count_before
= GetTerminatedExtensionCount();
529 // Open a tab extension.
530 chrome::NewTab(browser());
531 ui_test_utils::NavigateToURL(
533 GURL("chrome-extension://" + first_extension_id_
+ "/background.html"));
535 const int tabs_before
= tab_strip
->count();
536 CrashExtension(first_extension_id_
);
538 // Tab should still be open, and extension should be crashed.
539 EXPECT_EQ(tabs_before
, tab_strip
->count());
540 EXPECT_EQ(count_before
, GetEnabledExtensionCount());
541 EXPECT_EQ(crash_count_before
+ 1, GetTerminatedExtensionCount());
544 content::WindowedNotificationObserver
observer(
545 content::NOTIFICATION_LOAD_STOP
,
546 content::Source
<NavigationController
>(
547 &browser()->tab_strip_model()->GetActiveWebContents()->
549 chrome::Reload(browser(), CURRENT_TAB
);
552 // Extension should now be loaded.
553 SCOPED_TRACE("after reloading the tab");
554 CheckExtensionConsistency(first_extension_id_
);
555 ASSERT_EQ(count_before
+ 1, GetEnabledExtensionCount());
556 ASSERT_EQ(0U, CountBalloons());