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