root/chrome/browser/download/save_page_browsertest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. persisted_
  2. WaitForPersisted
  3. OnDownloadStored
  4. download_id_
  5. WaitForRemoved
  6. OnDownloadStored
  7. OnDownloadsRemoved
  8. DownloadStoredProperly
  9. manager_
  10. WaitForDownloadItem
  11. OnDownloadCreated
  12. ManagerGoingDown
  13. callback_
  14. OnSavePackageSuccessfullyFinished
  15. ManagerGoingDown
  16. SetUp
  17. SetUpOnMainThread
  18. NavigateToMockURL
  19. GetDestinationPaths
  20. GetCurrentTab
  21. VerifySavePackageExpectations
  22. GetDownloadManager
  23. IN_PROC_BROWSER_TEST_F
  24. IN_PROC_BROWSER_TEST_F
  25. ShouldCompleteDownload
  26. IN_PROC_BROWSER_TEST_F
  27. IN_PROC_BROWSER_TEST_F
  28. IN_PROC_BROWSER_TEST_F
  29. IN_PROC_BROWSER_TEST_F
  30. IN_PROC_BROWSER_TEST_F
  31. IN_PROC_BROWSER_TEST_F
  32. IN_PROC_BROWSER_TEST_F
  33. IN_PROC_BROWSER_TEST_F
  34. SetUpCommandLine
  35. IN_PROC_BROWSER_TEST_F
  36. IN_PROC_BROWSER_TEST_F

// 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/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/prefs/pref_member.h"
#include "base/prefs/pref_service.h"
#include "base/test/test_file_util.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_service.h"
#include "chrome/browser/download/download_service_factory.h"
#include "chrome/browser/download/save_package_file_picker.h"
#include "chrome/browser/history/download_row.h"
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_utils.h"
#include "content/test/net/url_request_mock_http_job.h"
#include "testing/gtest/include/gtest/gtest.h"

using content::BrowserContext;
using content::BrowserThread;
using content::DownloadItem;
using content::DownloadManager;
using content::URLRequestMockHTTPJob;
using content::WebContents;

namespace {

// Waits for an item record in the downloads database to match |filter|. See
// DownloadStoredProperly() below for an example filter.
class DownloadPersistedObserver : public DownloadHistory::Observer {
 public:
  typedef base::Callback<bool(
      DownloadItem* item,
      const history::DownloadRow&)> PersistedFilter;

  DownloadPersistedObserver(Profile* profile, const PersistedFilter& filter)
    : profile_(profile),
      filter_(filter),
      waiting_(false),
      persisted_(false) {
    DownloadServiceFactory::GetForBrowserContext(profile_)->
      GetDownloadHistory()->AddObserver(this);
  }

  virtual ~DownloadPersistedObserver() {
    DownloadService* service = DownloadServiceFactory::GetForBrowserContext(
        profile_);
    if (service && service->GetDownloadHistory())
      service->GetDownloadHistory()->RemoveObserver(this);
  }

  bool WaitForPersisted() {
    if (persisted_)
      return true;
    waiting_ = true;
    content::RunMessageLoop();
    waiting_ = false;
    return persisted_;
  }

  virtual void OnDownloadStored(DownloadItem* item,
                                const history::DownloadRow& info) OVERRIDE {
    persisted_ = persisted_ || filter_.Run(item, info);
    if (persisted_ && waiting_)
      base::MessageLoopForUI::current()->Quit();
  }

 private:
  Profile* profile_;
  PersistedFilter filter_;
  bool waiting_;
  bool persisted_;

  DISALLOW_COPY_AND_ASSIGN(DownloadPersistedObserver);
};

// Waits for an item record to be removed from the downloads database.
class DownloadRemovedObserver : public DownloadPersistedObserver {
 public:
  DownloadRemovedObserver(Profile* profile, int32 download_id)
      : DownloadPersistedObserver(profile, PersistedFilter()),
        removed_(false),
        waiting_(false),
        download_id_(download_id) {
  }
  virtual ~DownloadRemovedObserver() {}

  bool WaitForRemoved() {
    if (removed_)
      return true;
    waiting_ = true;
    content::RunMessageLoop();
    waiting_ = false;
    return removed_;
  }

  virtual void OnDownloadStored(DownloadItem* item,
                                const history::DownloadRow& info) OVERRIDE {
  }

