extension_crash_recovery_browsertest.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2010 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 "base/process_util.h" 6#include "chrome/browser/extensions/crashed_extension_infobar.h" 7#include "chrome/browser/extensions/extension_browsertest.h" 8#include "chrome/browser/extensions/extension_host.h" 9#include "chrome/browser/extensions/extension_process_manager.h" 10#include "chrome/browser/extensions/extensions_service.h" 11#include "chrome/browser/profile.h" 12#include "chrome/browser/renderer_host/render_process_host.h" 13#include "chrome/browser/renderer_host/render_view_host.h" 14#include "chrome/browser/tab_contents/infobar_delegate.h" 15#include "chrome/browser/tab_contents/tab_contents.h" 16#include "chrome/browser/ui/browser.h" 17#include "chrome/test/ui_test_utils.h" 18 19class ExtensionCrashRecoveryTest : public ExtensionBrowserTest { 20 protected: 21 ExtensionsService* GetExtensionsService() { 22 return browser()->profile()->GetExtensionsService(); 23 } 24 25 ExtensionProcessManager* GetExtensionProcessManager() { 26 return browser()->profile()->GetExtensionProcessManager(); 27 } 28 29 CrashedExtensionInfoBarDelegate* GetCrashedExtensionInfoBarDelegate( 30 int index) { 31 TabContents* current_tab = browser()->GetSelectedTabContents(); 32 EXPECT_LT(index, current_tab->infobar_delegate_count()); 33 InfoBarDelegate* delegate = current_tab->GetInfoBarDelegateAt(index); 34 return delegate->AsCrashedExtensionInfoBarDelegate(); 35 } 36 37 void AcceptCrashedExtensionInfobar(int index) { 38 CrashedExtensionInfoBarDelegate* infobar = 39 GetCrashedExtensionInfoBarDelegate(index); 40 ASSERT_TRUE(infobar); 41 infobar->Accept(); 42 WaitForExtensionLoad(); 43 } 44 45 void CancelCrashedExtensionInfobar(int index) { 46 CrashedExtensionInfoBarDelegate* infobar = 47 GetCrashedExtensionInfoBarDelegate(index); 48 ASSERT_TRUE(infobar); 49 infobar->Cancel(); 50 } 51 52 void CrashExtension(size_t index) { 53 ASSERT_LT(index, GetExtensionsService()->extensions()->size()); 54 const Extension* extension = 55 GetExtensionsService()->extensions()->at(index); 56 ASSERT_TRUE(extension); 57 std::string extension_id(extension->id()); 58 ExtensionHost* extension_host = 59 GetExtensionProcessManager()->GetBackgroundHostForExtension(extension); 60 ASSERT_TRUE(extension_host); 61 62 RenderProcessHost* extension_rph = 63 extension_host->render_view_host()->process(); 64 base::KillProcess(extension_rph->GetHandle(), 65 base::PROCESS_END_KILLED_BY_USER, false); 66 ASSERT_TRUE(WaitForExtensionCrash(extension_id)); 67 ASSERT_FALSE( 68 GetExtensionProcessManager()->GetBackgroundHostForExtension(extension)); 69 } 70 71 void CheckExtensionConsistency(size_t index) { 72 ASSERT_LT(index, GetExtensionsService()->extensions()->size()); 73 const Extension* extension = 74 GetExtensionsService()->extensions()->at(index); 75 ASSERT_TRUE(extension); 76 ExtensionHost* extension_host = 77 GetExtensionProcessManager()->GetBackgroundHostForExtension(extension); 78 ASSERT_TRUE(extension_host); 79 ASSERT_TRUE(GetExtensionProcessManager()->HasExtensionHost(extension_host)); 80 ASSERT_TRUE(extension_host->IsRenderViewLive()); 81 ASSERT_EQ(extension_host->render_view_host()->process(), 82 GetExtensionProcessManager()->GetExtensionProcess(extension->id())); 83 } 84 85 void LoadTestExtension() { 86 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture(); 87 const size_t size_before = GetExtensionsService()->extensions()->size(); 88 ASSERT_TRUE(LoadExtension( 89 test_data_dir_.AppendASCII("common").AppendASCII("background_page"))); 90 const Extension* extension = GetExtensionsService()->extensions()->back(); 91 ASSERT_TRUE(extension); 92 first_extension_id_ = extension->id(); 93 CheckExtensionConsistency(size_before); 94 } 95 96 void LoadSecondExtension() { 97 int offset = GetExtensionsService()->extensions()->size(); 98 ASSERT_TRUE(LoadExtension( 99 test_data_dir_.AppendASCII("install").AppendASCII("install"))); 100 const Extension* extension = 101 GetExtensionsService()->extensions()->at(offset); 102 ASSERT_TRUE(extension); 103 second_extension_id_ = extension->id(); 104 CheckExtensionConsistency(offset); 105 } 106 107 std::string first_extension_id_; 108 std::string second_extension_id_; 109}; 110 111IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, Basic) { 112 const size_t size_before = GetExtensionsService()->extensions()->size(); 113 LoadTestExtension(); 114 CrashExtension(size_before); 115 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 116 AcceptCrashedExtensionInfobar(0); 117 118 SCOPED_TRACE("after clicking the infobar"); 119 CheckExtensionConsistency(size_before); 120} 121 122IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, CloseAndReload) { 123 const size_t size_before = GetExtensionsService()->extensions()->size(); 124 LoadTestExtension(); 125 CrashExtension(size_before); 126 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 127 CancelCrashedExtensionInfobar(0); 128 ReloadExtension(first_extension_id_); 129 130 SCOPED_TRACE("after reloading"); 131 CheckExtensionConsistency(size_before); 132} 133 134IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ReloadIndependently) { 135 const size_t size_before = GetExtensionsService()->extensions()->size(); 136 LoadTestExtension(); 137 CrashExtension(size_before); 138 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 139 140 ReloadExtension(first_extension_id_); 141 142 SCOPED_TRACE("after reloading"); 143 CheckExtensionConsistency(size_before); 144 145 TabContents* current_tab = browser()->GetSelectedTabContents(); 146 ASSERT_TRUE(current_tab); 147 148 // The infobar should automatically hide after the extension is successfully 149 // reloaded. 150 ASSERT_EQ(0, current_tab->infobar_delegate_count()); 151} 152 153// Make sure that when we don't do anything about the crashed extension 154// and close the browser, it doesn't crash. The browser is closed implicitly 155// at the end of each browser test. 156IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, ShutdownWhileCrashed) { 157 const size_t size_before = GetExtensionsService()->extensions()->size(); 158 LoadTestExtension(); 159 CrashExtension(size_before); 160 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 161} 162 163IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashFirst) { 164 const size_t size_before = GetExtensionsService()->extensions()->size(); 165 LoadTestExtension(); 166 LoadSecondExtension(); 167 CrashExtension(size_before); 168 ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); 169 AcceptCrashedExtensionInfobar(0); 170 171 SCOPED_TRACE("after clicking the infobar"); 172 CheckExtensionConsistency(size_before); 173 CheckExtensionConsistency(size_before + 1); 174} 175 176IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsCrashSecond) { 177 const size_t size_before = GetExtensionsService()->extensions()->size(); 178 LoadTestExtension(); 179 LoadSecondExtension(); 180 CrashExtension(size_before + 1); 181 ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); 182 AcceptCrashedExtensionInfobar(0); 183 184 SCOPED_TRACE("after clicking the infobar"); 185 CheckExtensionConsistency(size_before); 186 CheckExtensionConsistency(size_before + 1); 187} 188 189IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, 190 TwoExtensionsCrashBothAtOnce) { 191 const size_t size_before = GetExtensionsService()->extensions()->size(); 192 LoadTestExtension(); 193 LoadSecondExtension(); 194 CrashExtension(size_before); 195 ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); 196 CrashExtension(size_before); 197 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 198 199 { 200 SCOPED_TRACE("first infobar"); 201 AcceptCrashedExtensionInfobar(0); 202 CheckExtensionConsistency(size_before); 203 } 204 205 { 206 SCOPED_TRACE("second infobar"); 207 AcceptCrashedExtensionInfobar(0); 208 CheckExtensionConsistency(size_before); 209 CheckExtensionConsistency(size_before + 1); 210 } 211} 212 213IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, TwoExtensionsOneByOne) { 214 const size_t size_before = GetExtensionsService()->extensions()->size(); 215 LoadTestExtension(); 216 CrashExtension(size_before); 217 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 218 LoadSecondExtension(); 219 CrashExtension(size_before); 220 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 221 222 { 223 SCOPED_TRACE("first infobar"); 224 AcceptCrashedExtensionInfobar(0); 225 CheckExtensionConsistency(size_before); 226 } 227 228 { 229 SCOPED_TRACE("second infobar"); 230 AcceptCrashedExtensionInfobar(0); 231 CheckExtensionConsistency(size_before); 232 CheckExtensionConsistency(size_before + 1); 233 } 234} 235 236// Make sure that when we don't do anything about the crashed extensions 237// and close the browser, it doesn't crash. The browser is closed implicitly 238// at the end of each browser test. 239IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, 240 TwoExtensionsShutdownWhileCrashed) { 241 const size_t size_before = GetExtensionsService()->extensions()->size(); 242 LoadTestExtension(); 243 CrashExtension(size_before); 244 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 245 LoadSecondExtension(); 246 CrashExtension(size_before); 247 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 248} 249 250IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, 251 TwoExtensionsIgnoreFirst) { 252 const size_t size_before = GetExtensionsService()->extensions()->size(); 253 LoadTestExtension(); 254 LoadSecondExtension(); 255 CrashExtension(size_before); 256 ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); 257 CrashExtension(size_before); 258 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 259 260 CancelCrashedExtensionInfobar(0); 261 AcceptCrashedExtensionInfobar(1); 262 263 SCOPED_TRACE("infobars done"); 264 ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); 265 CheckExtensionConsistency(size_before); 266} 267 268IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, 269 TwoExtensionsReloadIndependently) { 270 const size_t size_before = GetExtensionsService()->extensions()->size(); 271 LoadTestExtension(); 272 LoadSecondExtension(); 273 CrashExtension(size_before); 274 ASSERT_EQ(size_before + 1, GetExtensionsService()->extensions()->size()); 275 CrashExtension(size_before); 276 ASSERT_EQ(size_before, GetExtensionsService()->extensions()->size()); 277 278 { 279 SCOPED_TRACE("first: reload"); 280 TabContents* current_tab = browser()->GetSelectedTabContents(); 281 ASSERT_TRUE(current_tab); 282 // At the beginning we should have one infobar displayed for each extension. 283 ASSERT_EQ(2, current_tab->infobar_delegate_count()); 284 ReloadExtension(first_extension_id_); 285 // One of the infobars should hide after the extension is reloaded. 286 ASSERT_EQ(1, current_tab->infobar_delegate_count()); 287 CheckExtensionConsistency(size_before); 288 } 289 290 { 291 SCOPED_TRACE("second: infobar"); 292 AcceptCrashedExtensionInfobar(0); 293 CheckExtensionConsistency(size_before); 294 CheckExtensionConsistency(size_before + 1); 295 } 296} 297