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::GetForBrowserContext(profile_)-> 67 GetDownloadHistory()->AddObserver(this); 68 } 69 70 virtual ~DownloadPersistedObserver() { 71 DownloadService* service = DownloadServiceFactory::GetForBrowserContext( 72 profile_); 73 if (service && service->GetDownloadHistory()) 74 service->GetDownloadHistory()->RemoveObserver(this); 75 } 76 77 bool WaitForPersisted() { 78 if (persisted_) 79 return true; 80 waiting_ = true; 81 content::RunMessageLoop(); 82 waiting_ = false; 83 return persisted_; 84 } 85 86 virtual void OnDownloadStored(DownloadItem* item, 87 const history::DownloadRow& info) OVERRIDE { 88 persisted_ = persisted_ || filter_.Run(item, info); 89 if (persisted_ && waiting_) 90 base::MessageLoopForUI::current()->Quit(); 91 } 92 93 private: 94 Profile* profile_; 95 DownloadItem* item_; 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[] = 182#if defined(OS_WIN) 183 ".htm"; 184#else 185 ".html"; 186#endif 187 188// Loosely based on logic in DownloadTestObserver. 189class DownloadItemCreatedObserver : public DownloadManager::Observer { 190 public: 191 explicit DownloadItemCreatedObserver(DownloadManager* manager) 192 : waiting_(false), manager_(manager) { 193 manager->AddObserver(this); 194 } 195 196 virtual ~DownloadItemCreatedObserver() { 197 if (manager_) 198 manager_->RemoveObserver(this); 199 } 200 201 // Wait for the first download item created after object creation. 202 // Note that this class provides no protection against the download 203 // being destroyed between creation and return of WaitForNewDownloadItem(); 204 // the caller must guarantee that in some other fashion. 205 void WaitForDownloadItem(std::vector<DownloadItem*>* items_seen) { 206 if (!manager_) { 207 // The manager went away before we were asked to wait; return 208 // what we have, even if it's null. 209 *items_seen = items_seen_; 210 return; 211 } 212 213 if (items_seen_.empty()) { 214 waiting_ = true; 215 content::RunMessageLoop(); 216 waiting_ = false; 217 } 218 219 *items_seen = items_seen_; 220 return; 221 } 222 223 private: 224 // DownloadManager::Observer 225 virtual void OnDownloadCreated( 226 DownloadManager* manager, DownloadItem* item) OVERRIDE { 227 DCHECK_EQ(manager, manager_); 228 items_seen_.push_back(item); 229 230 if (waiting_) 231 base::MessageLoopForUI::current()->Quit(); 232 } 233 234 virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE { 235 manager_->RemoveObserver(this); 236 manager_ = NULL; 237 if (waiting_) 238 base::MessageLoopForUI::current()->Quit(); 239 } 240 241 bool waiting_; 242 DownloadManager* manager_; 243 std::vector<DownloadItem*> items_seen_; 244 245 DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver); 246}; 247 248class SavePackageFinishedObserver : public content::DownloadManager::Observer { 249 public: 250 SavePackageFinishedObserver(content::DownloadManager* manager, 251 const base::Closure& callback) 252 : download_manager_(manager), 253 callback_(callback) { 254 download_manager_->AddObserver(this); 255 } 256 257 virtual ~SavePackageFinishedObserver() { 258 if (download_manager_) 259 download_manager_->RemoveObserver(this); 260 } 261 262 // DownloadManager::Observer: 263 virtual void OnSavePackageSuccessfullyFinished( 264 content::DownloadManager* manager, content::DownloadItem* item) OVERRIDE { 265 callback_.Run(); 266 } 267 virtual void ManagerGoingDown(content::DownloadManager* manager) OVERRIDE { 268 download_manager_->RemoveObserver(this); 269 download_manager_ = NULL; 270 } 271 272 private: 273 content::DownloadManager* download_manager_; 274 base::Closure callback_; 275 276 DISALLOW_COPY_AND_ASSIGN(SavePackageFinishedObserver); 277}; 278 279class SavePageBrowserTest : public InProcessBrowserTest { 280 public: 281 SavePageBrowserTest() {} 282 virtual ~SavePageBrowserTest(); 283 284 protected: 285 virtual void SetUp() OVERRIDE { 286 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir_)); 287 ASSERT_TRUE(save_dir_.CreateUniqueTempDir()); 288 InProcessBrowserTest::SetUp(); 289 } 290 291 virtual void SetUpOnMainThread() OVERRIDE { 292 browser()->profile()->GetPrefs()->SetFilePath( 293 prefs::kDownloadDefaultDirectory, save_dir_.path()); 294 browser()->profile()->GetPrefs()->SetFilePath( 295 prefs::kSaveFileDefaultDirectory, 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(base::PathExists(full_file_name)); 406 EXPECT_FALSE(base::PathExists(dir)); 407 EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath( 408 kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name)); 409} 410 411// http://crbug.com/162323 412// http://crbug.com/163931 413IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, DISABLED_SaveHTMLOnlyCancel) { 414 GURL url = NavigateToMockURL("a"); 415 DownloadManager* manager(GetDownloadManager()); 416 std::vector<DownloadItem*> downloads; 417 manager->GetAllDownloads(&downloads); 418 ASSERT_EQ(0u, downloads.size()); 419 420 base::FilePath full_file_name, dir; 421 GetDestinationPaths("a", &full_file_name, &dir); 422 DownloadItemCreatedObserver creation_observer(manager); 423 DownloadPersistedObserver persisted(browser()->profile(), base::Bind( 424 &DownloadStoredProperly, url, full_file_name, -1, 425 DownloadItem::CANCELLED)); 426 // -1 to disable number of files check; we don't update after cancel, and 427 // we don't know when the single file completed in relationship to 428 // the cancel. 429 430 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, 431 content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); 432 std::vector<DownloadItem*> items; 433 creation_observer.WaitForDownloadItem(&items); 434 ASSERT_EQ(1UL, items.size()); 435 ASSERT_EQ(url.spec(), items[0]->GetOriginalUrl().spec()); 436 items[0]->Cancel(true); 437 // TODO(rdsmith): Fix DII::Cancel() to actually cancel the save package. 438 // Currently it's ignored. 439 440 persisted.WaitForPersisted(); 441 442 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); 443 444 // TODO(benjhayden): Figure out how to safely wait for SavePackage's finished 445 // notification, then expect the contents of the downloaded file. 446} 447 448class DelayingDownloadManagerDelegate : public ChromeDownloadManagerDelegate { 449 public: 450 explicit DelayingDownloadManagerDelegate(Profile* profile) 451 : ChromeDownloadManagerDelegate(profile) { 452 } 453 virtual bool ShouldCompleteDownload( 454 content::DownloadItem* item, 455 const base::Closure& user_complete_callback) OVERRIDE { 456 return false; 457 } 458 459 protected: 460 virtual ~DelayingDownloadManagerDelegate() {} 461 462 private: 463 DISALLOW_COPY_AND_ASSIGN(DelayingDownloadManagerDelegate); 464}; 465 466IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveHTMLOnlyTabDestroy) { 467 GURL url = NavigateToMockURL("a"); 468 DownloadManager* manager(GetDownloadManager()); 469 scoped_refptr<DelayingDownloadManagerDelegate> delaying_delegate( 470 new DelayingDownloadManagerDelegate(browser()->profile())); 471 delaying_delegate->SetNextId(content::DownloadItem::kInvalidId + 1); 472 manager->SetDelegate(delaying_delegate.get()); 473 std::vector<DownloadItem*> downloads; 474 manager->GetAllDownloads(&downloads); 475 ASSERT_EQ(0u, downloads.size()); 476 477 base::FilePath full_file_name, dir; 478 GetDestinationPaths("a", &full_file_name, &dir); 479 DownloadItemCreatedObserver creation_observer(manager); 480 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, 481 content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); 482 std::vector<DownloadItem*> items; 483 creation_observer.WaitForDownloadItem(&items); 484 ASSERT_TRUE(items.size() == 1); 485 486 // Close the tab; does this cancel the download? 487 GetCurrentTab(browser())->Close(); 488 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); 489 490 EXPECT_FALSE(base::PathExists(full_file_name)); 491 EXPECT_FALSE(base::PathExists(dir)); 492 493 manager->SetDelegate(NULL); 494} 495 496// Disabled on Windows due to flakiness. http://crbug.com/162323 497// TODO(linux_aura) http://crbug.com/163931 498#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)) 499#define MAYBE_SaveViewSourceHTMLOnly DISABLED_SaveViewSourceHTMLOnly 500#else 501#define MAYBE_SaveViewSourceHTMLOnly SaveViewSourceHTMLOnly 502#endif 503IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveViewSourceHTMLOnly) { 504 base::FilePath file_name(FILE_PATH_LITERAL("a.htm")); 505 GURL view_source_url = URLRequestMockHTTPJob::GetMockViewSourceUrl( 506 base::FilePath(kTestDir).Append(file_name)); 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// TODO(linux_aura) http://crbug.com/163931 538#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)) 539#define MAYBE_SaveCompleteHTML DISABLED_SaveCompleteHTML 540#else 541#define MAYBE_SaveCompleteHTML SaveCompleteHTML 542#endif 543IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_SaveCompleteHTML) { 544 GURL url = NavigateToMockURL("b"); 545 546 base::FilePath full_file_name, dir; 547 GetDestinationPaths("b", &full_file_name, &dir); 548 DownloadPersistedObserver persisted(browser()->profile(), base::Bind( 549 &DownloadStoredProperly, url, full_file_name, 3, 550 DownloadItem::COMPLETE)); 551 scoped_refptr<content::MessageLoopRunner> loop_runner( 552 new content::MessageLoopRunner); 553 SavePackageFinishedObserver observer( 554 content::BrowserContext::GetDownloadManager(browser()->profile()), 555 loop_runner->QuitClosure()); 556 ASSERT_TRUE(GetCurrentTab(browser())->SavePage( 557 full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); 558 loop_runner->Run(); 559 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); 560 persisted.WaitForPersisted(); 561 562 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); 563 564 EXPECT_TRUE(base::PathExists(full_file_name)); 565 EXPECT_TRUE(base::PathExists(dir)); 566 EXPECT_TRUE(base::TextContentsEqual( 567 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved1.htm"), 568 full_file_name)); 569 EXPECT_TRUE(base::ContentsEqual( 570 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"), 571 dir.AppendASCII("1.png"))); 572 EXPECT_TRUE(base::ContentsEqual( 573 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"), 574 dir.AppendASCII("1.css"))); 575} 576 577// Invoke a save page during the initial navigation. 578// (Regression test for http://crbug.com/156538). 579// Disabled on Windows due to flakiness. http://crbug.com/162323 580// TODO(linux_aura) http://crbug.com/163931 581#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)) 582#define MAYBE_SaveDuringInitialNavigationIncognito DISABLED_SaveDuringInitialNavigationIncognito 583#else 584#define MAYBE_SaveDuringInitialNavigationIncognito SaveDuringInitialNavigationIncognito 585#endif 586IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, 587 MAYBE_SaveDuringInitialNavigationIncognito) { 588 // Open an Incognito window. 589 Browser* incognito = CreateIncognitoBrowser(); // Waits. 590 ASSERT_TRUE(incognito); 591 592 // Create a download item creation waiter on that window. 593 DownloadItemCreatedObserver creation_observer( 594 BrowserContext::GetDownloadManager(incognito->profile())); 595 596 // Navigate, unblocking with new tab. 597 GURL url = URLRequestMockHTTPJob::GetMockUrl( 598 base::FilePath(kTestDir).AppendASCII("b.htm")); 599 NavigateToURLWithDisposition(incognito, url, NEW_FOREGROUND_TAB, 600 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); 601 602 // Save the page before completion. 603 base::FilePath full_file_name, dir; 604 GetDestinationPaths("b", &full_file_name, &dir); 605 scoped_refptr<content::MessageLoopRunner> loop_runner( 606 new content::MessageLoopRunner); 607 SavePackageFinishedObserver observer( 608 content::BrowserContext::GetDownloadManager(incognito->profile()), 609 loop_runner->QuitClosure()); 610 ASSERT_TRUE(GetCurrentTab(incognito)->SavePage( 611 full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); 612 613 loop_runner->Run(); 614 ASSERT_TRUE(VerifySavePackageExpectations(incognito, url)); 615 616 // Confirm download shelf is visible. 617 EXPECT_TRUE(incognito->window()->IsDownloadShelfVisible()); 618 619 // We can't check more than this because SavePackage is racing with 620 // the page load. If the page load won the race, then SavePackage 621 // might have completed. If the page load lost the race, then 622 // SavePackage will cancel because there aren't any resources to 623 // save. 624} 625 626IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, NoSave) { 627 ui_test_utils::NavigateToURL(browser(), GURL(content::kAboutBlankURL)); 628 EXPECT_FALSE(chrome::CanSavePage(browser())); 629} 630 631// Disabled on Windows due to flakiness. http://crbug.com/162323 632// TODO(linux_aura) http://crbug.com/163931 633#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)) 634#define MAYBE_FileNameFromPageTitle DISABLED_FileNameFromPageTitle 635#else 636#define MAYBE_FileNameFromPageTitle FileNameFromPageTitle 637#endif 638IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_FileNameFromPageTitle) { 639 GURL url = NavigateToMockURL("b"); 640 641 base::FilePath full_file_name = save_dir_.path().AppendASCII( 642 std::string("Test page for saving page feature") + kAppendedExtension); 643 base::FilePath dir = save_dir_.path().AppendASCII( 644 "Test page for saving page feature_files"); 645 DownloadPersistedObserver persisted(browser()->profile(), base::Bind( 646 &DownloadStoredProperly, url, full_file_name, 3, 647 DownloadItem::COMPLETE)); 648 scoped_refptr<content::MessageLoopRunner> loop_runner( 649 new content::MessageLoopRunner); 650 SavePackageFinishedObserver observer( 651 content::BrowserContext::GetDownloadManager(browser()->profile()), 652 loop_runner->QuitClosure()); 653 ASSERT_TRUE(GetCurrentTab(browser())->SavePage( 654 full_file_name, dir, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML)); 655 656 loop_runner->Run(); 657 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); 658 persisted.WaitForPersisted(); 659 660 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); 661 662 EXPECT_TRUE(base::PathExists(full_file_name)); 663 EXPECT_TRUE(base::PathExists(dir)); 664 EXPECT_TRUE(base::TextContentsEqual( 665 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("b.saved2.htm"), 666 full_file_name)); 667 EXPECT_TRUE(base::ContentsEqual( 668 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.png"), 669 dir.AppendASCII("1.png"))); 670 EXPECT_TRUE(base::ContentsEqual( 671 test_dir_.Append(base::FilePath(kTestDir)).AppendASCII("1.css"), 672 dir.AppendASCII("1.css"))); 673} 674 675// Disabled on Windows due to flakiness. http://crbug.com/162323 676// TODO(linux_aura) http://crbug.com/163931 677#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)) 678#define MAYBE_RemoveFromList DISABLED_RemoveFromList 679#else 680#define MAYBE_RemoveFromList RemoveFromList 681#endif 682IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, MAYBE_RemoveFromList) { 683 GURL url = NavigateToMockURL("a"); 684 685 base::FilePath full_file_name, dir; 686 GetDestinationPaths("a", &full_file_name, &dir); 687 DownloadPersistedObserver persisted(browser()->profile(), base::Bind( 688 &DownloadStoredProperly, url, full_file_name, 1, 689 DownloadItem::COMPLETE)); 690 scoped_refptr<content::MessageLoopRunner> loop_runner( 691 new content::MessageLoopRunner); 692 SavePackageFinishedObserver observer( 693 content::BrowserContext::GetDownloadManager(browser()->profile()), 694 loop_runner->QuitClosure()); 695 ASSERT_TRUE(GetCurrentTab(browser())->SavePage(full_file_name, dir, 696 content::SAVE_PAGE_TYPE_AS_ONLY_HTML)); 697 698 loop_runner->Run(); 699 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); 700 persisted.WaitForPersisted(); 701 702 EXPECT_TRUE(browser()->window()->IsDownloadShelfVisible()); 703 704 DownloadManager* manager(GetDownloadManager()); 705 std::vector<DownloadItem*> downloads; 706 manager->GetAllDownloads(&downloads); 707 ASSERT_EQ(1UL, downloads.size()); 708 DownloadRemovedObserver removed(browser()->profile(), downloads[0]->GetId()); 709 710 EXPECT_EQ(manager->RemoveAllDownloads(), 1); 711 712 removed.WaitForRemoved(); 713 714 EXPECT_TRUE(base::PathExists(full_file_name)); 715 EXPECT_FALSE(base::PathExists(dir)); 716 EXPECT_TRUE(base::ContentsEqual(test_dir_.Append(base::FilePath( 717 kTestDir)).Append(FILE_PATH_LITERAL("a.htm")), full_file_name)); 718} 719 720// This tests that a webpage with the title "test.exe" is saved as 721// "test.exe.htm". 722// We probably don't care to handle this on Linux or Mac. 723#if defined(OS_WIN) 724IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, CleanFilenameFromPageTitle) { 725 const base::FilePath file_name(FILE_PATH_LITERAL("c.htm")); 726 base::FilePath download_dir = 727 DownloadPrefs::FromDownloadManager(GetDownloadManager())-> 728 DownloadPath(); 729 base::FilePath full_file_name = 730 download_dir.AppendASCII(std::string("test.exe") + kAppendedExtension); 731 base::FilePath dir = download_dir.AppendASCII("test.exe_files"); 732 733 EXPECT_FALSE(base::PathExists(full_file_name)); 734 GURL url = URLRequestMockHTTPJob::GetMockUrl( 735 base::FilePath(kTestDir).Append(file_name)); 736 ui_test_utils::NavigateToURL(browser(), url); 737 738 SavePackageFilePicker::SetShouldPromptUser(false); 739 scoped_refptr<content::MessageLoopRunner> loop_runner( 740 new content::MessageLoopRunner); 741 SavePackageFinishedObserver observer( 742 content::BrowserContext::GetDownloadManager(browser()->profile()), 743 loop_runner->QuitClosure()); 744 chrome::SavePage(browser()); 745 loop_runner->Run(); 746 747 EXPECT_TRUE(base::PathExists(full_file_name)); 748 749 EXPECT_TRUE(file_util::DieFileDie(full_file_name, false)); 750 EXPECT_TRUE(file_util::DieFileDie(dir, true)); 751} 752#endif 753 754class SavePageAsMHTMLBrowserTest : public SavePageBrowserTest { 755 public: 756 SavePageAsMHTMLBrowserTest() {} 757 virtual ~SavePageAsMHTMLBrowserTest(); 758 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 759 command_line->AppendSwitch(switches::kSavePageAsMHTML); 760 } 761 762 private: 763 DISALLOW_COPY_AND_ASSIGN(SavePageAsMHTMLBrowserTest); 764}; 765 766SavePageAsMHTMLBrowserTest::~SavePageAsMHTMLBrowserTest() { 767} 768 769IN_PROC_BROWSER_TEST_F(SavePageAsMHTMLBrowserTest, SavePageAsMHTML) { 770 static const int64 kFileSizeMin = 2758; 771 GURL url = NavigateToMockURL("b"); 772 base::FilePath download_dir = DownloadPrefs::FromDownloadManager( 773 GetDownloadManager())->DownloadPath(); 774 base::FilePath full_file_name = download_dir.AppendASCII(std::string( 775 "Test page for saving page feature.mhtml")); 776 SavePackageFilePicker::SetShouldPromptUser(false); 777 DownloadPersistedObserver persisted(browser()->profile(), base::Bind( 778 &DownloadStoredProperly, url, full_file_name, -1, 779 DownloadItem::COMPLETE)); 780 scoped_refptr<content::MessageLoopRunner> loop_runner( 781 new content::MessageLoopRunner); 782 SavePackageFinishedObserver observer( 783 content::BrowserContext::GetDownloadManager(browser()->profile()), 784 loop_runner->QuitClosure()); 785 chrome::SavePage(browser()); 786 loop_runner->Run(); 787 ASSERT_TRUE(VerifySavePackageExpectations(browser(), url)); 788 persisted.WaitForPersisted(); 789 790 ASSERT_TRUE(base::PathExists(full_file_name)); 791 int64 actual_file_size = -1; 792 EXPECT_TRUE(file_util::GetFileSize(full_file_name, &actual_file_size)); 793 EXPECT_LE(kFileSizeMin, actual_file_size); 794} 795 796IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SavePageBrowserTest_NonMHTML) { 797 SavePackageFilePicker::SetShouldPromptUser(false); 798 GURL url("data:text/plain,foo"); 799 ui_test_utils::NavigateToURL(browser(), url); 800 scoped_refptr<content::MessageLoopRunner> loop_runner( 801 new content::MessageLoopRunner); 802 SavePackageFinishedObserver observer( 803 content::BrowserContext::GetDownloadManager(browser()->profile()), 804 loop_runner->QuitClosure()); 805 chrome::SavePage(browser()); 806 loop_runner->Run(); 807 base::FilePath download_dir = DownloadPrefs::FromDownloadManager( 808 GetDownloadManager())->DownloadPath(); 809 base::FilePath filename = download_dir.AppendASCII("dataurl.txt"); 810 ASSERT_TRUE(base::PathExists(filename)); 811 std::string contents; 812 EXPECT_TRUE(file_util::ReadFileToString(filename, &contents)); 813 EXPECT_EQ("foo", contents); 814} 815 816} // namespace 817 818