download_browsertest.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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// This file contains download browser tests that are known to be runnable 6// in a pure content context. Over time tests should be migrated here. 7 8#include "base/command_line.h" 9#include "base/file_util.h" 10#include "base/files/file_path.h" 11#include "base/files/scoped_temp_dir.h" 12#include "content/browser/byte_stream.h" 13#include "content/browser/download/download_file_factory.h" 14#include "content/browser/download/download_file_impl.h" 15#include "content/browser/download/download_item_impl.h" 16#include "content/browser/download/download_manager_impl.h" 17#include "content/browser/download/download_resource_handler.h" 18#include "content/browser/web_contents/web_contents_impl.h" 19#include "content/public/browser/power_save_blocker.h" 20#include "content/public/common/content_switches.h" 21#include "content/public/test/download_test_observer.h" 22#include "content/public/test/test_file_error_injector.h" 23#include "content/public/test/test_utils.h" 24#include "content/shell/shell.h" 25#include "content/shell/shell_browser_context.h" 26#include "content/shell/shell_download_manager_delegate.h" 27#include "content/test/content_browser_test.h" 28#include "content/test/content_browser_test_utils.h" 29#include "content/test/net/url_request_mock_http_job.h" 30#include "content/test/net/url_request_slow_download_job.h" 31#include "googleurl/src/gurl.h" 32#include "net/test/spawned_test_server/spawned_test_server.h" 33#include "testing/gmock/include/gmock/gmock.h" 34#include "testing/gtest/include/gtest/gtest.h" 35 36using ::testing::_; 37using ::testing::AllOf; 38using ::testing::Field; 39using ::testing::InSequence; 40using ::testing::Property; 41using ::testing::Return; 42using ::testing::StrictMock; 43 44namespace content { 45 46namespace { 47 48class MockDownloadItemObserver : public DownloadItem::Observer { 49 public: 50 MockDownloadItemObserver() {} 51 virtual ~MockDownloadItemObserver() {} 52 53 MOCK_METHOD1(OnDownloadUpdated, void(DownloadItem*)); 54 MOCK_METHOD1(OnDownloadOpened, void(DownloadItem*)); 55 MOCK_METHOD1(OnDownloadRemoved, void(DownloadItem*)); 56 MOCK_METHOD1(OnDownloadDestroyed, void(DownloadItem*)); 57}; 58 59class MockDownloadManagerObserver : public DownloadManager::Observer { 60 public: 61 MockDownloadManagerObserver(DownloadManager* manager) { 62 manager_ = manager; 63 manager->AddObserver(this); 64 } 65 virtual ~MockDownloadManagerObserver() { 66 if (manager_) 67 manager_->RemoveObserver(this); 68 } 69 70 MOCK_METHOD2(OnDownloadCreated, void(DownloadManager*, DownloadItem*)); 71 MOCK_METHOD1(ModelChanged, void(DownloadManager*)); 72 void ManagerGoingDown(DownloadManager* manager) { 73 DCHECK_EQ(manager_, manager); 74 MockManagerGoingDown(manager); 75 76 manager_->RemoveObserver(this); 77 manager_ = NULL; 78 } 79 80 MOCK_METHOD1(MockManagerGoingDown, void(DownloadManager*)); 81 private: 82 DownloadManager* manager_; 83}; 84 85class DownloadFileWithDelayFactory; 86 87static DownloadManagerImpl* DownloadManagerForShell(Shell* shell) { 88 // We're in a content_browsertest; we know that the DownloadManager 89 // is a DownloadManagerImpl. 90 return static_cast<DownloadManagerImpl*>( 91 BrowserContext::GetDownloadManager( 92 shell->web_contents()->GetBrowserContext())); 93} 94 95class DownloadFileWithDelay : public DownloadFileImpl { 96 public: 97 DownloadFileWithDelay( 98 scoped_ptr<DownloadSaveInfo> save_info, 99 const base::FilePath& default_download_directory, 100 const GURL& url, 101 const GURL& referrer_url, 102 bool calculate_hash, 103 scoped_ptr<ByteStreamReader> stream, 104 const net::BoundNetLog& bound_net_log, 105 scoped_ptr<PowerSaveBlocker> power_save_blocker, 106 base::WeakPtr<DownloadDestinationObserver> observer, 107 base::WeakPtr<DownloadFileWithDelayFactory> owner); 108 109 virtual ~DownloadFileWithDelay(); 110 111 // Wraps DownloadFileImpl::Rename* and intercepts the return callback, 112 // storing it in the factory that produced this object for later 113 // retrieval. 114 virtual void RenameAndUniquify( 115 const base::FilePath& full_path, 116 const RenameCompletionCallback& callback) OVERRIDE; 117 virtual void RenameAndAnnotate( 118 const base::FilePath& full_path, 119 const RenameCompletionCallback& callback) OVERRIDE; 120 121 private: 122 static void RenameCallbackWrapper( 123 DownloadFileWithDelayFactory* factory, 124 const RenameCompletionCallback& original_callback, 125 DownloadInterruptReason reason, 126 const base::FilePath& path); 127 128 // This variable may only be read on the FILE thread, and may only be 129 // indirected through (e.g. methods on DownloadFileWithDelayFactory called) 130 // on the UI thread. This is because after construction, 131 // DownloadFileWithDelay lives on the file thread, but 132 // DownloadFileWithDelayFactory is purely a UI thread object. 133 base::WeakPtr<DownloadFileWithDelayFactory> owner_; 134 135 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelay); 136}; 137 138// All routines on this class must be called on the UI thread. 139class DownloadFileWithDelayFactory : public DownloadFileFactory { 140 public: 141 DownloadFileWithDelayFactory(); 142 virtual ~DownloadFileWithDelayFactory(); 143 144 // DownloadFileFactory interface. 145 virtual DownloadFile* CreateFile( 146 scoped_ptr<DownloadSaveInfo> save_info, 147 const base::FilePath& default_download_directory, 148 const GURL& url, 149 const GURL& referrer_url, 150 bool calculate_hash, 151 scoped_ptr<ByteStreamReader> stream, 152 const net::BoundNetLog& bound_net_log, 153 base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE; 154 155 void AddRenameCallback(base::Closure callback); 156 void GetAllRenameCallbacks(std::vector<base::Closure>* results); 157 158 // Do not return until GetAllRenameCallbacks() will return a non-empty list. 159 void WaitForSomeCallback(); 160 161 private: 162 base::WeakPtrFactory<DownloadFileWithDelayFactory> weak_ptr_factory_; 163 std::vector<base::Closure> rename_callbacks_; 164 bool waiting_; 165 166 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelayFactory); 167}; 168 169DownloadFileWithDelay::DownloadFileWithDelay( 170 scoped_ptr<DownloadSaveInfo> save_info, 171 const base::FilePath& default_download_directory, 172 const GURL& url, 173 const GURL& referrer_url, 174 bool calculate_hash, 175 scoped_ptr<ByteStreamReader> stream, 176 const net::BoundNetLog& bound_net_log, 177 scoped_ptr<PowerSaveBlocker> power_save_blocker, 178 base::WeakPtr<DownloadDestinationObserver> observer, 179 base::WeakPtr<DownloadFileWithDelayFactory> owner) 180 : DownloadFileImpl( 181 save_info.Pass(), default_download_directory, url, referrer_url, 182 calculate_hash, stream.Pass(), bound_net_log, 183 power_save_blocker.Pass(), observer), 184 owner_(owner) {} 185 186DownloadFileWithDelay::~DownloadFileWithDelay() {} 187 188void DownloadFileWithDelay::RenameAndUniquify( 189 const base::FilePath& full_path, 190 const RenameCompletionCallback& callback) { 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 192 DownloadFileImpl::RenameAndUniquify( 193 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper, 194 owner_, callback)); 195} 196 197void DownloadFileWithDelay::RenameAndAnnotate( 198 const base::FilePath& full_path, const RenameCompletionCallback& callback) { 199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 200 DownloadFileImpl::RenameAndAnnotate( 201 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper, 202 owner_, callback)); 203} 204 205// static 206void DownloadFileWithDelay::RenameCallbackWrapper( 207 DownloadFileWithDelayFactory* factory, 208 const RenameCompletionCallback& original_callback, 209 DownloadInterruptReason reason, 210 const base::FilePath& path) { 211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 212 factory->AddRenameCallback(base::Bind(original_callback, reason, path)); 213} 214 215DownloadFileWithDelayFactory::DownloadFileWithDelayFactory() 216 : weak_ptr_factory_(this), 217 waiting_(false) {} 218DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {} 219 220DownloadFile* DownloadFileWithDelayFactory::CreateFile( 221 scoped_ptr<DownloadSaveInfo> save_info, 222 const base::FilePath& default_download_directory, 223 const GURL& url, 224 const GURL& referrer_url, 225 bool calculate_hash, 226 scoped_ptr<ByteStreamReader> stream, 227 const net::BoundNetLog& bound_net_log, 228 base::WeakPtr<DownloadDestinationObserver> observer) { 229 scoped_ptr<PowerSaveBlocker> psb( 230 PowerSaveBlocker::Create( 231 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, 232 "Download in progress")); 233 return new DownloadFileWithDelay( 234 save_info.Pass(), default_download_directory, url, referrer_url, 235 calculate_hash, stream.Pass(), bound_net_log, 236 psb.Pass(), observer, weak_ptr_factory_.GetWeakPtr()); 237} 238 239void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) { 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 241 rename_callbacks_.push_back(callback); 242 if (waiting_) 243 base::MessageLoopForUI::current()->Quit(); 244} 245 246void DownloadFileWithDelayFactory::GetAllRenameCallbacks( 247 std::vector<base::Closure>* results) { 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 results->swap(rename_callbacks_); 250} 251 252void DownloadFileWithDelayFactory::WaitForSomeCallback() { 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 254 255 if (rename_callbacks_.empty()) { 256 waiting_ = true; 257 RunMessageLoop(); 258 waiting_ = false; 259 } 260} 261 262class CountingDownloadFile : public DownloadFileImpl { 263 public: 264 CountingDownloadFile( 265 scoped_ptr<DownloadSaveInfo> save_info, 266 const base::FilePath& default_downloads_directory, 267 const GURL& url, 268 const GURL& referrer_url, 269 bool calculate_hash, 270 scoped_ptr<ByteStreamReader> stream, 271 const net::BoundNetLog& bound_net_log, 272 scoped_ptr<PowerSaveBlocker> power_save_blocker, 273 base::WeakPtr<DownloadDestinationObserver> observer) 274 : DownloadFileImpl(save_info.Pass(), default_downloads_directory, 275 url, referrer_url, calculate_hash, 276 stream.Pass(), bound_net_log, 277 power_save_blocker.Pass(), observer) {} 278 279 virtual ~CountingDownloadFile() { 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 281 active_files_--; 282 } 283 284 virtual void Initialize(const InitializeCallback& callback) OVERRIDE { 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 286 active_files_++; 287 return DownloadFileImpl::Initialize(callback); 288 } 289 290 static void GetNumberActiveFiles(int* result) { 291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 292 *result = active_files_; 293 } 294 295 // Can be called on any thread, and will block (running message loop) 296 // until data is returned. 297 static int GetNumberActiveFilesFromFileThread() { 298 int result = -1; 299 BrowserThread::PostTaskAndReply( 300 BrowserThread::FILE, 301 FROM_HERE, 302 base::Bind(&CountingDownloadFile::GetNumberActiveFiles, &result), 303 base::MessageLoop::current()->QuitClosure()); 304 base::MessageLoop::current()->Run(); 305 DCHECK_NE(-1, result); 306 return result; 307 } 308 309 private: 310 static int active_files_; 311}; 312 313int CountingDownloadFile::active_files_ = 0; 314 315class CountingDownloadFileFactory : public DownloadFileFactory { 316 public: 317 CountingDownloadFileFactory() {} 318 virtual ~CountingDownloadFileFactory() {} 319 320 // DownloadFileFactory interface. 321 virtual DownloadFile* CreateFile( 322 scoped_ptr<DownloadSaveInfo> save_info, 323 const base::FilePath& default_downloads_directory, 324 const GURL& url, 325 const GURL& referrer_url, 326 bool calculate_hash, 327 scoped_ptr<ByteStreamReader> stream, 328 const net::BoundNetLog& bound_net_log, 329 base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE { 330 scoped_ptr<PowerSaveBlocker> psb( 331 PowerSaveBlocker::Create( 332 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, 333 "Download in progress")); 334 return new CountingDownloadFile( 335 save_info.Pass(), default_downloads_directory, url, referrer_url, 336 calculate_hash, stream.Pass(), bound_net_log, 337 psb.Pass(), observer); 338 } 339}; 340 341class TestShellDownloadManagerDelegate : public ShellDownloadManagerDelegate { 342 public: 343 TestShellDownloadManagerDelegate() 344 : delay_download_open_(false) {} 345 346 virtual bool ShouldOpenDownload( 347 DownloadItem* item, 348 const DownloadOpenDelayedCallback& callback) OVERRIDE { 349 if (delay_download_open_) { 350 delayed_callbacks_.push_back(callback); 351 return false; 352 } 353 return true; 354 } 355 356 void SetDelayedOpen(bool delay) { 357 delay_download_open_ = delay; 358 } 359 360 void GetDelayedCallbacks( 361 std::vector<DownloadOpenDelayedCallback>* callbacks) { 362 callbacks->swap(delayed_callbacks_); 363 } 364 private: 365 virtual ~TestShellDownloadManagerDelegate() {} 366 367 bool delay_download_open_; 368 std::vector<DownloadOpenDelayedCallback> delayed_callbacks_; 369}; 370 371// Record all state transitions and byte counts on the observed download. 372class RecordingDownloadObserver : DownloadItem::Observer { 373 public: 374 struct RecordStruct { 375 DownloadItem::DownloadState state; 376 int bytes_received; 377 }; 378 379 typedef std::vector<RecordStruct> RecordVector; 380 381 RecordingDownloadObserver(DownloadItem* download) 382 : download_(download) { 383 last_state_.state = download->GetState(); 384 last_state_.bytes_received = download->GetReceivedBytes(); 385 download_->AddObserver(this); 386 } 387 388 virtual ~RecordingDownloadObserver() { 389 RemoveObserver(); 390 } 391 392 void CompareToExpectedRecord(const RecordStruct expected[], size_t size) { 393 EXPECT_EQ(size, record_.size()); 394 int min = size > record_.size() ? record_.size() : size; 395 for (int i = 0; i < min; ++i) { 396 EXPECT_EQ(expected[i].state, record_[i].state) << "Iteration " << i; 397 EXPECT_EQ(expected[i].bytes_received, record_[i].bytes_received) 398 << "Iteration " << i; 399 } 400 } 401 402 private: 403 virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE { 404 DCHECK_EQ(download_, download); 405 DownloadItem::DownloadState state = download->GetState(); 406 int bytes = download->GetReceivedBytes(); 407 if (last_state_.state != state || last_state_.bytes_received > bytes) { 408 last_state_.state = state; 409 last_state_.bytes_received = bytes; 410 record_.push_back(last_state_); 411 } 412 } 413 414 virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE { 415 DCHECK_EQ(download_, download); 416 RemoveObserver(); 417 } 418 419 void RemoveObserver() { 420 if (download_) { 421 download_->RemoveObserver(this); 422 download_ = NULL; 423 } 424 } 425 426 DownloadItem* download_; 427 RecordStruct last_state_; 428 RecordVector record_; 429}; 430 431// Get the next created download. 432class DownloadCreateObserver : DownloadManager::Observer { 433 public: 434 DownloadCreateObserver(DownloadManager* manager) 435 : manager_(manager), 436 item_(NULL), 437 waiting_(false) { 438 manager_->AddObserver(this); 439 } 440 441 virtual ~DownloadCreateObserver() { 442 if (manager_) 443 manager_->RemoveObserver(this); 444 manager_ = NULL; 445 } 446 447 virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE { 448 DCHECK_EQ(manager_, manager); 449 manager_->RemoveObserver(this); 450 manager_ = NULL; 451 } 452 453 virtual void OnDownloadCreated(DownloadManager* manager, 454 DownloadItem* download) OVERRIDE { 455 if (!item_) 456 item_ = download; 457 458 if (waiting_) 459 base::MessageLoopForUI::current()->Quit(); 460 } 461 462 DownloadItem* WaitForFinished() { 463 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 464 if (!item_) { 465 waiting_ = true; 466 RunMessageLoop(); 467 waiting_ = false; 468 } 469 return item_; 470 } 471 472 private: 473 DownloadManager* manager_; 474 DownloadItem* item_; 475 bool waiting_; 476}; 477 478 479// Filter for waiting for a certain number of bytes. 480bool DataReceivedFilter(int number_of_bytes, DownloadItem* download) { 481 return download->GetReceivedBytes() >= number_of_bytes; 482} 483 484// Filter for download completion. 485bool DownloadCompleteFilter(DownloadItem* download) { 486 return download->GetState() == DownloadItem::COMPLETE; 487} 488 489// Filter for saving the size of the download when the first IN_PROGRESS 490// is hit. 491bool InitialSizeFilter(int* download_size, DownloadItem* download) { 492 if (download->GetState() != DownloadItem::IN_PROGRESS) 493 return false; 494 495 *download_size = download->GetReceivedBytes(); 496 return true; 497} 498 499} // namespace 500 501class DownloadContentTest : public ContentBrowserTest { 502 protected: 503 // An initial send from a website of at least this size will not be 504 // help up by buffering in the underlying downloads ByteStream data 505 // transfer. This is important because on resumption tests we wait 506 // until we've gotten the data we expect before allowing the test server 507 // to send its reset, to get around hard close semantics on the Windows 508 // socket layer implementation. 509 int GetSafeBufferChunk() const { 510 return (DownloadResourceHandler::kDownloadByteStreamSize / 511 ByteStreamWriter::kFractionBufferBeforeSending) + 1; 512 } 513 514 virtual void SetUpOnMainThread() OVERRIDE { 515 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir()); 516 517 TestShellDownloadManagerDelegate* delegate = 518 new TestShellDownloadManagerDelegate(); 519 delegate->SetDownloadBehaviorForTesting(downloads_directory_.path()); 520 DownloadManager* manager = DownloadManagerForShell(shell()); 521 manager->SetDelegate(delegate); 522 delegate->SetDownloadManager(manager); 523 524 BrowserThread::PostTask( 525 BrowserThread::IO, FROM_HERE, 526 base::Bind(&URLRequestSlowDownloadJob::AddUrlHandler)); 527 base::FilePath mock_base(GetTestFilePath("download", "")); 528 BrowserThread::PostTask( 529 BrowserThread::IO, FROM_HERE, 530 base::Bind(&URLRequestMockHTTPJob::AddUrlHandler, mock_base)); 531 } 532 533 TestShellDownloadManagerDelegate* GetDownloadManagerDelegate( 534 DownloadManager* manager) { 535 return static_cast<TestShellDownloadManagerDelegate*>( 536 manager->GetDelegate()); 537 } 538 539 // Create a DownloadTestObserverTerminal that will wait for the 540 // specified number of downloads to finish. 541 DownloadTestObserver* CreateWaiter( 542 Shell* shell, int num_downloads) { 543 DownloadManager* download_manager = DownloadManagerForShell(shell); 544 return new DownloadTestObserverTerminal(download_manager, num_downloads, 545 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL); 546 } 547 548 // Create a DownloadTestObserverInProgress that will wait for the 549 // specified number of downloads to start. 550 DownloadCreateObserver* CreateInProgressWaiter( 551 Shell* shell, int num_downloads) { 552 DownloadManager* download_manager = DownloadManagerForShell(shell); 553 return new DownloadCreateObserver(download_manager); 554 } 555 556 // Note: Cannot be used with other alternative DownloadFileFactorys 557 void SetupEnsureNoPendingDownloads() { 558 DownloadManagerForShell(shell())->SetDownloadFileFactoryForTesting( 559 scoped_ptr<DownloadFileFactory>( 560 new CountingDownloadFileFactory()).Pass()); 561 } 562 563 bool EnsureNoPendingDownloads() { 564 bool result = true; 565 BrowserThread::PostTask( 566 BrowserThread::IO, FROM_HERE, 567 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result)); 568 base::MessageLoop::current()->Run(); 569 return result && 570 (CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0); 571 } 572 573 void DownloadAndWait(Shell* shell, const GURL& url, 574 DownloadItem::DownloadState expected_terminal_state) { 575 scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell, 1)); 576 NavigateToURL(shell, url); 577 observer->WaitForFinished(); 578 EXPECT_EQ(1u, observer->NumDownloadsSeenInState(expected_terminal_state)); 579 } 580 581 // Checks that |path| is has |file_size| bytes, and matches the |value| 582 // string. 583 bool VerifyFile(const base::FilePath& path, 584 const std::string& value, 585 const int64 file_size) { 586 std::string file_contents; 587 588 bool read = file_util::ReadFileToString(path, &file_contents); 589 EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl; 590 if (!read) 591 return false; // Couldn't read the file. 592 593 // Note: we don't handle really large files (more than size_t can hold) 594 // so we will fail in that case. 595 size_t expected_size = static_cast<size_t>(file_size); 596 597 // Check the size. 598 EXPECT_EQ(expected_size, file_contents.size()); 599 if (expected_size != file_contents.size()) 600 return false; 601 602 // Check the contents. 603 EXPECT_EQ(value, file_contents); 604 if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0) 605 return false; 606 607 return true; 608 } 609 610 // Start a download and return the item. 611 DownloadItem* StartDownloadAndReturnItem(GURL url) { 612 scoped_ptr<DownloadCreateObserver> observer( 613 CreateInProgressWaiter(shell(), 1)); 614 NavigateToURL(shell(), url); 615 observer->WaitForFinished(); 616 std::vector<DownloadItem*> downloads; 617 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 618 EXPECT_EQ(1u, downloads.size()); 619 if (1u != downloads.size()) 620 return NULL; 621 return downloads[0]; 622 } 623 624 // Wait for data 625 void WaitForData(DownloadItem* download, int size) { 626 DownloadUpdatedObserver data_observer( 627 download, base::Bind(&DataReceivedFilter, size)); 628 data_observer.WaitForEvent(); 629 ASSERT_EQ(size, download->GetReceivedBytes()); 630 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState()); 631 } 632 633 // Tell the test server to release a pending RST and confirm 634 // that the interrupt is received properly (for download resumption 635 // testing). 636 void ReleaseRSTAndConfirmInterruptForResume(DownloadItem* download) { 637 scoped_ptr<DownloadTestObserver> rst_observer(CreateWaiter(shell(), 1)); 638 NavigateToURL(shell(), test_server()->GetURL("download-finish")); 639 rst_observer->WaitForFinished(); 640 EXPECT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 641 } 642 643 // Confirm file status expected for the given location in a stream 644 // provided by the resume test server. 645 void ConfirmFileStatusForResume( 646 DownloadItem* download, bool file_exists, 647 int received_bytes, int total_bytes, 648 const base::FilePath& expected_filename) { 649 // expected_filename is only known if the file exists. 650 ASSERT_EQ(file_exists, !expected_filename.empty()); 651 EXPECT_EQ(received_bytes, download->GetReceivedBytes()); 652 EXPECT_EQ(total_bytes, download->GetTotalBytes()); 653 EXPECT_EQ(expected_filename.value(), 654 download->GetFullPath().BaseName().value()); 655 EXPECT_EQ(file_exists, 656 (!download->GetFullPath().empty() && 657 file_util::PathExists(download->GetFullPath()))); 658 659 if (file_exists) { 660 std::string file_contents; 661 EXPECT_TRUE(file_util::ReadFileToString( 662 download->GetFullPath(), &file_contents)); 663 664 ASSERT_EQ(static_cast<size_t>(received_bytes), file_contents.size()); 665 for (int i = 0; i < received_bytes; ++i) { 666 EXPECT_EQ(static_cast<char>((i * 2 + 15) % 256), file_contents[i]) 667 << "File contents diverged at position " << i 668 << " for " << expected_filename.value(); 669 670 if (static_cast<char>((i * 2 + 15) % 256) != file_contents[i]) 671 return; 672 } 673 } 674 } 675 676 private: 677 static void EnsureNoPendingDownloadJobsOnIO(bool* result) { 678 if (URLRequestSlowDownloadJob::NumberOutstandingRequests()) 679 *result = false; 680 BrowserThread::PostTask( 681 BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure()); 682 } 683 684 // Location of the downloads directory for these tests 685 base::ScopedTempDir downloads_directory_; 686}; 687 688IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) { 689 SetupEnsureNoPendingDownloads(); 690 691 // Create a download, wait until it's started, and confirm 692 // we're in the expected state. 693 scoped_ptr<DownloadCreateObserver> observer( 694 CreateInProgressWaiter(shell(), 1)); 695 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); 696 observer->WaitForFinished(); 697 698 std::vector<DownloadItem*> downloads; 699 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 700 ASSERT_EQ(1u, downloads.size()); 701 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState()); 702 703 // Cancel the download and wait for download system quiesce. 704 downloads[0]->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD); 705 scoped_refptr<DownloadTestFlushObserver> flush_observer( 706 new DownloadTestFlushObserver(DownloadManagerForShell(shell()))); 707 flush_observer->WaitForFlush(); 708 709 // Get the important info from other threads and check it. 710 EXPECT_TRUE(EnsureNoPendingDownloads()); 711} 712 713// Check that downloading multiple (in this case, 2) files does not result in 714// corrupted files. 715IN_PROC_BROWSER_TEST_F(DownloadContentTest, MultiDownload) { 716 SetupEnsureNoPendingDownloads(); 717 718 // Create a download, wait until it's started, and confirm 719 // we're in the expected state. 720 scoped_ptr<DownloadCreateObserver> observer1( 721 CreateInProgressWaiter(shell(), 1)); 722 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); 723 observer1->WaitForFinished(); 724 725 std::vector<DownloadItem*> downloads; 726 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 727 ASSERT_EQ(1u, downloads.size()); 728 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->GetState()); 729 DownloadItem* download1 = downloads[0]; // The only download. 730 731 // Start the second download and wait until it's done. 732 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 733 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 734 // Download the file and wait. 735 DownloadAndWait(shell(), url, DownloadItem::COMPLETE); 736 737 // Should now have 2 items on the manager. 738 downloads.clear(); 739 DownloadManagerForShell(shell())->GetAllDownloads(&downloads); 740 ASSERT_EQ(2u, downloads.size()); 741 // We don't know the order of the downloads. 742 DownloadItem* download2 = downloads[(download1 == downloads[0]) ? 1 : 0]; 743 744 ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState()); 745 ASSERT_EQ(DownloadItem::COMPLETE, download2->GetState()); 746 747 // Allow the first request to finish. 748 scoped_ptr<DownloadTestObserver> observer2(CreateWaiter(shell(), 1)); 749 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kFinishDownloadUrl)); 750 observer2->WaitForFinished(); // Wait for the third request. 751 EXPECT_EQ(1u, observer2->NumDownloadsSeenInState(DownloadItem::COMPLETE)); 752 753 // Get the important info from other threads and check it. 754 EXPECT_TRUE(EnsureNoPendingDownloads()); 755 756 // The |DownloadItem|s should now be done and have the final file names. 757 // Verify that the files have the expected data and size. 758 // |file1| should be full of '*'s, and |file2| should be the same as the 759 // source file. 760 base::FilePath file1(download1->GetTargetFilePath()); 761 size_t file_size1 = URLRequestSlowDownloadJob::kFirstDownloadSize + 762 URLRequestSlowDownloadJob::kSecondDownloadSize; 763 std::string expected_contents(file_size1, '*'); 764 ASSERT_TRUE(VerifyFile(file1, expected_contents, file_size1)); 765 766 base::FilePath file2(download2->GetTargetFilePath()); 767 ASSERT_TRUE(file_util::ContentsEqual( 768 file2, GetTestFilePath("download", "download-test.lib"))); 769} 770 771// Try to cancel just before we release the download file, by delaying final 772// rename callback. 773IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtFinalRename) { 774 // Setup new factory. 775 DownloadFileWithDelayFactory* file_factory = 776 new DownloadFileWithDelayFactory(); 777 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); 778 download_manager->SetDownloadFileFactoryForTesting( 779 scoped_ptr<DownloadFileFactory>(file_factory).Pass()); 780 781 // Create a download 782 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 783 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); 784 785 // Wait until the first (intermediate file) rename and execute the callback. 786 file_factory->WaitForSomeCallback(); 787 std::vector<base::Closure> callbacks; 788 file_factory->GetAllRenameCallbacks(&callbacks); 789 ASSERT_EQ(1u, callbacks.size()); 790 callbacks[0].Run(); 791 callbacks.clear(); 792 793 // Wait until the second (final) rename callback is posted. 794 file_factory->WaitForSomeCallback(); 795 file_factory->GetAllRenameCallbacks(&callbacks); 796 ASSERT_EQ(1u, callbacks.size()); 797 798 // Cancel it. 799 std::vector<DownloadItem*> items; 800 download_manager->GetAllDownloads(&items); 801 ASSERT_EQ(1u, items.size()); 802 items[0]->Cancel(true); 803 RunAllPendingInMessageLoop(); 804 805 // Check state. 806 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); 807 808 // Run final rename callback. 809 callbacks[0].Run(); 810 callbacks.clear(); 811 812 // Check state. 813 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState()); 814} 815 816// Try to cancel just after we release the download file, by delaying 817// in ShouldOpenDownload. 818IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelAtRelease) { 819 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); 820 821 // Mark delegate for delayed open. 822 GetDownloadManagerDelegate(download_manager)->SetDelayedOpen(true); 823 824 // Setup new factory. 825 DownloadFileWithDelayFactory* file_factory = 826 new DownloadFileWithDelayFactory(); 827 download_manager->SetDownloadFileFactoryForTesting( 828 scoped_ptr<DownloadFileFactory>(file_factory).Pass()); 829 830 // Create a download 831 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 832 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); 833 834 // Wait until the first (intermediate file) rename and execute the callback. 835 file_factory->WaitForSomeCallback(); 836 std::vector<base::Closure> callbacks; 837 file_factory->GetAllRenameCallbacks(&callbacks); 838 ASSERT_EQ(1u, callbacks.size()); 839 callbacks[0].Run(); 840 callbacks.clear(); 841 842 // Wait until the second (final) rename callback is posted. 843 file_factory->WaitForSomeCallback(); 844 file_factory->GetAllRenameCallbacks(&callbacks); 845 ASSERT_EQ(1u, callbacks.size()); 846 847 // Call it. 848 callbacks[0].Run(); 849 callbacks.clear(); 850 851 // Confirm download still IN_PROGRESS (internal state COMPLETING). 852 std::vector<DownloadItem*> items; 853 download_manager->GetAllDownloads(&items); 854 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 855 856 // Cancel the download; confirm cancel fails. 857 ASSERT_EQ(1u, items.size()); 858 items[0]->Cancel(true); 859 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 860 861 // Need to complete open test. 862 std::vector<DownloadOpenDelayedCallback> delayed_callbacks; 863 GetDownloadManagerDelegate(download_manager)->GetDelayedCallbacks( 864 &delayed_callbacks); 865 ASSERT_EQ(1u, delayed_callbacks.size()); 866 delayed_callbacks[0].Run(true); 867 868 // *Now* the download should be complete. 869 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState()); 870} 871 872// Try to shutdown with a download in progress to make sure shutdown path 873// works properly. 874IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownInProgress) { 875 // Create a download that won't complete. 876 scoped_ptr<DownloadCreateObserver> observer( 877 CreateInProgressWaiter(shell(), 1)); 878 NavigateToURL(shell(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); 879 observer->WaitForFinished(); 880 881 // Get the item. 882 std::vector<DownloadItem*> items; 883 DownloadManagerForShell(shell())->GetAllDownloads(&items); 884 ASSERT_EQ(1u, items.size()); 885 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 886 887 // Shutdown the download manager and make sure we get the right 888 // notifications in the right order. 889 StrictMock<MockDownloadItemObserver> item_observer; 890 items[0]->AddObserver(&item_observer); 891 MockDownloadManagerObserver manager_observer( 892 DownloadManagerForShell(shell())); 893 // Don't care about ModelChanged() events. 894 EXPECT_CALL(manager_observer, ModelChanged(_)) 895 .WillRepeatedly(Return()); 896 { 897 InSequence notifications; 898 899 EXPECT_CALL(manager_observer, MockManagerGoingDown( 900 DownloadManagerForShell(shell()))) 901 .WillOnce(Return()); 902 EXPECT_CALL(item_observer, OnDownloadUpdated( 903 AllOf(items[0], 904 Property(&DownloadItem::GetState, DownloadItem::CANCELLED)))) 905 .WillOnce(Return()); 906 EXPECT_CALL(item_observer, OnDownloadDestroyed(items[0])) 907 .WillOnce(Return()); 908 } 909 DownloadManagerForShell(shell())->Shutdown(); 910 items.clear(); 911} 912 913// Try to shutdown just after we release the download file, by delaying 914// release. 915IN_PROC_BROWSER_TEST_F(DownloadContentTest, ShutdownAtRelease) { 916 DownloadManagerImpl* download_manager(DownloadManagerForShell(shell())); 917 918 // Mark delegate for delayed open. 919 GetDownloadManagerDelegate(download_manager)->SetDelayedOpen(true); 920 921 // Setup new factory. 922 DownloadFileWithDelayFactory* file_factory = 923 new DownloadFileWithDelayFactory(); 924 download_manager->SetDownloadFileFactoryForTesting( 925 scoped_ptr<DownloadFileFactory>(file_factory).Pass()); 926 927 // Create a download 928 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 929 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file)); 930 931 // Wait until the first (intermediate file) rename and execute the callback. 932 file_factory->WaitForSomeCallback(); 933 std::vector<base::Closure> callbacks; 934 file_factory->GetAllRenameCallbacks(&callbacks); 935 ASSERT_EQ(1u, callbacks.size()); 936 callbacks[0].Run(); 937 callbacks.clear(); 938 939 // Wait until the second (final) rename callback is posted. 940 file_factory->WaitForSomeCallback(); 941 file_factory->GetAllRenameCallbacks(&callbacks); 942 ASSERT_EQ(1u, callbacks.size()); 943 944 // Call it. 945 callbacks[0].Run(); 946 callbacks.clear(); 947 948 // Confirm download isn't complete yet. 949 std::vector<DownloadItem*> items; 950 DownloadManagerForShell(shell())->GetAllDownloads(&items); 951 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 952 953 // Cancel the download; confirm cancel fails anyway. 954 ASSERT_EQ(1u, items.size()); 955 items[0]->Cancel(true); 956 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 957 RunAllPendingInMessageLoop(); 958 EXPECT_EQ(DownloadItem::IN_PROGRESS, items[0]->GetState()); 959 960 MockDownloadItemObserver observer; 961 items[0]->AddObserver(&observer); 962 EXPECT_CALL(observer, OnDownloadDestroyed(items[0])); 963 964 // Shutdown the download manager. Mostly this is confirming a lack of 965 // crashes. 966 DownloadManagerForShell(shell())->Shutdown(); 967} 968 969IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) { 970 CommandLine::ForCurrentProcess()->AppendSwitch( 971 switches::kEnableDownloadResumption); 972 ASSERT_TRUE(test_server()->Start()); 973 974 GURL url = test_server()->GetURL( 975 base::StringPrintf("rangereset?size=%d&rst_boundary=%d", 976 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 977 978 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell())); 979 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1); 980 981 DownloadItem* download(StartDownloadAndReturnItem(url)); 982 WaitForData(download, GetSafeBufferChunk()); 983 ::testing::Mock::VerifyAndClearExpectations(&dm_observer); 984 985 // Confirm resumption while in progress doesn't do anything. 986 download->Resume(); 987 ASSERT_EQ(GetSafeBufferChunk(), download->GetReceivedBytes()); 988 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState()); 989 990 // Tell the server to send the RST and confirm the interrupt happens. 991 ReleaseRSTAndConfirmInterruptForResume(download); 992 ConfirmFileStatusForResume( 993 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 994 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 995 996 // Resume, confirming received bytes on resumption is correct. 997 // Make sure no creation calls are included. 998 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(0); 999 int initial_size = 0; 1000 DownloadUpdatedObserver initial_size_observer( 1001 download, base::Bind(&InitialSizeFilter, &initial_size)); 1002 download->Resume(); 1003 initial_size_observer.WaitForEvent(); 1004 EXPECT_EQ(GetSafeBufferChunk(), initial_size); 1005 ::testing::Mock::VerifyAndClearExpectations(&dm_observer); 1006 1007 // and wait for expected data. 1008 WaitForData(download, GetSafeBufferChunk() * 2); 1009 1010 // Tell the server to send the RST and confirm the interrupt happens. 1011 ReleaseRSTAndConfirmInterruptForResume(download); 1012 ConfirmFileStatusForResume( 1013 download, true, GetSafeBufferChunk() * 2, GetSafeBufferChunk() * 3, 1014 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1015 1016 // Resume and wait for completion. 1017 DownloadUpdatedObserver completion_observer( 1018 download, base::Bind(DownloadCompleteFilter)); 1019 download->Resume(); 1020 completion_observer.WaitForEvent(); 1021 1022 ConfirmFileStatusForResume( 1023 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1024 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1025 1026 // Confirm resumption while complete doesn't do anything. 1027 download->Resume(); 1028 ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes()); 1029 ASSERT_EQ(DownloadItem::COMPLETE, download->GetState()); 1030 RunAllPendingInMessageLoop(); 1031 ASSERT_EQ(GetSafeBufferChunk() * 3, download->GetReceivedBytes()); 1032 ASSERT_EQ(DownloadItem::COMPLETE, download->GetState()); 1033} 1034 1035// Confirm restart fallback happens if a range request is bounced. 1036IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownloadNoRange) { 1037 CommandLine::ForCurrentProcess()->AppendSwitch( 1038 switches::kEnableDownloadResumption); 1039 ASSERT_TRUE(test_server()->Start()); 1040 1041 // Auto-restart if server doesn't handle ranges. 1042 GURL url = test_server()->GetURL( 1043 base::StringPrintf( 1044 // First download hits an RST, rest don't, no ranges. 1045 "rangereset?size=%d&rst_boundary=%d&" 1046 "token=NoRange&rst_limit=1&bounce_range", 1047 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1048 1049 // Start the download and wait for first data chunk. 1050 DownloadItem* download(StartDownloadAndReturnItem(url)); 1051 WaitForData(download, GetSafeBufferChunk()); 1052 1053 RecordingDownloadObserver recorder(download); 1054 1055 ReleaseRSTAndConfirmInterruptForResume(download); 1056 ConfirmFileStatusForResume( 1057 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1058 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1059 1060 DownloadUpdatedObserver completion_observer( 1061 download, base::Bind(DownloadCompleteFilter)); 1062 download->Resume(); 1063 completion_observer.WaitForEvent(); 1064 1065 ConfirmFileStatusForResume( 1066 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1067 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1068 1069 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1070 // Result of RST 1071 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1072 // Starting continuation 1073 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()}, 1074 // Notification of receiving whole file. 1075 {DownloadItem::IN_PROGRESS, 0}, 1076 // Completion. 1077 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1078 }; 1079 1080 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1081} 1082 1083// Confirm restart fallback happens if a precondition is failed. 1084IN_PROC_BROWSER_TEST_F(DownloadContentTest, 1085 ResumeInterruptedDownloadBadPrecondition) { 1086 CommandLine::ForCurrentProcess()->AppendSwitch( 1087 switches::kEnableDownloadResumption); 1088 ASSERT_TRUE(test_server()->Start()); 1089 1090 GURL url = test_server()->GetURL( 1091 base::StringPrintf( 1092 // First download hits an RST, rest don't, precondition fail. 1093 "rangereset?size=%d&rst_boundary=%d&" 1094 "token=NoRange&rst_limit=1&fail_precondition=2", 1095 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1096 1097 // Start the download and wait for first data chunk. 1098 DownloadItem* download(StartDownloadAndReturnItem(url)); 1099 WaitForData(download, GetSafeBufferChunk()); 1100 1101 RecordingDownloadObserver recorder(download); 1102 1103 ReleaseRSTAndConfirmInterruptForResume(download); 1104 ConfirmFileStatusForResume( 1105 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1106 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1107 1108 DownloadUpdatedObserver completion_observer( 1109 download, base::Bind(DownloadCompleteFilter)); 1110 download->Resume(); 1111 completion_observer.WaitForEvent(); 1112 1113 ConfirmFileStatusForResume( 1114 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1115 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1116 1117 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1118 // Result of RST 1119 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1120 // Starting continuation 1121 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()}, 1122 // Server precondition fail. 1123 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1124 // Notification of successful restart. 1125 {DownloadItem::IN_PROGRESS, 0}, 1126 // Completion. 1127 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1128 }; 1129 1130 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1131} 1132 1133// Confirm we don't try to resume if we don't have a verifier. 1134IN_PROC_BROWSER_TEST_F(DownloadContentTest, 1135 ResumeInterruptedDownloadNoVerifiers) { 1136 CommandLine::ForCurrentProcess()->AppendSwitch( 1137 switches::kEnableDownloadResumption); 1138 ASSERT_TRUE(test_server()->Start()); 1139 1140 GURL url = test_server()->GetURL( 1141 base::StringPrintf( 1142 // First download hits an RST, rest don't, no verifiers. 1143 "rangereset?size=%d&rst_boundary=%d&" 1144 "token=NoRange&rst_limit=1&no_verifiers", 1145 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1146 1147 // Start the download and wait for first data chunk. 1148 DownloadItem* download(StartDownloadAndReturnItem(url)); 1149 WaitForData(download, GetSafeBufferChunk()); 1150 1151 RecordingDownloadObserver recorder(download); 1152 1153 ReleaseRSTAndConfirmInterruptForResume(download); 1154 ConfirmFileStatusForResume( 1155 download, false, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1156 base::FilePath()); 1157 1158 DownloadUpdatedObserver completion_observer( 1159 download, base::Bind(DownloadCompleteFilter)); 1160 download->Resume(); 1161 completion_observer.WaitForEvent(); 1162 1163 ConfirmFileStatusForResume( 1164 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1165 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1166 1167 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1168 // Result of RST 1169 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1170 // Restart for lack of verifiers 1171 {DownloadItem::IN_PROGRESS, 0}, 1172 // Completion. 1173 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1174 }; 1175 1176 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1177} 1178 1179IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) { 1180 CommandLine::ForCurrentProcess()->AppendSwitch( 1181 switches::kEnableDownloadResumption); 1182 ASSERT_TRUE(test_server()->Start()); 1183 1184 GURL url = test_server()->GetURL( 1185 base::StringPrintf( 1186 // First download hits an RST, rest don't 1187 "rangereset?size=%d&rst_boundary=%d&" 1188 "token=NoRange&rst_limit=1", 1189 GetSafeBufferChunk() * 3, GetSafeBufferChunk())); 1190 1191 // Start the download and wait for first data chunk. 1192 DownloadItem* download(StartDownloadAndReturnItem(url)); 1193 WaitForData(download, GetSafeBufferChunk()); 1194 1195 RecordingDownloadObserver recorder(download); 1196 1197 ReleaseRSTAndConfirmInterruptForResume(download); 1198 ConfirmFileStatusForResume( 1199 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3, 1200 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload"))); 1201 1202 // Delete the intermediate file. 1203 file_util::Delete(download->GetFullPath(), false); 1204 1205 DownloadUpdatedObserver completion_observer( 1206 download, base::Bind(DownloadCompleteFilter)); 1207 download->Resume(); 1208 completion_observer.WaitForEvent(); 1209 1210 ConfirmFileStatusForResume( 1211 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3, 1212 base::FilePath(FILE_PATH_LITERAL("rangereset"))); 1213 1214 static const RecordingDownloadObserver::RecordStruct expected_record[] = { 1215 // Result of RST 1216 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1217 // Starting continuation 1218 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()}, 1219 // Error because file isn't there. 1220 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()}, 1221 // Restart 1222 {DownloadItem::IN_PROGRESS, 0}, 1223 // Completion. 1224 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3}, 1225 }; 1226 1227 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record)); 1228} 1229 1230IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) { 1231 CommandLine::ForCurrentProcess()->AppendSwitch( 1232 switches::kEnableDownloadResumption); 1233 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 1234 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1235 1236 // Setup the error injector. 1237 scoped_refptr<TestFileErrorInjector> injector( 1238 TestFileErrorInjector::Create(DownloadManagerForShell(shell()))); 1239 1240 TestFileErrorInjector::FileErrorInfo err = { 1241 url.spec(), 1242 TestFileErrorInjector::FILE_OPERATION_INITIALIZE, 1243 0, 1244 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE 1245 }; 1246 injector->AddError(err); 1247 injector->InjectErrors(); 1248 1249 // Start and watch for interrupt. 1250 scoped_ptr<DownloadTestObserver> int_observer(CreateWaiter(shell(), 1)); 1251 DownloadItem* download(StartDownloadAndReturnItem(url)); 1252 int_observer->WaitForFinished(); 1253 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 1254 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, 1255 download->GetLastReason()); 1256 EXPECT_EQ(0, download->GetReceivedBytes()); 1257 EXPECT_TRUE(download->GetFullPath().empty()); 1258 EXPECT_TRUE(download->GetTargetFilePath().empty()); 1259 1260 // We need to make sure that any cross-thread downloads communication has 1261 // quiesced before clearing and injecting the new errors, as the 1262 // InjectErrors() routine alters the currently in use download file 1263 // factory, which is a file thread object. 1264 RunAllPendingInMessageLoop(BrowserThread::FILE); 1265 RunAllPendingInMessageLoop(); 1266 1267 // Clear the old errors list. 1268 injector->ClearErrors(); 1269 injector->InjectErrors(); 1270 1271 // Resume and watch completion. 1272 DownloadUpdatedObserver completion_observer( 1273 download, base::Bind(DownloadCompleteFilter)); 1274 download->Resume(); 1275 completion_observer.WaitForEvent(); 1276 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE); 1277} 1278 1279IN_PROC_BROWSER_TEST_F(DownloadContentTest, 1280 ResumeWithFileIntermediateRenameError) { 1281 CommandLine::ForCurrentProcess()->AppendSwitch( 1282 switches::kEnableDownloadResumption); 1283 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 1284 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1285 1286 // Setup the error injector. 1287 scoped_refptr<TestFileErrorInjector> injector( 1288 TestFileErrorInjector::Create(DownloadManagerForShell(shell()))); 1289 1290 TestFileErrorInjector::FileErrorInfo err = { 1291 url.spec(), 1292 TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY, 1293 0, 1294 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE 1295 }; 1296 injector->AddError(err); 1297 injector->InjectErrors(); 1298 1299 // Start and watch for interrupt. 1300 scoped_ptr<DownloadTestObserver> int_observer(CreateWaiter(shell(), 1)); 1301 DownloadItem* download(StartDownloadAndReturnItem(url)); 1302 int_observer->WaitForFinished(); 1303 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 1304 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, 1305 download->GetLastReason()); 1306 EXPECT_TRUE(download->GetFullPath().empty()); 1307 // Target path will have been set after file name determination. GetFullPath() 1308 // being empty is sufficient to signal that filename determination needs to be 1309 // redone. 1310 EXPECT_FALSE(download->GetTargetFilePath().empty()); 1311 1312 // We need to make sure that any cross-thread downloads communication has 1313 // quiesced before clearing and injecting the new errors, as the 1314 // InjectErrors() routine alters the currently in use download file 1315 // factory, which is a file thread object. 1316 RunAllPendingInMessageLoop(BrowserThread::FILE); 1317 RunAllPendingInMessageLoop(); 1318 1319 // Clear the old errors list. 1320 injector->ClearErrors(); 1321 injector->InjectErrors(); 1322 1323 // Resume and watch completion. 1324 DownloadUpdatedObserver completion_observer( 1325 download, base::Bind(DownloadCompleteFilter)); 1326 download->Resume(); 1327 completion_observer.WaitForEvent(); 1328 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE); 1329} 1330 1331IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) { 1332 CommandLine::ForCurrentProcess()->AppendSwitch( 1333 switches::kEnableDownloadResumption); 1334 base::FilePath file(FILE_PATH_LITERAL("download-test.lib")); 1335 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1336 1337 // Setup the error injector. 1338 scoped_refptr<TestFileErrorInjector> injector( 1339 TestFileErrorInjector::Create(DownloadManagerForShell(shell()))); 1340 1341 DownloadManagerForShell(shell())->RemoveAllDownloads(); 1342 TestFileErrorInjector::FileErrorInfo err = { 1343 url.spec(), 1344 TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE, 1345 0, 1346 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE 1347 }; 1348 injector->AddError(err); 1349 injector->InjectErrors(); 1350 1351 // Start and watch for interrupt. 1352 scoped_ptr<DownloadTestObserver> int_observer(CreateWaiter(shell(), 1)); 1353 DownloadItem* download(StartDownloadAndReturnItem(url)); 1354 int_observer->WaitForFinished(); 1355 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState()); 1356 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE, 1357 download->GetLastReason()); 1358 EXPECT_TRUE(download->GetFullPath().empty()); 1359 // Target path should still be intact. 1360 EXPECT_FALSE(download->GetTargetFilePath().empty()); 1361 1362 // We need to make sure that any cross-thread downloads communication has 1363 // quiesced before clearing and injecting the new errors, as the 1364 // InjectErrors() routine alters the currently in use download file 1365 // factory, which is a file thread object. 1366 RunAllPendingInMessageLoop(BrowserThread::FILE); 1367 RunAllPendingInMessageLoop(); 1368 1369 // Clear the old errors list. 1370 injector->ClearErrors(); 1371 injector->InjectErrors(); 1372 1373 // Resume and watch completion. 1374 DownloadUpdatedObserver completion_observer( 1375 download, base::Bind(DownloadCompleteFilter)); 1376 download->Resume(); 1377 completion_observer.WaitForEvent(); 1378 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE); 1379} 1380 1381} // namespace content 1382