save_page_browsertest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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
44using content::BrowserContext;
45using content::BrowserThread;
46using content::DownloadItem;
47using content::DownloadManager;
48using content::URLRequestMockHTTPJob;
49using content::WebContents;
50
51namespace {
52
53// Waits for an item record in the downloads database to match |filter|. See
54// DownloadStoredProperly() below for an example filter.
55class 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::GetForProfile(profile_)->
67      GetDownloadHistory()->AddObserver(this);
68  }
69
70  virtual ~DownloadPersistedObserver() {
71    DownloadService* service = DownloadServiceFactory::GetForProfile(profile_);
72    if (service && service->GetDownloadHistory())
73      service->GetDownloadHistory()->RemoveObserver(this);
74  }
75
76  bool WaitForPersisted() {
77    if (persisted_)
78      return true;
79    waiting_ = true;
80    content::RunMessageLoop();
81    waiting_ = false;
82    return persisted_;
83  }
84
85  virtual void OnDownloadStored(DownloadItem* item,
86                                const history::DownloadRow& info) OVERRIDE {
87    persisted_ = persisted_ || filter_.Run(item, info);
88    if (persisted_ && waiting_)
89      base::MessageLoopForUI::current()->Quit();
90  }
91
92 private:
93  Profile* profile_;
94  DownloadItem* item_;
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.
103class 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
140bool 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
178const base::FilePath::CharType kTestDir[] = FILE_PATH_LITERAL("save_page");
179
180static const char kAppendedExtension[] =
181#if defined(OS_WIN)
182    ".htm";
183#else
184    ".html";
185#endif
186
187// Loosely based on logic in DownloadTestObserver.
188class 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
247class 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
278class 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
375SavePageBrowserTest::~SavePageBrowserTest() {
376}
377
378// Disabled on Windows due to flakiness. http://crbug.com/162323
379// TODO(linux_aura) http://crbug.com/163931
380#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
381#define MAYBE_SaveHTMLOnly DISABLED_SaveHTMLOnly
382#else
383#define MAYBE_SaveHTMLOnly SaveHTMLOnly
384#endif
385IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveHTMLOnly) {
386  GURL url = NavigateToMockURL("a");
387
388  base::FilePath full_file_name, dir;
389  GetDestinationPaths("a", &full_file_name, &dir);
390  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
391      &DownloadStoredProperly, url, full_file_name, 1,
392      DownloadItem::COMPLETE));
393  scoped_refptr<content::MessageLoopRunner> loop_runner(
394      new content::MessageLoopRunner);
395  SavePackageFinishedObserver observer(
396      content::BrowserContext::GetDownloadManager(browser()->profile()),
397      loop_runner->QuitClosure());
398  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
399                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
400  loop_runner->Run();
401  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
402  persisted.WaitForPersisted();
403  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
404  EXPECT_TRUE(base::PathExists(full_file_name));
405  EXPECT_FALSE(base::PathExists(dir));
406  EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
407      kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
408}
409
410// http://crbug.com/162323
411// http://crbug.com/163931
412IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, DISABLED_SaveHTMLOnlyCancel) {
413  GURL url = NavigateToMockURL("a");
414  DownloadManager* manager(GetDownloadManager());
415  std::vector<DownloadItem*> downloads;
416  manager->GetAllDownloads(&downloads);
417  ASSERT_EQ(0u, downloads.size());
418
419  base::FilePath full_file_name, dir;
420  GetDestinationPaths("a", &full_file_name, &dir);
421  DownloadItemCreatedObserver creation_observer(manager);
422  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
423      &DownloadStoredProperly, url, full_file_name, -1,
424      DownloadItem::CANCELLED));
425  // -1 to disable number of files check; we don't update after cancel, and
426  // we don't know when the single file completed in relationship to
427  // the cancel.
428
429  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
430                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
431  std::vector<DownloadItem*> items;
432  creation_observer.WaitForDownloadItem(&items);
433  ASSERT_EQ(1UL, items.size());
434  ASSERT_EQ(url.spec(), items[0]->GetOriginalUrl().spec());
435  items[0]->Cancel(true);
436  // TODO(rdsmith): Fix DII::Cancel() to actually cancel the save package.
437  // Currently it's ignored.
438
439  persisted.WaitForPersisted();
440
441  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
442
443  // TODO(benjhayden): Figure out how to safely wait for SavePackage's finished
444  // notification, then expect the contents of the downloaded file.
445}
446
447class DelayingDownloadManagerDelegate : public ChromeDownloadManagerDelegate {
448 public:
449  explicit DelayingDownloadManagerDelegate(Profile* profile)
450    : ChromeDownloadManagerDelegate(profile) {
451  }
452  virtual bool ShouldCompleteDownload(
453      content::DownloadItem* item,
454      const base::Closure& user_complete_callback) OVERRIDE {
455    return false;
456  }
457
458 protected:
459  virtual ~DelayingDownloadManagerDelegate() {}
460
461 private:
462  DISALLOW_COPY_AND_ASSIGN(DelayingDownloadManagerDelegate);
463};
464
465IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyTabDestroy) {
466  GURL url = NavigateToMockURL("a");
467  DownloadManager* manager(GetDownloadManager());
468  scoped_refptr<DelayingDownloadManagerDelegate> delaying_delegate(
469      new DelayingDownloadManagerDelegate(browser()->profile()));
470  delaying_delegate->SetNextId(content::DownloadItem::kInvalidId + 1);
471  manager->SetDelegate(delaying_delegate.get());
472  std::vector<DownloadItem*> downloads;
473  manager->GetAllDownloads(&downloads);
474  ASSERT_EQ(0u, downloads.size());
475
476  base::FilePath full_file_name, dir;
477  GetDestinationPaths("a", &full_file_name, &dir);
478  DownloadItemCreatedObserver creation_observer(manager);
479  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
480                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
481  std::vector<DownloadItem*> items;
482  creation_observer.WaitForDownloadItem(&items);
483  ASSERT_TRUE(items.size() == 1);
484
485  // Close the tab; does this cancel the download?
486  GetCurrentTab(browser())->Close();
487  EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
488
489  EXPECT_FALSE(base::PathExists(full_file_name));
490  EXPECT_FALSE(base::PathExists(dir));
491
492  manager->SetDelegate(NULL);
493}
494
495// Disabled on Windows due to flakiness. http://crbug.com/162323
496// TODO(linux_aura) http://crbug.com/163931
497#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
498#define MAYBE_SaveViewSourceHTMLOnly DISABLED_SaveViewSourceHTMLOnly
499#else
500#define MAYBE_SaveViewSourceHTMLOnly SaveViewSourceHTMLOnly
501#endif
502IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveViewSourceHTMLOnly) {
503  base::FilePath file_name(FILE_PATH_LITERAL("a.htm"));
504  GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl(
505      base::FilePath(kTestDir).Append(file_name));
506  GURL actual_page_url = URLRequestMockHTTPJob::GetMockUrl(
507      base::FilePath(kTestDir).Append(file_name));
508  ui_test_utils::NavigateToURL(browser(), view_source_url);
509
510  base::FilePath full_file_name, dir;
511  GetDestinationPaths("a", &full_file_name, &dir);
512  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
513      &DownloadStoredProperly, actual_page_url, full_file_name, 1,
514      DownloadItem::COMPLETE));
515  scoped_refptr<content::MessageLoopRunner> loop_runner(
516      new content::MessageLoopRunner);
517  SavePackageFinishedObserver observer(
518      content::BrowserContext::GetDownloadManager(browser()->profile()),
519      loop_runner->QuitClosure());
520  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
521                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
522  loop_runner->Run();
523  ASSERT_TRUE(VerifySavePackageExpectations(browser(), actual_page_url));
524  persisted.WaitForPersisted();
525
526  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
527
528  EXPECT_TRUE(base::PathExists(full_file_name));
529  EXPECT_FALSE(base::PathExists(dir));
530  EXPECT_TRUE(base::ContentsEqual(
531      test_dir_.Append(base::FilePath(kTestDir)).Append(file_name),
532      full_file_name));
533}
534
535// Disabled on Windows due to flakiness. http://crbug.com/162323
536// TODO(linux_aura) http://crbug.com/163931
537#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
538#define MAYBE_SaveCompleteHTML DISABLED_SaveCompleteHTML
539#else
540#define MAYBE_SaveCompleteHTML SaveCompleteHTML
541#endif
542IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveCompleteHTML) {
543  GURL url = NavigateToMockURL("b");
544
545  base::FilePath full_file_name, dir;
546  GetDestinationPaths("b", &full_file_name, &dir);
547  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
548      &DownloadStoredProperly, url, full_file_name, 3,
549      DownloadItem::COMPLETE));
550  scoped_refptr<content::MessageLoopRunner> loop_runner(
551      new content::MessageLoopRunner);
552  SavePackageFinishedObserver observer(
553      content::BrowserContext::GetDownloadManager(browser()->profile()),
554      loop_runner->QuitClosure());
555  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(
556      full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
557  loop_runner->Run();
558  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
559  persisted.WaitForPersisted();
560
561  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
562
563  EXPECT_TRUE(base::PathExists(full_file_name));
564  EXPECT_TRUE(base::PathExists(dir));
565  EXPECT_TRUE(base::TextContentsEqual(
566      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved1.htm"),
567      full_file_name));
568  EXPECT_TRUE(base::ContentsEqual(
569      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"),
570      dir.AppendASCII("1.png")));
571  EXPECT_TRUE(base::ContentsEqual(
572      test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"),
573      dir.AppendASCII("1.css")));
574}
575
576// Invoke a save page during the initial navigation.
577// (Regression test for http://crbug.com/156538).
578// Disabled on Windows due to flakiness. http://crbug.com/162323
579// TODO(linux_aura) http://crbug.com/163931
580#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
581#define MAYBE_SaveDuringInitialNavigationIncognito DISABLED_SaveDuringInitialNavigationIncognito
582#else
583#define MAYBE_SaveDuringInitialNavigationIncognito SaveDuringInitialNavigationIncognito
584#endif
585IN_PROC_BROWSER_TEST_F(SavePageBrowserTest,
586                       MAYBE_SaveDuringInitialNavigationIncognito) {
587  // Open an Incognito window.
588  Browser* incognito = CreateIncognitoBrowser();  // Waits.
589  ASSERT_TRUE(incognito);
590
591  // Create a download item creation waiter on that window.
592  DownloadItemCreatedObserver creation_observer(
593      BrowserContext::GetDownloadManager(incognito->profile()));
594
595  // Navigate, unblocking with new tab.
596  GURL url = URLRequestMockHTTPJob::GetMockUrl(
597      base::FilePath(kTestDir).AppendASCII("b.htm"));
598  NavigateToURLWithDisposition(incognito, url, NEW_FOREGROUND_TAB,
599                               ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
600
601  // Save the page before completion.
602  base::FilePath full_file_name, dir;
603  GetDestinationPaths("b", &full_file_name, &dir);
604  scoped_refptr<content::MessageLoopRunner> loop_runner(
605      new content::MessageLoopRunner);
606  SavePackageFinishedObserver observer(
607      content::BrowserContext::GetDownloadManager(incognito->profile()),
608      loop_runner->QuitClosure());
609  ASSERT_TRUE(GetCurrentTab(incognito)->SavePage(
610      full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML));
611
612  loop_runner->Run();
613  ASSERT_TRUE(VerifySavePackageExpectations(incognito, url));
614
615  // Confirm download shelf is visible.
616  EXPECT_TRUE(incognito->window()->IsDownloadShelfVisible());
617
618  // We can't check more than this because SavePackage is racing with
619  // the page load.  If the page load won the race, then SavePackage
620  // might have completed. If the page load lost the race, then
621  // SavePackage will cancel because there aren't any resources to
622  // save.
623}
624
625IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) {
626  ui_test_utils::NavigateToURL(browser(), GURL(content::kAboutBlankURL));
627  EXPECT_FALSE(chrome::CanSavePage(browser()));
628}
629
630// Disabled on Windows due to flakiness. http://crbug.com/162323
631// TODO(linux_aura) http://crbug.com/163931
632#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
633#define MAYBE_FileNameFromPageTitle DISABLED_FileNameFromPageTitle
634#else
635#define MAYBE_FileNameFromPageTitle FileNameFromPageTitle
636#endif
637IN_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// TODO(linux_aura) http://crbug.com/163931
676#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
677#define MAYBE_RemoveFromList DISABLED_RemoveFromList
678#else
679#define MAYBE_RemoveFromList RemoveFromList
680#endif
681IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_RemoveFromList) {
682  GURL url = NavigateToMockURL("a");
683
684  base::FilePath full_file_name, dir;
685  GetDestinationPaths("a", &full_file_name, &dir);
686  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
687      &DownloadStoredProperly, url, full_file_name, 1,
688      DownloadItem::COMPLETE));
689  scoped_refptr<content::MessageLoopRunner> loop_runner(
690      new content::MessageLoopRunner);
691  SavePackageFinishedObserver observer(
692      content::BrowserContext::GetDownloadManager(browser()->profile()),
693      loop_runner->QuitClosure());
694  ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir,
695                                        content::SAVE_PAGE_TYPE_AS_ONLY_HTML));
696
697  loop_runner->Run();
698  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
699  persisted.WaitForPersisted();
700
701  EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible());
702
703  DownloadManager* manager(GetDownloadManager());
704  std::vector<DownloadItem*> downloads;
705  manager->GetAllDownloads(&downloads);
706  ASSERT_EQ(1UL, downloads.size());
707  DownloadRemovedObserver removed(browser()->profile(), downloads[0]->GetId());
708
709  EXPECT_EQ(manager->RemoveAllDownloads(), 1);
710
711  removed.WaitForRemoved();
712
713  EXPECT_TRUE(base::PathExists(full_file_name));
714  EXPECT_FALSE(base::PathExists(dir));
715  EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath(
716      kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name));
717}
718
719// This tests that a webpage with the title "test.exe" is saved as
720// "test.exe.htm".
721// We probably don't care to handle this on Linux or Mac.
722#if defined(OS_WIN)
723IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, CleanFilenameFromPageTitle) {
724  const base::FilePath file_name(FILE_PATH_LITERAL("c.htm"));
725  base::FilePath download_dir =
726      DownloadPrefs::FromDownloadManager(GetDownloadManager())->
727          DownloadPath();
728  base::FilePath full_file_name =
729      download_dir.AppendASCII(std::string("test.exe") + kAppendedExtension);
730  base::FilePath dir = download_dir.AppendASCII("test.exe_files");
731
732  EXPECT_FALSE(base::PathExists(full_file_name));
733  GURL url = URLRequestMockHTTPJob::GetMockUrl(
734      base::FilePath(kTestDir).Append(file_name));
735  ui_test_utils::NavigateToURL(browser(), url);
736
737  SavePackageFilePicker::SetShouldPromptUser(false);
738  scoped_refptr<content::MessageLoopRunner> loop_runner(
739      new content::MessageLoopRunner);
740  SavePackageFinishedObserver observer(
741      content::BrowserContext::GetDownloadManager(browser()->profile()),
742      loop_runner->QuitClosure());
743  chrome::SavePage(browser());
744  loop_runner->Run();
745
746  EXPECT_TRUE(base::PathExists(full_file_name));
747
748  EXPECT_TRUE(file_util::DieFileDie(full_file_name, false));
749  EXPECT_TRUE(file_util::DieFileDie(dir, true));
750}
751#endif
752
753class SavePageAsMHTMLBrowserTest : public SavePageBrowserTest {
754 public:
755  SavePageAsMHTMLBrowserTest() {}
756  virtual ~SavePageAsMHTMLBrowserTest();
757  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
758    command_line->AppendSwitch(switches::kSavePageAsMHTML);
759  }
760
761 private:
762  DISALLOW_COPY_AND_ASSIGN(SavePageAsMHTMLBrowserTest);
763};
764
765SavePageAsMHTMLBrowserTest::~SavePageAsMHTMLBrowserTest() {
766}
767
768IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest, SavePageAsMHTML) {
769  static const int64 kFileSizeMin = 2758;
770  GURL url = NavigateToMockURL("b");
771  base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
772      GetDownloadManager())->DownloadPath();
773  base::FilePath full_file_name = download_dir.AppendASCII(std::string(
774      "Test page for saving page feature.mhtml"));
775  SavePackageFilePicker::SetShouldPromptUser(false);
776  DownloadPersistedObserver persisted(browser()->profile(), base::Bind(
777      &DownloadStoredProperly, url, full_file_name, -1,
778      DownloadItem::COMPLETE));
779  scoped_refptr<content::MessageLoopRunner> loop_runner(
780      new content::MessageLoopRunner);
781  SavePackageFinishedObserver observer(
782      content::BrowserContext::GetDownloadManager(browser()->profile()),
783      loop_runner->QuitClosure());
784  chrome::SavePage(browser());
785  loop_runner->Run();
786  ASSERT_TRUE(VerifySavePackageExpectations(browser(), url));
787  persisted.WaitForPersisted();
788
789  ASSERT_TRUE(base::PathExists(full_file_name));
790  int64 actual_file_size = -1;
791  EXPECT_TRUE(file_util::GetFileSize(full_file_name, &actual_file_size));
792  EXPECT_LE(kFileSizeMin, actual_file_size);
793}
794
795IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SavePageBrowserTest_NonMHTML) {
796  SavePackageFilePicker::SetShouldPromptUser(false);
797  GURL url("data:text/plain,foo");
798  ui_test_utils::NavigateToURL(browser(), url);
799  scoped_refptr<content::MessageLoopRunner> loop_runner(
800      new content::MessageLoopRunner);
801  SavePackageFinishedObserver observer(
802      content::BrowserContext::GetDownloadManager(browser()->profile()),
803      loop_runner->QuitClosure());
804  chrome::SavePage(browser());
805  loop_runner->Run();
806  base::FilePath download_dir = DownloadPrefs::FromDownloadManager(
807      GetDownloadManager())->DownloadPath();
808  base::FilePath filename = download_dir.AppendASCII("dataurl.txt");
809  ASSERT_TRUE(base::PathExists(filename));
810  std::string contents;
811  EXPECT_TRUE(file_util::ReadFileToString(filename, &contents));
812  EXPECT_EQ("foo", contents);
813}
814
815}  // namespace
816
817