Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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/command_line.h" | |
| 6 #include "base/file_path.h" | |
| 7 #include "base/file_util.h" | |
| 8 #include "base/path_service.h" | |
| 9 #include "base/string_split.h" | |
| 10 #include "base/string_util.h" | |
| 11 #include "base/threading/sequenced_worker_pool.h" | |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/page_cycler/page_cycler.h" | |
| 14 #include "chrome/browser/profiles/profile.h" | |
| 15 #include "chrome/browser/profiles/profile_manager.h" | |
| 16 #include "chrome/browser/ui/browser_list.h" | |
| 17 #include "chrome/common/chrome_notification_types.h" | |
| 18 #include "chrome/common/chrome_paths.h" | |
| 19 #include "chrome/common/chrome_switches.h" | |
| 20 #include "chrome/test/base/in_process_browser_test.h" | |
| 21 #include "chrome/test/base/testing_profile.h" | |
| 22 #include "chrome/test/base/ui_test_utils.h" | |
| 23 #include "content/public/browser/notification_observer.h" | |
| 24 #include "content/public/browser/notification_registrar.h" | |
| 25 #include "content/public/browser/notification_service.h" | |
| 26 #include "content/public/common/content_switches.h" | |
| 27 #include "content/public/common/url_constants.h" | |
| 28 #include "googleurl/src/gurl.h" | |
| 29 | |
| 30 // Basic PageCyclerBrowserTest structure; used in testing most of PageCycler's | |
| 31 // functionality. | |
| 32 class PageCyclerBrowserTest : public content::NotificationObserver, | |
| 33 public InProcessBrowserTest { | |
| 34 public: | |
| 35 virtual void CleanUpOnMainThread() { | |
| 36 file_util::Delete(temp_path_, true); // recursive. | |
| 37 } | |
| 38 | |
| 39 // Initialize file paths within a temporary directory; this should be | |
| 40 // empty and nonexistent. | |
| 41 virtual void InitFilePaths(FilePath temp_path) { | |
| 42 temp_path_ = temp_path; | |
| 43 urls_file_ = temp_path.AppendASCII("urls_file"); | |
| 44 errors_file_ = temp_path.AppendASCII("errors"); | |
| 45 stats_file_ = temp_path.AppendASCII("stats"); | |
| 46 | |
| 47 ASSERT_FALSE(file_util::PathExists(urls_file_)); | |
| 48 ASSERT_FALSE(file_util::PathExists(errors_file_)); | |
| 49 ASSERT_FALSE(file_util::PathExists(stats_file_)); | |
| 50 } | |
| 51 | |
| 52 // Initialize a PageCycler using either the base fields, or using provided | |
| 53 // ones. | |
| 54 void InitPageCycler() { | |
| 55 page_cycler_ = new PageCycler(browser(), urls_file()); | |
| 56 page_cycler_->set_errors_file(errors_file()); | |
| 57 page_cycler_->set_stats_file(stats_file()); | |
| 58 } | |
| 59 void InitPageCycler(FilePath urls_file, | |
|
Aaron Boodman
2012/05/29 21:39:08
Insert blank line here.
Devlin
2012/05/30 01:45:15
Done.
| |
| 60 FilePath errors_file, | |
| 61 FilePath stats_file) { | |
| 62 page_cycler_ = new PageCycler(browser(), urls_file); | |
| 63 page_cycler_->set_errors_file(errors_file); | |
| 64 page_cycler_->set_stats_file(stats_file); | |
| 65 } | |
| 66 | |
| 67 void RegisterForNotifications() { | |
| 68 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, | |
| 69 content::NotificationService::AllSources()); | |
| 70 } | |
| 71 | |
| 72 // Get a collection of basic urls which are stored in the test directory. | |
| 73 // NOTE: |test_server| must be started first! | |
| 74 std::vector<GURL> GetURLs() { | |
| 75 std::vector<GURL> urls; | |
| 76 urls.push_back(test_server()->GetURL("files/page_cycler/basic_html.html")); | |
| 77 urls.push_back(test_server()->GetURL("files/page_cycler/basic_js.html")); | |
| 78 urls.push_back(test_server()->GetURL("files/page_cycler/basic_css.html")); | |
| 79 return urls; | |
| 80 } | |
| 81 | |
| 82 // Read the errors file, and generate a vector of error strings. | |
| 83 std::vector<std::string> GetErrorsFromFile() { | |
| 84 std::string error_file_contents; | |
| 85 CHECK(file_util::ReadFileToString(errors_file_, | |
| 86 &error_file_contents)); | |
| 87 if (error_file_contents[error_file_contents.size() - 1] == '\n') { | |
| 88 error_file_contents = | |
| 89 error_file_contents.substr(0, error_file_contents.size() - 1); | |
| 90 } | |
| 91 | |
| 92 std::vector<std::string> errors; | |
| 93 base::SplitString(error_file_contents, '\n', &errors); | |
| 94 | |
| 95 return errors; | |
| 96 } | |
| 97 | |
| 98 // Convert a vector of GURLs into a newline-separated string, ready to be | |
| 99 // written to the urls file for PageCycler to use. | |
| 100 std::string GetStringFromURLs(std::vector<GURL> urls) { | |
| 101 std::string urls_string; | |
| 102 for (std::vector<GURL>::const_iterator iter = urls.begin(); | |
| 103 iter != urls.end(); ++iter) | |
| 104 urls_string.append(iter->spec() + "\n"); | |
| 105 return urls_string; | |
| 106 } | |
| 107 | |
| 108 // content::NotificationObserver. | |
| 109 virtual void Observe(int type, | |
| 110 const content::NotificationSource& source, | |
| 111 const content::NotificationDetails& details) { | |
| 112 switch (type) { | |
| 113 case chrome::NOTIFICATION_BROWSER_CLOSED: | |
| 114 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | |
| 115 break; | |
| 116 default: | |
| 117 NOTREACHED(); | |
| 118 break; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 FilePath urls_file() { return urls_file_; } | |
| 123 FilePath errors_file() { return errors_file_; } | |
| 124 FilePath stats_file() { return stats_file_; } | |
| 125 PageCycler* page_cycler() { return page_cycler_; } | |
| 126 | |
| 127 protected: | |
| 128 FilePath temp_path_; | |
| 129 FilePath urls_file_; | |
| 130 FilePath errors_file_; | |
| 131 FilePath stats_file_; | |
| 132 PageCycler* page_cycler_; | |
|
Aaron Boodman
2012/05/29 21:39:08
Please create a constructor so that this can be in
Devlin
2012/05/30 01:45:15
Done.
| |
| 133 content::NotificationRegistrar registrar_; | |
| 134 }; | |
| 135 | |
| 136 // Structure used for testing PageCycler's ability to playback a series of | |
| 137 // URLs given a cache directory. | |
| 138 class PageCyclerCachedBrowserTest : public PageCyclerBrowserTest { | |
| 139 public: | |
| 140 // For a cached test, we use the provided user data directory from the test | |
| 141 // directory. | |
| 142 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
| 143 InProcessBrowserTest::SetUpCommandLine(command_line); | |
| 144 | |
| 145 FilePath test_dir; | |
| 146 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); | |
| 147 test_dir = test_dir.AppendASCII("page_cycler"); | |
| 148 | |
| 149 FilePath source_data_dir = test_dir.AppendASCII("cached_data_dir"); | |
| 150 CHECK(file_util::PathExists(source_data_dir)); | |
| 151 | |
| 152 CHECK(user_data_dir_.CreateUniqueTempDir()); | |
| 153 | |
| 154 FilePath dest_data_dir = | |
| 155 user_data_dir_.path().AppendASCII("cached_data_dir"); | |
| 156 CHECK(!file_util::PathExists(dest_data_dir)); | |
| 157 | |
| 158 CHECK(file_util::CopyDirectory(source_data_dir, | |
| 159 user_data_dir_.path(), | |
| 160 true)); // recursive. | |
| 161 CHECK(file_util::PathExists(dest_data_dir)); | |
| 162 | |
| 163 command_line->AppendSwitchPath(switches::kUserDataDir, | |
| 164 dest_data_dir); | |
|
Aaron Boodman
2012/05/29 21:39:08
This should line up with the first param.
Devlin
2012/05/30 01:45:15
Done.
| |
| 165 command_line->AppendSwitch(switches::kPlaybackMode); | |
| 166 } | |
| 167 | |
| 168 virtual void CleanUpOnMainThread() { | |
| 169 file_util::Delete(user_data_dir_.path(), true); // recursive | |
| 170 PageCyclerBrowserTest::CleanUpOnMainThread(); | |
| 171 } | |
| 172 | |
| 173 // Initialize the file paths to use the UserDataDir's urls file, instead | |
| 174 // of one to be written. | |
| 175 virtual void InitFilePaths(FilePath temp_path) OVERRIDE { | |
| 176 urls_file_ = user_data_dir_.path().AppendASCII("cached_data_dir") | |
| 177 .AppendASCII("urls"); | |
| 178 errors_file_ = temp_path.AppendASCII("errors"); | |
| 179 stats_file_ = temp_path.AppendASCII("stats"); | |
| 180 | |
| 181 ASSERT_TRUE(file_util::PathExists(urls_file_)); | |
| 182 ASSERT_FALSE(file_util::PathExists(errors_file_)); | |
| 183 ASSERT_FALSE(file_util::PathExists(stats_file_)); | |
| 184 } | |
| 185 | |
| 186 private: | |
| 187 // The directory storing the copy of the UserDataDir. | |
| 188 ScopedTempDir user_data_dir_; | |
| 189 }; | |
| 190 | |
| 191 // Structure used to test PageCycler's ability to record the all necessary | |
| 192 // information to revisit a series of URLs. | |
| 193 class PageCyclerRecordingBrowserTest : public PageCyclerBrowserTest { | |
| 194 public: | |
| 195 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
| 196 InProcessBrowserTest::SetUpCommandLine(command_line); | |
| 197 | |
| 198 CHECK(user_data_dir_.CreateUniqueTempDir()); | |
| 199 CHECK(file_util::PathExists(user_data_dir_.path())); | |
| 200 | |
| 201 command_line->AppendSwitchPath(switches::kUserDataDir, | |
| 202 user_data_dir_.path()); | |
| 203 // We have to be in record mode for these tests to work. | |
| 204 command_line->AppendSwitch(switches::kRecordMode); | |
| 205 } | |
| 206 | |
| 207 virtual void CleanUpOnMainThread() { | |
| 208 file_util::Delete(user_data_dir_.path(), true); // recursive | |
| 209 PageCyclerBrowserTest::CleanUpOnMainThread(); | |
| 210 } | |
| 211 | |
| 212 const FilePath& user_data_dir() { return user_data_dir_.path(); } | |
| 213 | |
| 214 private: | |
| 215 ScopedTempDir user_data_dir_; | |
| 216 }; | |
| 217 | |
| 218 // Sanity check; iterate through a series of URLs and make sure there are no | |
| 219 // errors. | |
| 220 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, BasicTest) { | |
| 221 const size_t kNumIterations = 3; | |
| 222 ScopedTempDir temp; | |
| 223 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 224 | |
| 225 RegisterForNotifications(); | |
| 226 InitFilePaths(temp.path()); | |
| 227 | |
| 228 ASSERT_TRUE(test_server()->Start()); | |
| 229 | |
| 230 std::string urls_string = GetStringFromURLs(GetURLs());; | |
| 231 | |
| 232 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
| 233 urls_string.size())); | |
| 234 | |
| 235 InitPageCycler(); | |
| 236 page_cycler()->Run(kNumIterations); | |
| 237 | |
| 238 ui_test_utils::RunMessageLoop(); | |
| 239 ASSERT_FALSE(file_util::PathExists(errors_file())); | |
| 240 ASSERT_TRUE(file_util::PathExists(stats_file())); | |
| 241 } | |
| 242 | |
| 243 // Test to make sure that PageCycler will recognize unvisitable URLs, and will | |
| 244 // handle them appropriately. | |
| 245 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, UnvisitableURL) { | |
| 246 const size_t kNumIterations = 3; | |
| 247 const char kFakeURL[] = "http://www.pleasenoonehavethisurlanytimeinthenext" | |
| 248 "century.com/gibberish"; | |
| 249 ScopedTempDir temp; | |
| 250 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 251 | |
| 252 RegisterForNotifications(); | |
| 253 InitFilePaths(temp.path()); | |
| 254 | |
| 255 ASSERT_TRUE(test_server()->Start()); | |
| 256 | |
| 257 std::vector<GURL> urls = GetURLs(); | |
| 258 urls.push_back(GURL(kFakeURL)); | |
| 259 std::string urls_string = GetStringFromURLs(urls); | |
| 260 | |
| 261 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
| 262 urls_string.size())); | |
| 263 | |
| 264 InitPageCycler(); | |
| 265 page_cycler()->Run(kNumIterations); | |
| 266 | |
| 267 ui_test_utils::RunMessageLoop(); | |
| 268 ASSERT_TRUE(file_util::PathExists(errors_file())); | |
| 269 ASSERT_TRUE(file_util::PathExists(stats_file())); | |
| 270 | |
| 271 std::vector<std::string> errors = GetErrorsFromFile(); | |
| 272 | |
| 273 size_t num_errors = errors.size(); | |
| 274 ASSERT_EQ(kNumIterations, num_errors); | |
| 275 | |
| 276 // Check that each error message contains the fake URL (i.e., that it wasn't | |
| 277 // from a valid URL, and that the fake URL was caught each time). | |
| 278 for (std::vector<std::string>::const_iterator iter = errors.begin(); | |
| 279 iter != errors.end(); ++iter) { | |
| 280 ASSERT_NE(iter->find(kFakeURL), std::string::npos); | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 // Test that PageCycler will remove an invalid URL prior to running. | |
| 285 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, InvalidURL) { | |
| 286 const size_t kNumIterations = 1; | |
| 287 const char kBadURL[] = "notarealurl"; | |
| 288 | |
| 289 ScopedTempDir temp; | |
| 290 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 291 | |
| 292 RegisterForNotifications(); | |
| 293 InitFilePaths(temp.path()); | |
| 294 | |
| 295 ASSERT_TRUE(test_server()->Start()); | |
| 296 | |
| 297 std::string urls_string = GetStringFromURLs(GetURLs()); | |
| 298 urls_string.append(kBadURL).append("\n"); | |
| 299 | |
| 300 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
| 301 urls_string.size())); | |
| 302 | |
| 303 InitPageCycler(); | |
| 304 page_cycler()->Run(kNumIterations); | |
| 305 | |
| 306 ui_test_utils::RunMessageLoop(); | |
| 307 ASSERT_TRUE(file_util::PathExists(errors_file())); | |
| 308 ASSERT_TRUE(file_util::PathExists(stats_file())); | |
| 309 | |
| 310 std::vector<std::string> errors = GetErrorsFromFile(); | |
| 311 ASSERT_EQ(1u, errors.size()); | |
| 312 | |
| 313 std::string expected_error = "Omitting invalid URL: "; | |
| 314 expected_error.append(kBadURL).append("."); | |
| 315 | |
| 316 ASSERT_FALSE(errors[0].compare(expected_error)); | |
| 317 } | |
| 318 | |
| 319 // Test that PageCycler will remove a Chrome Error URL prior to running. | |
| 320 IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, ChromeErrorURL) { | |
| 321 const size_t kNumIterations = 1; | |
| 322 ScopedTempDir temp; | |
| 323 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 324 | |
| 325 RegisterForNotifications(); | |
| 326 InitFilePaths(temp.path()); | |
| 327 | |
| 328 ASSERT_TRUE(test_server()->Start()); | |
| 329 | |
| 330 std::vector<GURL> urls = GetURLs(); | |
| 331 urls.push_back(GURL(content::kUnreachableWebDataURL)); | |
| 332 std::string urls_string = GetStringFromURLs(urls); | |
| 333 | |
| 334 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
| 335 urls_string.size())); | |
| 336 | |
| 337 InitPageCycler(); | |
| 338 page_cycler()->Run(kNumIterations); | |
| 339 | |
| 340 ui_test_utils::RunMessageLoop(); | |
| 341 ASSERT_TRUE(file_util::PathExists(errors_file())); | |
| 342 ASSERT_TRUE(file_util::PathExists(stats_file())); | |
| 343 | |
| 344 std::vector<std::string> errors = GetErrorsFromFile(); | |
| 345 ASSERT_EQ(1u, errors.size()); | |
| 346 | |
| 347 std::string expected_error = "Chrome error pages are not allowed as urls. " | |
| 348 "Omitting url: "; | |
| 349 expected_error.append(content::kUnreachableWebDataURL).append("."); | |
| 350 | |
| 351 ASSERT_FALSE(errors[0].compare(expected_error)); | |
| 352 } | |
| 353 | |
| 354 // Test that PageCycler will visit all the urls from a cache directory | |
| 355 // successfully while in playback mode. | |
| 356 IN_PROC_BROWSER_TEST_F(PageCyclerCachedBrowserTest, PlaybackMode) { | |
| 357 const size_t kNumIterations = 1; | |
| 358 ScopedTempDir temp; | |
| 359 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 360 | |
| 361 RegisterForNotifications(); | |
| 362 InitFilePaths(temp.path()); | |
| 363 | |
| 364 InitPageCycler(); | |
| 365 | |
| 366 page_cycler()->Run(kNumIterations); | |
| 367 | |
| 368 ui_test_utils::RunMessageLoop(); | |
| 369 ASSERT_TRUE(file_util::PathExists(stats_file())); | |
| 370 ASSERT_FALSE(file_util::PathExists(errors_file())); | |
| 371 } | |
| 372 | |
| 373 // Test that PageCycler will have a cache miss if a URL is missing from the | |
| 374 // cache directory while in playback mode. | |
| 375 IN_PROC_BROWSER_TEST_F(PageCyclerCachedBrowserTest, URLNotInCache) { | |
| 376 const size_t kNumIterations = 1; | |
| 377 const char kCacheMissURL[] = "http://www.images.google.com/"; | |
| 378 | |
| 379 ScopedTempDir temp; | |
| 380 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 381 | |
| 382 RegisterForNotifications(); | |
| 383 InitFilePaths(temp.path()); | |
| 384 | |
| 385 std::string urls_string; | |
| 386 ASSERT_TRUE(file_util::ReadFileToString(urls_file(), | |
| 387 &urls_string)); | |
| 388 | |
| 389 urls_string.append("\n").append(kCacheMissURL); | |
| 390 FilePath new_urls_file = temp.path().AppendASCII("urls"); | |
| 391 ASSERT_FALSE(file_util::PathExists(new_urls_file)); | |
| 392 | |
| 393 ASSERT_TRUE(file_util::WriteFile(new_urls_file, urls_string.c_str(), | |
| 394 urls_string.size())); | |
| 395 | |
| 396 InitPageCycler(new_urls_file, errors_file(), stats_file()); | |
| 397 page_cycler()->Run(kNumIterations); | |
| 398 | |
| 399 ui_test_utils::RunMessageLoop(); | |
| 400 ASSERT_TRUE(file_util::PathExists(errors_file())); | |
| 401 ASSERT_TRUE(file_util::PathExists(stats_file())); | |
| 402 | |
| 403 std::vector<std::string> errors = GetErrorsFromFile(); | |
| 404 ASSERT_EQ(1u, errors.size()); | |
| 405 | |
| 406 std::string expected_error; | |
| 407 expected_error.append("Failed to load the page at: ") | |
| 408 .append(kCacheMissURL) | |
| 409 .append(": The requested entry was not found in the cache."); | |
| 410 | |
| 411 ASSERT_FALSE(errors[0].compare(expected_error)); | |
| 412 } | |
| 413 | |
| 414 // Test that PageCycler will record properly. | |
| 415 // NOTE: This test operates by comparing the size of a generated cache | |
|
Aaron Boodman
2012/05/29 21:39:08
This is probably going to be too brittle. Also I w
Devlin
2012/05/30 01:45:15
Skipped for now; will look into a better way of do
| |
| 416 // directory to a previously-generated cache directory. If the way or | |
| 417 // amount Chrome caches pages changes significantly, this test will fail. | |
| 418 // If this happens, please update the cache directory in | |
| 419 // chrome/test/data/page_cycler. | |
| 420 IN_PROC_BROWSER_TEST_F(PageCyclerRecordingBrowserTest, RecordMode) { | |
| 421 const size_t kNumIterations = 1; | |
| 422 ScopedTempDir temp; | |
| 423 ASSERT_TRUE(temp.CreateUniqueTempDir()); | |
| 424 | |
| 425 RegisterForNotifications(); | |
| 426 InitFilePaths(temp.path()); | |
| 427 | |
| 428 ASSERT_TRUE(test_server()->Start()); | |
| 429 std::string urls_string = GetStringFromURLs(GetURLs()); | |
| 430 | |
| 431 ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), | |
| 432 urls_string.size())); | |
| 433 | |
| 434 InitPageCycler(); | |
| 435 page_cycler()->Run(kNumIterations); | |
| 436 | |
| 437 ui_test_utils::RunMessageLoop(); | |
| 438 ASSERT_FALSE(file_util::PathExists(errors_file())); | |
| 439 ASSERT_TRUE(file_util::PathExists(stats_file())); | |
| 440 | |
| 441 FilePath test_cache_dir = user_data_dir().AppendASCII("Default") | |
| 442 .AppendASCII("Cache"); | |
| 443 ASSERT_TRUE(file_util::PathExists(test_cache_dir)); | |
| 444 | |
| 445 FilePath expected_cache_dir; | |
| 446 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &expected_cache_dir)); | |
| 447 expected_cache_dir = expected_cache_dir.AppendASCII("page_cycler") | |
| 448 .AppendASCII("expected_cache"); | |
| 449 ASSERT_TRUE(file_util::PathExists(test_cache_dir)); | |
| 450 | |
| 451 ASSERT_EQ(file_util::ComputeDirectorySize(expected_cache_dir), | |
| 452 file_util::ComputeDirectorySize(test_cache_dir)); | |
| 453 } | |
| OLD | NEW |