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_host.h"
8 #include "chrome/browser/extensions/extension_process_manager.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_system.h"
11 #include "chrome/browser/notifications/balloon.h"
12 #include "chrome/browser/notifications/balloon_collection.h"
13 #include "chrome/browser/notifications/balloon_host.h"
14 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
15 #include "chrome/browser/notifications/notification.h"
16 #include "chrome/browser/notifications/notification_delegate.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_commands.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/common/result_codes.h"
27 #include "ui/message_center/message_center.h"
28 #include "ui/message_center/message_center_switches.h"
29 #include "ui/message_center/message_center_util.h"
30 #include "ui/message_center/notification_list.h"
32 using content::NavigationController;
33 using content::WebContents;
34 using extensions::Extension;
36 // Tests are timing out waiting for extension to crash.
37 // http://crbug.com/174705
38 #if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_LINUX)
39 #define MAYBE_ExtensionCrashRecoveryTest DISABLED_ExtensionCrashRecoveryTest
41 #define MAYBE_ExtensionCrashRecoveryTest ExtensionCrashRecoveryTest
42 #endif // defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_LINUX)
44 class ExtensionCrashRecoveryTestBase : public ExtensionBrowserTest {
46 virtual void AcceptNotification(size_t index) = 0;
47 virtual void CancelNotification(size_t index) = 0;
48 virtual size_t CountBalloons() = 0;
50 ExtensionService* GetExtensionService() {
51 return browser()->profile()->GetExtensionService();
54 ExtensionProcessManager* GetExtensionProcessManager() {
55 return extensions::ExtensionSystem::Get(browser()->profile())->
59 void CrashExtension(std::string extension_id) {
60 const Extension* extension =
61 GetExtensionService()->GetExtensionById(extension_id, false);
62 ASSERT_TRUE(extension);
63 extensions::ExtensionHost* extension_host = GetExtensionProcessManager()->
64 GetBackgroundHostForExtension(extension_id);
65 ASSERT_TRUE(extension_host);
67 base::KillProcess(extension_host->render_process_host()->GetHandle(),
68 content::RESULT_CODE_KILLED, false);
69 ASSERT_TRUE(WaitForExtensionCrash(extension_id));
70 ASSERT_FALSE(GetExtensionProcessManager()->
71 GetBackgroundHostForExtension(extension_id));
73 // Wait for extension crash balloon to appear.
74 base::MessageLoop::current()->RunUntilIdle();
77 void CheckExtensionConsistency(std::string extension_id) {
78 const Extension* extension =
79 GetExtensionService()->extensions()->GetByID(extension_id);
80 ASSERT_TRUE(extension);
81 extensions::ExtensionHost* extension_host = GetExtensionProcessManager()->
82 GetBackgroundHostForExtension(extension_id);
83 ASSERT_TRUE(extension_host);
84 ExtensionProcessManager::ViewSet all_views =
85 GetExtensionProcessManager()->GetAllViews();
86 ExtensionProcessManager::ViewSet::const_iterator it =
87 all_views.find(extension_host->host_contents()->GetRenderViewHost());
88 ASSERT_FALSE(it == all_views.end());
89 ASSERT_TRUE(extension_host->IsRenderViewLive());
90 extensions::ProcessMap* process_map =
91 browser()->profile()->GetExtensionService()->process_map();
92 ASSERT_TRUE(process_map->Contains(
94 extension_host->render_view_host()->GetProcess()->GetID()));
97 void LoadTestExtension() {
98 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
99 const Extension* extension = LoadExtension(
100 test_data_dir_.AppendASCII("common").AppendASCII("background_page"));
101 ASSERT_TRUE(extension);
102 first_extension_id_ = extension->id();
103 CheckExtensionConsistency(first_extension_id_);
106 void LoadSecondExtension() {
107 const Extension* extension = LoadExtension(
108 test_data_dir_.AppendASCII("install").AppendASCII("install"));
109 ASSERT_TRUE(extension);
110 second_extension_id_ = extension->id();
111 CheckExtensionConsistency(second_extension_id_);
114 std::string first_extension_id_;
115 std::string second_extension_id_;
118 class MAYBE_ExtensionCrashRecoveryTest
119 : public ExtensionCrashRecoveryTestBase {
121 virtual void AcceptNotification(size_t index) OVERRIDE {
122 if (message_center::IsRichNotificationEnabled()) {
123 message_center::MessageCenter* message_center =
124 message_center::MessageCenter::Get();
125 ASSERT_GT(message_center->NotificationCount(), index);
126 message_center::NotificationList::Notifications::reverse_iterator it =
127 message_center->GetVisibleNotifications().rbegin();
128 for (size_t i=0; i < index; ++i)
130 std::string id = (*it)->id();
131 message_center->ClickOnNotification(id);
133 Balloon* balloon = GetNotificationDelegate(index);
134 ASSERT_TRUE(balloon);
137 WaitForExtensionLoad();
140 virtual void CancelNotification(size_t index) OVERRIDE {
141 if (message_center::IsRichNotificationEnabled()) {
142 message_center::MessageCenter* message_center =
143 message_center::MessageCenter::Get();
144 ASSERT_GT(message_center->NotificationCount(), index);
145 message_center::NotificationList::Notifications::reverse_iterator it =
146 message_center->GetVisibleNotifications().rbegin();
147 for (size_t i=0; i < index; i++) { it++; }
148 ASSERT_TRUE(g_browser_process->notification_ui_manager()->
149 CancelById((*it)->id()));
151 Balloon* balloon = GetNotificationDelegate(index);
152 ASSERT_TRUE(balloon);
153 std::string id = balloon->notification().notification_id();
154 ASSERT_TRUE(g_browser_process->notification_ui_manager()->CancelById(id));
158 virtual size_t CountBalloons() OVERRIDE {
159 if (message_center::IsRichNotificationEnabled())
160 return message_center::MessageCenter::Get()->NotificationCount();
162 return BalloonNotificationUIManager::GetInstanceForTesting()->
163 balloon_collection()->GetActiveBalloons().size();
167 Balloon* GetNotificationDelegate(size_t index) {
168 BalloonNotificationUIManager* manager =
169 BalloonNotificationUIManager::GetInstanceForTesting();
170 BalloonCollection::Balloons balloons =
171 manager->balloon_collection()->GetActiveBalloons();
172 return index < balloons.size() ? balloons.at(index) : NULL;
176 // Flaky: http://crbug.com/242167.
177 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest, DISABLED_Basic) {
178 const size_t size_before = GetExtensionService()->extensions()->size();
179 const size_t crash_size_before =
180 GetExtensionService()->terminated_extensions()->size();
182 CrashExtension(first_extension_id_);
183 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
184 ASSERT_EQ(crash_size_before + 1,
185 GetExtensionService()->terminated_extensions()->size());
186 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
188 SCOPED_TRACE("after clicking the balloon");
189 CheckExtensionConsistency(first_extension_id_);
190 ASSERT_EQ(crash_size_before,
191 GetExtensionService()->terminated_extensions()->size());
194 // Flaky, http://crbug.com/241191.
195 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
196 DISABLED_CloseAndReload) {
197 const size_t size_before = GetExtensionService()->extensions()->size();
198 const size_t crash_size_before =
199 GetExtensionService()->terminated_extensions()->size();
201 CrashExtension(first_extension_id_);
203 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
204 ASSERT_EQ(crash_size_before + 1,
205 GetExtensionService()->terminated_extensions()->size());
207 ASSERT_NO_FATAL_FAILURE(CancelNotification(0));
208 ReloadExtension(first_extension_id_);
210 SCOPED_TRACE("after reloading");
211 CheckExtensionConsistency(first_extension_id_);
212 ASSERT_EQ(crash_size_before,
213 GetExtensionService()->terminated_extensions()->size());
216 // Test is timing out on Windows http://crbug.com/174705.
218 #define MAYBE_ReloadIndependently DISABLED_ReloadIndependently
220 #define MAYBE_ReloadIndependently ReloadIndependently
221 #endif // defined(OS_WIN)
222 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
223 MAYBE_ReloadIndependently) {
224 const size_t size_before = GetExtensionService()->extensions()->size();
226 CrashExtension(first_extension_id_);
227 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
229 ReloadExtension(first_extension_id_);
231 SCOPED_TRACE("after reloading");
232 CheckExtensionConsistency(first_extension_id_);
234 WebContents* current_tab =
235 browser()->tab_strip_model()->GetActiveWebContents();
236 ASSERT_TRUE(current_tab);
238 // The balloon should automatically hide after the extension is successfully
240 ASSERT_EQ(0U, CountBalloons());
243 // Test is timing out on Windows http://crbug.com/174705.
245 #define MAYBE_ReloadIndependentlyChangeTabs DISABLED_ReloadIndependentlyChangeTabs
247 #define MAYBE_ReloadIndependentlyChangeTabs ReloadIndependentlyChangeTabs
248 #endif // defined(OS_WIN)
250 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
251 MAYBE_ReloadIndependentlyChangeTabs) {
252 const size_t size_before = GetExtensionService()->extensions()->size();
254 CrashExtension(first_extension_id_);
255 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
257 WebContents* original_tab =
258 browser()->tab_strip_model()->GetActiveWebContents();
259 ASSERT_TRUE(original_tab);
260 ASSERT_EQ(1U, CountBalloons());
262 // Open a new tab, but the balloon will still be there.
263 chrome::NewTab(browser());
264 WebContents* new_current_tab =
265 browser()->tab_strip_model()->GetActiveWebContents();
266 ASSERT_TRUE(new_current_tab);
267 ASSERT_NE(new_current_tab, original_tab);
268 ASSERT_EQ(1U, CountBalloons());
270 ReloadExtension(first_extension_id_);
272 SCOPED_TRACE("after reloading");
273 CheckExtensionConsistency(first_extension_id_);
275 // The balloon should automatically hide after the extension is successfully
277 ASSERT_EQ(0U, CountBalloons());
280 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
281 DISABLED_ReloadIndependentlyNavigatePage) {
282 const size_t size_before = GetExtensionService()->extensions()->size();
284 CrashExtension(first_extension_id_);
285 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
287 WebContents* current_tab =
288 browser()->tab_strip_model()->GetActiveWebContents();
289 ASSERT_TRUE(current_tab);
290 ASSERT_EQ(1U, CountBalloons());
292 // Navigate to another page.
293 ui_test_utils::NavigateToURL(
294 browser(), ui_test_utils::GetTestUrl(
295 base::FilePath(base::FilePath::kCurrentDirectory),
296 base::FilePath(FILE_PATH_LITERAL("title1.html"))));
297 ASSERT_EQ(1U, CountBalloons());
299 ReloadExtension(first_extension_id_);
301 SCOPED_TRACE("after reloading");
302 CheckExtensionConsistency(first_extension_id_);
304 // The balloon should automatically hide after the extension is successfully
306 ASSERT_EQ(0U, CountBalloons());
309 // Make sure that when we don't do anything about the crashed extension
310 // and close the browser, it doesn't crash. The browser is closed implicitly
311 // at the end of each browser test.
313 // http://crbug.com/84719
314 #if defined(OS_LINUX)
315 #define MAYBE_ShutdownWhileCrashed DISABLED_ShutdownWhileCrashed
317 #define MAYBE_ShutdownWhileCrashed ShutdownWhileCrashed
318 #endif // defined(OS_LINUX)
320 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
321 MAYBE_ShutdownWhileCrashed) {
322 const size_t size_before = GetExtensionService()->extensions()->size();
324 CrashExtension(first_extension_id_);
325 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
328 // Flaky, http://crbug.com/241245.
329 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
330 DISABLED_TwoExtensionsCrashFirst) {
331 const size_t size_before = GetExtensionService()->extensions()->size();
333 LoadSecondExtension();
334 CrashExtension(first_extension_id_);
335 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
336 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
338 SCOPED_TRACE("after clicking the balloon");
339 CheckExtensionConsistency(first_extension_id_);
340 CheckExtensionConsistency(second_extension_id_);
343 // Flaky: http://crbug.com/242196
344 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
345 DISABLED_TwoExtensionsCrashSecond) {
346 const size_t size_before = GetExtensionService()->extensions()->size();
348 LoadSecondExtension();
349 CrashExtension(second_extension_id_);
350 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
351 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
353 SCOPED_TRACE("after clicking the balloon");
354 CheckExtensionConsistency(first_extension_id_);
355 CheckExtensionConsistency(second_extension_id_);
358 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
359 TwoExtensionsCrashBothAtOnce) {
360 const size_t size_before = GetExtensionService()->extensions()->size();
361 const size_t crash_size_before =
362 GetExtensionService()->terminated_extensions()->size();
364 LoadSecondExtension();
365 CrashExtension(first_extension_id_);
366 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
367 ASSERT_EQ(crash_size_before + 1,
368 GetExtensionService()->terminated_extensions()->size());
369 CrashExtension(second_extension_id_);
370 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
371 ASSERT_EQ(crash_size_before + 2,
372 GetExtensionService()->terminated_extensions()->size());
375 SCOPED_TRACE("first balloon");
376 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
377 CheckExtensionConsistency(first_extension_id_);
381 SCOPED_TRACE("second balloon");
382 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
383 CheckExtensionConsistency(first_extension_id_);
384 CheckExtensionConsistency(second_extension_id_);
388 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
389 TwoExtensionsOneByOne) {
390 const size_t size_before = GetExtensionService()->extensions()->size();
392 CrashExtension(first_extension_id_);
393 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
394 LoadSecondExtension();
395 CrashExtension(second_extension_id_);
396 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
399 SCOPED_TRACE("first balloon");
400 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
401 CheckExtensionConsistency(first_extension_id_);
405 SCOPED_TRACE("second balloon");
406 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
407 CheckExtensionConsistency(first_extension_id_);
408 CheckExtensionConsistency(second_extension_id_);
412 // http://crbug.com/84719
413 #if defined(OS_LINUX)
414 #define MAYBE_TwoExtensionsShutdownWhileCrashed \
415 DISABLED_TwoExtensionsShutdownWhileCrashed
417 #define MAYBE_TwoExtensionsShutdownWhileCrashed \
418 TwoExtensionsShutdownWhileCrashed
419 #endif // defined(OS_LINUX)
421 // Make sure that when we don't do anything about the crashed extensions
422 // and close the browser, it doesn't crash. The browser is closed implicitly
423 // at the end of each browser test.
424 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
425 MAYBE_TwoExtensionsShutdownWhileCrashed) {
426 const size_t size_before = GetExtensionService()->extensions()->size();
428 CrashExtension(first_extension_id_);
429 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
430 LoadSecondExtension();
431 CrashExtension(second_extension_id_);
432 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
435 // Flaky, http://crbug.com/241573.
436 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
437 DISABLED_TwoExtensionsIgnoreFirst) {
438 const size_t size_before = GetExtensionService()->extensions()->size();
440 LoadSecondExtension();
441 CrashExtension(first_extension_id_);
442 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
443 CrashExtension(second_extension_id_);
444 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
446 // Accept notification 1 before canceling notification 0.
447 // Otherwise, on Linux and Windows, there is a race here, in which
448 // canceled notifications do not immediately go away.
449 ASSERT_NO_FATAL_FAILURE(AcceptNotification(1));
450 ASSERT_NO_FATAL_FAILURE(CancelNotification(0));
452 SCOPED_TRACE("balloons done");
453 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
454 CheckExtensionConsistency(second_extension_id_);
457 // Flaky, http://crbug.com/241164.
458 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
459 DISABLED_TwoExtensionsReloadIndependently) {
460 const size_t size_before = GetExtensionService()->extensions()->size();
462 LoadSecondExtension();
463 CrashExtension(first_extension_id_);
464 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
465 CrashExtension(second_extension_id_);
466 ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
469 SCOPED_TRACE("first: reload");
470 WebContents* current_tab =
471 browser()->tab_strip_model()->GetActiveWebContents();
472 ASSERT_TRUE(current_tab);
473 // At the beginning we should have one balloon displayed for each extension.
474 ASSERT_EQ(2U, CountBalloons());
475 ReloadExtension(first_extension_id_);
476 // One of the balloons should hide after the extension is reloaded.
477 ASSERT_EQ(1U, CountBalloons());
478 CheckExtensionConsistency(first_extension_id_);
482 SCOPED_TRACE("second: balloon");
483 ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
484 CheckExtensionConsistency(first_extension_id_);
485 CheckExtensionConsistency(second_extension_id_);
489 // http://crbug.com/243648
491 #define MAYBE_CrashAndUninstall DISABLED_CrashAndUninstall
493 #define MAYBE_CrashAndUninstall CrashAndUninstall
495 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
496 MAYBE_CrashAndUninstall) {
497 const size_t size_before = GetExtensionService()->extensions()->size();
498 const size_t crash_size_before =
499 GetExtensionService()->terminated_extensions()->size();
501 LoadSecondExtension();
502 CrashExtension(first_extension_id_);
503 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
504 ASSERT_EQ(crash_size_before + 1,
505 GetExtensionService()->terminated_extensions()->size());
507 ASSERT_EQ(1U, CountBalloons());
508 UninstallExtension(first_extension_id_);
509 base::MessageLoop::current()->RunUntilIdle();
511 SCOPED_TRACE("after uninstalling");
512 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
513 ASSERT_EQ(crash_size_before,
514 GetExtensionService()->terminated_extensions()->size());
515 ASSERT_EQ(0U, CountBalloons());
518 // http://crbug.com/84719
519 #if defined(OS_LINUX)
520 #define MAYBE_CrashAndUnloadAll DISABLED_CrashAndUnloadAll
522 #define MAYBE_CrashAndUnloadAll CrashAndUnloadAll
523 #endif // defined(OS_LINUX)
525 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
526 MAYBE_CrashAndUnloadAll) {
527 const size_t size_before = GetExtensionService()->extensions()->size();
528 const size_t crash_size_before =
529 GetExtensionService()->terminated_extensions()->size();
531 LoadSecondExtension();
532 CrashExtension(first_extension_id_);
533 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
534 ASSERT_EQ(crash_size_before + 1,
535 GetExtensionService()->terminated_extensions()->size());
537 GetExtensionService()->UnloadAllExtensions();
538 ASSERT_EQ(crash_size_before,
539 GetExtensionService()->terminated_extensions()->size());
542 // Fails a DCHECK on Aura and Linux: http://crbug.com/169622
543 // Failing on Windows: http://crbug.com/232340
544 #if defined(USE_AURA) || defined(OS_WIN) || defined(OS_LINUX)
545 #define MAYBE_ReloadTabsWithBackgroundPage DISABLED_ReloadTabsWithBackgroundPage
547 #define MAYBE_ReloadTabsWithBackgroundPage ReloadTabsWithBackgroundPage
550 // Test that when an extension with a background page that has a tab open
551 // crashes, the tab stays open, and reloading it reloads the extension.
552 // Regression test for issue 71629.
553 IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
554 MAYBE_ReloadTabsWithBackgroundPage) {
555 TabStripModel* tab_strip = browser()->tab_strip_model();
556 const size_t size_before = GetExtensionService()->extensions()->size();
557 const size_t crash_size_before =
558 GetExtensionService()->terminated_extensions()->size();
561 // Open a tab extension.
562 chrome::NewTab(browser());
563 ui_test_utils::NavigateToURL(
565 GURL("chrome-extension://" + first_extension_id_ + "/background.html"));
567 const int tabs_before = tab_strip->count();
568 CrashExtension(first_extension_id_);
570 // Tab should still be open, and extension should be crashed.
571 EXPECT_EQ(tabs_before, tab_strip->count());
572 EXPECT_EQ(size_before, GetExtensionService()->extensions()->size());
573 EXPECT_EQ(crash_size_before + 1,
574 GetExtensionService()->terminated_extensions()->size());
577 content::WindowedNotificationObserver observer(
578 content::NOTIFICATION_LOAD_STOP,
579 content::Source<NavigationController>(
580 &browser()->tab_strip_model()->GetActiveWebContents()->
582 chrome::Reload(browser(), CURRENT_TAB);
585 // Extension should now be loaded.
586 SCOPED_TRACE("after reloading the tab");
587 CheckExtensionConsistency(first_extension_id_);
588 ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
589 ASSERT_EQ(0U, CountBalloons());