diff options
-rw-r--r-- | chrome/browser/chrome_browser_main.cc | 28 | ||||
-rw-r--r-- | chrome/browser/chrome_browser_main.h | 5 | ||||
-rw-r--r-- | chrome/browser/page_cycler/page_cycler.cc | 263 | ||||
-rw-r--r-- | chrome/browser/page_cycler/page_cycler.h | 154 | ||||
-rw-r--r-- | chrome/browser/page_cycler/page_cycler_browsertest.cc | 381 | ||||
-rw-r--r-- | chrome/browser/page_cycler/page_cycler_unittest.cc | 338 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_impl_io_data.cc | 14 | ||||
-rw-r--r-- | chrome/browser/ui/startup/startup_browser_creator_impl.cc | 4 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 9 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 2 | ||||
-rw-r--r-- | chrome/common/chrome_constants.cc | 10 |
11 files changed, 1195 insertions, 13 deletions
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 3b48f9c..191f26f 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -59,6 +59,7 @@ #include "chrome/browser/net/chrome_net_log.h" #include "chrome/browser/net/predictor.h" #include "chrome/browser/notifications/desktop_notification_service.h" +#include "chrome/browser/page_cycler/page_cycler.h" #include "chrome/browser/notifications/desktop_notification_service_factory.h" #include "chrome/browser/plugin_prefs.h" #include "chrome/browser/prefs/pref_service.h" @@ -79,6 +80,7 @@ #include "chrome/browser/shell_integration.h" #include "chrome/browser/translate/translate_manager.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" #include "chrome/browser/ui/user_data_dir_dialog.h" #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h" @@ -1443,12 +1445,38 @@ void ChromeBrowserMainParts::PreBrowserStart() { } void ChromeBrowserMainParts::PostBrowserStart() { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kVisitURLs)) + RunPageCycler(); + for (size_t i = 0; i < chrome_extra_parts_.size(); ++i) chrome_extra_parts_[i]->PostBrowserStart(); // Allow ProcessSingleton to process messages. process_singleton_->Unlock(); } +void ChromeBrowserMainParts::RunPageCycler() { + CommandLine* command_line = CommandLine::ForCurrentProcess(); + Browser* browser = browser::FindBrowserWithProfile(profile_); + DCHECK(browser); + PageCycler* page_cycler = NULL; + FilePath input_file = + command_line->GetSwitchValuePath(switches::kVisitURLs); + page_cycler = new PageCycler(browser, input_file); + page_cycler->set_errors_file( + input_file.AddExtension(FILE_PATH_LITERAL(".errors"))); + if (command_line->HasSwitch(switches::kRecordStats)) { + page_cycler->set_stats_file( + command_line->GetSwitchValuePath(switches::kRecordStats)); + } + int iterations = 1; + if (command_line->HasSwitch(switches::kVisitURLsCount)) { + CHECK(base::StringToInt( + command_line->GetSwitchValueNative(switches::kVisitURLsCount), + &iterations)); + } + page_cycler->Run(iterations); +} + int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { // Now that the file thread has been started, start recording. StartMetricsRecording(); diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h index 71afa03..d078254 100644 --- a/chrome/browser/chrome_browser_main.h +++ b/chrome/browser/chrome_browser_main.h @@ -72,12 +72,15 @@ class ChromeBrowserMainParts : public content::BrowserMainParts { virtual void PostDestroyThreads() OVERRIDE; // Additional stages for ChromeBrowserMainExtraParts. These stages are called - // in order from PreMainMessageLoopStart(). See implementation for details. + // in order from PreMainMessageLoopRun(). See implementation for details. virtual void PreProfileInit(); virtual void PostProfileInit(); virtual void PreBrowserStart(); virtual void PostBrowserStart(); + // Runs the PageCycler; called if the switch kVisitURLs is present. + virtual void RunPageCycler(); + // Displays a warning message that we can't find any locale data files. virtual void ShowMissingLocaleMessageBox() = 0; diff --git a/chrome/browser/page_cycler/page_cycler.cc b/chrome/browser/page_cycler/page_cycler.cc new file mode 100644 index 0000000..7866328 --- /dev/null +++ b/chrome/browser/page_cycler/page_cycler.cc @@ -0,0 +1,263 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/page_cycler/page_cycler.h" + +#include "base/bind.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/process_util.h" +#include "base/string_number_conversions.h" +#include "base/string_split.h" +#include "base/utf_string_conversions.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/test/base/chrome_process_util.h" +#include "chrome/test/perf/perf_test.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/url_constants.h" + +using content::NavigationController; +using content::OpenURLParams; +using content::Referrer; +using content::WebContents; + +PageCycler::PageCycler(Browser* browser, + FilePath urls_file) + : content::WebContentsObserver(browser->GetSelectedWebContents()), + browser_(browser), + urls_file_(urls_file), + url_index_(0), + total_iterations_(0), + current_iteration_(0), + aborted_(false) { + BrowserList::AddObserver(this); + AddRef(); // Balanced in Finish()/Abort() (only one should be called). +} + +PageCycler::~PageCycler() { +} + +bool PageCycler::IsLoadCallbackValid(const GURL& validated_url, + bool is_main_frame) { + // If |url_index_| is equal to zero, that means that this was called before + // LoadNextURL() - this can happen at startup, loading the new tab page; or + // if the user specified a bad url as the final url in the list. In these + // cases, do not report success or failure, and load the next page. + if (!url_index_) { + LoadNextURL(); + return false; + } + return (is_main_frame && + validated_url.spec() != content::kUnreachableWebDataURL); +} + +void PageCycler::DidFinishLoad(int64 frame_id, + const GURL& validated_url, + bool is_main_frame) { + if (IsLoadCallbackValid(validated_url, is_main_frame)) + LoadSucceeded(); +} + +void PageCycler::DidFailProvisionalLoad( + int64 frame_id, + bool is_main_frame, + const GURL& validated_url, + int error_code, + const string16& error_description, + content::RenderViewHost* render_view_host) { + if (IsLoadCallbackValid(validated_url, is_main_frame)) + LoadFailed(validated_url, error_description); +} + +void PageCycler::Run(const int& total_iterations) { + total_iterations_ = total_iterations; + if (browser_) + content::BrowserThread::PostBlockingPoolTask( + FROM_HERE, + base::Bind(&PageCycler::ReadURLsOnBackgroundThread, this)); +} + +void PageCycler::ReadURLsOnBackgroundThread() { + CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + std::string file_contents; + std::vector<std::string> url_strings; + + CHECK(file_util::PathExists(urls_file_)) << urls_file_.value(); + file_util::ReadFileToString(urls_file_, &file_contents); + base::SplitStringAlongWhitespace(file_contents, &url_strings); + + if (!url_strings.size()) { +#if defined(OS_POSIX) + error_.append(ASCIIToUTF16("Page Cycler: No URLs in given file: " + + urls_file_.value())); +#elif defined(OS_WIN) + error_.append(ASCIIToUTF16("Page Cycler: No URLs in given file: ")) + .append(urls_file_.value()); +#endif // OS_WIN + } + + for (std::vector<std::string>::const_iterator iter = url_strings.begin(); + iter != url_strings.end(); ++iter) { + GURL gurl(*iter); + if (!gurl.is_valid()) + error_.append(ASCIIToUTF16("Omitting invalid URL: " + *iter + ".\n")); + // Since we don't count kUnreachableWebData as a valid load, we don't want + // the user to specify this as one of the pages to visit. + else if (*iter == content::kUnreachableWebDataURL) { + error_.append(ASCIIToUTF16( + "Chrome error pages are not allowed as urls. Omitting url: " + + *iter + ".\n")); + } else { + urls_.push_back(gurl); + } + } + + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(&PageCycler::BeginCycle, this)); +} + +void PageCycler::BeginCycle() { + CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + CHECK(browser_); + // Upon launch, Chrome will automatically load the newtab page. This can + // result in the browser being in a state of loading when PageCycler is ready + // to start. Instead of interrupting the load, we wait for it to finish, and + // will call LoadNextURL() from DidFinishLoad() or DidFailProvisionalLoad(). + if (browser_->GetSelectedWebContents()->IsLoading()) + return; + LoadNextURL(); +} + +void PageCycler::LoadNextURL() { + CHECK(browser_); + if (url_index_ >= urls_.size()) { + if (current_iteration_ < total_iterations_ - 1) { + ++current_iteration_; + url_index_ = 0; + } else { + content::BrowserThread::PostBlockingPoolTask( + FROM_HERE, + base::Bind(&PageCycler::PrepareResultsOnBackgroundThread, this)); + return; + } + } + if (url_index_ || current_iteration_) { + timings_string_.append(", "); + urls_string_.append(", "); + } + urls_string_.append(urls_[url_index_].spec()); + initial_time_ = base::TimeTicks::HighResNow(); + OpenURLParams params(urls_[url_index_], + Referrer(), + CURRENT_TAB, + content::PAGE_TRANSITION_TYPED, + false); + ++url_index_; + browser_->OpenURL(params); +} + +void PageCycler::LoadSucceeded() { + base::TimeDelta time_elapsed = + (base::TimeTicks::HighResNow() - initial_time_) / 1000.0; + timings_string_.append(base::Int64ToString(time_elapsed.ToInternalValue())); + LoadNextURL(); +} + +void PageCycler::LoadFailed(const GURL& url, + const string16& error_description) { + error_.append(ASCIIToUTF16("Failed to load the page at: " + + url.spec() + ": ")).append(error_description). + append(ASCIIToUTF16("\n")); + base::TimeDelta time_elapsed = + (base::TimeTicks::HighResNow() - initial_time_) / 1000.0; + timings_string_.append(base::Int64ToString(time_elapsed.ToInternalValue()) + + (" (failed)")); + LoadNextURL(); +} + +void PageCycler::PrepareResultsOnBackgroundThread() { + CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + std::string output; + if (!stats_file_.empty()) { +#if defined(OS_POSIX) + base::ProcessId pid = base::GetParentProcessId(base::GetCurrentProcId()); +#elif defined(OS_WIN) + base::ProcessId pid = base::GetCurrentProcId(); +#endif // OS_WIN + ChromeProcessList chrome_processes(GetRunningChromeProcesses(pid)); + output += perf_test::MemoryUsageInfoToString("", chrome_processes, pid); + output += perf_test::IOPerfInfoToString("", chrome_processes, pid); + output += perf_test::SystemCommitChargeToString("", + base::GetSystemCommitCharge(), false); + output.append("Pages: [" + urls_string_ + "]\n"); + output.append("*RESULT times: t_ref= [" + timings_string_ + "] ms\n"); + } + WriteResultsOnBackgroundThread(output); +} + +void PageCycler::WriteResultsOnBackgroundThread(std::string output) { + CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + if (!output.empty()) { + CHECK(!stats_file_.empty()); + file_util::WriteFile(stats_file_, output.c_str(), output.size()); + } + if (!errors_file_.empty()) { + if (!error_.empty()) { + file_util::WriteFile(errors_file_, UTF16ToUTF8(error_).c_str(), + error_.size()); + } else if (file_util::PathExists(errors_file_)) { + // If there is an old error file, delete it to avoid confusion. + file_util::Delete(errors_file_, false); + } + } + if (aborted_) { + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(&PageCycler::Abort, this)); + } else { + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(&PageCycler::Finish, this)); + } +} + +void PageCycler::Finish() { + CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + BrowserList::RemoveObserver(this); + browser_->OnWindowClosing(); + browser_->ExecuteCommand(IDC_EXIT); + Release(); // Balanced in PageCycler constructor; + // (only one of Finish/Abort should be called). +} + +void PageCycler::Abort() { + browser_ = NULL; + BrowserList::RemoveObserver(this); + Release(); // Balanced in PageCycler constructor; + // (only one of Finish/Abort should be called). +} + +void PageCycler::OnBrowserAdded(Browser* browser) {} + +void PageCycler::OnBrowserRemoved(Browser* browser) { + if (browser == browser_) { + aborted_ = true; + error_.append(ASCIIToUTF16( + "Browser was closed before the run was completed.")); + DLOG(WARNING) << + "Page Cycler: browser was closed before the run was completed."; + content::BrowserThread::PostBlockingPoolTask( + FROM_HERE, + base::Bind(&PageCycler::PrepareResultsOnBackgroundThread, this)); + } +} diff --git a/chrome/browser/page_cycler/page_cycler.h b/chrome/browser/page_cycler/page_cycler.h new file mode 100644 index 0000000..82add82 --- /dev/null +++ b/chrome/browser/page_cycler/page_cycler.h @@ -0,0 +1,154 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_PAGE_CYCLER_PAGE_CYCLER_H_ +#define CHROME_BROWSER_PAGE_CYCLER_PAGE_CYCLER_H_ +#pragma once + +#include "base/file_path.h" +#include "base/memory/ref_counted.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/web_contents_observer.h" + +namespace content { +class RenderViewHost; +} // namespace content + +namespace base { +class TimeTicks; +} // namespace base + +// Performance test to track the resources used and speed with which chromium +// fully loads a given set of URLs. This class is created on the UI thread and +// does most of its work there. However, some work happens on background threads +// too; those are named with 'OnBackgroundThread'. +class PageCycler : public base::RefCountedThreadSafe<PageCycler>, + public BrowserList::Observer, + public content::WebContentsObserver { + public: + PageCycler(Browser* browser, FilePath urls_file); + + // Begin running the page cycler. + void Run(const int& total_iterations); + + // content::WebContentsObserver + virtual void DidFinishLoad(int64 frame_id, + const GURL& validated_url, + bool is_main_frame) OVERRIDE; + virtual void DidFailProvisionalLoad( + int64 frame_id, + bool is_main_frame, + const GURL& validated_url, + int error_code, + const string16& error_description, + content::RenderViewHost* render_view_host) OVERRIDE; + + // This method should never be necessary while running PageCycler; this is + // for testing purposes only. + const std::vector<GURL>* urls_for_test() { return &urls_; } + + void set_stats_file(const FilePath& stats_file) { stats_file_ = stats_file; } + void set_errors_file(const FilePath& errors_file) { + errors_file_ = errors_file; + } + + + protected: + virtual ~PageCycler(); + + private: + friend class base::RefCountedThreadSafe<PageCycler>; + friend class MockPageCycler; + + // Check to see if a load callback is valid; i.e. the load should be from the + // main frame, the url should not be a chrome error url, and |url_index| + // should not be 0. + bool IsLoadCallbackValid(const GURL& validated_url, + bool is_main_frame); + + // Read in the urls from |urls_file_| and store them in |urls_|. + void ReadURLsOnBackgroundThread(); + + // Perform any initial setup neccessary, and begin visiting the pages. + void BeginCycle(); + + // If |url_index_| points to a valid position in |urls_|, load the url, + // capturing any statistics information. Otherwise, call WriteResults. + void LoadNextURL(); + + // Complete statistics gathering for the finished visit, and try to load the + // next url. + void LoadSucceeded(); + + // Inidicate that the load failed with an error; try to load the next url. + void LoadFailed(const GURL& url, const string16& error_description); + + // Finalize the output strings. + void PrepareResultsOnBackgroundThread(); + + // Write the data stored within output to the file indicated by |stats_file_|, + // if |stats_file_| is not empty. Write any errors to |errors_file_|. + void WriteResultsOnBackgroundThread(std::string output); + + // Perform any necessary cleanup and exit |browser_|. + void Finish(); + + // Called when the Browser to which |browser_| points is closed; exits + // PageCycler. + void Abort(); + + // BrowserList::Observer + virtual void OnBrowserAdded(Browser* browser) OVERRIDE; + virtual void OnBrowserRemoved(Browser* browser) OVERRIDE; + + // The Browser context in which the page cycler is running. + Browser* browser_; + + // The path to the file containing the list of urls to visit. + FilePath urls_file_; + + // The path to the file to which we write any errors encountered. + FilePath errors_file_; + + // The path to the file to which we write the statistics (optional, may be + // an empty path). + FilePath stats_file_; + + // The list of urls to visit. + std::vector<GURL> urls_; + + // The current index into the |urls_| vector. + size_t url_index_; + + // The number of total iterations to be run. + int total_iterations_; + + // The number of the current iteration. + int current_iteration_; + + // The generated string of urls which we have visited; this is built one url + // at a time as we iterate through the |urls_| vector. This is primarily + // included for interfacing with the previous page_cycler's output style. + std::string urls_string_; + + // The generated string of the times taken to visit each url. As with + // |urls_string_|, this is built as we visit each url, and is primarily to + // produce output similar to the previous page_cycler's. + std::string timings_string_; + + // The time at which we begin the process of loading the next url; this is + // used to calculate the time taken for each url load. + base::TimeTicks initial_time_; + + // Indicates the abort status of the page cycler; true means aborted. + bool aborted_; + + string16 error_; + + DISALLOW_COPY_AND_ASSIGN(PageCycler); +}; + +#endif // CHROME_BROWSER_PAGE_CYCLER_PAGE_CYCLER_H_ diff --git a/chrome/browser/page_cycler/page_cycler_browsertest.cc b/chrome/browser/page_cycler/page_cycler_browsertest.cc new file mode 100644 index 0000000..960f8b0 --- /dev/null +++ b/chrome/browser/page_cycler/page_cycler_browsertest.cc @@ -0,0 +1,381 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/string_split.h" +#include "base/string_util.h" +#include "base/threading/sequenced_worker_pool.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/page_cycler/page_cycler.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_service.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/url_constants.h" +#include "googleurl/src/gurl.h" + +// Basic PageCyclerBrowserTest structure; used in testing most of PageCycler's +// functionality. +class PageCyclerBrowserTest : public content::NotificationObserver, + public InProcessBrowserTest { + public: + PageCyclerBrowserTest() : page_cycler_(NULL) { + } + + virtual ~PageCyclerBrowserTest() { + } + + // Initialize file paths within a temporary directory; this should be + // empty and nonexistent. + virtual void InitFilePaths(FilePath temp_path) { + temp_path_ = temp_path; + urls_file_ = temp_path.AppendASCII("urls_file"); + errors_file_ = temp_path.AppendASCII("errors"); + stats_file_ = temp_path.AppendASCII("stats"); + + ASSERT_FALSE(file_util::PathExists(urls_file_)); + ASSERT_FALSE(file_util::PathExists(errors_file_)); + ASSERT_FALSE(file_util::PathExists(stats_file_)); + } + + // Initialize a PageCycler using either the base fields, or using provided + // ones. + void InitPageCycler() { + page_cycler_ = new PageCycler(browser(), urls_file()); + page_cycler_->set_errors_file(errors_file()); + page_cycler_->set_stats_file(stats_file()); + } + + void InitPageCycler(FilePath urls_file, + FilePath errors_file, + FilePath stats_file) { + page_cycler_ = new PageCycler(browser(), urls_file); + page_cycler_->set_errors_file(errors_file); + page_cycler_->set_stats_file(stats_file); + } + + void RegisterForNotifications() { + registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, + content::NotificationService::AllSources()); + } + + // Get a collection of basic urls which are stored in the test directory. + // NOTE: |test_server| must be started first! + std::vector<GURL> GetURLs() { + std::vector<GURL> urls; + urls.push_back(test_server()->GetURL("files/page_cycler/basic_html.html")); + urls.push_back(test_server()->GetURL("files/page_cycler/basic_js.html")); + urls.push_back(test_server()->GetURL("files/page_cycler/basic_css.html")); + return urls; + } + + // Read the errors file, and generate a vector of error strings. + std::vector<std::string> GetErrorsFromFile() { + std::string error_file_contents; + CHECK(file_util::ReadFileToString(errors_file_, + &error_file_contents)); + if (error_file_contents[error_file_contents.size() - 1] == '\n') + error_file_contents.resize(error_file_contents.size() - 1); + + std::vector<std::string> errors; + base::SplitString(error_file_contents, '\n', &errors); + + return errors; + } + + // Convert a vector of GURLs into a newline-separated string, ready to be + // written to the urls file for PageCycler to use. + std::string GetStringFromURLs(std::vector<GURL> urls) { + std::string urls_string; + for (std::vector<GURL>::const_iterator iter = urls.begin(); + iter != urls.end(); ++iter) + urls_string.append(iter->spec() + "\n"); + return urls_string; + } + + // content::NotificationObserver. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case chrome::NOTIFICATION_BROWSER_CLOSED: + MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + break; + default: + NOTREACHED(); + break; + } + } + + FilePath urls_file() { return urls_file_; } + FilePath errors_file() { return errors_file_; } + FilePath stats_file() { return stats_file_; } + PageCycler* page_cycler() { return page_cycler_; } + + protected: + FilePath temp_path_; + FilePath urls_file_; + FilePath errors_file_; + FilePath stats_file_; + PageCycler* page_cycler_; + content::NotificationRegistrar registrar_; +}; + +// Structure used for testing PageCycler's ability to playback a series of +// URLs given a cache directory. +class PageCyclerCachedBrowserTest : public PageCyclerBrowserTest { + public: + // For a cached test, we use the provided user data directory from the test + // directory. + virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { + InProcessBrowserTest::SetUpCommandLine(command_line); + + FilePath test_dir; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); + test_dir = test_dir.AppendASCII("page_cycler"); + + FilePath source_data_dir = test_dir.AppendASCII("cached_data_dir"); + CHECK(file_util::PathExists(source_data_dir)); + + CHECK(user_data_dir_.CreateUniqueTempDir()); + + FilePath dest_data_dir = + user_data_dir_.path().AppendASCII("cached_data_dir"); + CHECK(!file_util::PathExists(dest_data_dir)); + + CHECK(file_util::CopyDirectory(source_data_dir, + user_data_dir_.path(), + true)); // recursive. + CHECK(file_util::PathExists(dest_data_dir)); + + command_line->AppendSwitchPath(switches::kUserDataDir, + dest_data_dir); + command_line->AppendSwitch(switches::kPlaybackMode); + } + + // Initialize the file paths to use the UserDataDir's urls file, instead + // of one to be written. + virtual void InitFilePaths(FilePath temp_path) OVERRIDE { + urls_file_ = user_data_dir_.path().AppendASCII("cached_data_dir") + .AppendASCII("urls"); + errors_file_ = temp_path.AppendASCII("errors"); + stats_file_ = temp_path.AppendASCII("stats"); + + ASSERT_TRUE(file_util::PathExists(urls_file_)); + ASSERT_FALSE(file_util::PathExists(errors_file_)); + ASSERT_FALSE(file_util::PathExists(stats_file_)); + } + + private: + // The directory storing the copy of the UserDataDir. + ScopedTempDir user_data_dir_; +}; + +// Sanity check; iterate through a series of URLs and make sure there are no +// errors. +IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, BasicTest) { + const size_t kNumIterations = 3; + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + RegisterForNotifications(); + InitFilePaths(temp.path()); + + ASSERT_TRUE(test_server()->Start()); + + std::string urls_string = GetStringFromURLs(GetURLs());; + + ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), + urls_string.size())); + + InitPageCycler(); + page_cycler()->Run(kNumIterations); + + ui_test_utils::RunMessageLoop(); + ASSERT_FALSE(file_util::PathExists(errors_file())); + ASSERT_TRUE(file_util::PathExists(stats_file())); +} + +// Test to make sure that PageCycler will recognize unvisitable URLs, and will +// handle them appropriately. +IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, UnvisitableURL) { + const size_t kNumIterations = 3; + const char kFakeURL[] = "http://www.pleasenoonehavethisurlanytimeinthenext" + "century.com/gibberish"; + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + RegisterForNotifications(); + InitFilePaths(temp.path()); + + ASSERT_TRUE(test_server()->Start()); + + std::vector<GURL> urls = GetURLs(); + urls.push_back(GURL(kFakeURL)); + std::string urls_string = GetStringFromURLs(urls); + + ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), + urls_string.size())); + + InitPageCycler(); + page_cycler()->Run(kNumIterations); + + ui_test_utils::RunMessageLoop(); + ASSERT_TRUE(file_util::PathExists(errors_file())); + ASSERT_TRUE(file_util::PathExists(stats_file())); + + std::vector<std::string> errors = GetErrorsFromFile(); + + size_t num_errors = errors.size(); + ASSERT_EQ(kNumIterations, num_errors); + + // Check that each error message contains the fake URL (i.e., that it wasn't + // from a valid URL, and that the fake URL was caught each time). + for (std::vector<std::string>::const_iterator iter = errors.begin(); + iter != errors.end(); ++iter) { + ASSERT_NE(iter->find(kFakeURL), std::string::npos); + } +} + +// Test that PageCycler will remove an invalid URL prior to running. +IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, InvalidURL) { + const size_t kNumIterations = 1; + const char kBadURL[] = "notarealurl"; + + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + RegisterForNotifications(); + InitFilePaths(temp.path()); + + ASSERT_TRUE(test_server()->Start()); + + std::string urls_string = GetStringFromURLs(GetURLs()); + urls_string.append(kBadURL).append("\n"); + + ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), + urls_string.size())); + + InitPageCycler(); + page_cycler()->Run(kNumIterations); + + ui_test_utils::RunMessageLoop(); + ASSERT_TRUE(file_util::PathExists(errors_file())); + ASSERT_TRUE(file_util::PathExists(stats_file())); + + std::vector<std::string> errors = GetErrorsFromFile(); + ASSERT_EQ(1u, errors.size()); + + std::string expected_error = "Omitting invalid URL: "; + expected_error.append(kBadURL).append("."); + + ASSERT_FALSE(errors[0].compare(expected_error)); +} + +// Test that PageCycler will remove a Chrome Error URL prior to running. +IN_PROC_BROWSER_TEST_F(PageCyclerBrowserTest, ChromeErrorURL) { + const size_t kNumIterations = 1; + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + RegisterForNotifications(); + InitFilePaths(temp.path()); + + ASSERT_TRUE(test_server()->Start()); + + std::vector<GURL> urls = GetURLs(); + urls.push_back(GURL(content::kUnreachableWebDataURL)); + std::string urls_string = GetStringFromURLs(urls); + + ASSERT_TRUE(file_util::WriteFile(urls_file(), urls_string.c_str(), + urls_string.size())); + + InitPageCycler(); + page_cycler()->Run(kNumIterations); + + ui_test_utils::RunMessageLoop(); + ASSERT_TRUE(file_util::PathExists(errors_file())); + ASSERT_TRUE(file_util::PathExists(stats_file())); + + std::vector<std::string> errors = GetErrorsFromFile(); + ASSERT_EQ(1u, errors.size()); + + std::string expected_error = "Chrome error pages are not allowed as urls. " + "Omitting url: "; + expected_error.append(content::kUnreachableWebDataURL).append("."); + + ASSERT_FALSE(errors[0].compare(expected_error)); +} + +// Test that PageCycler will visit all the urls from a cache directory +// successfully while in playback mode. +IN_PROC_BROWSER_TEST_F(PageCyclerCachedBrowserTest, PlaybackMode) { + const size_t kNumIterations = 1; + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + RegisterForNotifications(); + InitFilePaths(temp.path()); + + InitPageCycler(); + + page_cycler()->Run(kNumIterations); + + ui_test_utils::RunMessageLoop(); + ASSERT_TRUE(file_util::PathExists(stats_file())); + ASSERT_FALSE(file_util::PathExists(errors_file())); +} + +// Test that PageCycler will have a cache miss if a URL is missing from the +// cache directory while in playback mode. +IN_PROC_BROWSER_TEST_F(PageCyclerCachedBrowserTest, URLNotInCache) { + const size_t kNumIterations = 1; + const char kCacheMissURL[] = "http://www.images.google.com/"; + + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + + RegisterForNotifications(); + InitFilePaths(temp.path()); + + std::string urls_string; + ASSERT_TRUE(file_util::ReadFileToString(urls_file(), + &urls_string)); + + urls_string.append("\n").append(kCacheMissURL); + FilePath new_urls_file = temp.path().AppendASCII("urls"); + ASSERT_FALSE(file_util::PathExists(new_urls_file)); + + ASSERT_TRUE(file_util::WriteFile(new_urls_file, urls_string.c_str(), + urls_string.size())); + + InitPageCycler(new_urls_file, errors_file(), stats_file()); + page_cycler()->Run(kNumIterations); + + ui_test_utils::RunMessageLoop(); + ASSERT_TRUE(file_util::PathExists(errors_file())); + ASSERT_TRUE(file_util::PathExists(stats_file())); + + std::vector<std::string> errors = GetErrorsFromFile(); + ASSERT_EQ(1u, errors.size()); + + std::string expected_error; + expected_error.append("Failed to load the page at: ") + .append(kCacheMissURL) + .append(": The requested entry was not found in the cache."); + + ASSERT_FALSE(errors[0].compare(expected_error)); +} diff --git a/chrome/browser/page_cycler/page_cycler_unittest.cc b/chrome/browser/page_cycler/page_cycler_unittest.cc new file mode 100644 index 0000000..42c61ac --- /dev/null +++ b/chrome/browser/page_cycler/page_cycler_unittest.cc @@ -0,0 +1,338 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/string_split.h" +#include "base/string_util.h" +#include "base/threading/sequenced_worker_pool.h" +#include "base/utf_string_conversions.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/page_cycler/page_cycler.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/base/browser_with_test_window_test.h" +#include "chrome/test/base/testing_pref_service.h" +#include "content/public/browser/render_view_host.h" +#include "content/test/test_browser_thread.h" +#include "net/base/net_errors.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::Invoke; +using content::RenderViewHost; +using content::TestBrowserThread; +using content::WebContentsObserver; +using file_util::ContentsEqual; +using file_util::PathExists; + +namespace { +const int kFrameID = 1; +const bool kIsMainFrame = true; +const GURL kAboutURL = GURL(chrome::kAboutBlankURL); +const int kSingleIteration = 1; +} // namespace + +class MockPageCycler : public PageCycler { + public: + MockPageCycler(Browser* browser, FilePath urls_file, FilePath errors_file) + : PageCycler(browser, urls_file) { + set_errors_file(errors_file); + } + + MockPageCycler(Browser* browser, + FilePath urls_file, + FilePath errors_file, + FilePath stats_file) + : PageCycler(browser, urls_file) { + set_stats_file(stats_file); + set_errors_file(errors_file); + } + + MOCK_METHOD3(DidFinishLoad, void(int64 frame_id, + const GURL& validated_url, + bool is_main_frame)); + MOCK_METHOD6(DidFailProvisionalLoad, void(int64 frame_id, + bool is_main_frame, + const GURL& validated_url, + int error_code, + const string16& error_description, + RenderViewHost* render_view_host)); + MOCK_METHOD1(RenderViewGone, void(base::TerminationStatus status)); + + void PageCyclerDidFailProvisionalLoad( + int64 frame_id, + bool is_main_frame, + const GURL& validated_url, + int error_code, + const string16& error_description, + RenderViewHost* render_view_host) { + PageCycler::DidFailProvisionalLoad(frame_id, is_main_frame, + validated_url, + error_code, error_description, + render_view_host); + } + + void PageCyclerDidFinishLoad(int64 frame_id, + const GURL& validated_url, + bool is_main_frame) { + PageCycler::DidFinishLoad(frame_id, validated_url, is_main_frame); + } + + private: + virtual ~MockPageCycler() {} + DISALLOW_COPY_AND_ASSIGN(MockPageCycler); +}; + +class PageCyclerTest : public BrowserWithTestWindowTest { + public: + PageCyclerTest() { + } + + virtual ~PageCyclerTest() { + } + + virtual void SetUp() OVERRIDE { + PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_); + test_data_dir_ = test_data_dir_.AppendASCII("page_cycler"); + + BrowserWithTestWindowTest::SetUp(); + AddTab(browser(), kAboutURL); + ASSERT_FALSE(browser()->GetSelectedWebContents() == NULL); + } + + void InitFilePaths(const FilePath& temp_path) { + errors_file_ = temp_path.AppendASCII("errors_file"); + stats_file_ = temp_path.AppendASCII("stats_file"); + + CHECK(!file_util::PathExists(errors_file_)); + CHECK(!file_util::PathExists(stats_file_)); + } + + void FailProvisionalLoad(int error_code, string16& error_description) { + FOR_EACH_OBSERVER(WebContentsObserver, + observers_, + DidFailProvisionalLoad(kFrameID, kIsMainFrame, kAboutURL, error_code, + error_description, NULL)); + PumpLoop(); + } + + void FinishLoad() { + FOR_EACH_OBSERVER(WebContentsObserver, + observers_, + DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame)); + PumpLoop(); + } + + void RunPageCycler(int total_iterations) { + page_cycler_->Run(total_iterations); + PumpLoop(); + } + + void PumpLoop() { + content::BrowserThread::GetBlockingPool()->FlushForTesting(); + message_loop()->RunAllPending(); + } + + void CloseBrowser() { + browser()->OnWindowClosing(); + DestroyBrowser(); + PumpLoop(); + } + + MockPageCycler* page_cycler() { + return page_cycler_.get(); + } + + void set_page_cycler(MockPageCycler* page_cycler) { + page_cycler_ = page_cycler; + observers_.AddObserver(page_cycler); + } + + const std::vector<GURL>* urls_for_test() { + return page_cycler_->urls_for_test(); + } + + FilePath stats_file() { + return stats_file_; + } + + FilePath errors_file() { + return errors_file_; + } + + FilePath urls_file() { + return test_data_dir_.AppendASCII("about_url"); + } + + FilePath test_data_dir() { + return test_data_dir_; + } + + private: + ObserverList<WebContentsObserver> observers_; + scoped_refptr<MockPageCycler> page_cycler_; + FilePath test_data_dir_; + FilePath stats_file_; + FilePath errors_file_; + FilePath urls_file_; +}; + +TEST_F(PageCyclerTest, FailProvisionalLoads) { + const FilePath errors_expected_file = + test_data_dir().AppendASCII("errors_expected"); + + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + InitFilePaths(temp.path()); + + ASSERT_TRUE(PathExists(errors_expected_file)); + ASSERT_TRUE(PathExists(urls_file())); + + set_page_cycler(new MockPageCycler(browser(), + urls_file(), + errors_file())); + RunPageCycler(kSingleIteration); + + // Page cycler expects browser to automatically start loading the first page. + EXPECT_CALL(*page_cycler(), DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame)) + .WillOnce(Invoke(page_cycler(), + &MockPageCycler::PageCyclerDidFinishLoad)); + FinishLoad(); + + // DNS server fail error message. + string16 error_string = + string16(ASCIIToUTF16(net::ErrorToString(net::ERR_DNS_SERVER_FAILED))); + EXPECT_CALL(*page_cycler(), + DidFailProvisionalLoad(kFrameID, kIsMainFrame, _, + net::ERR_DNS_SERVER_FAILED, error_string, + _)) + .WillOnce(Invoke(page_cycler(), + &MockPageCycler::PageCyclerDidFailProvisionalLoad)); + FailProvisionalLoad(net::ERR_DNS_SERVER_FAILED, error_string); + + // DNS time-out error message. + error_string = string16( + ASCIIToUTF16(net::ErrorToString(net::ERR_DNS_TIMED_OUT))); + EXPECT_CALL(*page_cycler(), + DidFailProvisionalLoad(kFrameID, + kIsMainFrame, _, net::ERR_DNS_TIMED_OUT, + error_string, _)) + .WillOnce(Invoke(page_cycler(), + &MockPageCycler::PageCyclerDidFailProvisionalLoad)); + + FailProvisionalLoad(net::ERR_DNS_TIMED_OUT, error_string); + + // DNS time-out error message. + error_string = string16( + ASCIIToUTF16(net::ErrorToString(net::ERR_INVALID_URL))); + EXPECT_CALL(*page_cycler(), + DidFailProvisionalLoad(kFrameID, kIsMainFrame, _, + net::ERR_INVALID_URL, error_string, _)) + .WillOnce(Invoke(page_cycler(), + &MockPageCycler::PageCyclerDidFailProvisionalLoad)); + FailProvisionalLoad(net::ERR_INVALID_URL, error_string); + + PumpLoop(); + + std::string errors_output; + std::string errors_expected; + ASSERT_TRUE(file_util::ReadFileToString(errors_file(), + &errors_output)); + ASSERT_TRUE(file_util::ReadFileToString(errors_expected_file, + &errors_expected)); + ASSERT_EQ(errors_output, errors_expected); +} + +TEST_F(PageCyclerTest, StatsFile) { + const int kNumLoads = 4; + + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + InitFilePaths(temp.path()); + + ASSERT_TRUE(PathExists(urls_file())); + + set_page_cycler(new MockPageCycler(browser(), urls_file(), + errors_file())); + page_cycler()->set_stats_file(stats_file()); + RunPageCycler(kSingleIteration); + + for (int i = 0; i < kNumLoads; ++i) { + EXPECT_CALL(*page_cycler(), DidFinishLoad( + kFrameID, kAboutURL, kIsMainFrame)) + .WillOnce(Invoke(page_cycler(), + &MockPageCycler::PageCyclerDidFinishLoad)); + FinishLoad(); + } + + PumpLoop(); + EXPECT_FALSE(PathExists(errors_file())); + ASSERT_TRUE(PathExists(stats_file())); +} + +TEST_F(PageCyclerTest, KillBrowserAndAbort) { + const FilePath errors_expected_file = + test_data_dir().AppendASCII("abort_expected"); + + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + InitFilePaths(temp.path()); + + ASSERT_TRUE(PathExists(errors_expected_file)); + ASSERT_TRUE(PathExists(urls_file())); + + set_page_cycler(new MockPageCycler(browser(), + urls_file(), + errors_file())); + RunPageCycler(kSingleIteration); + + EXPECT_CALL(*page_cycler(), DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame)) + .WillOnce(Invoke(page_cycler(), + &MockPageCycler::PageCyclerDidFinishLoad)); + message_loop()->RunAllPending(); + + FinishLoad(); + + CloseBrowser(); + PumpLoop(); + + std::string errors_output; + std::string errors_expected; + ASSERT_TRUE(file_util::ReadFileToString(errors_file(), + &errors_output)); + ASSERT_TRUE(file_util::ReadFileToString(errors_expected_file, + &errors_expected)); + ASSERT_EQ(errors_output, errors_expected); +} + +TEST_F(PageCyclerTest, MultipleIterations) { + const int kMultipleIterations = 3; + const int kNumLoads = 10; + + ScopedTempDir temp; + ASSERT_TRUE(temp.CreateUniqueTempDir()); + InitFilePaths(temp.path()); + + ASSERT_TRUE(PathExists(urls_file())); + + set_page_cycler(new MockPageCycler(browser(), + urls_file(), + errors_file())); + page_cycler()->set_stats_file(stats_file()); + RunPageCycler(kMultipleIterations); + + EXPECT_CALL(*page_cycler(), DidFinishLoad(kFrameID, kAboutURL, kIsMainFrame)) + .WillRepeatedly(Invoke(page_cycler(), + &MockPageCycler::PageCyclerDidFinishLoad)); + + for (int i = 0; i < kNumLoads; ++i) + FinishLoad(); + + PumpLoop(); + EXPECT_FALSE(PathExists(errors_file())); + ASSERT_TRUE(PathExists(stats_file())); +} diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc index 454f0b04..a3af32e 100644 --- a/chrome/browser/profiles/profile_impl_io_data.cc +++ b/chrome/browser/profiles/profile_impl_io_data.cc @@ -272,8 +272,11 @@ void ProfileImplIOData::LazyInitializeInternal( IOThread* const io_thread = profile_params->io_thread; IOThread::Globals* const io_thread_globals = io_thread->globals(); const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - bool record_mode = chrome::kRecordModeEnabled && - command_line.HasSwitch(switches::kRecordMode); + // Only allow Record Mode if we are in a Debug build or where we are running + // a cycle, and the user has limited control. + bool record_mode = command_line.HasSwitch(switches::kRecordMode) && + (chrome::kRecordModeEnabled || + command_line.HasSwitch(switches::kVisitURLs)); bool playback_mode = command_line.HasSwitch(switches::kPlaybackMode); // Initialize context members. @@ -472,8 +475,11 @@ ProfileImplIOData::InitializeAppRequestContext( int cache_max_size = 0; const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - bool record_mode = chrome::kRecordModeEnabled && - command_line.HasSwitch(switches::kRecordMode); + // Only allow Record Mode if we are in a Debug build or where we are running + // a cycle, and the user has limited control. + bool record_mode = command_line.HasSwitch(switches::kRecordMode) && + (chrome::kRecordModeEnabled || + command_line.HasSwitch(switches::kVisitURLs)); bool playback_mode = command_line.HasSwitch(switches::kPlaybackMode); // Use a separate HTTP disk cache for isolated apps. diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc index ce2f292..ac3f468 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc @@ -351,7 +351,9 @@ bool StartupBrowserCreatorImpl::Launch(Profile* profile, if (record_mode && chrome::kRecordModeEnabled) base::EventRecorder::current()->StartRecording(script_path); - if (playback_mode) + // Do not enter Playback mode if PageCycler is running; Playback mode does + // not work correctly. + if (playback_mode && !command_line_.HasSwitch(switches::kVisitURLs)) base::EventRecorder::current()->StartPlayback(script_path); } diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 4502a12..5f5bf4c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1468,6 +1468,8 @@ 'browser/ntp_background_util.h', 'browser/omnibox_search_hint.cc', 'browser/omnibox_search_hint.h', + 'browser/page_cycler/page_cycler.cc', + 'browser/page_cycler/page_cycler.h', 'browser/page_info_model.cc', 'browser/page_info_model.h', 'browser/page_info_model_observer.h', @@ -4083,6 +4085,13 @@ 'browser/webdata/web_intents_table.h', 'browser/website_settings.cc', 'browser/website_settings.h', + 'test/base/test_switches.cc', + 'test/base/test_switches.h', + 'test/base/chrome_process_util.cc', + 'test/base/chrome_process_util.h', + 'test/base/chrome_process_util_mac.cc', + 'test/perf/perf_test.cc', + 'test/perf/perf_test.h', # These files are generated by GRIT. '<(grit_out_dir)/grit/component_extension_resources_map.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index be35a4d..beeb939 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1326,6 +1326,7 @@ 'browser/net/url_fixer_upper_unittest.cc', 'browser/net/url_info_unittest.cc', 'browser/notifications/desktop_notification_service_unittest.cc', + 'browser/page_cycler/page_cycler_unittest.cc', 'browser/parsers/metadata_parser_filebase_unittest.cc', 'browser/password_manager/encryptor_password_mac_unittest.cc', 'browser/password_manager/encryptor_unittest.cc', @@ -2816,6 +2817,7 @@ 'browser/notifications/desktop_notifications_unittest.cc', 'browser/notifications/desktop_notifications_unittest.h', 'browser/notifications/notification_browsertest.cc', + 'browser/page_cycler/page_cycler_browsertest.cc', 'browser/policy/device_management_service_browsertest.cc', 'browser/popup_blocker_browsertest.cc', 'browser/prefs/pref_service_browsertest.cc', diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index 496a05c..1d3e430 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc @@ -176,15 +176,11 @@ const FilePath::CharType kPepperFlashPluginFilename[] = FPL("libpepflashplayer.so"); #endif -// We don't enable record mode in the released product because users could -// potentially be tricked into running a product in record mode without -// knowing it. Enable in debug builds. Playback mode is allowed always, +// Since users could potentially be tricked into running a product in record +// mode without knowing it, we only run record mode if the visit-urls flag is +// also present (this check is done elsewhere). Playback mode is allowed always, // because it is useful for testing and not hazardous by itself. -#ifndef NDEBUG const bool kRecordModeEnabled = true; -#else -const bool kRecordModeEnabled = false; -#endif const int kHistogramSynchronizerReservedSequenceNumber = 0; |