This source file includes following definitions.
- GetExtensionService
- GetProcessManager
- GetEnabledExtensionCount
- GetTerminatedExtensionCount
- CrashExtension
- CheckExtensionConsistency
- LoadTestExtension
- LoadSecondExtension
- AcceptNotification
- CancelNotification
- CountBalloons
- GetNotificationDelegate
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
- IN_PROC_BROWSER_TEST_F
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/browser/notifications/balloon_host.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_delegate.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/result_codes.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/process_map.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_switches.h"
#include "ui/message_center/message_center_util.h"
#include "ui/message_center/notification_list.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/notifications/notification_ui_manager.h"
#else
#include "chrome/browser/notifications/balloon_notification_ui_manager.h"
#endif
using content::NavigationController;
using content::WebContents;
using extensions::Extension;
using extensions::ExtensionRegistry;
#if defined(OS_MACOSX) || defined(USE_AURA) || defined(OS_LINUX)
#define MAYBE_ExtensionCrashRecoveryTest DISABLED_ExtensionCrashRecoveryTest
#else
#define MAYBE_ExtensionCrashRecoveryTest ExtensionCrashRecoveryTest
#endif
class ExtensionCrashRecoveryTestBase : public ExtensionBrowserTest {
protected:
virtual void AcceptNotification(size_t index) = 0;
virtual void CancelNotification(size_t index) = 0;
virtual size_t CountBalloons() = 0;
ExtensionService* GetExtensionService() {
return browser()->profile()->GetExtensionService();
}
extensions::ProcessManager* GetProcessManager() {
return extensions::ExtensionSystem::Get(browser()->profile())->
process_manager();
}
size_t GetEnabledExtensionCount() {
ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile());
return registry->enabled_extensions().size();
}
size_t GetTerminatedExtensionCount() {
ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile());
return registry->terminated_extensions().size();
}
void CrashExtension(std::string extension_id) {
const Extension* extension =
GetExtensionService()->GetExtensionById(extension_id, false);
ASSERT_TRUE(extension);
extensions::ExtensionHost* extension_host = GetProcessManager()->
GetBackgroundHostForExtension(extension_id);
ASSERT_TRUE(extension_host);
base::KillProcess(extension_host->render_process_host()->GetHandle(),
content::RESULT_CODE_KILLED, false);
ASSERT_TRUE(WaitForExtensionCrash(extension_id));
ASSERT_FALSE(GetProcessManager()->
GetBackgroundHostForExtension(extension_id));
base::MessageLoop::current()->RunUntilIdle();
}
void CheckExtensionConsistency(std::string extension_id) {
const Extension* extension =
GetExtensionService()->extensions()->GetByID(extension_id);
ASSERT_TRUE(extension);
extensions::ExtensionHost* extension_host = GetProcessManager()->
GetBackgroundHostForExtension(extension_id);
ASSERT_TRUE(extension_host);
extensions::ProcessManager::ViewSet all_views =
GetProcessManager()->GetAllViews();
extensions::ProcessManager::ViewSet::const_iterator it =
all_views.find(extension_host->host_contents()->GetRenderViewHost());
ASSERT_FALSE(it == all_views.end());
ASSERT_TRUE(extension_host->IsRenderViewLive());
extensions::ProcessMap* process_map =
extensions::ProcessMap::Get(browser()->profile());
ASSERT_TRUE(process_map->Contains(
extension_id,
extension_host->render_view_host()->GetProcess()->GetID()));
}
void LoadTestExtension() {
ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("common").AppendASCII("background_page"));
ASSERT_TRUE(extension);
first_extension_id_ = extension->id();
CheckExtensionConsistency(first_extension_id_);
}
void LoadSecondExtension() {
const Extension* extension = LoadExtension(
test_data_dir_.AppendASCII("install").AppendASCII("install"));
ASSERT_TRUE(extension);
second_extension_id_ = extension->id();
CheckExtensionConsistency(second_extension_id_);
}
std::string first_extension_id_;
std::string second_extension_id_;
};
class MAYBE_ExtensionCrashRecoveryTest
: public ExtensionCrashRecoveryTestBase {
protected:
virtual void AcceptNotification(size_t index) OVERRIDE {
if (message_center::IsRichNotificationEnabled()) {
message_center::MessageCenter* message_center =
message_center::MessageCenter::Get();
ASSERT_GT(message_center->NotificationCount(), index);
message_center::NotificationList::Notifications::reverse_iterator it =
message_center->GetVisibleNotifications().rbegin();
for (size_t i=0; i < index; ++i)
it++;
std::string id = (*it)->id();
message_center->ClickOnNotification(id);
#if !defined(OS_CHROMEOS)
} else {
Balloon* balloon = GetNotificationDelegate(index);
ASSERT_TRUE(balloon);
balloon->OnClick();
#endif
}
WaitForExtensionLoad();
}
virtual void CancelNotification(size_t index) OVERRIDE {
if (message_center::IsRichNotificationEnabled()) {
message_center::MessageCenter* message_center =
message_center::MessageCenter::Get();
ASSERT_GT(message_center->NotificationCount(), index);
message_center::NotificationList::Notifications::reverse_iterator it =
message_center->GetVisibleNotifications().rbegin();
for (size_t i=0; i < index; i++) { it++; }
ASSERT_TRUE(g_browser_process->notification_ui_manager()->
CancelById((*it)->id()));
#if !defined(OS_CHROMEOS)
} else {
Balloon* balloon = GetNotificationDelegate(index);
ASSERT_TRUE(balloon);
std::string id = balloon->notification().notification_id();
ASSERT_TRUE(g_browser_process->notification_ui_manager()->CancelById(id));
#endif
}
}
virtual size_t CountBalloons() OVERRIDE {
if (message_center::IsRichNotificationEnabled())
return message_center::MessageCenter::Get()->NotificationCount();
#if defined(OS_CHROMEOS)
CHECK(false);
return 0;
#else
return BalloonNotificationUIManager::GetInstanceForTesting()->
balloon_collection()->GetActiveBalloons().size();
#endif
}
private:
#if !defined(OS_CHROMEOS)
Balloon* GetNotificationDelegate(size_t index) {
BalloonNotificationUIManager* manager =
BalloonNotificationUIManager::GetInstanceForTesting();
BalloonCollection::Balloons balloons =
manager->balloon_collection()->GetActiveBalloons();
return index < balloons.size() ? balloons.at(index) : NULL;
}
#endif
};
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest, DISABLED_Basic) {
const size_t count_before = GetEnabledExtensionCount();
const size_t crash_count_before = GetTerminatedExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
ASSERT_EQ(crash_count_before + 1, GetTerminatedExtensionCount());
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
SCOPED_TRACE("after clicking the balloon");
CheckExtensionConsistency(first_extension_id_);
ASSERT_EQ(crash_count_before, GetTerminatedExtensionCount());
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
DISABLED_CloseAndReload) {
const size_t count_before = GetEnabledExtensionCount();
const size_t crash_count_before = GetTerminatedExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
ASSERT_EQ(crash_count_before + 1, GetTerminatedExtensionCount());
ASSERT_NO_FATAL_FAILURE(CancelNotification(0));
ReloadExtension(first_extension_id_);
SCOPED_TRACE("after reloading");
CheckExtensionConsistency(first_extension_id_);
ASSERT_EQ(crash_count_before, GetTerminatedExtensionCount());
}
#if defined(OS_WIN)
#define MAYBE_ReloadIndependently DISABLED_ReloadIndependently
#else
#define MAYBE_ReloadIndependently ReloadIndependently
#endif
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
MAYBE_ReloadIndependently) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
ReloadExtension(first_extension_id_);
SCOPED_TRACE("after reloading");
CheckExtensionConsistency(first_extension_id_);
WebContents* current_tab =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(current_tab);
ASSERT_EQ(0U, CountBalloons());
}
#if defined(OS_WIN)
#define MAYBE_ReloadIndependentlyChangeTabs DISABLED_ReloadIndependentlyChangeTabs
#else
#define MAYBE_ReloadIndependentlyChangeTabs ReloadIndependentlyChangeTabs
#endif
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
MAYBE_ReloadIndependentlyChangeTabs) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
WebContents* original_tab =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(original_tab);
ASSERT_EQ(1U, CountBalloons());
chrome::NewTab(browser());
WebContents* new_current_tab =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(new_current_tab);
ASSERT_NE(new_current_tab, original_tab);
ASSERT_EQ(1U, CountBalloons());
ReloadExtension(first_extension_id_);
SCOPED_TRACE("after reloading");
CheckExtensionConsistency(first_extension_id_);
ASSERT_EQ(0U, CountBalloons());
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
DISABLED_ReloadIndependentlyNavigatePage) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
WebContents* current_tab =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(current_tab);
ASSERT_EQ(1U, CountBalloons());
ui_test_utils::NavigateToURL(
browser(), ui_test_utils::GetTestUrl(
base::FilePath(base::FilePath::kCurrentDirectory),
base::FilePath(FILE_PATH_LITERAL("title1.html"))));
ASSERT_EQ(1U, CountBalloons());
ReloadExtension(first_extension_id_);
SCOPED_TRACE("after reloading");
CheckExtensionConsistency(first_extension_id_);
ASSERT_EQ(0U, CountBalloons());
}
#if defined(OS_LINUX)
#define MAYBE_ShutdownWhileCrashed DISABLED_ShutdownWhileCrashed
#else
#define MAYBE_ShutdownWhileCrashed ShutdownWhileCrashed
#endif
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
MAYBE_ShutdownWhileCrashed) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
DISABLED_TwoExtensionsCrashFirst) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
SCOPED_TRACE("after clicking the balloon");
CheckExtensionConsistency(first_extension_id_);
CheckExtensionConsistency(second_extension_id_);
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
DISABLED_TwoExtensionsCrashSecond) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(second_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
SCOPED_TRACE("after clicking the balloon");
CheckExtensionConsistency(first_extension_id_);
CheckExtensionConsistency(second_extension_id_);
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
TwoExtensionsCrashBothAtOnce) {
const size_t count_before = GetEnabledExtensionCount();
const size_t crash_count_before = GetTerminatedExtensionCount();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
ASSERT_EQ(crash_count_before + 1, GetTerminatedExtensionCount());
CrashExtension(second_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
ASSERT_EQ(crash_count_before + 2, GetTerminatedExtensionCount());
{
SCOPED_TRACE("first balloon");
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
CheckExtensionConsistency(first_extension_id_);
}
{
SCOPED_TRACE("second balloon");
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
CheckExtensionConsistency(first_extension_id_);
CheckExtensionConsistency(second_extension_id_);
}
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
TwoExtensionsOneByOne) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
LoadSecondExtension();
CrashExtension(second_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
{
SCOPED_TRACE("first balloon");
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
CheckExtensionConsistency(first_extension_id_);
}
{
SCOPED_TRACE("second balloon");
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
CheckExtensionConsistency(first_extension_id_);
CheckExtensionConsistency(second_extension_id_);
}
}
#if defined(OS_LINUX)
#define MAYBE_TwoExtensionsShutdownWhileCrashed \
DISABLED_TwoExtensionsShutdownWhileCrashed
#else
#define MAYBE_TwoExtensionsShutdownWhileCrashed \
TwoExtensionsShutdownWhileCrashed
#endif
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
MAYBE_TwoExtensionsShutdownWhileCrashed) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
LoadSecondExtension();
CrashExtension(second_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
DISABLED_TwoExtensionsIgnoreFirst) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
CrashExtension(second_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
ASSERT_NO_FATAL_FAILURE(AcceptNotification(1));
ASSERT_NO_FATAL_FAILURE(CancelNotification(0));
SCOPED_TRACE("balloons done");
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
CheckExtensionConsistency(second_extension_id_);
}
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
DISABLED_TwoExtensionsReloadIndependently) {
const size_t count_before = GetEnabledExtensionCount();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
CrashExtension(second_extension_id_);
ASSERT_EQ(count_before, GetEnabledExtensionCount());
{
SCOPED_TRACE("first: reload");
WebContents* current_tab =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(current_tab);
ASSERT_EQ(2U, CountBalloons());
ReloadExtension(first_extension_id_);
ASSERT_EQ(1U, CountBalloons());
CheckExtensionConsistency(first_extension_id_);
}
{
SCOPED_TRACE("second: balloon");
ASSERT_NO_FATAL_FAILURE(AcceptNotification(0));
CheckExtensionConsistency(first_extension_id_);
CheckExtensionConsistency(second_extension_id_);
}
}
#if defined(OS_WIN)
#define MAYBE_CrashAndUninstall DISABLED_CrashAndUninstall
#else
#define MAYBE_CrashAndUninstall CrashAndUninstall
#endif
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
MAYBE_CrashAndUninstall) {
const size_t count_before = GetEnabledExtensionCount();
const size_t crash_count_before = GetTerminatedExtensionCount();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
ASSERT_EQ(crash_count_before + 1, GetTerminatedExtensionCount());
ASSERT_EQ(1U, CountBalloons());
UninstallExtension(first_extension_id_);
base::MessageLoop::current()->RunUntilIdle();
SCOPED_TRACE("after uninstalling");
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
ASSERT_EQ(crash_count_before, GetTerminatedExtensionCount());
ASSERT_EQ(0U, CountBalloons());
}
#if defined(OS_LINUX)
#define MAYBE_CrashAndUnloadAll DISABLED_CrashAndUnloadAll
#else
#define MAYBE_CrashAndUnloadAll CrashAndUnloadAll
#endif
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
MAYBE_CrashAndUnloadAll) {
const size_t count_before = GetEnabledExtensionCount();
const size_t crash_count_before = GetTerminatedExtensionCount();
LoadTestExtension();
LoadSecondExtension();
CrashExtension(first_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
ASSERT_EQ(crash_count_before + 1, GetTerminatedExtensionCount());
GetExtensionService()->UnloadAllExtensionsForTest();
ASSERT_EQ(crash_count_before, GetTerminatedExtensionCount());
}
#if defined(USE_AURA) || defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_ReloadTabsWithBackgroundPage DISABLED_ReloadTabsWithBackgroundPage
#else
#define MAYBE_ReloadTabsWithBackgroundPage ReloadTabsWithBackgroundPage
#endif
IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest,
MAYBE_ReloadTabsWithBackgroundPage) {
TabStripModel* tab_strip = browser()->tab_strip_model();
const size_t count_before = GetEnabledExtensionCount();
const size_t crash_count_before = GetTerminatedExtensionCount();
LoadTestExtension();
chrome::NewTab(browser());
ui_test_utils::NavigateToURL(
browser(),
GURL("chrome-extension://" + first_extension_id_ + "/background.html"));
const int tabs_before = tab_strip->count();
CrashExtension(first_extension_id_);
EXPECT_EQ(tabs_before, tab_strip->count());
EXPECT_EQ(count_before, GetEnabledExtensionCount());
EXPECT_EQ(crash_count_before + 1, GetTerminatedExtensionCount());
{
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(
&browser()->tab_strip_model()->GetActiveWebContents()->
GetController()));
chrome::Reload(browser(), CURRENT_TAB);
observer.Wait();
}
SCOPED_TRACE("after reloading the tab");
CheckExtensionConsistency(first_extension_id_);
ASSERT_EQ(count_before + 1, GetEnabledExtensionCount());
ASSERT_EQ(0U, CountBalloons());
}