  virtual void OnDownloadsRemoved(const DownloadHistory::IdSet& ids) OVERRIDE {
    removed_ = ids.find(download_id_) != ids.end();
    if (removed_ && waiting_)
      base::MessageLoopForUI::current()->Quit();
  }

 private:
  bool removed_;
  bool waiting_;
  int32 download_id_;

  DISALLOW_COPY_AND_ASSIGN(DownloadRemovedObserver);
};

bool DownloadStoredProperly(
    const GURL& expected_url,
    const base::FilePath& expected_path,
    int64 num_files,
    DownloadItem::DownloadState expected_state,
    DownloadItem* item,
    const history::DownloadRow& info) {
  // This function may be called multiple times for a given test. Returning
  // false doesn't necessarily mean that the test has failed or will fail, it
  // might just mean that the test hasn't passed yet.
  if (info.target_path != expected_path) {
    VLOG(20) << __FUNCTION__ << " " << info.target_path.value()
             << " != " << expected_path.value();
    return false;
  }
  if (info.url_chain.size() != 1u) {
    VLOG(20) << __FUNCTION__ << " " << info.url_chain.size()
             << " != 1";
    return false;
  }
  if (info.url_chain[0] != expected_url) {
    VLOG(20) << __FUNCTION__ << " " << info.url_chain[0].spec()
             << " != " << expected_url.spec();
    return false;
  }
  if ((num_files >= 0) && (info.received_bytes != num_files)) {
    VLOG(20) << __FUNCTION__ << " " << num_files
             << " != " << info.received_bytes;
    return false;
  }
  if (info.state != expected_state) {
    VLOG(20) << __FUNCTION__ << " " << info.state
             << " != " << expected_state;
    return false;
  }
  return true;
}

const base::FilePath::CharType kTestDir[] = FILE_PATH_LITERAL("save_page");

static const char kAppendedExtension[] =
#if defined(OS_WIN)
    ".htm";
#else
    ".html";
#endif

// Loosely based on logic in DownloadTestObserver.
class DownloadItemCreatedObserver : public DownloadManager::Observer {
 public:
  explicit DownloadItemCreatedObserver(DownloadManager* manager)
      : waiting_(false), manager_(manager) {
    manager->AddObserver(this);
  }

  virtual ~DownloadItemCreatedObserver() {
    if (manager_)
      manager_->RemoveObserver(this);
  }

  // Wait for the first download item created after object creation.
  // Note that this class provides no protection against the download
  // being destroyed between creation and return of WaitForNewDownloadItem();
  // the caller must guarantee that in some other fashion.
  void WaitForDownloadItem(std::vector<DownloadItem*>* items_seen) {
    if (!manager_) {
      // The manager went away before we were asked to wait; return
      // what we have, even if it's null.
      *items_seen = items_seen_;
      return;
    }

    if (items_seen_.empty()) {
      waiting_ = true;
      content::RunMessageLoop();
      waiting_ = false;
    }

    *items_seen = items_seen_;
    return;
  }

 private:
  // DownloadManager::Observer
  virtual void OnDownloadCreated(
      DownloadManager* manager, DownloadItem* item) OVERRIDE {
    DCHECK_EQ(manager, manager_);
    items_seen_.push_back(item);

    if (waiting_)
      base::MessageLoopForUI::current()->Quit();
  }

  virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE {
    manager_->RemoveObserver(this);
    manager_ = NULL;
    if (waiting_)
      base::MessageLoopForUI::current()->Quit();
  }

  bool waiting_;
  DownloadManager* manager_;
  std::vector<DownloadItem*> items_seen_;

  DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver);
};

class SavePackageFinishedObserver : public content::DownloadManager::Observer {
 public:
  SavePackageFinishedObserver(content::DownloadManager* manager,
                              const base::Closure& callback)
      : download_manager_(manager),
        callback_(callback) {
    download_manager_->AddObserver(this);
  }

  virtual ~SavePackageFinishedObserver() {
    if (download_manager_)
      download_manager_->RemoveObserver(this);
  }

  // DownloadManager::Observer:
  virtual void OnSavePackageSuccessfullyFinished(
      content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE {
    callback_.Run();
  }
  virtual void ManagerGoingDown(content::DownloadManager* manager) OVERRIDE {
    download_manager_->RemoveObserver(this);
    download_manager_ = NULL;
  }

 private:
  content::DownloadManager* download_manager_;
  base::Closure callback_;

  DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver);
};

