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. 4 5 #include "chrome/test/base/browser_with_test_window_test.h" 6 7 #include "base/run_loop.h" 8 #include "chrome/browser/profiles/profile_destroyer.h" 9 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/browser_navigator.h" 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" 12 #include "chrome/common/render_messages.h" 13 #include "chrome/test/base/testing_profile.h" 14 #include "content/public/browser/navigation_controller.h" 15 #include "content/public/browser/navigation_entry.h" 16 #include "content/public/browser/web_contents.h" 17 #include "content/public/test/test_renderer_host.h" 18 #include "ui/base/page_transition_types.h" 19 20 #if defined(USE_AURA) 21 #include "ui/aura/test/aura_test_helper.h" 22 #include "ui/compositor/compositor.h" 23 #include "ui/compositor/test/context_factories_for_test.h" 24 #include "ui/wm/core/default_activation_client.h" 25 #endif 26 27 #if defined(USE_ASH) 28 #include "ash/test/ash_test_helper.h" 29 #include "ash/test/ash_test_views_delegate.h" 30 #endif 31 32 #if defined(TOOLKIT_VIEWS) 33 #include "ui/views/test/test_views_delegate.h" 34 #endif 35 36 using content::NavigationController; 37 using content::RenderViewHost; 38 using content::RenderViewHostTester; 39 using content::WebContents; 40 41 BrowserWithTestWindowTest::BrowserWithTestWindowTest() 42 : browser_type_(Browser::TYPE_TABBED), 43 host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE), 44 hosted_app_(false) { 45 } 46 47 BrowserWithTestWindowTest::BrowserWithTestWindowTest( 48 Browser::Type browser_type, 49 chrome::HostDesktopType host_desktop_type, 50 bool hosted_app) 51 : browser_type_(browser_type), 52 host_desktop_type_(host_desktop_type), 53 hosted_app_(hosted_app) { 54 } 55 56 BrowserWithTestWindowTest::~BrowserWithTestWindowTest() { 57 } 58 59 void BrowserWithTestWindowTest::SetUp() { 60 testing::Test::SetUp(); 61 #if defined(OS_CHROMEOS) 62 // TODO(jamescook): Windows Ash support. This will require refactoring 63 // AshTestHelper and AuraTestHelper so they can be used at the same time, 64 // perhaps by AshTestHelper owning an AuraTestHelper. Also, need to cleanup 65 // CreateViewsDelegate() below when cleanup done. 66 ash_test_helper_.reset(new ash::test::AshTestHelper( 67 base::MessageLoopForUI::current())); 68 ash_test_helper_->SetUp(true); 69 #elif defined(USE_AURA) 70 // The ContextFactory must exist before any Compositors are created. 71 bool enable_pixel_output = false; 72 ui::ContextFactory* context_factory = 73 ui::InitializeContextFactoryForTests(enable_pixel_output); 74 75 aura_test_helper_.reset(new aura::test::AuraTestHelper( 76 base::MessageLoopForUI::current())); 77 aura_test_helper_->SetUp(context_factory); 78 new wm::DefaultActivationClient(aura_test_helper_->root_window()); 79 #endif // USE_AURA 80 #if !defined(OS_CHROMEOS) && defined(TOOLKIT_VIEWS) 81 views_delegate_.reset(CreateViewsDelegate()); 82 #endif 83 84 // Subclasses can provide their own Profile. 85 profile_ = CreateProfile(); 86 // Subclasses can provide their own test BrowserWindow. If they return NULL 87 // then Browser will create the a production BrowserWindow and the subclass 88 // is responsible for cleaning it up (usually by NativeWidget destruction). 89 window_.reset(CreateBrowserWindow()); 90 91 browser_.reset(CreateBrowser(profile(), browser_type_, hosted_app_, 92 host_desktop_type_, window_.get())); 93 } 94 95 void BrowserWithTestWindowTest::TearDown() { 96 // Some tests end up posting tasks to the DB thread that must be completed 97 // before the profile can be destroyed and the test safely shut down. 98 base::RunLoop().RunUntilIdle(); 99 100 // Reset the profile here because some profile keyed services (like the 101 // audio service) depend on test stubs that the helpers below will remove. 102 DestroyBrowserAndProfile(); 103 104 #if defined(OS_CHROMEOS) 105 ash_test_helper_->TearDown(); 106 #elif defined(USE_AURA) 107 aura_test_helper_->TearDown(); 108 ui::TerminateContextFactoryForTests(); 109 #endif 110 testing::Test::TearDown(); 111 112 // A Task is leaked if we don't destroy everything, then run the message 113 // loop. 114 base::MessageLoop::current()->PostTask(FROM_HERE, 115 base::MessageLoop::QuitClosure()); 116 base::MessageLoop::current()->Run(); 117 118 #if defined(TOOLKIT_VIEWS) 119 views_delegate_.reset(NULL); 120 #endif 121 } 122 123 void BrowserWithTestWindowTest::AddTab(Browser* browser, const GURL& url) { 124 chrome::NavigateParams params(browser, url, ui::PAGE_TRANSITION_TYPED); 125 params.tabstrip_index = 0; 126 params.disposition = NEW_FOREGROUND_TAB; 127 chrome::Navigate(¶ms); 128 CommitPendingLoad(¶ms.target_contents->GetController()); 129 } 130 131 void BrowserWithTestWindowTest::CommitPendingLoad( 132 NavigationController* controller) { 133 if (!controller->GetPendingEntry()) 134 return; // Nothing to commit. 135 136 RenderViewHost* old_rvh = 137 controller->GetWebContents()->GetRenderViewHost(); 138 139 RenderViewHost* pending_rvh = RenderViewHostTester::GetPendingForController( 140 controller); 141 if (pending_rvh) { 142 // Simulate the BeforeUnload_ACK that is received from the current renderer 143 // for a cross-site navigation. 144 DCHECK_NE(old_rvh, pending_rvh); 145 RenderViewHostTester::For(old_rvh)->SendBeforeUnloadACK(true); 146 } 147 // Commit on the pending_rvh, if one exists. 148 RenderViewHost* test_rvh = pending_rvh ? pending_rvh : old_rvh; 149 RenderViewHostTester* test_rvh_tester = RenderViewHostTester::For(test_rvh); 150 151 // Simulate a SwapOut_ACK before the navigation commits. 152 if (pending_rvh) 153 RenderViewHostTester::For(old_rvh)->SimulateSwapOutACK(); 154 155 // For new navigations, we need to send a larger page ID. For renavigations, 156 // we need to send the preexisting page ID. We can tell these apart because 157 // renavigations will have a pending_entry_index while new ones won't (they'll 158 // just have a standalong pending_entry that isn't in the list already). 159 if (controller->GetPendingEntryIndex() >= 0) { 160 test_rvh_tester->SendNavigateWithTransition( 161 controller->GetPendingEntry()->GetPageID(), 162 controller->GetPendingEntry()->GetURL(), 163 controller->GetPendingEntry()->GetTransitionType()); 164 } else { 165 test_rvh_tester->SendNavigateWithTransition( 166 controller->GetWebContents()-> 167 GetMaxPageIDForSiteInstance(test_rvh->GetSiteInstance()) + 1, 168 controller->GetPendingEntry()->GetURL(), 169 controller->GetPendingEntry()->GetTransitionType()); 170 } 171 } 172 173 void BrowserWithTestWindowTest::NavigateAndCommit( 174 NavigationController* controller, 175 const GURL& url) { 176 controller->LoadURL( 177 url, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); 178 CommitPendingLoad(controller); 179 } 180 181 void BrowserWithTestWindowTest::NavigateAndCommitActiveTab(const GURL& url) { 182 NavigateAndCommit(&browser()->tab_strip_model()->GetActiveWebContents()-> 183 GetController(), 184 url); 185 } 186 187 void BrowserWithTestWindowTest::NavigateAndCommitActiveTabWithTitle( 188 Browser* navigating_browser, 189 const GURL& url, 190 const base::string16& title) { 191 NavigationController* controller = &navigating_browser->tab_strip_model()-> 192 GetActiveWebContents()->GetController(); 193 NavigateAndCommit(controller, url); 194 controller->GetActiveEntry()->SetTitle(title); 195 } 196 197 void BrowserWithTestWindowTest::DestroyBrowserAndProfile() { 198 if (browser_.get()) { 199 // Make sure we close all tabs, otherwise Browser isn't happy in its 200 // destructor. 201 browser()->tab_strip_model()->CloseAllTabs(); 202 browser_.reset(NULL); 203 } 204 window_.reset(NULL); 205 // Destroy the profile here - otherwise, if the profile is freed in the 206 // destructor, and a test subclass owns a resource that the profile depends 207 // on (such as g_browser_process()->local_state()) there's no way for the 208 // subclass to free it after the profile. 209 if (profile_) 210 DestroyProfile(profile_); 211 profile_ = NULL; 212 } 213 214 TestingProfile* BrowserWithTestWindowTest::CreateProfile() { 215 return new TestingProfile(); 216 } 217 218 void BrowserWithTestWindowTest::DestroyProfile(TestingProfile* profile) { 219 delete profile; 220 } 221 222 BrowserWindow* BrowserWithTestWindowTest::CreateBrowserWindow() { 223 return new TestBrowserWindow(); 224 } 225 226 Browser* BrowserWithTestWindowTest::CreateBrowser( 227 Profile* profile, 228 Browser::Type browser_type, 229 bool hosted_app, 230 chrome::HostDesktopType host_desktop_type, 231 BrowserWindow* browser_window) { 232 Browser::CreateParams params(profile, host_desktop_type); 233 if (hosted_app) { 234 params = Browser::CreateParams::CreateForApp("Test", 235 true /* trusted_source */, 236 gfx::Rect(), 237 profile, 238 host_desktop_type); 239 } else { 240 params.type = browser_type; 241 } 242 params.window = browser_window; 243 return new Browser(params); 244 } 245 246 #if !defined(OS_CHROMEOS) && defined(TOOLKIT_VIEWS) 247 views::ViewsDelegate* BrowserWithTestWindowTest::CreateViewsDelegate() { 248 #if defined(USE_ASH) 249 return new ash::test::AshTestViewsDelegate; 250 #else 251 return new views::TestViewsDelegate; 252 #endif 253 } 254 #endif 255