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 "base/file_util.h" 6 #include "base/path_service.h" 7 #include "base/prefs/testing_pref_service.h" 8 #include "base/run_loop.h" 9 #include "base/strings/string_split.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/threading/sequenced_worker_pool.h" 13 #include "chrome/app/chrome_command_ids.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/page_cycler/page_cycler.h" 16 #include "chrome/browser/ui/browser.h" 17 #include "chrome/browser/ui/browser_list.h" 18 #include "chrome/browser/ui/tabs/tab_strip_model.h" 19 #include "chrome/common/chrome_paths.h" 20 #include "chrome/common/url_constants.h" 21 #include "chrome/test/base/browser_with_test_window_test.h" 22 #include "content/public/browser/render_view_host.h" 23 #include "content/public/test/test_browser_thread.h" 24 #include "net/base/net_errors.h" 25 #include "testing/gmock/include/gmock/gmock.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 28 using ::testing::_; 29 using ::testing::Invoke; 30 using content::RenderViewHost; 31 using content::TestBrowserThread; 32 using content::WebContentsObserver; 33 using base::ContentsEqual; 34 using base::PathExists; 35 36 namespace { 37 const int kFrameID = 1; 38 const bool kIsMainFrame = true; 39 const GURL kAboutURL = GURL(content::kAboutBlankURL); 40 } // namespace 41 42 class MockPageCycler : public PageCycler { 43 public: 44 MockPageCycler(Browser* browser, base::FilePath urls_file, 45 base::FilePath errors_file) 46 : PageCycler(browser, urls_file) { 47 set_errors_file(errors_file); 48 } 49 50 MockPageCycler(Browser* browser, 51 base::FilePath urls_file, 52 base::FilePath errors_file, 53 base::FilePath stats_file) 54 : PageCycler(browser, urls_file) { 55 set_stats_file(stats_file); 56 set_errors_file(errors_file); 57 } 58 59 MOCK_METHOD4(DidFinishLoad, void(int64 frame_id, 60 const GURL& validated_url, 61 bool is_main_frame, 62 RenderViewHost* render_view_host)); 63 MOCK_METHOD6(DidFailProvisionalLoad, void(int64 frame_id, 64 bool is_main_frame, 65 const GURL& validated_url, 66 int error_code, 67 const string16& error_description, 68 RenderViewHost* render_view_host)); 69 MOCK_METHOD1(RenderProcessGone, void(base::TerminationStatus status)); 70 71 void PageCyclerDidFailProvisionalLoad( 72 int64 frame_id, 73 bool is_main_frame, 74 const GURL& validated_url, 75 int error_code, 76 const string16& error_description, 77 RenderViewHost* render_view_host) { 78 PageCycler::DidFailProvisionalLoad(frame_id, is_main_frame, 79 validated_url, 80 error_code, error_description, 81 render_view_host); 82 } 83 84 void PageCyclerDidFinishLoad(int64 frame_id, 85 const GURL& validated_url, 86 bool is_main_frame, 87 RenderViewHost* render_view_host) { 88 PageCycler::DidFinishLoad( 89 frame_id, validated_url, is_main_frame, render_view_host); 90 } 91 92 private: 93 // We need to override Finish() because the calls to exit the browser in a 94 // real PageCycler do not work in unittests (they interfere with later tests). 95 virtual void Finish() OVERRIDE { 96 BrowserList::RemoveObserver(this); 97 Release(); 98 } 99 100 virtual ~MockPageCycler() {}\ 101 102 DISALLOW_COPY_AND_ASSIGN(MockPageCycler); 103 }; 104 105 class PageCyclerTest : public BrowserWithTestWindowTest { 106 public: 107 PageCyclerTest() { 108 } 109 110 virtual ~PageCyclerTest() { 111 } 112 113 virtual void SetUp() OVERRIDE { 114 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_); 115 test_data_dir_ = test_data_dir_.AppendASCII("page_cycler"); 116 117 BrowserWithTestWindowTest::SetUp(); 118 AddTab(browser(), kAboutURL); 119 ASSERT_FALSE(browser()->tab_strip_model()->GetActiveWebContents() == NULL); 120 } 121 122 void InitFilePaths(const base::FilePath& temp_path) { 123 errors_file_ = temp_path.AppendASCII("errors_file"); 124 stats_file_ = temp_path.AppendASCII("stats_file"); 125 126 CHECK(!base::PathExists(errors_file_)); 127 CHECK(!base::PathExists(stats_file_)); 128 } 129 130 void FailProvisionalLoad(int error_code, string16& error_description) { 131 FOR_EACH_OBSERVER( 132 WebContentsObserver, 133 observers_, 134 DidFailProvisionalLoad(kFrameID, kIsMainFrame, kAboutURL, error_code, 135 error_description, NULL)); 136 PumpLoop(); 137 } 138 139 void FinishLoad() { 140 FOR_EACH_OBSERVER( 141 WebContentsObserver, 142 observers_, 143 DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame, NULL)); 144 PumpLoop(); 145 } 146 147 void RunPageCycler() { 148 page_cycler_->Run(); 149 PumpLoop(); 150 } 151 152 void PumpLoop() { 153 content::BrowserThread::GetBlockingPool()->FlushForTesting(); 154 base::RunLoop().RunUntilIdle(); 155 } 156 157 void CloseBrowser() { 158 DestroyBrowserAndProfile(); 159 PumpLoop(); 160 } 161 162 MockPageCycler* page_cycler() { 163 return page_cycler_.get(); 164 } 165 166 void set_page_cycler(MockPageCycler* page_cycler) { 167 page_cycler_ = page_cycler; 168 observers_.AddObserver(page_cycler); 169 } 170 171 const std::vector<GURL>* urls_for_test() { 172 return page_cycler_->urls_for_test(); 173 } 174 175 base::FilePath stats_file() { 176 return stats_file_; 177 } 178 179 base::FilePath errors_file() { 180 return errors_file_; 181 } 182 183 base::FilePath urls_file() { 184 return test_data_dir_.AppendASCII("about_url"); 185 } 186 187 base::FilePath test_data_dir() { 188 return test_data_dir_; 189 } 190 191 private: 192 ObserverList<WebContentsObserver> observers_; 193 scoped_refptr<MockPageCycler> page_cycler_; 194 base::FilePath test_data_dir_; 195 base::FilePath stats_file_; 196 base::FilePath errors_file_; 197 base::FilePath urls_file_; 198 }; 199 200 TEST_F(PageCyclerTest, FailProvisionalLoads) { 201 const base::FilePath errors_expected_file = 202 test_data_dir().AppendASCII("errors_expected"); 203 204 base::ScopedTempDir temp; 205 ASSERT_TRUE(temp.CreateUniqueTempDir()); 206 InitFilePaths(temp.path()); 207 208 ASSERT_TRUE(PathExists(errors_expected_file)); 209 ASSERT_TRUE(PathExists(urls_file())); 210 211 set_page_cycler(new MockPageCycler(browser(), 212 urls_file(), 213 errors_file())); 214 RunPageCycler(); 215 216 // Page cycler expects browser to automatically start loading the first page. 217 EXPECT_CALL(*page_cycler(), 218 DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame, _)) 219 .WillOnce(Invoke(page_cycler(), 220 &MockPageCycler::PageCyclerDidFinishLoad)); 221 FinishLoad(); 222 223 // DNS server fail error message. 224 string16 error_string = 225 string16(ASCIIToUTF16(net::ErrorToString(net::ERR_DNS_SERVER_FAILED))); 226 EXPECT_CALL(*page_cycler(), 227 DidFailProvisionalLoad(kFrameID, kIsMainFrame, _, 228 net::ERR_DNS_SERVER_FAILED, error_string, 229 _)) 230 .WillOnce(Invoke(page_cycler(), 231 &MockPageCycler::PageCyclerDidFailProvisionalLoad)); 232 FailProvisionalLoad(net::ERR_DNS_SERVER_FAILED, error_string); 233 234 // DNS time-out error message. 235 error_string = string16( 236 ASCIIToUTF16(net::ErrorToString(net::ERR_DNS_TIMED_OUT))); 237 EXPECT_CALL(*page_cycler(), 238 DidFailProvisionalLoad(kFrameID, 239 kIsMainFrame, _, net::ERR_DNS_TIMED_OUT, 240 error_string, _)) 241 .WillOnce(Invoke(page_cycler(), 242 &MockPageCycler::PageCyclerDidFailProvisionalLoad)); 243 244 FailProvisionalLoad(net::ERR_DNS_TIMED_OUT, error_string); 245 246 // DNS time-out error message. 247 error_string = string16( 248 ASCIIToUTF16(net::ErrorToString(net::ERR_INVALID_URL))); 249 EXPECT_CALL(*page_cycler(), 250 DidFailProvisionalLoad(kFrameID, kIsMainFrame, _, 251 net::ERR_INVALID_URL, error_string, _)) 252 .WillOnce(Invoke(page_cycler(), 253 &MockPageCycler::PageCyclerDidFailProvisionalLoad)); 254 FailProvisionalLoad(net::ERR_INVALID_URL, error_string); 255 256 PumpLoop(); 257 258 std::string errors_output; 259 std::string errors_expected; 260 ASSERT_TRUE(file_util::ReadFileToString(errors_file(), 261 &errors_output)); 262 ASSERT_TRUE(file_util::ReadFileToString(errors_expected_file, 263 &errors_expected)); 264 ASSERT_EQ(errors_output, errors_expected); 265 } 266 267 TEST_F(PageCyclerTest, StatsFile) { 268 const int kNumLoads = 4; 269 270 base::ScopedTempDir temp; 271 ASSERT_TRUE(temp.CreateUniqueTempDir()); 272 InitFilePaths(temp.path()); 273 274 ASSERT_TRUE(PathExists(urls_file())); 275 276 set_page_cycler(new MockPageCycler(browser(), urls_file(), 277 errors_file())); 278 page_cycler()->set_stats_file(stats_file()); 279 RunPageCycler(); 280 281 for (int i = 0; i < kNumLoads; ++i) { 282 EXPECT_CALL(*page_cycler(), DidFinishLoad( 283 kFrameID, kAboutURL, kIsMainFrame, _)) 284 .WillOnce(Invoke(page_cycler(), 285 &MockPageCycler::PageCyclerDidFinishLoad)); 286 FinishLoad(); 287 } 288 289 PumpLoop(); 290 EXPECT_FALSE(PathExists(errors_file())); 291 ASSERT_TRUE(PathExists(stats_file())); 292 } 293 294 TEST_F(PageCyclerTest, KillBrowserAndAbort) { 295 const base::FilePath errors_expected_file = 296 test_data_dir().AppendASCII("abort_expected"); 297 298 base::ScopedTempDir temp; 299 ASSERT_TRUE(temp.CreateUniqueTempDir()); 300 InitFilePaths(temp.path()); 301 302 ASSERT_TRUE(PathExists(errors_expected_file)); 303 ASSERT_TRUE(PathExists(urls_file())); 304 305 set_page_cycler(new MockPageCycler(browser(), 306 urls_file(), 307 errors_file())); 308 RunPageCycler(); 309 310 EXPECT_CALL(*page_cycler(), 311 DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame, _)) 312 .WillOnce(Invoke(page_cycler(), 313 &MockPageCycler::PageCyclerDidFinishLoad)); 314 base::RunLoop().RunUntilIdle(); 315 316 FinishLoad(); 317 318 CloseBrowser(); 319 PumpLoop(); 320 321 std::string errors_output; 322 std::string errors_expected; 323 ASSERT_TRUE(file_util::ReadFileToString(errors_file(), 324 &errors_output)); 325 ASSERT_TRUE(file_util::ReadFileToString(errors_expected_file, 326 &errors_expected)); 327 ASSERT_EQ(errors_output, errors_expected); 328 } 329 330 TEST_F(PageCyclerTest, MultipleIterations) { 331 const int kNumLoads = 4; 332 333 base::ScopedTempDir temp; 334 ASSERT_TRUE(temp.CreateUniqueTempDir()); 335 InitFilePaths(temp.path()); 336 337 ASSERT_TRUE(PathExists(urls_file())); 338 339 set_page_cycler(new MockPageCycler(browser(), 340 urls_file(), 341 errors_file())); 342 page_cycler()->set_stats_file(stats_file()); 343 RunPageCycler(); 344 345 EXPECT_CALL(*page_cycler(), 346 DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame, _)) 347 .WillRepeatedly(Invoke(page_cycler(), 348 &MockPageCycler::PageCyclerDidFinishLoad)); 349 350 for (int i = 0; i < kNumLoads; ++i) 351 FinishLoad(); 352 353 PumpLoop(); 354 EXPECT_FALSE(PathExists(errors_file())); 355 ASSERT_TRUE(PathExists(stats_file())); 356 } 357