class SavePageBrowserTest : public InProcessBrowserTest {
 public:
  SavePageBrowserTest() {}
  virtual ~SavePageBrowserTest();

 protected:
  virtual void SetUp() OVERRIDE {
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_));
    ASSERT_TRUE(save_dir_.CreateUniqueTempDir());
    InProcessBrowserTest::SetUp();
  }

  virtual void SetUpOnMainThread() OVERRIDE {
    browser()->profile()->GetPrefs()->SetFilePath(
        prefs::kDownloadDefaultDirectory, save_dir_.path());
    browser()->profile()->GetPrefs()->SetFilePath(
        prefs::kSaveFileDefaultDirectory, save_dir_.path());
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
  }

  GURL NavigateToMockURL(const std::string& prefix) {
    GURL url = URLRequestMockHTTPJob::GetMockUrl(
        base::FilePath(kTestDir).AppendASCII(prefix + ".htm"));
    ui_test_utils::NavigateToURL(browser(), url);
    return url;
  }

  // Returns full paths of destination file and directory.
  void GetDestinationPaths(const std::string& prefix,
                base::FilePath* full_file_name,
                base::FilePath* dir) {
    *full_file_name = save_dir_.path().AppendASCII(prefix + ".htm");
    *dir = save_dir_.path().AppendASCII(prefix + "_files");
  }

  WebContents* GetCurrentTab(Browser* browser) const {
    WebContents* current_tab =
        browser->tab_strip_model()->GetActiveWebContents();
    EXPECT_TRUE(current_tab);
    return current_tab;
  }

  // Returns true if and when there was a single download created, and its url
  // is |expected_url|.
  bool VerifySavePackageExpectations(
      Browser* browser,
      const GURL& expected_url) const {
    // Generally, there should only be one download item created
    // in all of these tests.  If it's already here, grab it; if not,
    // wait for it to show up.
    std::vector<DownloadItem*> items;
    DownloadManager* manager(
        BrowserContext::GetDownloadManager(browser->profile()));
    manager->GetAllDownloads(&items);
    if (items.size() == 0u) {
      DownloadItemCreatedObserver(manager).WaitForDownloadItem(&items);
    }

    EXPECT_EQ(1u, items.size());
    if (1u != items.size())
      return false;
    DownloadItem* download_item(items[0]);

    return (expected_url == download_item->GetOriginalUrl());
  }

  // Note on synchronization:
  //
  // For each Save Page As operation, we create a corresponding shell
  // DownloadItem to display progress to the user.  That DownloadItem goes
  // through its own state transitions, including being persisted out to the
  // history database, and the download shelf is not shown until after the
  // persistence occurs.  Save Package completion (and marking the DownloadItem
  // as completed) occurs asynchronously from persistence.  Thus if we want to
  // examine either UI state or DB state, we need to wait until both the save
  // package operation is complete and the relevant download item has been
  // persisted.

  DownloadManager* GetDownloadManager() const {
    DownloadManager* download_manager =
        BrowserContext::GetDownloadManager(browser()->profile());
    EXPECT_TRUE(download_manager);
    return download_manager;
  }

  // Path to directory containing test data.
  base::FilePath test_dir_;

  // Temporary directory we will save pages to.
  base::ScopedTempDir save_dir_;

 private:
  DISALLOW_COPY_AND_ASSIGN(SavePageBrowserTest);
};

SavePageBrowserTest::~SavePageBrowserTest() {
}

// Disabled on Windows due to flakiness. http://crbug.com/162323
#if defined(OS_WIN)
#define MAYBE_SaveHTMLOnly DISABLED_SaveHTMLOnly
#else
#define MAYBE_SaveHTMLOnly SaveHTMLOnly
#endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveHTMLOnly) {
  GURL url = NavigateToMockURL("a");

  base::FilePath full_file_name, dir;
  GetDestinationPaths("a", &full_file_name, &dir);
  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
      &DownloadStoredProperly, url, full_file_name, 1,
      DownloadItem::COMPLETE));
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
  loop_runner->Run();
  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
  persisted.WaitForPersisted();
  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
  EXPECT_TRUE(base::PathExists(full_file_name));
  EXPECT_FALSE(base::PathExists(dir));
  EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
      kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
}

