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