15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/page_cycler/page_cycler.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
10ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_commands.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/chrome_process_util.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/perf/perf_test.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/url_constants.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationController;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::OpenURLParams;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::Referrer;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PageCycler::PageCycler(Browser* browser,
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       const base::FilePath& urls_file)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : content::WebContentsObserver(
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          browser->tab_strip_model()->GetActiveWebContents()),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_(browser),
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      urls_file_(urls_file),
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_index_(0),
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      aborted_(false) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserList::AddObserver(this);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();  // Balanced in Finish()/Abort() (only one should be called).
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PageCycler::~PageCycler() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PageCycler::IsLoadCallbackValid(const GURL& validated_url,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     bool is_main_frame) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |url_index_| is equal to zero, that means that this was called before
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LoadNextURL() - this can happen at startup, loading the new tab page; or
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if the user specified a bad url as the final url in the list. In these
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cases, do not report success or failure, and load the next page.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url_index_) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LoadNextURL();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (is_main_frame &&
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          validated_url.spec() != content::kUnreachableWebDataURL);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::DidFinishLoad(int64 frame_id,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const GURL& validated_url,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               bool is_main_frame,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               content::RenderViewHost* render_view_host) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsLoadCallbackValid(validated_url, is_main_frame))
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LoadSucceeded();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::DidFailProvisionalLoad(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 frame_id,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_main_frame,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& validated_url,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int error_code,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& error_description,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RenderViewHost* render_view_host) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsLoadCallbackValid(validated_url, is_main_frame))
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LoadFailed(validated_url, error_description);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::Run() {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (browser_)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostBlockingPoolTask(
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&PageCycler::ReadURLsOnBackgroundThread, this));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::ReadURLsOnBackgroundThread() {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string file_contents;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> url_strings;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  CHECK(base::PathExists(urls_file_)) << urls_file_.value();
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_util::ReadFileToString(urls_file_, &file_contents);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::SplitStringAlongWhitespace(file_contents, &url_strings);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!url_strings.size()) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_.append(ASCIIToUTF16("Page Cycler: No URLs in given file: " +
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        urls_file_.value()));
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_.append(ASCIIToUTF16("Page Cycler: No URLs in given file: "))
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          .append(urls_file_.value());
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_WIN
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<std::string>::const_iterator iter = url_strings.begin();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != url_strings.end(); ++iter) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GURL gurl(*iter);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!gurl.is_valid())
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_.append(ASCIIToUTF16("Omitting invalid URL: " + *iter + ".\n"));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Since we don't count kUnreachableWebData as a valid load, we don't want
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the user to specify this as one of the pages to visit.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (*iter == content::kUnreachableWebDataURL) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_.append(ASCIIToUTF16(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "Chrome error pages are not allowed as urls. Omitting url: " +
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          *iter + ".\n"));
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      urls_.push_back(gurl);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::BrowserThread::PostTask(content::BrowserThread::UI,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   FROM_HERE,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   base::Bind(&PageCycler::BeginCycle, this));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::BeginCycle() {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(browser_);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Upon launch, Chrome will automatically load the newtab page. This can
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // result in the browser being in a state of loading when PageCycler is ready
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to start. Instead of interrupting the load, we wait for it to finish, and
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will call LoadNextURL() from DidFinishLoad() or DidFailProvisionalLoad().
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (browser_->tab_strip_model()->GetActiveWebContents()->IsLoading())
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadNextURL();
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::LoadNextURL() {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(browser_);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_index_ >= urls_.size()) {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostBlockingPoolTask(
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&PageCycler::PrepareResultsOnBackgroundThread, this));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (url_index_) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timings_string_.append(", ");
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    urls_string_.append(", ");
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  urls_string_.append(urls_[url_index_].spec());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initial_time_ = base::TimeTicks::HighResNow();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OpenURLParams params(urls_[url_index_],
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       Referrer(),
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       CURRENT_TAB,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       content::PAGE_TRANSITION_TYPED,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       false);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++url_index_;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_->OpenURL(params);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::LoadSucceeded() {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta time_elapsed =
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (base::TimeTicks::HighResNow() - initial_time_) / 1000.0;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timings_string_.append(base::Int64ToString(time_elapsed.ToInternalValue()));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadNextURL();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::LoadFailed(const GURL& url,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const string16& error_description) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_.append(ASCIIToUTF16("Failed to load the page at: " +
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url.spec() + ": ")).append(error_description).
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      append(ASCIIToUTF16("\n"));
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta time_elapsed =
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (base::TimeTicks::HighResNow() - initial_time_) / 1000.0;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timings_string_.append(base::Int64ToString(time_elapsed.ToInternalValue()) +
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (" (failed)"));
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadNextURL();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::PrepareResultsOnBackgroundThread() {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string output;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stats_file_.empty()) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessId pid = base::GetParentProcessId(base::GetCurrentProcId());
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ProcessId pid = base::GetCurrentProcId();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_WIN
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChromeProcessList chrome_processes(GetRunningChromeProcesses(pid));
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output += perf_test::MemoryUsageInfoToString(
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        std::string(), chrome_processes, pid);
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output +=
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        perf_test::IOPerfInfoToString(std::string(), chrome_processes, pid);
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output += perf_test::SystemCommitChargeToString(
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        std::string(), base::GetSystemCommitCharge(), false);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append("Pages: [" + urls_string_ + "]\n");
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output.append("*RESULT times: t_ref= [" + timings_string_ + "] ms\n");
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WriteResultsOnBackgroundThread(output);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::WriteResultsOnBackgroundThread(const std::string& output) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!output.empty()) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(!stats_file_.empty());
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (base::PathExists(stats_file_)) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(1) << "PageCycler: Previous stats file found; appending.";
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_util::AppendToFile(stats_file_, output.c_str(), output.size());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_util::WriteFile(stats_file_, output.c_str(), output.size());
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!errors_file_.empty()) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!error_.empty()) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_util::WriteFile(errors_file_, UTF16ToUTF8(error_).c_str(),
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           error_.size());
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else if (base::PathExists(errors_file_)) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If there is an old error file, delete it to avoid confusion.
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::DeleteFile(errors_file_, false);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (aborted_) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostTask(content::BrowserThread::UI,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     FROM_HERE,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     base::Bind(&PageCycler::Abort, this));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostTask(content::BrowserThread::UI,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     FROM_HERE,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     base::Bind(&PageCycler::Finish, this));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::Finish() {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserList::RemoveObserver(this);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_->OnWindowClosing();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::ExecuteCommand(browser_, IDC_EXIT);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in PageCycler constructor;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // (only one of Finish/Abort should be called).
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::Abort() {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  browser_ = NULL;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserList::RemoveObserver(this);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Balanced in PageCycler constructor;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // (only one of Finish/Abort should be called).
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::OnBrowserAdded(Browser* browser) {}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PageCycler::OnBrowserRemoved(Browser* browser) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (browser == browser_) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    aborted_ = true;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_.append(ASCIIToUTF16(
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Browser was closed before the run was completed."));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) <<
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "Page Cycler: browser was closed before the run was completed.";
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::BrowserThread::PostBlockingPoolTask(
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&PageCycler::PrepareResultsOnBackgroundThread, this));
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
268