// http://crbug.com/162323
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, DISABLED_SaveHTMLOnlyCancel) {
  GURL url = NavigateToMockURL("a");
  DownloadManager* manager(GetDownloadManager());
  std::vector<DownloadItem*> downloads;
  manager->GetAllDownloads(&downloads);
  ASSERT_EQ(0u, downloads.size());

  base::FilePath full_file_name, dir;
  GetDestinationPaths("a", &full_file_name, &dir);
  DownloadItemCreatedObserver creation_observer(manager);
  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
      &DownloadStoredProperly, url, full_file_name, -1,
      DownloadItem::CANCELLED));
  // -1 to disable number of files check; we don't update after cancel, and
  // we don't know when the single file completed in relationship to
  // the cancel.

  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
  std::vector<DownloadItem*> items;
  creation_observer.WaitForDownloadItem(&items);
  ASSERT_EQ(1UL, items.size());
  ASSERT_EQ(url.spec(), items[0]->GetOriginalUrl().spec());
  items[0]->Cancel(true);
  // TODO(rdsmith): Fix DII::Cancel() to actually cancel the save package.
  // Currently it's ignored.

  persisted.WaitForPersisted();

  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());

  // TODO(benjhayden): Figure out how to safely wait for SavePackage's finished
  // notification, then expect the contents of the downloaded file.
}

class DelayingDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
 public:
  explicit DelayingDownloadManagerDelegate(Profile* profile)
    : ChromeDownloadManagerDelegate(profile) {
  }
  virtual ~DelayingDownloadManagerDelegate() {}

  virtual bool ShouldCompleteDownload(
      content::DownloadItem* item,
      const base::Closure& user_complete_callback) OVERRIDE {
    return false;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DelayingDownloadManagerDelegate);
};

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyTabDestroy) {
  GURL url = NavigateToMockURL("a");
  scoped_ptr<DelayingDownloadManagerDelegate> delaying_delegate(
      new DelayingDownloadManagerDelegate(browser()->profile()));
  delaying_delegate->GetDownloadIdReceiverCallback().Run(
      content::DownloadItem::kInvalidId + 1);
  DownloadServiceFactory::GetForBrowserContext(browser()->profile())->
      SetDownloadManagerDelegateForTesting(
          delaying_delegate.PassAs<ChromeDownloadManagerDelegate>());
  DownloadManager* manager(GetDownloadManager());
  std::vector<DownloadItem*> downloads;
  manager->GetAllDownloads(&downloads);
  ASSERT_EQ(0u, downloads.size());

  base::FilePath full_file_name, dir;
  GetDestinationPaths("a", &full_file_name, &dir);
  DownloadItemCreatedObserver creation_observer(manager);
  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
  std::vector<DownloadItem*> items;
  creation_observer.WaitForDownloadItem(&items);
  ASSERT_TRUE(items.size() == 1);

  // Close the tab; does this cancel the download?
  GetCurrentTab(browser())->Close();
  EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());

  EXPECT_FALSE(base::PathExists(full_file_name));
  EXPECT_FALSE(base::PathExists(dir));
}

// Disabled on Windows due to flakiness. http://crbug.com/162323
#if defined(OS_WIN)
#define MAYBE_SaveViewSourceHTMLOnly DISABLED_SaveViewSourceHTMLOnly
#else
#define MAYBE_SaveViewSourceHTMLOnly SaveViewSourceHTMLOnly
#endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveViewSourceHTMLOnly) {
  base::FilePath file_name(FILE_PATH_LITERAL("a.htm"));
  GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl(
      base::FilePath(kTestDir).Append(file_name));
  GURL actual_page_url = URLRequestMockHTTPJob::GetMockUrl(
      base::FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), view_source_url);

  base::FilePath full_file_name, dir;
  GetDestinationPaths("a", &full_file_name, &dir);
  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
      &DownloadStoredProperly, actual_page_url, full_file_name, 1,
      DownloadItem::COMPLETE));
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
  loop_runner->Run();
  ASSERT_TRUE(VerifySavePackageExpectations(browser(), actual_page_url));
  persisted.WaitForPersisted();

  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());

  EXPECT_TRUE(base::PathExists(full_file_name));
  EXPECT_FALSE(base::PathExists(dir));
  EXPECT_TRUE(base::ContentsEqual(
      test_dir_.Append(base::FilePath(kTestDir)).Append(file_name),
      full_file_name));
}

