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 36using content::NavigationController; 37using content::RenderViewHost; 38using content::RenderViewHostTester; 39using content::WebContents; 40 41BrowserWithTestWindowTest::BrowserWithTestWindowTest() 42 : browser_type_(Browser::TYPE_TABBED), 43 host_desktop_type_(chrome::HOST_DESKTOP_TYPE_NATIVE), 44 hosted_app_(false) { 45} 46 47BrowserWithTestWindowTest::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 56BrowserWithTestWindowTest::~BrowserWithTestWindowTest() { 57} 58 59void 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 95void 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 123void 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 131void 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 173void 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 181void BrowserWithTestWindowTest::NavigateAndCommitActiveTab(const GURL& url) { 182 NavigateAndCommit(&browser()->tab_strip_model()->GetActiveWebContents()-> 183 GetController(), 184 url); 185} 186 187void 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 197void 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 214TestingProfile* BrowserWithTestWindowTest::CreateProfile() { 215 return new TestingProfile(); 216} 217 218void BrowserWithTestWindowTest::DestroyProfile(TestingProfile* profile) { 219 delete profile; 220} 221 222BrowserWindow* BrowserWithTestWindowTest::CreateBrowserWindow() { 223 return new TestBrowserWindow(); 224} 225 226Browser* 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) 247views::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