Home | History | Annotate | Download | only in download
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/bind.h"
      6 #include "base/bind_helpers.h"
      7 #include "base/command_line.h"
      8 #include "base/file_util.h"
      9 #include "base/files/file_path.h"
     10 #include "base/files/scoped_temp_dir.h"
     11 #include "base/path_service.h"
     12 #include "base/prefs/pref_member.h"
     13 #include "base/prefs/pref_service.h"
     14 #include "base/test/test_file_util.h"
     15 #include "chrome/app/chrome_command_ids.h"
     16 #include "chrome/browser/download/chrome_download_manager_delegate.h"
     17 #include "chrome/browser/download/download_history.h"
     18 #include "chrome/browser/download/download_prefs.h"
     19 #include "chrome/browser/download/download_service.h"
     20 #include "chrome/browser/download/download_service_factory.h"
     21 #include "chrome/browser/download/save_package_file_picker.h"
     22 #include "chrome/browser/history/download_row.h"
     23 #include "chrome/browser/net/url_request_mock_util.h"
     24 #include "chrome/browser/profiles/profile.h"
     25 #include "chrome/browser/ui/browser.h"
     26 #include "chrome/browser/ui/browser_commands.h"
     27 #include "chrome/browser/ui/browser_window.h"
     28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     29 #include "chrome/common/chrome_paths.h"
     30 #include "chrome/common/chrome_switches.h"
     31 #include "chrome/common/pref_names.h"
     32 #include "chrome/common/url_constants.h"
     33 #include "chrome/test/base/in_process_browser_test.h"
     34 #include "chrome/test/base/ui_test_utils.h"
     35 #include "content/public/browser/download_item.h"
     36 #include "content/public/browser/download_manager.h"
     37 #include "content/public/browser/notification_service.h"
     38 #include "content/public/browser/notification_types.h"
     39 #include "content/public/browser/web_contents.h"
     40 #include "content/public/test/test_utils.h"
     41 #include "content/test/net/url_request_mock_http_job.h"
     42 #include "testing/gtest/include/gtest/gtest.h"
     43 
     44 using content::BrowserContext;
     45 using content::BrowserThread;
     46 using content::DownloadItem;
     47 using content::DownloadManager;
     48 using content::URLRequestMockHTTPJob;
     49 using content::WebContents;
     50 
     51 namespace {
     52 
     53 // Waits for an item record in the downloads database to match |filter|. See
     54 // DownloadStoredProperly() below for an example filter.
     55 class DownloadPersistedObserver : public DownloadHistory::Observer {
     56  public:
     57   typedef base::Callback<bool(
     58       DownloadItem* item,
     59       const history::DownloadRow&)> PersistedFilter;
     60 
     61   DownloadPersistedObserver(Profile* profile, const PersistedFilter& filter)
     62     : profile_(profile),
     63       filter_(filter),
     64       waiting_(false),
     65       persisted_(false) {
     66     DownloadServiceFactory::GetForBrowserContext(profile_)->
     67       GetDownloadHistory()->AddObserver(this);
     68   }
     69 
     70   virtual ~DownloadPersistedObserver() {
     71     DownloadService* service = DownloadServiceFactory::GetForBrowserContext(
     72         profile_);
     73     if (service && service->GetDownloadHistory())
     74       service->GetDownloadHistory()->RemoveObserver(this);
     75   }
     76 
     77   bool WaitForPersisted() {
     78     if (persisted_)
     79       return true;
     80     waiting_ = true;
     81     content::RunMessageLoop();
     82     waiting_ = false;
     83     return persisted_;
     84   }
     85 
     86   virtual void OnDownloadStored(DownloadItem* item,
     87                                 const history::DownloadRow& info) OVERRIDE {
     88     persisted_ = persisted_ || filter_.Run(item, info);
     89     if (persisted_ && waiting_)
     90       base::MessageLoopForUI::current()->Quit();
     91   }
     92 
     93  private:
     94   Profile* profile_;
     95   DownloadItem* item_;
     96   PersistedFilter filter_;
     97   bool waiting_;
     98   bool persisted_;
     99 
    100   DISALLOW_COPY_AND_ASSIGN(DownloadPersistedObserver);
    101 };
    102 
    103 // Waits for an item record to be removed from the downloads database.
    104 class DownloadRemovedObserver : public DownloadPersistedObserver {
    105  public:
    106   DownloadRemovedObserver(Profile* profile, int32 download_id)
    107       : DownloadPersistedObserver(profile, PersistedFilter()),
    108         removed_(false),
    109         waiting_(false),
    110         download_id_(download_id) {
    111   }
    112   virtual ~DownloadRemovedObserver() {}
    113 
    114   bool WaitForRemoved() {
    115     if (removed_)
    116       return true;
    117     waiting_ = true;
    118     content::RunMessageLoop();
    119     waiting_ = false;
    120     return removed_;
    121   }
    122 
    123   virtual void OnDownloadStored(DownloadItem* item,
    124                                 const history::DownloadRow& info) OVERRIDE {
    125   }
    126 
    127   virtual void OnDownloadsRemoved(const DownloadHistory::IdSet& ids) OVERRIDE {
    128     removed_ = ids.find(download_id_) != ids.end();
    129     if (removed_ && waiting_)
    130       base::MessageLoopForUI::current()->Quit();
    131   }
    132 
    133  private:
    134   bool removed_;
    135   bool waiting_;
    136   int32 download_id_;
    137 
    138   DISALLOW_COPY_AND_ASSIGN(DownloadRemovedObserver);
    139 };
    140 
    141 bool DownloadStoredProperly(
    142     const GURL& expected_url,
    143     const base::FilePath& expected_path,
    144     int64 num_files,
    145     DownloadItem::DownloadState expected_state,
    146     DownloadItem* item,
    147     const history::DownloadRow& info) {
    148   // This function may be called multiple times for a given test. Returning
    149   // false doesn't necessarily mean that the test has failed or will fail, it
    150   // might just mean that the test hasn't passed yet.
    151   if (info.target_path != expected_path) {
    152     VLOG(20) << __FUNCTION__ << " " << info.target_path.value()
    153              << " != " << expected_path.value();
    154     return false;
    155   }
    156   if (info.url_chain.size() != 1u) {
    157     VLOG(20) << __FUNCTION__ << " " << info.url_chain.size()
    158              << " != 1";
    159     return false;
    160   }
    161   if (info.url_chain[0] != expected_url) {
    162     VLOG(20) << __FUNCTION__ << " " << info.url_chain[0].spec()
    163              << " != " << expected_url.spec();
    164     return false;
    165   }
    166   if ((num_files >= 0) && (info.received_bytes != num_files)) {
    167     VLOG(20) << __FUNCTION__ << " " << num_files
    168              << " != " << info.received_bytes;
    169     return false;
    170   }
    171   if (info.state != expected_state) {
    172     VLOG(20) << __FUNCTION__ << " " << info.state
    173              << " != " << expected_state;
    174     return false;
    175   }
    176   return true;
    177 }
    178 
    179 const base::FilePath::CharType kTestDir[] = FILE_PATH_LITERAL("save_page");
    180 
    181 static const char kAppendedExtension[] =
    182 #if defined(OS_WIN)
    183     ".htm";
    184 #else
    185     ".html";
    186 #endif
    187 
    188 // Loosely based on logic in DownloadTestObserver.
    189 class DownloadItemCreatedObserver : public DownloadManager::Observer {
    190  public:
    191   explicit DownloadItemCreatedObserver(DownloadManager* manager)
    192       : waiting_(false), manager_(manager) {
    193     manager->AddObserver(this);
    194   }
    195 
    196   virtual ~DownloadItemCreatedObserver() {
    197     if (manager_)
    198       manager_->RemoveObserver(this);
    199   }
    200 
    201   // Wait for the first download item created after object creation.
    202   // Note that this class provides no protection against the download
    203   // being destroyed between creation and return of WaitForNewDownloadItem();
    204   // the caller must guarantee that in some other fashion.
    205   void WaitForDownloadItem(std::vector<DownloadItem*>* items_seen) {
    206     if (!manager_) {
    207       // The manager went away before we were asked to wait; return
    208       // what we have, even if it's null.
    209       *items_seen = items_seen_;
    210       return;
    211     }
    212 
    213     if (items_seen_.empty()) {
    214       waiting_ = true;
    215       content::RunMessageLoop();
    216       waiting_ = false;
    217     }
    218 
    219     *items_seen = items_seen_;
    220     return;
    221   }
    222 
    223  private:
    224   // DownloadManager::Observer
    225   virtual void OnDownloadCreated(
    226       DownloadManager* manager, DownloadItem* item) OVERRIDE {
    227     DCHECK_EQ(manager, manager_);
    228     items_seen_.push_back(item);
    229 
    230     if (waiting_)
    231       base::MessageLoopForUI::current()->Quit();
    232   }
    233 
    234   virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE {
    235     manager_->RemoveObserver(this);
    236     manager_ = NULL;
    237     if (waiting_)
    238       base::MessageLoopForUI::current()->Quit();
    239   }
    240 
    241   bool waiting_;
    242   DownloadManager* manager_;
    243   std::vector<DownloadItem*> items_seen_;
    244 
    245   DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver);
    246 };
    247 
    248 class SavePackageFinishedObserver : public content::DownloadManager::Observer {
    249  public:
    250   SavePackageFinishedObserver(content::DownloadManager* manager,
    251                               const base::Closure& callback)
    252       : download_manager_(manager),
    253         callback_(callback) {
    254     download_manager_->AddObserver(this);
    255   }
    256 
    257   virtual ~SavePackageFinishedObserver() {
    258     if (download_manager_)
    259       download_manager_->RemoveObserver(this);
    260   }
    261 
    262   // DownloadManager::Observer:
    263   virtual void OnSavePackageSuccessfullyFinished(
    264       content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE {
    265     callback_.Run();
    266   }
    267   virtual void ManagerGoingDown(content::DownloadManager* manager) OVERRIDE {
    268     download_manager_->RemoveObserver(this);
    269     download_manager_ = NULL;
    270   }
    271 
    272  private:
    273   content::DownloadManager* download_manager_;
    274   base::Closure callback_;
    275 
    276   DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver);
    277 };
    278 
    279 class SavePageBrowserTest : public InProcessBrowserTest {
    280  public:
    281   SavePageBrowserTest() {}
    282   virtual ~SavePageBrowserTest();
    283 
    284  protected:
    285   virtual void SetUp() OVERRIDE {
    286     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_));
    287     ASSERT_TRUE(save_dir_.CreateUniqueTempDir());
    288     InProcessBrowserTest::SetUp();
    289   }
    290 
    291   virtual void SetUpOnMainThread() OVERRIDE {
    292     browser()->profile()->GetPrefs()->SetFilePath(
    293         prefs::kDownloadDefaultDirectory, save_dir_.path());
    294     browser()->profile()->GetPrefs()->SetFilePath(
    295         prefs::kSaveFileDefaultDirectory, save_dir_.path());
    296     BrowserThread::PostTask(
    297         BrowserThread::IO, FROM_HERE,
    298         base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
    299   }
    300 
    301   GURL NavigateToMockURL(const std::string& prefix) {
    302     GURL url = URLRequestMockHTTPJob::GetMockUrl(
    303         base::FilePath(kTestDir).AppendASCII(prefix + ".htm"));
    304     ui_test_utils::NavigateToURL(browser(), url);
    305     return url;
    306   }
    307 
    308   // Returns full paths of destination file and directory.
    309   void GetDestinationPaths(const std::string& prefix,
    310                 base::FilePath* full_file_name,
    311                 base::FilePath* dir) {
    312     *full_file_name = save_dir_.path().AppendASCII(prefix + ".htm");
    313     *dir = save_dir_.path().AppendASCII(prefix + "_files");
    314   }
    315 
    316   WebContents* GetCurrentTab(Browser* browser) const {
    317     WebContents* current_tab =
    318         browser->tab_strip_model()->GetActiveWebContents();
    319     EXPECT_TRUE(current_tab);
    320     return current_tab;
    321   }
    322 
    323   // Returns true if and when there was a single download created, and its url
    324   // is |expected_url|.
    325   bool VerifySavePackageExpectations(
    326       Browser* browser,
    327       const GURL& expected_url) const {
    328     // Generally, there should only be one download item created
    329     // in all of these tests.  If it's already here, grab it; if not,
    330     // wait for it to show up.
    331     std::vector<DownloadItem*> items;
    332     DownloadManager* manager(
    333         BrowserContext::GetDownloadManager(browser->profile()));
    334     manager->GetAllDownloads(&items);
    335     if (items.size() == 0u) {
    336       DownloadItemCreatedObserver(manager).WaitForDownloadItem(&items);
    337     }
    338 
    339     EXPECT_EQ(1u, items.size());
    340     if (1u != items.size())
    341       return false;
    342     DownloadItem* download_item(items[0]);
    343 
    344     return (expected_url == download_item->GetOriginalUrl());
    345   }
    346 
    347   // Note on synchronization:
    348   //
    349   // For each Save Page As operation, we create a corresponding shell
    350   // DownloadItem to display progress to the user.  That DownloadItem goes
    351   // through its own state transitions, including being persisted out to the
    352   // history database, and the download shelf is not shown until after the
    353   // persistence occurs.  Save Package completion (and marking the DownloadItem
    354   // as completed) occurs asynchronously from persistence.  Thus if we want to
    355   // examine either UI state or DB state, we need to wait until both the save
    356   // package operation is complete and the relevant download item has been
    357   // persisted.
    358 
    359   DownloadManager* GetDownloadManager() const {
    360     DownloadManager* download_manager =
    361         BrowserContext::GetDownloadManager(browser()->profile());
    362     EXPECT_TRUE(download_manager);
    363     return download_manager;
    364   }
    365 
    366   // Path to directory containing test data.
    367   base::FilePath test_dir_;
    368 
    369   // Temporary directory we will save pages to.
    370   base::ScopedTempDir save_dir_;
    371 
    372  private:
    373   DISALLOW_COPY_AND_ASSIGN(SavePageBrowserTest);
    374 };
    375 
    376 SavePageBrowserTest::~SavePageBrowserTest() {
    377 }
    378 
    379 // Disabled on Windows due to flakiness. http://crbug.com/162323
    380 // TODO(linux_aura) http://crbug.com/163931
    381 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
    382 #define MAYBE_SaveHTMLOnly DISABLED_SaveHTMLOnly
    383 #else
    384 #define MAYBE_SaveHTMLOnly SaveHTMLOnly
    385 #endif
    386 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveHTMLOnly) {
    387   GURL url = NavigateToMockURL("a");
    388 
    389   base::FilePath full_file_name, dir;
    390   GetDestinationPaths("a", &full_file_name, &dir);
    391   DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
    392       &DownloadStoredProperly, url, full_file_name, 1,
    393       DownloadItem::COMPLETE));
    394   scoped_refptr<content::MessageLoopRunner> loop_runner(
    395       new content::MessageLoopRunner);
    396   SavePackageFinishedObserver observer(
    397       content::BrowserContext::GetDownloadManager(browser()->profile()),
    398       loop_runner->QuitClosure());
    399   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
    400                                         content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
    401   loop_runner->Run();
    402   ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
    403   persisted.WaitForPersisted();
    404   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
    405   EXPECT_TRUE(base::PathExists(full_file_name));
    406   EXPECT_FALSE(base::PathExists(dir));
    407   EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
    408       kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
    409 }
    410 
    411 // http://crbug.com/162323
    412 // http://crbug.com/163931
    413 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, DISABLED_SaveHTMLOnlyCancel) {
    414   GURL url = NavigateToMockURL("a");
    415   DownloadManager* manager(GetDownloadManager());
    416   std::vector<DownloadItem*> downloads;
    417   manager->GetAllDownloads(&downloads);
    418   ASSERT_EQ(0u, downloads.size());
    419 
    420   base::FilePath full_file_name, dir;
    421   GetDestinationPaths("a", &full_file_name, &dir);
    422   DownloadItemCreatedObserver creation_observer(manager);
    423   DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
    424       &DownloadStoredProperly, url, full_file_name, -1,
    425       DownloadItem::CANCELLED));
    426   // -1 to disable number of files check; we don't update after cancel, and
    427   // we don't know when the single file completed in relationship to
    428   // the cancel.
    429 
    430   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
    431                                         content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
    432   std::vector<DownloadItem*> items;
    433   creation_observer.WaitForDownloadItem(&items);
    434   ASSERT_EQ(1UL, items.size());
    435   ASSERT_EQ(url.spec(), items[0]->GetOriginalUrl().spec());
    436   items[0]->Cancel(true);
    437   // TODO(rdsmith): Fix DII::Cancel() to actually cancel the save package.
    438   // Currently it's ignored.
    439 
    440   persisted.WaitForPersisted();
    441 
    442   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
    443 
    444   // TODO(benjhayden): Figure out how to safely wait for SavePackage's finished
    445   // notification, then expect the contents of the downloaded file.
    446 }
    447 
    448 class DelayingDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
    449  public:
    450   explicit DelayingDownloadManagerDelegate(Profile* profile)
    451     : ChromeDownloadManagerDelegate(profile) {
    452   }
    453   virtual bool ShouldCompleteDownload(
    454       content::DownloadItem* item,
    455       const base::Closure& user_complete_callback) OVERRIDE {
    456     return false;
    457   }
    458 
    459  protected:
    460   virtual ~DelayingDownloadManagerDelegate() {}
    461 
    462  private:
    463   DISALLOW_COPY_AND_ASSIGN(DelayingDownloadManagerDelegate);
    464 };
    465 
    466 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyTabDestroy) {
    467   GURL url = NavigateToMockURL("a");
    468   DownloadManager* manager(GetDownloadManager());
    469   scoped_refptr<DelayingDownloadManagerDelegate> delaying_delegate(
    470       new DelayingDownloadManagerDelegate(browser()->profile()));
    471   delaying_delegate->SetNextId(content::DownloadItem::kInvalidId + 1);
    472   manager->SetDelegate(delaying_delegate.get());
    473   std::vector<DownloadItem*> downloads;
    474   manager->GetAllDownloads(&downloads);
    475   ASSERT_EQ(0u, downloads.size());
    476 
    477   base::FilePath full_file_name, dir;
    478   GetDestinationPaths("a", &full_file_name, &dir);
    479   DownloadItemCreatedObserver creation_observer(manager);
    480   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
    481                                         content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
    482   std::vector<DownloadItem*> items;
    483   creation_observer.WaitForDownloadItem(&items);
    484   ASSERT_TRUE(items.size() == 1);
    485 
    486   // Close the tab; does this cancel the download?
    487   GetCurrentTab(browser())->Close();
    488   EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
    489 
    490   EXPECT_FALSE(base::PathExists(full_file_name));
    491   EXPECT_FALSE(base::PathExists(dir));
    492 
    493   manager->SetDelegate(NULL);
    494 }
    495 
    496 // Disabled on Windows due to flakiness. http://crbug.com/162323
    497 // TODO(linux_aura) http://crbug.com/163931
    498 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
    499 #define MAYBE_SaveViewSourceHTMLOnly DISABLED_SaveViewSourceHTMLOnly
    500 #else
    501 #define MAYBE_SaveViewSourceHTMLOnly SaveViewSourceHTMLOnly
    502 #endif
    503 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveViewSourceHTMLOnly) {
    504   base::FilePath file_name(FILE_PATH_LITERAL("a.htm"));
    505   GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl(
    506       base::FilePath(kTestDir).Append(file_name));
    507   GURL actual_page_url = URLRequestMockHTTPJob::GetMockUrl(
    508       base::FilePath(kTestDir).Append(file_name));
    509   ui_test_utils::NavigateToURL(browser(), view_source_url);
    510 
    511   base::FilePath full_file_name, dir;
    512   GetDestinationPaths("a", &full_file_name, &dir);
    513   DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
    514       &DownloadStoredProperly, actual_page_url, full_file_name, 1,
    515       DownloadItem::COMPLETE));
    516   scoped_refptr<content::MessageLoopRunner> loop_runner(
    517       new content::MessageLoopRunner);
    518   SavePackageFinishedObserver observer(
    519       content::BrowserContext::GetDownloadManager(browser()->profile()),
    520       loop_runner->QuitClosure());
    521   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
    522                                         content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
    523   loop_runner->Run();
    524   ASSERT_TRUE(VerifySavePackageExpectations(browser(), actual_page_url));
    525   persisted.WaitForPersisted();
    526 
    527   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
    528 
    529   EXPECT_TRUE(base::PathExists(full_file_name));
    530   EXPECT_FALSE(base::PathExists(dir));
    531   EXPECT_TRUE(base::ContentsEqual(
    532       test_dir_.Append(base::FilePath(kTestDir)).Append(file_name),
    533       full_file_name));
    534 }
    535 
    536 // Disabled on Windows due to flakiness. http://crbug.com/162323
    537 // TODO(linux_aura) http://crbug.com/163931
    538 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
    539 #define MAYBE_SaveCompleteHTML DISABLED_SaveCompleteHTML
    540 #else
    541 #define MAYBE_SaveCompleteHTML SaveCompleteHTML
    542 #endif
    543 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveCompleteHTML) {
    544   GURL url = NavigateToMockURL("b");
    545 
    546   base::FilePath full_file_name, dir;
    547   GetDestinationPaths("b", &full_file_name, &dir);
    548   DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
    549       &DownloadStoredProperly, url, full_file_name, 3,
    550       DownloadItem::COMPLETE));
    551   scoped_refptr<content::MessageLoopRunner> loop_runner(
    552       new content::MessageLoopRunner);
    553   SavePackageFinishedObserver observer(
    554       content::BrowserContext::GetDownloadManager(browser()->profile()),
    555       loop_runner->QuitClosure());
    556   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
    557       full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
    558   loop_runner->Run();
    559   ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
    560   persisted.WaitForPersisted();
    561 
    562   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
    563 
    564   EXPECT_TRUE(base::PathExists(full_file_name));
    565   EXPECT_TRUE(base::PathExists(dir));
    566   EXPECT_TRUE(base::TextContentsEqual(
    567       test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved1.htm"),
    568       full_file_name));
    569   EXPECT_TRUE(base::ContentsEqual(
    570       test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"),
    571       dir.AppendASCII("1.png")));
    572   EXPECT_TRUE(base::ContentsEqual(
    573       test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"),
    574       dir.AppendASCII("1.css")));
    575 }
    576 
    577 // Invoke a save page during the initial navigation.
    578 // (Regression test for http://crbug.com/156538).
    579 // Disabled on Windows due to flakiness. http://crbug.com/162323
    580 // TODO(linux_aura) http://crbug.com/163931
    581 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
    582 #define MAYBE_SaveDuringInitialNavigationIncognito DISABLED_SaveDuringInitialNavigationIncognito
    583 #else
    584 #define MAYBE_SaveDuringInitialNavigationIncognito SaveDuringInitialNavigationIncognito
    585 #endif
    586 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,
    587                        MAYBE_SaveDuringInitialNavigationIncognito) {
    588   // Open an Incognito window.
    589   Browser* incognito = CreateIncognitoBrowser();  // Waits.
    590   ASSERT_TRUE(incognito);
    591 
    592   // Create a download item creation waiter on that window.
    593   DownloadItemCreatedObserver creation_observer(
    594       BrowserContext::GetDownloadManager(incognito->profile()));
    595 
    596   // Navigate, unblocking with new tab.
    597   GURL url = URLRequestMockHTTPJob::GetMockUrl(
    598       base::FilePath(kTestDir).AppendASCII("b.htm"));
    599   NavigateToURLWithDisposition(incognito, url, NEW_FOREGROUND_TAB,
    600                                ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
    601 
    602   // Save the page before completion.
    603   base::FilePath full_file_name, dir;
    604   GetDestinationPaths("b", &full_file_name, &dir);
    605   scoped_refptr<content::MessageLoopRunner> loop_runner(
    606       new content::MessageLoopRunner);
    607   SavePackageFinishedObserver observer(
    608       content::BrowserContext::GetDownloadManager(incognito->profile()),
    609       loop_runner->QuitClosure());
    610   ASSERT_TRUE(GetCurrentTab(incognito)->SavePage(
    611       full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
    612 
    613   loop_runner->Run();
    614   ASSERT_TRUE(VerifySavePackageExpectations(incognito, url));
    615 
    616   // Confirm download shelf is visible.
    617   EXPECT_TRUE(incognito->window()->IsDownloadShelfVisible());
    618 
    619   // We can't check more than this because SavePackage is racing with
    620   // the page load.  If the page load won the race, then SavePackage
    621   // might have completed. If the page load lost the race, then
    622   // SavePackage will cancel because there aren't any resources to
    623   // save.
    624 }
    625 
    626 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) {
    627   ui_test_utils::NavigateToURL(browser(), GURL(content::kAboutBlankURL));
    628   EXPECT_FALSE(chrome::CanSavePage(browser()));
    629 }
    630 
    631 // Disabled on Windows due to flakiness. http://crbug.com/162323
    632 // TODO(linux_aura) http://crbug.com/163931
    633 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
    634 #define MAYBE_FileNameFromPageTitle DISABLED_FileNameFromPageTitle
    635 #else
    636 #define MAYBE_FileNameFromPageTitle FileNameFromPageTitle
    637 #endif
    638 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_FileNameFromPageTitle) {
    639   GURL url = NavigateToMockURL("b");
    640 
    641   base::FilePath full_file_name = save_dir_.path().AppendASCII(
    642       std::string("Test page for saving page feature") + kAppendedExtension);
    643   base::FilePath dir = save_dir_.path().AppendASCII(
    644       "Test page for saving page feature_files");
    645   DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
    646       &DownloadStoredProperly, url, full_file_name, 3,
    647       DownloadItem::COMPLETE));
    648   scoped_refptr<content::MessageLoopRunner> loop_runner(
    649       new content::MessageLoopRunner);
    650   SavePackageFinishedObserver observer(
    651       content::BrowserContext::GetDownloadManager(browser()->profile()),
    652       loop_runner->QuitClosure());
    653   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
    654       full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
    655 
    656   loop_runner->Run();
    657   ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
    658   persisted.WaitForPersisted();
    659 
    660   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
    661 
    662   EXPECT_TRUE(base::PathExists(full_file_name));
    663   EXPECT_TRUE(base::PathExists(dir));
    664   EXPECT_TRUE(base::TextContentsEqual(
    665       test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved2.htm"),
    666       full_file_name));
    667   EXPECT_TRUE(base::ContentsEqual(
    668       test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"),
    669       dir.AppendASCII("1.png")));
    670   EXPECT_TRUE(base::ContentsEqual(
    671       test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"),
    672       dir.AppendASCII("1.css")));
    673 }
    674 
    675 // Disabled on Windows due to flakiness. http://crbug.com/162323
    676 // TODO(linux_aura) http://crbug.com/163931
    677 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
    678 #define MAYBE_RemoveFromList DISABLED_RemoveFromList
    679 #else
    680 #define MAYBE_RemoveFromList RemoveFromList
    681 #endif
    682 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_RemoveFromList) {
    683   GURL url = NavigateToMockURL("a");
    684 
    685   base::FilePath full_file_name, dir;
    686   GetDestinationPaths("a", &full_file_name, &dir);
    687   DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
    688       &DownloadStoredProperly, url, full_file_name, 1,
    689       DownloadItem::COMPLETE));
    690   scoped_refptr<content::MessageLoopRunner> loop_runner(
    691       new content::MessageLoopRunner);
    692   SavePackageFinishedObserver observer(
    693       content::BrowserContext::GetDownloadManager(browser()->profile()),
    694       loop_runner->QuitClosure());
    695   ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
    696                                         content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
    697 
    698   loop_runner->Run();
    699   ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
    700   persisted.WaitForPersisted();
    701 
    702   EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
    703 
    704   DownloadManager* manager(GetDownloadManager());
    705   std::vector<DownloadItem*> downloads;
    706   manager->GetAllDownloads(&downloads);
    707   ASSERT_EQ(1UL, downloads.size());
    708   DownloadRemovedObserver removed(browser()->profile(), downloads[0]->GetId());
    709 
    710   EXPECT_EQ(manager->RemoveAllDownloads(), 1);
    711 
    712   removed.WaitForRemoved();
    713 
    714   EXPECT_TRUE(base::PathExists(full_file_name));
    715   EXPECT_FALSE(base::PathExists(dir));
    716   EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
    717       kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
    718 }
    719 
    720 // This tests that a webpage with the title "test.exe" is saved as
    721 // "test.exe.htm".
    722 // We probably don't care to handle this on Linux or Mac.
    723 #if defined(OS_WIN)
    724 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, CleanFilenameFromPageTitle) {
    725   const base::FilePath file_name(FILE_PATH_LITERAL("c.htm"));
    726   base::FilePath download_dir =
    727       DownloadPrefs::FromDownloadManager(GetDownloadManager())->
    728           DownloadPath();
    729   base::FilePath full_file_name =
    730       download_dir.AppendASCII(std::string("test.exe") + kAppendedExtension);
    731   base::FilePath dir = download_dir.AppendASCII("test.exe_files");
    732 
    733   EXPECT_FALSE(base::PathExists(full_file_name));
    734   GURL url = URLRequestMockHTTPJob::GetMockUrl(
    735       base::FilePath(kTestDir).Append(file_name));
    736   ui_test_utils::NavigateToURL(browser(), url);
    737 
    738   SavePackageFilePicker::SetShouldPromptUser(false);
    739   scoped_refptr<content::MessageLoopRunner> loop_runner(
    740       new content::MessageLoopRunner);
    741   SavePackageFinishedObserver observer(
    742       content::BrowserContext::GetDownloadManager(browser()->profile()),
    743       loop_runner->QuitClosure());
    744   chrome::SavePage(browser());
    745   loop_runner->Run();
    746 
    747   EXPECT_TRUE(base::PathExists(full_file_name));
    748 
    749   EXPECT_TRUE(file_util::DieFileDie(full_file_name, false));
    750   EXPECT_TRUE(file_util::DieFileDie(dir, true));
    751 }
    752 #endif
    753 
    754 class SavePageAsMHTMLBrowserTest : public SavePageBrowserTest {
    755  public:
    756   SavePageAsMHTMLBrowserTest() {}
    757   virtual ~SavePageAsMHTMLBrowserTest();
    758   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    759     command_line->AppendSwitch(switches::kSavePageAsMHTML);
    760   }
    761 
    762  private:
    763   DISALLOW_COPY_AND_ASSIGN(SavePageAsMHTMLBrowserTest);
    764 };
    765 
    766 SavePageAsMHTMLBrowserTest::~SavePageAsMHTMLBrowserTest() {
    767 }
    768 
    769 IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest, SavePageAsMHTML) {
    770   static const int64 kFileSizeMin = 2758;
    771   GURL url = NavigateToMockURL("b");
    772   base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
    773       GetDownloadManager())->DownloadPath();
    774   base::FilePath full_file_name = download_dir.AppendASCII(std::string(
    775       "Test page for saving page feature.mhtml"));
    776   SavePackageFilePicker::SetShouldPromptUser(false);
    777   DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
    778       &DownloadStoredProperly, url, full_file_name, -1,
    779       DownloadItem::COMPLETE));
    780   scoped_refptr<content::MessageLoopRunner> loop_runner(
    781       new content::MessageLoopRunner);
    782   SavePackageFinishedObserver observer(
    783       content::BrowserContext::GetDownloadManager(browser()->profile()),
    784       loop_runner->QuitClosure());
    785   chrome::SavePage(browser());
    786   loop_runner->Run();
    787   ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
    788   persisted.WaitForPersisted();
    789 
    790   ASSERT_TRUE(base::PathExists(full_file_name));
    791   int64 actual_file_size = -1;
    792   EXPECT_TRUE(file_util::GetFileSize(full_file_name, &actual_file_size));
    793   EXPECT_LE(kFileSizeMin, actual_file_size);
    794 }
    795 
    796 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SavePageBrowserTest_NonMHTML) {
    797   SavePackageFilePicker::SetShouldPromptUser(false);
    798   GURL url("data:text/plain,foo");
    799   ui_test_utils::NavigateToURL(browser(), url);
    800   scoped_refptr<content::MessageLoopRunner> loop_runner(
    801       new content::MessageLoopRunner);
    802   SavePackageFinishedObserver observer(
    803       content::BrowserContext::GetDownloadManager(browser()->profile()),
    804       loop_runner->QuitClosure());
    805   chrome::SavePage(browser());
    806   loop_runner->Run();
    807   base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
    808       GetDownloadManager())->DownloadPath();
    809   base::FilePath filename = download_dir.AppendASCII("dataurl.txt");
    810   ASSERT_TRUE(base::PathExists(filename));
    811   std::string contents;
    812   EXPECT_TRUE(file_util::ReadFileToString(filename, &contents));
    813   EXPECT_EQ("foo", contents);
    814 }
    815 
    816 }  // namespace
    817 
    818