// Disabled on Windows due to flakiness. http://crbug.com/162323
#if defined(OS_WIN)
#define MAYBE_SaveCompleteHTML DISABLED_SaveCompleteHTML
#else
#define MAYBE_SaveCompleteHTML SaveCompleteHTML
#endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveCompleteHTML) {
  GURL url = NavigateToMockURL("b");

  base::FilePath full_file_name, dir;
  GetDestinationPaths("b", &full_file_name, &dir);
  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
      &DownloadStoredProperly, url, full_file_name, 3,
      DownloadItem::COMPLETE));
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
      full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
  loop_runner->Run();
  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
  persisted.WaitForPersisted();

  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());

  EXPECT_TRUE(base::PathExists(full_file_name));
  EXPECT_TRUE(base::PathExists(dir));
  EXPECT_TRUE(base::TextContentsEqual(
      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved1.htm"),
      full_file_name));
  EXPECT_TRUE(base::ContentsEqual(
      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"),
      dir.AppendASCII("1.png")));
  EXPECT_TRUE(base::ContentsEqual(
      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"),
      dir.AppendASCII("1.css")));
}

// Invoke a save page during the initial navigation.
// (Regression test for http://crbug.com/156538).
// Disabled on Windows due to flakiness. http://crbug.com/162323
#if defined(OS_WIN)
#define MAYBE_SaveDuringInitialNavigationIncognito DISABLED_SaveDuringInitialNavigationIncognito
#else
#define MAYBE_SaveDuringInitialNavigationIncognito SaveDuringInitialNavigationIncognito
#endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,
                       MAYBE_SaveDuringInitialNavigationIncognito) {
  // Open an Incognito window.
  Browser* incognito = CreateIncognitoBrowser();  // Waits.
  ASSERT_TRUE(incognito);

  // Create a download item creation waiter on that window.
  DownloadItemCreatedObserver creation_observer(
      BrowserContext::GetDownloadManager(incognito->profile()));

  // Navigate, unblocking with new tab.
  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      base::FilePath(kTestDir).AppendASCII("b.htm"));
  NavigateToURLWithDisposition(incognito, url, NEW_FOREGROUND_TAB,
                               ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);

  // Save the page before completion.
  base::FilePath full_file_name, dir;
  GetDestinationPaths("b", &full_file_name, &dir);
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(incognito->profile()),
      loop_runner->QuitClosure());
  ASSERT_TRUE(GetCurrentTab(incognito)->SavePage(
      full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));

  loop_runner->Run();
  ASSERT_TRUE(VerifySavePackageExpectations(incognito, url));

  // Confirm download shelf is visible.
  EXPECT_TRUE(incognito->window()->IsDownloadShelfVisible());

  // We can't check more than this because SavePackage is racing with
  // the page load.  If the page load won the race, then SavePackage
  // might have completed. If the page load lost the race, then
  // SavePackage will cancel because there aren't any resources to
  // save.
}

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) {
  ui_test_utils::NavigateToURL(browser(), GURL(content::kAboutBlankURL));
  EXPECT_FALSE(chrome::CanSavePage(browser()));
}

// Disabled on Windows due to flakiness. http://crbug.com/162323
#if defined(OS_WIN)
#define MAYBE_FileNameFromPageTitle DISABLED_FileNameFromPageTitle
#else
#define MAYBE_FileNameFromPageTitle FileNameFromPageTitle
#endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_FileNameFromPageTitle) {
  GURL url = NavigateToMockURL("b");

  base::FilePath full_file_name = save_dir_.path().AppendASCII(
      std::string("Test page for saving page feature") + kAppendedExtension);
  base::FilePath dir = save_dir_.path().AppendASCII(
      "Test page for saving page feature_files");
  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
      &DownloadStoredProperly, url, full_file_name, 3,
      DownloadItem::COMPLETE));
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
      full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));

  loop_runner->Run();
  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
  persisted.WaitForPersisted();

  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());

  EXPECT_TRUE(base::PathExists(full_file_name));
  EXPECT_TRUE(base::PathExists(dir));
  EXPECT_TRUE(base::TextContentsEqual(
      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved2.htm"),
      full_file_name));
  EXPECT_TRUE(base::ContentsEqual(
      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"),
      dir.AppendASCII("1.png")));
  EXPECT_TRUE(base::ContentsEqual(
      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"),
      dir.AppendASCII("1.css")));
}

