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/common/page_transition_types.h" 18 #include "content/public/test/test_renderer_host.h" 19 20 #if defined(USE_AURA) 21 #include "ui/aura/test/aura_test_helper.h" 22 #endif 23 24 #if defined(USE_ASH) 25 #include "ash/test/ash_test_helper.h" 26 #endif 27 28 using content::NavigationController; 29 using content::RenderViewHost; 30 using content::RenderViewHostTester; 31 using content::WebContents; 32 33 BrowserWithTestWindowTest::BrowserWithTestWindowTest() 34 : host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE) { 35 } 36 37 BrowserWithTestWindowTest::~BrowserWithTestWindowTest() { 38 } 39 40 void BrowserWithTestWindowTest::SetHostDesktopType( 41 chrome::HostDesktopType host_desktop_type) { 42 DCHECK(!window_); 43 host_desktop_type_ = host_desktop_type; 44 } 45 46 void BrowserWithTestWindowTest::SetUp() { 47 testing::Test::SetUp(); 48 #if defined(OS_CHROMEOS) 49 // TODO(jamescook): Windows Ash support. This will require refactoring 50 // AshTestHelper and AuraTestHelper so they can be used at the same time, 51 // perhaps by AshTestHelper owning an AuraTestHelper. 52 ash_test_helper_.reset(new ash::test::AshTestHelper( 53 base::MessageLoopForUI::current())); 54 ash_test_helper_->SetUp(true); 55 #elif defined(USE_AURA) 56 aura_test_helper_.reset(new aura::test::AuraTestHelper( 57 base::MessageLoopForUI::current())); 58 aura_test_helper_->SetUp(); 59 #endif // USE_AURA 60 61 // Subclasses can provide their own Profile. 62 profile_ = CreateProfile(); 63 // Subclasses can provide their own test BrowserWindow. If they return NULL 64 // then Browser will create the a production BrowserWindow and the subclass 65 // is responsible for cleaning it up (usually by NativeWidget destruction). 66 window_.reset(CreateBrowserWindow()); 67 68 browser_.reset(CreateBrowser(profile(), host_desktop_type_, window_.get())); 69 } 70 71 void BrowserWithTestWindowTest::TearDown() { 72 // Some tests end up posting tasks to the DB thread that must be completed 73 // before the profile can be destroyed and the test safely shut down. 74 base::RunLoop().RunUntilIdle(); 75 76 // Reset the profile here because some profile keyed services (like the 77 // audio service) depend on test stubs that the helpers below will remove. 78 DestroyBrowserAndProfile(); 79 80 #if defined(OS_CHROMEOS) 81 ash_test_helper_->TearDown(); 82 #elif defined(USE_AURA) 83 aura_test_helper_->TearDown(); 84 #endif 85 testing::Test::TearDown(); 86 87 // A Task is leaked if we don't destroy everything, then run the message 88 // loop. 89 base::MessageLoop::current()->PostTask(FROM_HERE, 90 base::MessageLoop::QuitClosure()); 91 base::MessageLoop::current()->Run(); 92 } 93 94 void BrowserWithTestWindowTest::AddTab(Browser* browser, const GURL& url) { 95 chrome::NavigateParams params(browser, url, content::PAGE_TRANSITION_TYPED); 96 params.tabstrip_index = 0; 97 params.disposition = NEW_FOREGROUND_TAB; 98 chrome::Navigate(¶ms); 99 CommitPendingLoad(¶ms.target_contents->GetController()); 100 } 101 102 void BrowserWithTestWindowTest::CommitPendingLoad( 103 NavigationController* controller) { 104 if (!controller->GetPendingEntry()) 105 return; // Nothing to commit. 106 107 RenderViewHost* old_rvh = 108 controller->GetWebContents()->GetRenderViewHost(); 109 110 RenderViewHost* pending_rvh = RenderViewHostTester::GetPendingForController( 111 controller); 112 if (pending_rvh) { 113 // Simulate the ShouldClose_ACK that is received from the current renderer 114 // for a cross-site navigation. 115 DCHECK_NE(old_rvh, pending_rvh); 116 RenderViewHostTester::For(old_rvh)->SendShouldCloseACK(true); 117 } 118 // Commit on the pending_rvh, if one exists. 119 RenderViewHost* test_rvh = pending_rvh ? pending_rvh : old_rvh; 120 RenderViewHostTester* test_rvh_tester = RenderViewHostTester::For(test_rvh); 121 122 // Simulate a SwapOut_ACK before the navigation commits. 123 if (pending_rvh) 124 RenderViewHostTester::For(old_rvh)->SimulateSwapOutACK(); 125 126 // For new navigations, we need to send a larger page ID. For renavigations, 127 // we need to send the preexisting page ID. We can tell these apart because 128 // renavigations will have a pending_entry_index while new ones won't (they'll 129 // just have a standalong pending_entry that isn't in the list already). 130 if (controller->GetPendingEntryIndex() >= 0) { 131 test_rvh_tester->SendNavigateWithTransition( 132 controller->GetPendingEntry()->GetPageID(), 133 controller->GetPendingEntry()->GetURL(), 134 controller->GetPendingEntry()->GetTransitionType()); 135 } else { 136 test_rvh_tester->SendNavigateWithTransition( 137 controller->GetWebContents()-> 138 GetMaxPageIDForSiteInstance(test_rvh->GetSiteInstance()) + 1, 139 controller->GetPendingEntry()->GetURL(), 140 controller->GetPendingEntry()->GetTransitionType()); 141 } 142 } 143 144 void BrowserWithTestWindowTest::NavigateAndCommit( 145 NavigationController* controller, 146 const GURL& url) { 147 controller->LoadURL( 148 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); 149 CommitPendingLoad(controller); 150 } 151 152 void BrowserWithTestWindowTest::NavigateAndCommitActiveTab(const GURL& url) { 153 NavigateAndCommit(&browser()->tab_strip_model()->GetActiveWebContents()-> 154 GetController(), 155 url); 156 } 157 158 void BrowserWithTestWindowTest::NavigateAndCommitActiveTabWithTitle( 159 Browser* navigating_browser, 160 const GURL& url, 161 const string16& title) { 162 NavigationController* controller = &navigating_browser->tab_strip_model()-> 163 GetActiveWebContents()->GetController(); 164 NavigateAndCommit(controller, url); 165 controller->GetActiveEntry()->SetTitle(title); 166 } 167 168 void BrowserWithTestWindowTest::DestroyBrowserAndProfile() { 169 if (browser_.get()) { 170 // Make sure we close all tabs, otherwise Browser isn't happy in its 171 // destructor. 172 browser()->tab_strip_model()->CloseAllTabs(); 173 browser_.reset(NULL); 174 } 175 window_.reset(NULL); 176 // Destroy the profile here - otherwise, if the profile is freed in the 177 // destructor, and a test subclass owns a resource that the profile depends 178 // on (such as g_browser_process()->local_state()) there's no way for the 179 // subclass to free it after the profile. 180 if (profile_) 181 DestroyProfile(profile_); 182 profile_ = NULL; 183 } 184 185 TestingProfile* BrowserWithTestWindowTest::CreateProfile() { 186 return new TestingProfile(); 187 } 188 189 void BrowserWithTestWindowTest::DestroyProfile(TestingProfile* profile) { 190 delete profile; 191 } 192 193 BrowserWindow* BrowserWithTestWindowTest::CreateBrowserWindow() { 194 return new TestBrowserWindow(); 195 } 196 197 Browser* BrowserWithTestWindowTest::CreateBrowser( 198 Profile* profile, 199 chrome::HostDesktopType host_desktop_type, 200 BrowserWindow* browser_window) { 201 Browser::CreateParams params(profile, host_desktop_type); 202 params.window = browser_window; 203 return new Browser(params); 204 } 205