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