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_.reset(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::CreateParams params(profile(), host_desktop_type_); 69 params.window = window_.get(); 70 browser_.reset(new Browser(params)); 71 } 72 73 void BrowserWithTestWindowTest::TearDown() { 74 // Some tests end up posting tasks to the DB thread that must be completed 75 // before the profile can be destroyed and the test safely shut down. 76 base::RunLoop().RunUntilIdle(); 77 78 // Reset the profile here because some profile keyed services (like the 79 // audio service) depend on test stubs that the helpers below will remove. 80 DestroyBrowserAndProfile(); 81 82 #if defined(OS_CHROMEOS) 83 ash_test_helper_->TearDown(); 84 #elif defined(USE_AURA) 85 aura_test_helper_->TearDown(); 86 #endif 87 testing::Test::TearDown(); 88 89 // A Task is leaked if we don't destroy everything, then run the message 90 // loop. 91 base::MessageLoop::current()->PostTask(FROM_HERE, 92 base::MessageLoop::QuitClosure()); 93 base::MessageLoop::current()->Run(); 94 } 95 96 void BrowserWithTestWindowTest::AddTab(Browser* browser, const GURL& url) { 97 chrome::NavigateParams params(browser, url, content::PAGE_TRANSITION_TYPED); 98 params.tabstrip_index = 0; 99 params.disposition = NEW_FOREGROUND_TAB; 100 chrome::Navigate(¶ms); 101 CommitPendingLoad(¶ms.target_contents->GetController()); 102 } 103 104 void BrowserWithTestWindowTest::CommitPendingLoad( 105 NavigationController* controller) { 106 if (!controller->GetPendingEntry()) 107 return; // Nothing to commit. 108 109 RenderViewHost* old_rvh = 110 controller->GetWebContents()->GetRenderViewHost(); 111 112 RenderViewHost* pending_rvh = RenderViewHostTester::GetPendingForController( 113 controller); 114 if (pending_rvh) { 115 // Simulate the ShouldClose_ACK that is received from the current renderer 116 // for a cross-site navigation. 117 DCHECK_NE(old_rvh, pending_rvh); 118 RenderViewHostTester::For(old_rvh)->SendShouldCloseACK(true); 119 } 120 // Commit on the pending_rvh, if one exists. 121 RenderViewHost* test_rvh = pending_rvh ? pending_rvh : old_rvh; 122 RenderViewHostTester* test_rvh_tester = RenderViewHostTester::For(test_rvh); 123 124 // Simulate a SwapOut_ACK before the navigation commits. 125 if (pending_rvh) 126 RenderViewHostTester::For(old_rvh)->SimulateSwapOutACK(); 127 128 // For new navigations, we need to send a larger page ID. For renavigations, 129 // we need to send the preexisting page ID. We can tell these apart because 130 // renavigations will have a pending_entry_index while new ones won't (they'll 131 // just have a standalong pending_entry that isn't in the list already). 132 if (controller->GetPendingEntryIndex() >= 0) { 133 test_rvh_tester->SendNavigateWithTransition( 134 controller->GetPendingEntry()->GetPageID(), 135 controller->GetPendingEntry()->GetURL(), 136 controller->GetPendingEntry()->GetTransitionType()); 137 } else { 138 test_rvh_tester->SendNavigateWithTransition( 139 controller->GetWebContents()-> 140 GetMaxPageIDForSiteInstance(test_rvh->GetSiteInstance()) + 1, 141 controller->GetPendingEntry()->GetURL(), 142 controller->GetPendingEntry()->GetTransitionType()); 143 } 144 } 145 146 void BrowserWithTestWindowTest::NavigateAndCommit( 147 NavigationController* controller, 148 const GURL& url) { 149 controller->LoadURL( 150 url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); 151 CommitPendingLoad(controller); 152 } 153 154 void BrowserWithTestWindowTest::NavigateAndCommitActiveTab(const GURL& url) { 155 NavigateAndCommit(&browser()->tab_strip_model()->GetActiveWebContents()-> 156 GetController(), 157 url); 158 } 159 160 void BrowserWithTestWindowTest::NavigateAndCommitActiveTabWithTitle( 161 Browser* navigating_browser, 162 const GURL& url, 163 const string16& title) { 164 NavigationController* controller = &navigating_browser->tab_strip_model()-> 165 GetActiveWebContents()->GetController(); 166 NavigateAndCommit(controller, url); 167 controller->GetActiveEntry()->SetTitle(title); 168 } 169 170 void BrowserWithTestWindowTest::DestroyBrowserAndProfile() { 171 if (browser_.get()) { 172 // Make sure we close all tabs, otherwise Browser isn't happy in its 173 // destructor. 174 browser()->tab_strip_model()->CloseAllTabs(); 175 browser_.reset(NULL); 176 } 177 window_.reset(NULL); 178 // Destroy the profile here - otherwise, if the profile is freed in the 179 // destructor, and a test subclass owns a resource that the profile depends 180 // on (such as g_browser_process()->local_state()) there's no way for the 181 // subclass to free it after the profile. 182 profile_.reset(NULL); 183 } 184 185 TestingProfile* BrowserWithTestWindowTest::CreateProfile() { 186 return new TestingProfile(); 187 } 188 189 BrowserWindow* BrowserWithTestWindowTest::CreateBrowserWindow() { 190 return new TestBrowserWindow(); 191 } 192