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