// Disabled on Windows due to flakiness. http://crbug.com/162323
#if defined(OS_WIN)
#define MAYBE_RemoveFromList DISABLED_RemoveFromList
#else
#define MAYBE_RemoveFromList RemoveFromList
#endif
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_RemoveFromList) {
  GURL url = NavigateToMockURL("a");

  base::FilePath full_file_name, dir;
  GetDestinationPaths("a", &full_file_name, &dir);
  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
      &DownloadStoredProperly, url, full_file_name, 1,
      DownloadItem::COMPLETE));
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));

  loop_runner->Run();
  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
  persisted.WaitForPersisted();

  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());

  DownloadManager* manager(GetDownloadManager());
  std::vector<DownloadItem*> downloads;
  manager->GetAllDownloads(&downloads);
  ASSERT_EQ(1UL, downloads.size());
  DownloadRemovedObserver removed(browser()->profile(), downloads[0]->GetId());

  EXPECT_EQ(manager->RemoveAllDownloads(), 1);

  removed.WaitForRemoved();

  EXPECT_TRUE(base::PathExists(full_file_name));
  EXPECT_FALSE(base::PathExists(dir));
  EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
      kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
}

// This tests that a webpage with the title "test.exe" is saved as
// "test.exe.htm".
// We probably don't care to handle this on Linux or Mac.
#if defined(OS_WIN)
IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, CleanFilenameFromPageTitle) {
  const base::FilePath file_name(FILE_PATH_LITERAL("c.htm"));
  base::FilePath download_dir =
      DownloadPrefs::FromDownloadManager(GetDownloadManager())->
          DownloadPath();
  base::FilePath full_file_name =
      download_dir.AppendASCII(std::string("test.exe") + kAppendedExtension);
  base::FilePath dir = download_dir.AppendASCII("test.exe_files");

  EXPECT_FALSE(base::PathExists(full_file_name));
  GURL url = URLRequestMockHTTPJob::GetMockUrl(
      base::FilePath(kTestDir).Append(file_name));
  ui_test_utils::NavigateToURL(browser(), url);

  SavePackageFilePicker::SetShouldPromptUser(false);
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  chrome::SavePage(browser());
  loop_runner->Run();

  EXPECT_TRUE(base::PathExists(full_file_name));

  EXPECT_TRUE(base::DieFileDie(full_file_name, false));
  EXPECT_TRUE(base::DieFileDie(dir, true));
}
#endif

class SavePageAsMHTMLBrowserTest : public SavePageBrowserTest {
 public:
  SavePageAsMHTMLBrowserTest() {}
  virtual ~SavePageAsMHTMLBrowserTest();
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    command_line->AppendSwitch(switches::kSavePageAsMHTML);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(SavePageAsMHTMLBrowserTest);
};

SavePageAsMHTMLBrowserTest::~SavePageAsMHTMLBrowserTest() {
}

IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest, SavePageAsMHTML) {
  static const int64 kFileSizeMin = 2758;
  GURL url = NavigateToMockURL("b");
  base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
      GetDownloadManager())->DownloadPath();
  base::FilePath full_file_name = download_dir.AppendASCII(std::string(
      "Test page for saving page feature.mhtml"));
  SavePackageFilePicker::SetShouldPromptUser(false);
  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
      &DownloadStoredProperly, url, full_file_name, -1,
      DownloadItem::COMPLETE));
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  chrome::SavePage(browser());
  loop_runner->Run();
  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
  persisted.WaitForPersisted();

  ASSERT_TRUE(base::PathExists(full_file_name));
  int64 actual_file_size = -1;
  EXPECT_TRUE(base::GetFileSize(full_file_name, &actual_file_size));
  EXPECT_LE(kFileSizeMin, actual_file_size);
}

IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SavePageBrowserTest_NonMHTML) {
  SavePackageFilePicker::SetShouldPromptUser(false);
  GURL url("data:text/plain,foo");
  ui_test_utils::NavigateToURL(browser(), url);
  scoped_refptr<content::MessageLoopRunner> loop_runner(
      new content::MessageLoopRunner);
  SavePackageFinishedObserver observer(
      content::BrowserContext::GetDownloadManager(browser()->profile()),
      loop_runner->QuitClosure());
  chrome::SavePage(browser());
  loop_runner->Run();
  base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
      GetDownloadManager())->DownloadPath();
  base::FilePath filename = download_dir.AppendASCII("dataurl.txt");
  ASSERT_TRUE(base::PathExists(filename));
  std::string contents;
  EXPECT_TRUE(base::ReadFileToString(filename, &contents));
  EXPECT_EQ("foo", contents);
}

}  // namespace


/* [<][>][^][v][top][bottom][index][help] */