// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/file_util.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" #include "base/path_service.h" #include "base/prefs/pref_member.h" #include "base/prefs/pref_service.h" #include "base/test/test_file_util.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/download/chrome_download_manager_delegate.h" #include "chrome/browser/download/download_history.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/download/download_service.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/download/save_package_file_picker.h" #include "chrome/browser/history/download_row.h" #include "chrome/browser/net/url_request_mock_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/download_item.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_utils.h" #include "content/test/net/url_request_mock_http_job.h" #include "testing/gtest/include/gtest/gtest.h" using content::BrowserContext; using content::BrowserThread; using content::DownloadItem; using content::DownloadManager; using content::URLRequestMockHTTPJob; using content::WebContents; namespace { // Waits for an item record in the downloads database to match |filter|. See // DownloadStoredProperly() below for an example filter. class DownloadPersistedObserver : public DownloadHistory::Observer { public: typedef base::Callback<bool( DownloadItem* item, const history::DownloadRow&)> PersistedFilter; DownloadPersistedObserver(Profile* profile, const PersistedFilter& filter) : profile_(profile), filter_(filter), waiting_(false), persisted_(false) { DownloadServiceFactory::GetForBrowserContext(profile_)-> GetDownloadHistory()->AddObserver(this); } virtual ~DownloadPersistedObserver() { DownloadService* service = DownloadServiceFactory::GetForBrowserContext( profile_); if (service && service->GetDownloadHistory()) service->GetDownloadHistory()->RemoveObserver(this); } bool WaitForPersisted() { if (persisted_) return true; waiting_ = true; content::RunMessageLoop(); waiting_ = false; return persisted_; } virtual void OnDownloadStored(DownloadItem* item, const history::DownloadRow& info) OVERRIDE { persisted_ = persisted_ || filter_.Run(item, info); if (persisted_ && waiting_) base::MessageLoopForUI::current()->Quit(); } private: Profile* profile_; DownloadItem* item_; PersistedFilter filter_; bool waiting_; bool persisted_; DISALLOW_COPY_AND_ASSIGN(DownloadPersistedObserver); }; // Waits for an item record to be removed from the downloads database. class DownloadRemovedObserver : public DownloadPersistedObserver { public: DownloadRemovedObserver(Profile* profile, int32 download_id) : DownloadPersistedObserver(profile, PersistedFilter()), removed_(false), waiting_(false), download_id_(download_id) { } virtual ~DownloadRemovedObserver() {} bool WaitForRemoved() { if (removed_) return true; waiting_ = true; content::RunMessageLoop(); waiting_ = false; return removed_; } virtual void OnDownloadStored(DownloadItem* item, const history::DownloadRow& info) OVERRIDE { } virtual void OnDownloadsRemoved(const DownloadHistory::IdSet& ids) OVERRIDE { removed_ = ids.find(download_id_) != ids.end(); if (removed_ && waiting_) base::MessageLoopForUI::current()->Quit(); } private: bool removed_; bool waiting_; int32 download_id_; DISALLOW_COPY_AND_ASSIGN(DownloadRemovedObserver); }; bool DownloadStoredProperly( const GURL& expected_url, const base::FilePath& expected_path, int64 num_files, DownloadItem::DownloadState expected_state, DownloadItem* item, const history::DownloadRow& info) { // This function may be called multiple times for a given test. Returning // false doesn't necessarily mean that the test has failed or will fail, it // might just mean that the test hasn't passed yet. if (info.target_path != expected_path) { VLOG(20) << __FUNCTION__ << " " << info.target_path.value() << " != " << expected_path.value(); return false; } if (info.url_chain.size() != 1u) { VLOG(20) << __FUNCTION__ << " " << info.url_chain.size() << " != 1"; return false; } if (info.url_chain[0] != expected_url) { VLOG(20) << __FUNCTION__ << " " << info.url_chain[0].spec() << " != " << expected_url.spec(); return false; } if ((num_files >= 0) && (info.received_bytes != num_files)) { VLOG(20) << __FUNCTION__ << " " << num_files << " != " << info.received_bytes; return false; } if (info.state != expected_state) { VLOG(20) << __FUNCTION__ << " " << info.state << " != " << expected_state; return false; } return true; } const base::FilePath::CharType kTestDir[] = FILE_PATH_LITERAL("save_page"); static const char kAppendedExtension[] = #if defined(OS_WIN) ".htm"; #else ".html"; #endif // Loosely based on logic in DownloadTestObserver. class DownloadItemCreatedObserver : public DownloadManager::Observer { public: explicit DownloadItemCreatedObserver(DownloadManager* manager) : waiting_(false), manager_(manager) { manager->AddObserver(this); } virtual ~DownloadItemCreatedObserver() { if (manager_) manager_->RemoveObserver(this); } // Wait for the first download item created after object creation. // Note that this class provides no protection against the download // being destroyed between creation and return of WaitForNewDownloadItem(); // the caller must guarantee that in some other fashion. void WaitForDownloadItem(std::vector<DownloadItem*>* items_seen) { if (!manager_) { // The manager went away before we were asked to wait; return // what we have, even if it's null. *items_seen = items_seen_; return; } if (items_seen_.empty()) { waiting_ = true; content::RunMessageLoop(); waiting_ = false; } *items_seen = items_seen_; return; } private: // DownloadManager::Observer virtual void OnDownloadCreated( DownloadManager* manager, DownloadItem* item) OVERRIDE { DCHECK_EQ(manager, manager_); items_seen_.push_back(item); if (waiting_) base::MessageLoopForUI::current()->Quit(); } virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE { manager_->RemoveObserver(this); manager_ = NULL; if (waiting_) base::MessageLoopForUI::current()->Quit(); } bool waiting_; DownloadManager* manager_; std::vector<DownloadItem*> items_seen_; DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver); }; class SavePackageFinishedObserver : public content::DownloadManager::Observer { public: SavePackageFinishedObserver(content::DownloadManager* manager, const base::Closure& callback) : download_manager_(manager), callback_(callback) { download_manager_->AddObserver(this); } virtual ~SavePackageFinishedObserver() { if (download_manager_) download_manager_->RemoveObserver(this); } // DownloadManager::Observer: virtual void OnSavePackageSuccessfullyFinished( content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE { callback_.Run(); } virtual void ManagerGoingDown(content::DownloadManager* manager) OVERRIDE { download_manager_->RemoveObserver(this); download_manager_ = NULL; } private: content::DownloadManager* download_manager_; base::Closure callback_; DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver); }; class SavePageBrowserTest : public InProcessBrowserTest { public: SavePageBrowserTest() {} virtual ~SavePageBrowserTest(); protected: virtual void SetUp() OVERRIDE { ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_)); ASSERT_TRUE(save_dir_.CreateUniqueTempDir()); InProcessBrowserTest::SetUp(); } virtual void SetUpOnMainThread() OVERRIDE { browser()->profile()->GetPrefs()->SetFilePath( prefs::kDownloadDefaultDirectory, save_dir_.path()); browser()->profile()->GetPrefs()->SetFilePath( prefs::kSaveFileDefaultDirectory, save_dir_.path()); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); } GURL NavigateToMockURL(const std::string& prefix) { GURL url = URLRequestMockHTTPJob::GetMockUrl( base::FilePath(kTestDir).AppendASCII(prefix + ".htm")); ui_test_utils::NavigateToURL(browser(), url); return url; } // Returns full paths of destination file and directory. void GetDestinationPaths(const std::string& prefix, base::FilePath* full_file_name, base::FilePath* dir) { *full_file_name = save_dir_.path().AppendASCII(prefix + ".htm"); *dir = save_dir_.path().AppendASCII(prefix + "_files"); } WebContents* GetCurrentTab(Browser* browser) const { WebContents* current_tab = browser->tab_strip_model()->GetActiveWebContents(); EXPECT_TRUE(current_tab); return current_tab; } // Returns true if and when there was a single download created, and its url // is |expected_url|. bool VerifySavePackageExpectations( Browser* browser, const GURL& expected_url) const { // Generally, there should only be one download item created // in all of these tests. If it's already here, grab it; if not, // wait for it to show up. std::vector<DownloadItem*> items; DownloadManager* manager( BrowserContext::GetDownloadManager(browser->profile())); manager->GetAllDownloads(&items); if (items.size() == 0u) { DownloadItemCreatedObserver(manager).WaitForDownloadItem(&items); } EXPECT_EQ(1u, items.size()); if (1u != items.size()) return false; DownloadItem* download_item(items[0]); return (expected_url == download_item->GetOriginalUrl()); } // Note on synchronization: // // For each Save Page As operation, we create a corresponding shell // DownloadItem to display progress to the user. That DownloadItem goes // through its own state transitions, including being persisted out to the // history database, and the download shelf is not shown until after the // persistence occurs. Save Package completion (and marking the DownloadItem // as completed) occurs asynchronously from persistence. Thus if we want to // examine either UI state or DB state, we need to wait until both the save // package operation is complete and the relevant download item has been // persisted. DownloadManager* GetDownloadManager() const { DownloadManager* download_manager = BrowserContext::GetDownloadManager(browser()->profile()); EXPECT_TRUE(download_manager); return download_manager; } // Path to directory containing test data. base::FilePath test_dir_; // Temporary directory we will save pages to. base::ScopedTempDir save_dir_; private: DISALLOW_COPY_AND_ASSIGN(SavePageBrowserTest); }; SavePageBrowserTest::~SavePageBrowserTest() { } // Disabled on Windows due to flakiness. http://crbug.com/162323 #if defined(OS_WIN) #define MAYBE_SaveHTMLOnly DISABLED_SaveHTMLOnly #else #define MAYBE_SaveHTMLOnly SaveHTMLOnly #endif IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveHTMLOnly) { GURL url = NavigateToMockURL("a"); base::FilePath full_file_name, dir; GetDestinationPaths("a", &full_file_name, &dir); DownloadPersistedObserver persisted(browser()->profile(), base::Bind( &DownloadStoredProperly, url, full_file_name, 1, DownloadItem::COMPLETE)); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); loop_runner->Run(); ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); persisted.WaitForPersisted(); EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); EXPECT_TRUE(base::PathExists(full_file_name)); EXPECT_FALSE(base::PathExists(dir)); EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath( kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name)); } // http://crbug.com/162323 IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, DISABLED_SaveHTMLOnlyCancel) { GURL url = NavigateToMockURL("a"); DownloadManager* manager(GetDownloadManager()); std::vector<DownloadItem*> downloads; manager->GetAllDownloads(&downloads); ASSERT_EQ(0u, downloads.size()); base::FilePath full_file_name, dir; GetDestinationPaths("a", &full_file_name, &dir); DownloadItemCreatedObserver creation_observer(manager); DownloadPersistedObserver persisted(browser()->profile(), base::Bind( &DownloadStoredProperly, url, full_file_name, -1, DownloadItem::CANCELLED)); // -1 to disable number of files check; we don't update after cancel, and // we don't know when the single file completed in relationship to // the cancel. ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); std::vector<DownloadItem*> items; creation_observer.WaitForDownloadItem(&items); ASSERT_EQ(1UL, items.size()); ASSERT_EQ(url.spec(), items[0]->GetOriginalUrl().spec()); items[0]->Cancel(true); // TODO(rdsmith): Fix DII::Cancel() to actually cancel the save package. // Currently it's ignored. persisted.WaitForPersisted(); EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); // TODO(benjhayden): Figure out how to safely wait for SavePackage's finished // notification, then expect the contents of the downloaded file. } class DelayingDownloadManagerDelegate : public ChromeDownloadManagerDelegate { public: explicit DelayingDownloadManagerDelegate(Profile* profile) : ChromeDownloadManagerDelegate(profile) { } virtual ~DelayingDownloadManagerDelegate() {} virtual bool ShouldCompleteDownload( content::DownloadItem* item, const base::Closure& user_complete_callback) OVERRIDE { return false; } private: DISALLOW_COPY_AND_ASSIGN(DelayingDownloadManagerDelegate); }; IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyTabDestroy) { GURL url = NavigateToMockURL("a"); scoped_ptr<DelayingDownloadManagerDelegate> delaying_delegate( new DelayingDownloadManagerDelegate(browser()->profile())); delaying_delegate->GetDownloadIdReceiverCallback().Run( content::DownloadItem::kInvalidId + 1); DownloadServiceFactory::GetForBrowserContext(browser()->profile())-> SetDownloadManagerDelegateForTesting( delaying_delegate.PassAs<ChromeDownloadManagerDelegate>()); DownloadManager* manager(GetDownloadManager()); std::vector<DownloadItem*> downloads; manager->GetAllDownloads(&downloads); ASSERT_EQ(0u, downloads.size()); base::FilePath full_file_name, dir; GetDestinationPaths("a", &full_file_name, &dir); DownloadItemCreatedObserver creation_observer(manager); ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); std::vector<DownloadItem*> items; creation_observer.WaitForDownloadItem(&items); ASSERT_TRUE(items.size() == 1); // Close the tab; does this cancel the download? GetCurrentTab(browser())->Close(); EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); EXPECT_FALSE(base::PathExists(full_file_name)); EXPECT_FALSE(base::PathExists(dir)); } // Disabled on Windows due to flakiness. http://crbug.com/162323 #if defined(OS_WIN) #define MAYBE_SaveViewSourceHTMLOnly DISABLED_SaveViewSourceHTMLOnly #else #define MAYBE_SaveViewSourceHTMLOnly SaveViewSourceHTMLOnly #endif IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveViewSourceHTMLOnly) { base::FilePath file_name(FILE_PATH_LITERAL("a.htm")); GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl( base::FilePath(kTestDir).Append(file_name)); GURL actual_page_url = URLRequestMockHTTPJob::GetMockUrl( base::FilePath(kTestDir).Append(file_name)); ui_test_utils::NavigateToURL(browser(), view_source_url); base::FilePath full_file_name, dir; GetDestinationPaths("a", &full_file_name, &dir); DownloadPersistedObserver persisted(browser()->profile(), base::Bind( &DownloadStoredProperly, actual_page_url, full_file_name, 1, DownloadItem::COMPLETE)); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); loop_runner->Run(); ASSERT_TRUE(VerifySavePackageExpectations(browser(), actual_page_url)); persisted.WaitForPersisted(); EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); EXPECT_TRUE(base::PathExists(full_file_name)); EXPECT_FALSE(base::PathExists(dir)); EXPECT_TRUE(base::ContentsEqual( test_dir_.Append(base::FilePath(kTestDir)).Append(file_name), full_file_name)); } // Disabled on Windows due to flakiness. http://crbug.com/162323 #if defined(OS_WIN) #define MAYBE_SaveCompleteHTML DISABLED_SaveCompleteHTML #else #define MAYBE_SaveCompleteHTML SaveCompleteHTML #endif IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveCompleteHTML) { GURL url = NavigateToMockURL("b"); base::FilePath full_file_name, dir; GetDestinationPaths("b", &full_file_name, &dir); DownloadPersistedObserver persisted(browser()->profile(), base::Bind( &DownloadStoredProperly, url, full_file_name, 3, DownloadItem::COMPLETE)); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); ASSERT_TRUE(GetCurrentTab(browser())->SavePage( full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); loop_runner->Run(); ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); persisted.WaitForPersisted(); EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); EXPECT_TRUE(base::PathExists(full_file_name)); EXPECT_TRUE(base::PathExists(dir)); EXPECT_TRUE(base::TextContentsEqual( test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved1.htm"), full_file_name)); EXPECT_TRUE(base::ContentsEqual( test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"), dir.AppendASCII("1.png"))); EXPECT_TRUE(base::ContentsEqual( test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"), dir.AppendASCII("1.css"))); } // Invoke a save page during the initial navigation. // (Regression test for http://crbug.com/156538). // Disabled on Windows due to flakiness. http://crbug.com/162323 #if defined(OS_WIN) #define MAYBE_SaveDuringInitialNavigationIncognito DISABLED_SaveDuringInitialNavigationIncognito #else #define MAYBE_SaveDuringInitialNavigationIncognito SaveDuringInitialNavigationIncognito #endif IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveDuringInitialNavigationIncognito) { // Open an Incognito window. Browser* incognito = CreateIncognitoBrowser(); // Waits. ASSERT_TRUE(incognito); // Create a download item creation waiter on that window. DownloadItemCreatedObserver creation_observer( BrowserContext::GetDownloadManager(incognito->profile())); // Navigate, unblocking with new tab. GURL url = URLRequestMockHTTPJob::GetMockUrl( base::FilePath(kTestDir).AppendASCII("b.htm")); NavigateToURLWithDisposition(incognito, url, NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); // Save the page before completion. base::FilePath full_file_name, dir; GetDestinationPaths("b", &full_file_name, &dir); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(incognito->profile()), loop_runner->QuitClosure()); ASSERT_TRUE(GetCurrentTab(incognito)->SavePage( full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); loop_runner->Run(); ASSERT_TRUE(VerifySavePackageExpectations(incognito, url)); // Confirm download shelf is visible. EXPECT_TRUE(incognito->window()->IsDownloadShelfVisible()); // We can't check more than this because SavePackage is racing with // the page load. If the page load won the race, then SavePackage // might have completed. If the page load lost the race, then // SavePackage will cancel because there aren't any resources to // save. } IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) { ui_test_utils::NavigateToURL(browser(), GURL(content::kAboutBlankURL)); EXPECT_FALSE(chrome::CanSavePage(browser())); } // Disabled on Windows due to flakiness. http://crbug.com/162323 #if defined(OS_WIN) #define MAYBE_FileNameFromPageTitle DISABLED_FileNameFromPageTitle #else #define MAYBE_FileNameFromPageTitle FileNameFromPageTitle #endif IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_FileNameFromPageTitle) { GURL url = NavigateToMockURL("b"); base::FilePath full_file_name = save_dir_.path().AppendASCII( std::string("Test page for saving page feature") + kAppendedExtension); base::FilePath dir = save_dir_.path().AppendASCII( "Test page for saving page feature_files"); DownloadPersistedObserver persisted(browser()->profile(), base::Bind( &DownloadStoredProperly, url, full_file_name, 3, DownloadItem::COMPLETE)); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); ASSERT_TRUE(GetCurrentTab(browser())->SavePage( full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); loop_runner->Run(); ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); persisted.WaitForPersisted(); EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); EXPECT_TRUE(base::PathExists(full_file_name)); EXPECT_TRUE(base::PathExists(dir)); EXPECT_TRUE(base::TextContentsEqual( test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved2.htm"), full_file_name)); EXPECT_TRUE(base::ContentsEqual( test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"), dir.AppendASCII("1.png"))); EXPECT_TRUE(base::ContentsEqual( test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"), dir.AppendASCII("1.css"))); } // Disabled on Windows due to flakiness. http://crbug.com/162323 #if defined(OS_WIN) #define MAYBE_RemoveFromList DISABLED_RemoveFromList #else #define MAYBE_RemoveFromList RemoveFromList #endif IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_RemoveFromList) { GURL url = NavigateToMockURL("a"); base::FilePath full_file_name, dir; GetDestinationPaths("a", &full_file_name, &dir); DownloadPersistedObserver persisted(browser()->profile(), base::Bind( &DownloadStoredProperly, url, full_file_name, 1, DownloadItem::COMPLETE)); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); loop_runner->Run(); ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); persisted.WaitForPersisted(); EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); DownloadManager* manager(GetDownloadManager()); std::vector<DownloadItem*> downloads; manager->GetAllDownloads(&downloads); ASSERT_EQ(1UL, downloads.size()); DownloadRemovedObserver removed(browser()->profile(), downloads[0]->GetId()); EXPECT_EQ(manager->RemoveAllDownloads(), 1); removed.WaitForRemoved(); EXPECT_TRUE(base::PathExists(full_file_name)); EXPECT_FALSE(base::PathExists(dir)); EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath( kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name)); } // This tests that a webpage with the title "test.exe" is saved as // "test.exe.htm". // We probably don't care to handle this on Linux or Mac. #if defined(OS_WIN) IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, CleanFilenameFromPageTitle) { const base::FilePath file_name(FILE_PATH_LITERAL("c.htm")); base::FilePath download_dir = DownloadPrefs::FromDownloadManager(GetDownloadManager())-> DownloadPath(); base::FilePath full_file_name = download_dir.AppendASCII(std::string("test.exe") + kAppendedExtension); base::FilePath dir = download_dir.AppendASCII("test.exe_files"); EXPECT_FALSE(base::PathExists(full_file_name)); GURL url = URLRequestMockHTTPJob::GetMockUrl( base::FilePath(kTestDir).Append(file_name)); ui_test_utils::NavigateToURL(browser(), url); SavePackageFilePicker::SetShouldPromptUser(false); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); chrome::SavePage(browser()); loop_runner->Run(); EXPECT_TRUE(base::PathExists(full_file_name)); EXPECT_TRUE(file_util::DieFileDie(full_file_name, false)); EXPECT_TRUE(file_util::DieFileDie(dir, true)); } #endif class SavePageAsMHTMLBrowserTest : public SavePageBrowserTest { public: SavePageAsMHTMLBrowserTest() {} virtual ~SavePageAsMHTMLBrowserTest(); virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { command_line->AppendSwitch(switches::kSavePageAsMHTML); } private: DISALLOW_COPY_AND_ASSIGN(SavePageAsMHTMLBrowserTest); }; SavePageAsMHTMLBrowserTest::~SavePageAsMHTMLBrowserTest() { } IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest, SavePageAsMHTML) { static const int64 kFileSizeMin = 2758; GURL url = NavigateToMockURL("b"); base::FilePath download_dir = DownloadPrefs::FromDownloadManager( GetDownloadManager())->DownloadPath(); base::FilePath full_file_name = download_dir.AppendASCII(std::string( "Test page for saving page feature.mhtml")); SavePackageFilePicker::SetShouldPromptUser(false); DownloadPersistedObserver persisted(browser()->profile(), base::Bind( &DownloadStoredProperly, url, full_file_name, -1, DownloadItem::COMPLETE)); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); chrome::SavePage(browser()); loop_runner->Run(); ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); persisted.WaitForPersisted(); ASSERT_TRUE(base::PathExists(full_file_name)); int64 actual_file_size = -1; EXPECT_TRUE(base::GetFileSize(full_file_name, &actual_file_size)); EXPECT_LE(kFileSizeMin, actual_file_size); } IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SavePageBrowserTest_NonMHTML) { SavePackageFilePicker::SetShouldPromptUser(false); GURL url("data:text/plain,foo"); ui_test_utils::NavigateToURL(browser(), url); scoped_refptr<content::MessageLoopRunner> loop_runner( new content::MessageLoopRunner); SavePackageFinishedObserver observer( content::BrowserContext::GetDownloadManager(browser()->profile()), loop_runner->QuitClosure()); chrome::SavePage(browser()); loop_runner->Run(); base::FilePath download_dir = DownloadPrefs::FromDownloadManager( GetDownloadManager())->DownloadPath(); base::FilePath filename = download_dir.AppendASCII("dataurl.txt"); ASSERT_TRUE(base::PathExists(filename)); std::string contents; EXPECT_TRUE(base::ReadFileToString(filename, &contents)); EXPECT_EQ("foo", contents); } } // namespace