[Download] Return DownloadInterruptReason from OnStartedCallback
[chromium-blink-merge.git] / content / browser / download / download_browsertest.cc
blobd2f2f2f2049584f6389fb8460c5976ba38e28250
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.
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.
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/browser_test_utils.h"
26 #include "content/public/test/download_test_observer.h"
27 #include "content/public/test/test_file_error_injector.h"
28 #include "content/public/test/test_utils.h"
29 #include "content/shell/browser/shell.h"
30 #include "content/shell/browser/shell_browser_context.h"
31 #include "content/shell/browser/shell_download_manager_delegate.h"
32 #include "content/shell/browser/shell_network_delegate.h"
33 #include "content/test/content_browser_test.h"
34 #include "content/test/content_browser_test_utils.h"
35 #include "content/test/net/url_request_mock_http_job.h"
36 #include "content/test/net/url_request_slow_download_job.h"
37 #include "net/test/spawned_test_server/spawned_test_server.h"
38 #include "testing/gmock/include/gmock/gmock.h"
39 #include "testing/gtest/include/gtest/gtest.h"
40 #include "url/gurl.h"
42 using ::testing::_;
43 using ::testing::AllOf;
44 using ::testing::Field;
45 using ::testing::InSequence;
46 using ::testing::Property;
47 using ::testing::Return;
48 using ::testing::StrictMock;
50 namespace content {
52 namespace {
54 class MockDownloadItemObserver : public DownloadItem::Observer {
55 public:
56 MockDownloadItemObserver() {}
57 virtual ~MockDownloadItemObserver() {}
59 MOCK_METHOD1(OnDownloadUpdated, void(DownloadItem*));
60 MOCK_METHOD1(OnDownloadOpened, void(DownloadItem*));
61 MOCK_METHOD1(OnDownloadRemoved, void(DownloadItem*));
62 MOCK_METHOD1(OnDownloadDestroyed, void(DownloadItem*));
65 class MockDownloadManagerObserver : public DownloadManager::Observer {
66 public:
67 MockDownloadManagerObserver(DownloadManager* manager) {
68 manager_ = manager;
69 manager->AddObserver(this);
71 virtual ~MockDownloadManagerObserver() {
72 if (manager_)
73 manager_->RemoveObserver(this);
76 MOCK_METHOD2(OnDownloadCreated, void(DownloadManager*, DownloadItem*));
77 MOCK_METHOD1(ModelChanged, void(DownloadManager*));
78 void ManagerGoingDown(DownloadManager* manager) {
79 DCHECK_EQ(manager_, manager);
80 MockManagerGoingDown(manager);
82 manager_->RemoveObserver(this);
83 manager_ = NULL;
86 MOCK_METHOD1(MockManagerGoingDown, void(DownloadManager*));
87 private:
88 DownloadManager* manager_;
91 class DownloadFileWithDelayFactory;
93 static DownloadManagerImpl* DownloadManagerForShell(Shell* shell) {
94 // We're in a content_browsertest; we know that the DownloadManager
95 // is a DownloadManagerImpl.
96 return static_cast<DownloadManagerImpl*>(
97 BrowserContext::GetDownloadManager(
98 shell->web_contents()->GetBrowserContext()));
101 class DownloadFileWithDelay : public DownloadFileImpl {
102 public:
103 DownloadFileWithDelay(
104 scoped_ptr<DownloadSaveInfo> save_info,
105 const base::FilePath& default_download_directory,
106 const GURL& url,
107 const GURL& referrer_url,
108 bool calculate_hash,
109 scoped_ptr<ByteStreamReader> stream,
110 const net::BoundNetLog& bound_net_log,
111 scoped_ptr<PowerSaveBlocker> power_save_blocker,
112 base::WeakPtr<DownloadDestinationObserver> observer,
113 base::WeakPtr<DownloadFileWithDelayFactory> owner);
115 virtual ~DownloadFileWithDelay();
117 // Wraps DownloadFileImpl::Rename* and intercepts the return callback,
118 // storing it in the factory that produced this object for later
119 // retrieval.
120 virtual void RenameAndUniquify(
121 const base::FilePath& full_path,
122 const RenameCompletionCallback& callback) OVERRIDE;
123 virtual void RenameAndAnnotate(
124 const base::FilePath& full_path,
125 const RenameCompletionCallback& callback) OVERRIDE;
127 private:
128 static void RenameCallbackWrapper(
129 const base::WeakPtr<DownloadFileWithDelayFactory>& factory,
130 const RenameCompletionCallback& original_callback,
131 DownloadInterruptReason reason,
132 const base::FilePath& path);
134 // This variable may only be read on the FILE thread, and may only be
135 // indirected through (e.g. methods on DownloadFileWithDelayFactory called)
136 // on the UI thread. This is because after construction,
137 // DownloadFileWithDelay lives on the file thread, but
138 // DownloadFileWithDelayFactory is purely a UI thread object.
139 base::WeakPtr<DownloadFileWithDelayFactory> owner_;
141 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelay);
144 // All routines on this class must be called on the UI thread.
145 class DownloadFileWithDelayFactory : public DownloadFileFactory {
146 public:
147 DownloadFileWithDelayFactory();
148 virtual ~DownloadFileWithDelayFactory();
150 // DownloadFileFactory interface.
151 virtual DownloadFile* CreateFile(
152 scoped_ptr<DownloadSaveInfo> save_info,
153 const base::FilePath& default_download_directory,
154 const GURL& url,
155 const GURL& referrer_url,
156 bool calculate_hash,
157 scoped_ptr<ByteStreamReader> stream,
158 const net::BoundNetLog& bound_net_log,
159 base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE;
161 void AddRenameCallback(base::Closure callback);
162 void GetAllRenameCallbacks(std::vector<base::Closure>* results);
164 // Do not return until GetAllRenameCallbacks() will return a non-empty list.
165 void WaitForSomeCallback();
167 private:
168 base::WeakPtrFactory<DownloadFileWithDelayFactory> weak_ptr_factory_;
169 std::vector<base::Closure> rename_callbacks_;
170 bool waiting_;
172 DISALLOW_COPY_AND_ASSIGN(DownloadFileWithDelayFactory);
175 DownloadFileWithDelay::DownloadFileWithDelay(
176 scoped_ptr<DownloadSaveInfo> save_info,
177 const base::FilePath& default_download_directory,
178 const GURL& url,
179 const GURL& referrer_url,
180 bool calculate_hash,
181 scoped_ptr<ByteStreamReader> stream,
182 const net::BoundNetLog& bound_net_log,
183 scoped_ptr<PowerSaveBlocker> power_save_blocker,
184 base::WeakPtr<DownloadDestinationObserver> observer,
185 base::WeakPtr<DownloadFileWithDelayFactory> owner)
186 : DownloadFileImpl(
187 save_info.Pass(), default_download_directory, url, referrer_url,
188 calculate_hash, stream.Pass(), bound_net_log,
189 power_save_blocker.Pass(), observer),
190 owner_(owner) {}
192 DownloadFileWithDelay::~DownloadFileWithDelay() {}
194 void DownloadFileWithDelay::RenameAndUniquify(
195 const base::FilePath& full_path,
196 const RenameCompletionCallback& callback) {
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
198 DownloadFileImpl::RenameAndUniquify(
199 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
200 owner_, callback));
203 void DownloadFileWithDelay::RenameAndAnnotate(
204 const base::FilePath& full_path, const RenameCompletionCallback& callback) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
206 DownloadFileImpl::RenameAndAnnotate(
207 full_path, base::Bind(DownloadFileWithDelay::RenameCallbackWrapper,
208 owner_, callback));
211 // static
212 void DownloadFileWithDelay::RenameCallbackWrapper(
213 const base::WeakPtr<DownloadFileWithDelayFactory>& factory,
214 const RenameCompletionCallback& original_callback,
215 DownloadInterruptReason reason,
216 const base::FilePath& path) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
218 if (!factory)
219 return;
220 factory->AddRenameCallback(base::Bind(original_callback, reason, path));
223 DownloadFileWithDelayFactory::DownloadFileWithDelayFactory()
224 : weak_ptr_factory_(this),
225 waiting_(false) {}
226 DownloadFileWithDelayFactory::~DownloadFileWithDelayFactory() {}
228 DownloadFile* DownloadFileWithDelayFactory::CreateFile(
229 scoped_ptr<DownloadSaveInfo> save_info,
230 const base::FilePath& default_download_directory,
231 const GURL& url,
232 const GURL& referrer_url,
233 bool calculate_hash,
234 scoped_ptr<ByteStreamReader> stream,
235 const net::BoundNetLog& bound_net_log,
236 base::WeakPtr<DownloadDestinationObserver> observer) {
237 scoped_ptr<PowerSaveBlocker> psb(
238 PowerSaveBlocker::Create(
239 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
240 "Download in progress"));
241 return new DownloadFileWithDelay(
242 save_info.Pass(), default_download_directory, url, referrer_url,
243 calculate_hash, stream.Pass(), bound_net_log,
244 psb.Pass(), observer, weak_ptr_factory_.GetWeakPtr());
247 void DownloadFileWithDelayFactory::AddRenameCallback(base::Closure callback) {
248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
249 rename_callbacks_.push_back(callback);
250 if (waiting_)
251 base::MessageLoopForUI::current()->Quit();
254 void DownloadFileWithDelayFactory::GetAllRenameCallbacks(
255 std::vector<base::Closure>* results) {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257 results->swap(rename_callbacks_);
260 void DownloadFileWithDelayFactory::WaitForSomeCallback() {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
263 if (rename_callbacks_.empty()) {
264 waiting_ = true;
265 RunMessageLoop();
266 waiting_ = false;
270 class CountingDownloadFile : public DownloadFileImpl {
271 public:
272 CountingDownloadFile(
273 scoped_ptr<DownloadSaveInfo> save_info,
274 const base::FilePath& default_downloads_directory,
275 const GURL& url,
276 const GURL& referrer_url,
277 bool calculate_hash,
278 scoped_ptr<ByteStreamReader> stream,
279 const net::BoundNetLog& bound_net_log,
280 scoped_ptr<PowerSaveBlocker> power_save_blocker,
281 base::WeakPtr<DownloadDestinationObserver> observer)
282 : DownloadFileImpl(save_info.Pass(), default_downloads_directory,
283 url, referrer_url, calculate_hash,
284 stream.Pass(), bound_net_log,
285 power_save_blocker.Pass(), observer) {}
287 virtual ~CountingDownloadFile() {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
289 active_files_--;
292 virtual void Initialize(const InitializeCallback& callback) OVERRIDE {
293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
294 active_files_++;
295 return DownloadFileImpl::Initialize(callback);
298 static void GetNumberActiveFiles(int* result) {
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
300 *result = active_files_;
303 // Can be called on any thread, and will block (running message loop)
304 // until data is returned.
305 static int GetNumberActiveFilesFromFileThread() {
306 int result = -1;
307 BrowserThread::PostTaskAndReply(
308 BrowserThread::FILE,
309 FROM_HERE,
310 base::Bind(&CountingDownloadFile::GetNumberActiveFiles, &result),
311 base::MessageLoop::current()->QuitClosure());
312 base::MessageLoop::current()->Run();
313 DCHECK_NE(-1, result);
314 return result;
317 private:
318 static int active_files_;
321 int CountingDownloadFile::active_files_ = 0;
323 class CountingDownloadFileFactory : public DownloadFileFactory {
324 public:
325 CountingDownloadFileFactory() {}
326 virtual ~CountingDownloadFileFactory() {}
328 // DownloadFileFactory interface.
329 virtual DownloadFile* CreateFile(
330 scoped_ptr<DownloadSaveInfo> save_info,
331 const base::FilePath& default_downloads_directory,
332 const GURL& url,
333 const GURL& referrer_url,
334 bool calculate_hash,
335 scoped_ptr<ByteStreamReader> stream,
336 const net::BoundNetLog& bound_net_log,
337 base::WeakPtr<DownloadDestinationObserver> observer) OVERRIDE {
338 scoped_ptr<PowerSaveBlocker> psb(
339 PowerSaveBlocker::Create(
340 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
341 "Download in progress"));
342 return new CountingDownloadFile(
343 save_info.Pass(), default_downloads_directory, url, referrer_url,
344 calculate_hash, stream.Pass(), bound_net_log,
345 psb.Pass(), observer);
349 class TestShellDownloadManagerDelegate : public ShellDownloadManagerDelegate {
350 public:
351 TestShellDownloadManagerDelegate()
352 : delay_download_open_(false) {}
353 virtual ~TestShellDownloadManagerDelegate() {}
355 virtual bool ShouldOpenDownload(
356 DownloadItem* item,
357 const DownloadOpenDelayedCallback& callback) OVERRIDE {
358 if (delay_download_open_) {
359 delayed_callbacks_.push_back(callback);
360 return false;
362 return true;
365 void SetDelayedOpen(bool delay) {
366 delay_download_open_ = delay;
369 void GetDelayedCallbacks(
370 std::vector<DownloadOpenDelayedCallback>* callbacks) {
371 callbacks->swap(delayed_callbacks_);
373 private:
374 bool delay_download_open_;
375 std::vector<DownloadOpenDelayedCallback> delayed_callbacks_;
378 // Record all state transitions and byte counts on the observed download.
379 class RecordingDownloadObserver : DownloadItem::Observer {
380 public:
381 struct RecordStruct {
382 DownloadItem::DownloadState state;
383 int bytes_received;
386 typedef std::vector<RecordStruct> RecordVector;
388 RecordingDownloadObserver(DownloadItem* download)
389 : download_(download) {
390 last_state_.state = download->GetState();
391 last_state_.bytes_received = download->GetReceivedBytes();
392 download_->AddObserver(this);
395 virtual ~RecordingDownloadObserver() {
396 RemoveObserver();
399 void CompareToExpectedRecord(const RecordStruct expected[], size_t size) {
400 EXPECT_EQ(size, record_.size());
401 int min = size > record_.size() ? record_.size() : size;
402 for (int i = 0; i < min; ++i) {
403 EXPECT_EQ(expected[i].state, record_[i].state) << "Iteration " << i;
404 EXPECT_EQ(expected[i].bytes_received, record_[i].bytes_received)
405 << "Iteration " << i;
409 private:
410 virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE {
411 DCHECK_EQ(download_, download);
412 DownloadItem::DownloadState state = download->GetState();
413 int bytes = download->GetReceivedBytes();
414 if (last_state_.state != state || last_state_.bytes_received > bytes) {
415 last_state_.state = state;
416 last_state_.bytes_received = bytes;
417 record_.push_back(last_state_);
421 virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE {
422 DCHECK_EQ(download_, download);
423 RemoveObserver();
426 void RemoveObserver() {
427 if (download_) {
428 download_->RemoveObserver(this);
429 download_ = NULL;
433 DownloadItem* download_;
434 RecordStruct last_state_;
435 RecordVector record_;
438 // Get the next created download.
439 class DownloadCreateObserver : DownloadManager::Observer {
440 public:
441 DownloadCreateObserver(DownloadManager* manager)
442 : manager_(manager),
443 item_(NULL),
444 waiting_(false) {
445 manager_->AddObserver(this);
448 virtual ~DownloadCreateObserver() {
449 if (manager_)
450 manager_->RemoveObserver(this);
451 manager_ = NULL;
454 virtual void ManagerGoingDown(DownloadManager* manager) OVERRIDE {
455 DCHECK_EQ(manager_, manager);
456 manager_->RemoveObserver(this);
457 manager_ = NULL;
460 virtual void OnDownloadCreated(DownloadManager* manager,
461 DownloadItem* download) OVERRIDE {
462 if (!item_)
463 item_ = download;
465 if (waiting_)
466 base::MessageLoopForUI::current()->Quit();
469 DownloadItem* WaitForFinished() {
470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
471 if (!item_) {
472 waiting_ = true;
473 RunMessageLoop();
474 waiting_ = false;
476 return item_;
479 private:
480 DownloadManager* manager_;
481 DownloadItem* item_;
482 bool waiting_;
486 // Filter for waiting for a certain number of bytes.
487 bool DataReceivedFilter(int number_of_bytes, DownloadItem* download) {
488 return download->GetReceivedBytes() >= number_of_bytes;
491 // Filter for download completion.
492 bool DownloadCompleteFilter(DownloadItem* download) {
493 return download->GetState() == DownloadItem::COMPLETE;
496 // Filter for saving the size of the download when the first IN_PROGRESS
497 // is hit.
498 bool InitialSizeFilter(int* download_size, DownloadItem* download) {
499 if (download->GetState() != DownloadItem::IN_PROGRESS)
500 return false;
502 *download_size = download->GetReceivedBytes();
503 return true;
506 } // namespace
508 class DownloadContentTest : public ContentBrowserTest {
509 protected:
510 // An initial send from a website of at least this size will not be
511 // help up by buffering in the underlying downloads ByteStream data
512 // transfer. This is important because on resumption tests we wait
513 // until we've gotten the data we expect before allowing the test server
514 // to send its reset, to get around hard close semantics on the Windows
515 // socket layer implementation.
516 int GetSafeBufferChunk() const {
517 return (DownloadResourceHandler::kDownloadByteStreamSize /
518 ByteStreamWriter::kFractionBufferBeforeSending) + 1;
521 virtual void SetUpOnMainThread() OVERRIDE {
522 ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
524 test_delegate_.reset(new TestShellDownloadManagerDelegate());
525 test_delegate_->SetDownloadBehaviorForTesting(downloads_directory_.path());
526 DownloadManager* manager = DownloadManagerForShell(shell());
527 manager->GetDelegate()->Shutdown();
528 manager->SetDelegate(test_delegate_.get());
529 test_delegate_->SetDownloadManager(manager);
531 BrowserThread::PostTask(
532 BrowserThread::IO, FROM_HERE,
533 base::Bind(&URLRequestSlowDownloadJob::AddUrlHandler));
534 base::FilePath mock_base(GetTestFilePath("download", ""));
535 BrowserThread::PostTask(
536 BrowserThread::IO, FROM_HERE,
537 base::Bind(&URLRequestMockHTTPJob::AddUrlHandler, mock_base));
540 TestShellDownloadManagerDelegate* GetDownloadManagerDelegate() {
541 return test_delegate_.get();
544 // Create a DownloadTestObserverTerminal that will wait for the
545 // specified number of downloads to finish.
546 DownloadTestObserver* CreateWaiter(
547 Shell* shell, int num_downloads) {
548 DownloadManager* download_manager = DownloadManagerForShell(shell);
549 return new DownloadTestObserverTerminal(download_manager, num_downloads,
550 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
553 // Create a DownloadTestObserverInProgress that will wait for the
554 // specified number of downloads to start.
555 DownloadCreateObserver* CreateInProgressWaiter(
556 Shell* shell, int num_downloads) {
557 DownloadManager* download_manager = DownloadManagerForShell(shell);
558 return new DownloadCreateObserver(download_manager);
561 DownloadTestObserver* CreateInterruptedWaiter(
562 Shell* shell, int num_downloads) {
563 DownloadManager* download_manager = DownloadManagerForShell(shell);
564 return new DownloadTestObserverInterrupted(download_manager, num_downloads,
565 DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
568 // Note: Cannot be used with other alternative DownloadFileFactorys
569 void SetupEnsureNoPendingDownloads() {
570 DownloadManagerForShell(shell())->SetDownloadFileFactoryForTesting(
571 scoped_ptr<DownloadFileFactory>(
572 new CountingDownloadFileFactory()).Pass());
575 bool EnsureNoPendingDownloads() {
576 bool result = true;
577 BrowserThread::PostTask(
578 BrowserThread::IO, FROM_HERE,
579 base::Bind(&EnsureNoPendingDownloadJobsOnIO, &result));
580 base::MessageLoop::current()->Run();
581 return result &&
582 (CountingDownloadFile::GetNumberActiveFilesFromFileThread() == 0);
585 void DownloadAndWait(Shell* shell, const GURL& url,
586 DownloadItem::DownloadState expected_terminal_state) {
587 scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell, 1));
588 NavigateToURL(shell, url);
589 observer->WaitForFinished();
590 EXPECT_EQ(1u, observer->NumDownloadsSeenInState(expected_terminal_state));
593 // Checks that |path| is has |file_size| bytes, and matches the |value|
594 // string.
595 bool VerifyFile(const base::FilePath& path,
596 const std::string& value,
597 const int64 file_size) {
598 std::string file_contents;
600 bool read = base::ReadFileToString(path, &file_contents);
601 EXPECT_TRUE(read) << "Failed reading file: " << path.value() << std::endl;
602 if (!read)
603 return false; // Couldn't read the file.
605 // Note: we don't handle really large files (more than size_t can hold)
606 // so we will fail in that case.
607 size_t expected_size = static_cast<size_t>(file_size);
609 // Check the size.
610 EXPECT_EQ(expected_size, file_contents.size());
611 if (expected_size != file_contents.size())
612 return false;
614 // Check the contents.
615 EXPECT_EQ(value, file_contents);
616 if (memcmp(file_contents.c_str(), value.c_str(), expected_size) != 0)
617 return false;
619 return true;
622 // Start a download and return the item.
623 DownloadItem* StartDownloadAndReturnItem(GURL url) {
624 scoped_ptr<DownloadCreateObserver> observer(
625 CreateInProgressWaiter(shell(), 1));
626 NavigateToURL(shell(), url);
627 observer->WaitForFinished();
628 std::vector<DownloadItem*> downloads;
629 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
630 EXPECT_EQ(1u, downloads.size());
631 if (1u != downloads.size())
632 return NULL;
633 return downloads[0];
636 // Wait for data
637 void WaitForData(DownloadItem* download, int size) {
638 DownloadUpdatedObserver data_observer(
639 download, base::Bind(&DataReceivedFilter, size));
640 data_observer.WaitForEvent();
641 ASSERT_EQ(size, download->GetReceivedBytes());
642 ASSERT_EQ(DownloadItem::IN_PROGRESS, download->GetState());
645 // Tell the test server to release a pending RST and confirm
646 // that the interrupt is received properly (for download resumption
647 // testing).
648 void ReleaseRSTAndConfirmInterruptForResume(DownloadItem* download) {
649 scoped_ptr<DownloadTestObserver> rst_observer(
650 CreateInterruptedWaiter(shell(), 1));
651 NavigateToURL(shell(), test_server()->GetURL("download-finish"));
652 rst_observer->WaitForFinished();
653 EXPECT_EQ(DownloadItem::INTERRUPTED, download->GetState());
656 // Confirm file status expected for the given location in a stream
657 // provided by the resume test server.
658 void ConfirmFileStatusForResume(
659 DownloadItem* download, bool file_exists,
660 int received_bytes, int total_bytes,
661 const base::FilePath& expected_filename) {
662 // expected_filename is only known if the file exists.
663 ASSERT_EQ(file_exists, !expected_filename.empty());
664 EXPECT_EQ(received_bytes, download->GetReceivedBytes());
665 EXPECT_EQ(total_bytes, download->GetTotalBytes());
666 EXPECT_EQ(expected_filename.value(),
667 download->GetFullPath().BaseName().value());
668 EXPECT_EQ(file_exists,
669 (!download->GetFullPath().empty() &&
670 base::PathExists(download->GetFullPath())));
672 if (file_exists) {
673 std::string file_contents;
674 EXPECT_TRUE(base::ReadFileToString(
675 download->GetFullPath(), &file_contents));
677 ASSERT_EQ(static_cast<size_t>(received_bytes), file_contents.size());
678 for (int i = 0; i < received_bytes; ++i) {
679 EXPECT_EQ(static_cast<char>((i * 2 + 15) % 256), file_contents[i])
680 << "File contents diverged at position " << i
681 << " for " << expected_filename.value();
683 if (static_cast<char>((i * 2 + 15) % 256) != file_contents[i])
684 return;
689 private:
690 static void EnsureNoPendingDownloadJobsOnIO(bool* result) {
691 if (URLRequestSlowDownloadJob::NumberOutstandingRequests())
692 *result = false;
693 BrowserThread::PostTask(
694 BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure());
697 // Location of the downloads directory for these tests
698 base::ScopedTempDir downloads_directory_;
699 scoped_ptr<TestShellDownloadManagerDelegate> test_delegate_;
702 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadCancelled) {
703 SetupEnsureNoPendingDownloads();
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();
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());
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();
723 // Get the important info from other threads and check it.
724 EXPECT_TRUE(EnsureNoPendingDownloads());
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();
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();
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.
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);
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];
758 ASSERT_EQ(DownloadItem::IN_PROGRESS, download1->GetState());
759 ASSERT_EQ(DownloadItem::COMPLETE, download2->GetState());
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));
767 // Get the important info from other threads and check it.
768 EXPECT_TRUE(EnsureNoPendingDownloads());
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));
780 base::FilePath file2(download2->GetTargetFilePath());
781 ASSERT_TRUE(base::ContentsEqual(
782 file2, GetTestFilePath("download", "download-test.lib")));
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";
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);
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);
805 #endif
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());
817 // Create a download
818 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
819 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file));
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();
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());
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();
841 // Check state.
842 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
844 // Run final rename callback.
845 callbacks[0].Run();
846 callbacks.clear();
848 // Check state.
849 EXPECT_EQ(DownloadItem::CANCELLED, items[0]->GetState());
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()));
857 // Mark delegate for delayed open.
858 GetDownloadManagerDelegate()->SetDelayedOpen(true);
860 // Setup new factory.
861 DownloadFileWithDelayFactory* file_factory =
862 new DownloadFileWithDelayFactory();
863 download_manager->SetDownloadFileFactoryForTesting(
864 scoped_ptr<DownloadFileFactory>(file_factory).Pass());
866 // Create a download
867 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
868 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file));
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();
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());
883 // Call it.
884 callbacks[0].Run();
885 callbacks.clear();
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());
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());
897 // Need to complete open test.
898 std::vector<DownloadOpenDelayedCallback> delayed_callbacks;
899 GetDownloadManagerDelegate()->GetDelayedCallbacks(
900 &delayed_callbacks);
901 ASSERT_EQ(1u, delayed_callbacks.size());
902 delayed_callbacks[0].Run(true);
904 // *Now* the download should be complete.
905 EXPECT_EQ(DownloadItem::COMPLETE, items[0]->GetState());
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();
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());
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());
933 InSequence notifications;
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());
945 DownloadManagerForShell(shell())->Shutdown();
946 items.clear();
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()));
954 // Mark delegate for delayed open.
955 GetDownloadManagerDelegate()->SetDelayedOpen(true);
957 // Setup new factory.
958 DownloadFileWithDelayFactory* file_factory =
959 new DownloadFileWithDelayFactory();
960 download_manager->SetDownloadFileFactoryForTesting(
961 scoped_ptr<DownloadFileFactory>(file_factory).Pass());
963 // Create a download
964 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
965 NavigateToURL(shell(), URLRequestMockHTTPJob::GetMockUrl(file));
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();
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());
980 // Call it.
981 callbacks[0].Run();
982 callbacks.clear();
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());
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());
996 MockDownloadItemObserver observer;
997 items[0]->AddObserver(&observer);
998 EXPECT_CALL(observer, OnDownloadDestroyed(items[0]));
1000 // Shutdown the download manager. Mostly this is confirming a lack of
1001 // crashes.
1002 DownloadManagerForShell(shell())->Shutdown();
1005 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeInterruptedDownload) {
1006 CommandLine::ForCurrentProcess()->AppendSwitch(
1007 switches::kEnableDownloadResumption);
1008 ASSERT_TRUE(test_server()->Start());
1010 GURL url = test_server()->GetURL(
1011 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1012 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1014 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1015 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1017 DownloadItem* download(StartDownloadAndReturnItem(url));
1018 WaitForData(download, GetSafeBufferChunk());
1019 ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
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());
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")));
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);
1043 // and wait for expected data.
1044 WaitForData(download, GetSafeBufferChunk() * 2);
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")));
1052 // Resume and wait for completion.
1053 DownloadUpdatedObserver completion_observer(
1054 download, base::Bind(DownloadCompleteFilter));
1055 download->Resume();
1056 completion_observer.WaitForEvent();
1058 ConfirmFileStatusForResume(
1059 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1060 base::FilePath(FILE_PATH_LITERAL("rangereset")));
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());
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());
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()));
1085 // Start the download and wait for first data chunk.
1086 DownloadItem* download(StartDownloadAndReturnItem(url));
1087 WaitForData(download, GetSafeBufferChunk());
1089 RecordingDownloadObserver recorder(download);
1091 ReleaseRSTAndConfirmInterruptForResume(download);
1092 ConfirmFileStatusForResume(
1093 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1094 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1096 DownloadUpdatedObserver completion_observer(
1097 download, base::Bind(DownloadCompleteFilter));
1098 download->Resume();
1099 completion_observer.WaitForEvent();
1101 ConfirmFileStatusForResume(
1102 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1103 base::FilePath(FILE_PATH_LITERAL("rangereset")));
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},
1116 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
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());
1126 GURL url = test_server()->GetURL(base::StringPrintf(
1127 // First download hits an RST, rest don't, precondition fail.
1128 "rangereset?size=%d&rst_boundary=%d&"
1129 "token=BadPrecondition&rst_limit=1&fail_precondition=2",
1130 GetSafeBufferChunk() * 3,
1131 GetSafeBufferChunk()));
1133 // Start the download and wait for first data chunk.
1134 DownloadItem* download(StartDownloadAndReturnItem(url));
1135 WaitForData(download, GetSafeBufferChunk());
1137 RecordingDownloadObserver recorder(download);
1139 ReleaseRSTAndConfirmInterruptForResume(download);
1140 ConfirmFileStatusForResume(
1141 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1142 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1143 EXPECT_EQ("BadPrecondition2", download->GetETag());
1145 DownloadUpdatedObserver completion_observer(
1146 download, base::Bind(DownloadCompleteFilter));
1147 download->Resume();
1148 completion_observer.WaitForEvent();
1150 ConfirmFileStatusForResume(
1151 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1152 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1153 EXPECT_EQ("BadPrecondition0", download->GetETag());
1155 static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1156 // Result of RST
1157 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1158 // Starting continuation
1159 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1160 // Server precondition fail.
1161 {DownloadItem::INTERRUPTED, 0},
1162 // Notification of successful restart.
1163 {DownloadItem::IN_PROGRESS, 0},
1164 // Completion.
1165 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1168 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1171 // Confirm we don't try to resume if we don't have a verifier.
1172 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1173 ResumeInterruptedDownloadNoVerifiers) {
1174 CommandLine::ForCurrentProcess()->AppendSwitch(
1175 switches::kEnableDownloadResumption);
1176 ASSERT_TRUE(test_server()->Start());
1178 GURL url = test_server()->GetURL(
1179 base::StringPrintf(
1180 // First download hits an RST, rest don't, no verifiers.
1181 "rangereset?size=%d&rst_boundary=%d&"
1182 "token=NoRange&rst_limit=1&no_verifiers",
1183 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1185 // Start the download and wait for first data chunk.
1186 DownloadItem* download(StartDownloadAndReturnItem(url));
1187 WaitForData(download, GetSafeBufferChunk());
1189 RecordingDownloadObserver recorder(download);
1191 ReleaseRSTAndConfirmInterruptForResume(download);
1192 ConfirmFileStatusForResume(
1193 download, false, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1194 base::FilePath());
1196 DownloadUpdatedObserver completion_observer(
1197 download, base::Bind(DownloadCompleteFilter));
1198 download->Resume();
1199 completion_observer.WaitForEvent();
1201 ConfirmFileStatusForResume(
1202 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1203 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1205 static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1206 // Result of RST
1207 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1208 // Restart for lack of verifiers
1209 {DownloadItem::IN_PROGRESS, 0},
1210 // Completion.
1211 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1214 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1217 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithDeletedFile) {
1218 CommandLine::ForCurrentProcess()->AppendSwitch(
1219 switches::kEnableDownloadResumption);
1220 ASSERT_TRUE(test_server()->Start());
1222 GURL url = test_server()->GetURL(
1223 base::StringPrintf(
1224 // First download hits an RST, rest don't
1225 "rangereset?size=%d&rst_boundary=%d&"
1226 "token=NoRange&rst_limit=1",
1227 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1229 // Start the download and wait for first data chunk.
1230 DownloadItem* download(StartDownloadAndReturnItem(url));
1231 WaitForData(download, GetSafeBufferChunk());
1233 RecordingDownloadObserver recorder(download);
1235 ReleaseRSTAndConfirmInterruptForResume(download);
1236 ConfirmFileStatusForResume(
1237 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1238 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1240 // Delete the intermediate file.
1241 base::DeleteFile(download->GetFullPath(), false);
1243 DownloadUpdatedObserver completion_observer(
1244 download, base::Bind(DownloadCompleteFilter));
1245 download->Resume();
1246 completion_observer.WaitForEvent();
1248 ConfirmFileStatusForResume(
1249 download, true, GetSafeBufferChunk() * 3, GetSafeBufferChunk() * 3,
1250 base::FilePath(FILE_PATH_LITERAL("rangereset")));
1252 static const RecordingDownloadObserver::RecordStruct expected_record[] = {
1253 // Result of RST
1254 {DownloadItem::INTERRUPTED, GetSafeBufferChunk()},
1255 // Starting continuation
1256 {DownloadItem::IN_PROGRESS, GetSafeBufferChunk()},
1257 // Error because file isn't there.
1258 {DownloadItem::INTERRUPTED, 0},
1259 // Restart.
1260 {DownloadItem::IN_PROGRESS, 0},
1261 // Completion.
1262 {DownloadItem::COMPLETE, GetSafeBufferChunk() * 3},
1265 recorder.CompareToExpectedRecord(expected_record, arraysize(expected_record));
1268 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileInitError) {
1269 CommandLine::ForCurrentProcess()->AppendSwitch(
1270 switches::kEnableDownloadResumption);
1271 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1272 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1274 // Setup the error injector.
1275 scoped_refptr<TestFileErrorInjector> injector(
1276 TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1278 TestFileErrorInjector::FileErrorInfo err = {
1279 url.spec(),
1280 TestFileErrorInjector::FILE_OPERATION_INITIALIZE,
1282 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1284 injector->AddError(err);
1285 injector->InjectErrors();
1287 // Start and watch for interrupt.
1288 scoped_ptr<DownloadTestObserver> int_observer(
1289 CreateInterruptedWaiter(shell(), 1));
1290 DownloadItem* download(StartDownloadAndReturnItem(url));
1291 int_observer->WaitForFinished();
1292 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1293 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1294 download->GetLastReason());
1295 EXPECT_EQ(0, download->GetReceivedBytes());
1296 EXPECT_TRUE(download->GetFullPath().empty());
1297 EXPECT_TRUE(download->GetTargetFilePath().empty());
1299 // We need to make sure that any cross-thread downloads communication has
1300 // quiesced before clearing and injecting the new errors, as the
1301 // InjectErrors() routine alters the currently in use download file
1302 // factory, which is a file thread object.
1303 RunAllPendingInMessageLoop(BrowserThread::FILE);
1304 RunAllPendingInMessageLoop();
1306 // Clear the old errors list.
1307 injector->ClearErrors();
1308 injector->InjectErrors();
1310 // Resume and watch completion.
1311 DownloadUpdatedObserver completion_observer(
1312 download, base::Bind(DownloadCompleteFilter));
1313 download->Resume();
1314 completion_observer.WaitForEvent();
1315 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1318 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
1319 ResumeWithFileIntermediateRenameError) {
1320 CommandLine::ForCurrentProcess()->AppendSwitch(
1321 switches::kEnableDownloadResumption);
1322 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1323 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1325 // Setup the error injector.
1326 scoped_refptr<TestFileErrorInjector> injector(
1327 TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1329 TestFileErrorInjector::FileErrorInfo err = {
1330 url.spec(),
1331 TestFileErrorInjector::FILE_OPERATION_RENAME_UNIQUIFY,
1333 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1335 injector->AddError(err);
1336 injector->InjectErrors();
1338 // Start and watch for interrupt.
1339 scoped_ptr<DownloadTestObserver> int_observer(
1340 CreateInterruptedWaiter(shell(), 1));
1341 DownloadItem* download(StartDownloadAndReturnItem(url));
1342 int_observer->WaitForFinished();
1343 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1344 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1345 download->GetLastReason());
1346 EXPECT_TRUE(download->GetFullPath().empty());
1347 // Target path will have been set after file name determination. GetFullPath()
1348 // being empty is sufficient to signal that filename determination needs to be
1349 // redone.
1350 EXPECT_FALSE(download->GetTargetFilePath().empty());
1352 // We need to make sure that any cross-thread downloads communication has
1353 // quiesced before clearing and injecting the new errors, as the
1354 // InjectErrors() routine alters the currently in use download file
1355 // factory, which is a file thread object.
1356 RunAllPendingInMessageLoop(BrowserThread::FILE);
1357 RunAllPendingInMessageLoop();
1359 // Clear the old errors list.
1360 injector->ClearErrors();
1361 injector->InjectErrors();
1363 // Resume and watch completion.
1364 DownloadUpdatedObserver completion_observer(
1365 download, base::Bind(DownloadCompleteFilter));
1366 download->Resume();
1367 completion_observer.WaitForEvent();
1368 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1371 IN_PROC_BROWSER_TEST_F(DownloadContentTest, ResumeWithFileFinalRenameError) {
1372 CommandLine::ForCurrentProcess()->AppendSwitch(
1373 switches::kEnableDownloadResumption);
1374 base::FilePath file(FILE_PATH_LITERAL("download-test.lib"));
1375 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1377 // Setup the error injector.
1378 scoped_refptr<TestFileErrorInjector> injector(
1379 TestFileErrorInjector::Create(DownloadManagerForShell(shell())));
1381 DownloadManagerForShell(shell())->RemoveAllDownloads();
1382 TestFileErrorInjector::FileErrorInfo err = {
1383 url.spec(),
1384 TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE,
1386 DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE
1388 injector->AddError(err);
1389 injector->InjectErrors();
1391 // Start and watch for interrupt.
1392 scoped_ptr<DownloadTestObserver> int_observer(
1393 CreateInterruptedWaiter(shell(), 1));
1394 DownloadItem* download(StartDownloadAndReturnItem(url));
1395 int_observer->WaitForFinished();
1396 ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
1397 EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
1398 download->GetLastReason());
1399 EXPECT_TRUE(download->GetFullPath().empty());
1400 // Target path should still be intact.
1401 EXPECT_FALSE(download->GetTargetFilePath().empty());
1403 // We need to make sure that any cross-thread downloads communication has
1404 // quiesced before clearing and injecting the new errors, as the
1405 // InjectErrors() routine alters the currently in use download file
1406 // factory, which is a file thread object.
1407 RunAllPendingInMessageLoop(BrowserThread::FILE);
1408 RunAllPendingInMessageLoop();
1410 // Clear the old errors list.
1411 injector->ClearErrors();
1412 injector->InjectErrors();
1414 // Resume and watch completion.
1415 DownloadUpdatedObserver completion_observer(
1416 download, base::Bind(DownloadCompleteFilter));
1417 download->Resume();
1418 completion_observer.WaitForEvent();
1419 EXPECT_EQ(download->GetState(), DownloadItem::COMPLETE);
1422 // An interrupted download should remove the intermediate file when it is
1423 // cancelled.
1424 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelInterruptedDownload) {
1425 CommandLine::ForCurrentProcess()->AppendSwitch(
1426 switches::kEnableDownloadResumption);
1427 ASSERT_TRUE(test_server()->Start());
1429 GURL url1 = test_server()->GetURL(
1430 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1431 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1433 DownloadItem* download(StartDownloadAndReturnItem(url1));
1434 WaitForData(download, GetSafeBufferChunk());
1436 ReleaseRSTAndConfirmInterruptForResume(download);
1437 ConfirmFileStatusForResume(
1438 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1439 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1441 base::FilePath intermediate_path(download->GetFullPath());
1442 ASSERT_FALSE(intermediate_path.empty());
1443 EXPECT_TRUE(base::PathExists(intermediate_path));
1445 download->Cancel(true /* user_cancel */);
1446 RunAllPendingInMessageLoop(BrowserThread::FILE);
1447 RunAllPendingInMessageLoop();
1449 // The intermediate file should now be gone.
1450 EXPECT_FALSE(base::PathExists(intermediate_path));
1451 EXPECT_TRUE(download->GetFullPath().empty());
1454 IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveDownload) {
1455 CommandLine::ForCurrentProcess()->AppendSwitch(
1456 switches::kEnableDownloadResumption);
1457 ASSERT_TRUE(test_server()->Start());
1459 // An interrupted download should remove the intermediate file when it is
1460 // removed.
1462 GURL url1 = test_server()->GetURL(
1463 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1464 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1466 DownloadItem* download(StartDownloadAndReturnItem(url1));
1467 WaitForData(download, GetSafeBufferChunk());
1468 ReleaseRSTAndConfirmInterruptForResume(download);
1469 ConfirmFileStatusForResume(
1470 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1471 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1473 base::FilePath intermediate_path(download->GetFullPath());
1474 ASSERT_FALSE(intermediate_path.empty());
1475 EXPECT_TRUE(base::PathExists(intermediate_path));
1477 download->Remove();
1478 RunAllPendingInMessageLoop(BrowserThread::FILE);
1479 RunAllPendingInMessageLoop();
1481 // The intermediate file should now be gone.
1482 EXPECT_FALSE(base::PathExists(intermediate_path));
1485 // A completed download shouldn't delete the downloaded file when it is
1486 // removed.
1488 // Start the second download and wait until it's done.
1489 base::FilePath file2(FILE_PATH_LITERAL("download-test.lib"));
1490 GURL url2(URLRequestMockHTTPJob::GetMockUrl(file2));
1491 scoped_ptr<DownloadTestObserver> completion_observer(
1492 CreateWaiter(shell(), 1));
1493 DownloadItem* download(StartDownloadAndReturnItem(url2));
1494 completion_observer->WaitForFinished();
1496 // The target path should exist.
1497 base::FilePath target_path(download->GetTargetFilePath());
1498 EXPECT_TRUE(base::PathExists(target_path));
1499 download->Remove();
1500 RunAllPendingInMessageLoop(BrowserThread::FILE);
1501 RunAllPendingInMessageLoop();
1503 // The file should still exist.
1504 EXPECT_TRUE(base::PathExists(target_path));
1508 IN_PROC_BROWSER_TEST_F(DownloadContentTest, RemoveResumingDownload) {
1509 SetupEnsureNoPendingDownloads();
1510 CommandLine::ForCurrentProcess()->AppendSwitch(
1511 switches::kEnableDownloadResumption);
1512 ASSERT_TRUE(test_server()->Start());
1514 GURL url = test_server()->GetURL(
1515 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1516 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1518 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1519 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1521 DownloadItem* download(StartDownloadAndReturnItem(url));
1522 WaitForData(download, GetSafeBufferChunk());
1523 ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1525 // Tell the server to send the RST and confirm the interrupt happens.
1526 ReleaseRSTAndConfirmInterruptForResume(download);
1527 ConfirmFileStatusForResume(
1528 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1529 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1531 base::FilePath intermediate_path(download->GetFullPath());
1532 ASSERT_FALSE(intermediate_path.empty());
1533 EXPECT_TRUE(base::PathExists(intermediate_path));
1535 // Resume and remove download. We expect only a single OnDownloadCreated()
1536 // call, and that's for the second download created below.
1537 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1538 download->Resume();
1539 download->Remove();
1541 // The intermediate file should now be gone.
1542 RunAllPendingInMessageLoop(BrowserThread::FILE);
1543 RunAllPendingInMessageLoop();
1544 EXPECT_FALSE(base::PathExists(intermediate_path));
1546 // Start the second download and wait until it's done. The test server is
1547 // single threaded. The response to this download request should follow the
1548 // response to the previous resumption request.
1549 GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
1550 DownloadAndWait(shell(), url2, DownloadItem::COMPLETE);
1552 EXPECT_TRUE(EnsureNoPendingDownloads());
1555 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CancelResumingDownload) {
1556 SetupEnsureNoPendingDownloads();
1557 CommandLine::ForCurrentProcess()->AppendSwitch(
1558 switches::kEnableDownloadResumption);
1559 ASSERT_TRUE(test_server()->Start());
1561 GURL url = test_server()->GetURL(
1562 base::StringPrintf("rangereset?size=%d&rst_boundary=%d",
1563 GetSafeBufferChunk() * 3, GetSafeBufferChunk()));
1565 MockDownloadManagerObserver dm_observer(DownloadManagerForShell(shell()));
1566 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1568 DownloadItem* download(StartDownloadAndReturnItem(url));
1569 WaitForData(download, GetSafeBufferChunk());
1570 ::testing::Mock::VerifyAndClearExpectations(&dm_observer);
1572 // Tell the server to send the RST and confirm the interrupt happens.
1573 ReleaseRSTAndConfirmInterruptForResume(download);
1574 ConfirmFileStatusForResume(
1575 download, true, GetSafeBufferChunk(), GetSafeBufferChunk() * 3,
1576 base::FilePath(FILE_PATH_LITERAL("rangereset.crdownload")));
1578 base::FilePath intermediate_path(download->GetFullPath());
1579 ASSERT_FALSE(intermediate_path.empty());
1580 EXPECT_TRUE(base::PathExists(intermediate_path));
1582 // Resume and cancel download. We expect only a single OnDownloadCreated()
1583 // call, and that's for the second download created below.
1584 EXPECT_CALL(dm_observer, OnDownloadCreated(_,_)).Times(1);
1585 download->Resume();
1586 download->Cancel(true);
1588 // The intermediate file should now be gone.
1589 RunAllPendingInMessageLoop(BrowserThread::FILE);
1590 RunAllPendingInMessageLoop();
1591 EXPECT_FALSE(base::PathExists(intermediate_path));
1592 EXPECT_TRUE(download->GetFullPath().empty());
1594 // Start the second download and wait until it's done. The test server is
1595 // single threaded. The response to this download request should follow the
1596 // response to the previous resumption request.
1597 GURL url2(test_server()->GetURL("rangereset?size=100&rst_limit=0&token=x"));
1598 DownloadAndWait(shell(), url2, DownloadItem::COMPLETE);
1600 EXPECT_TRUE(EnsureNoPendingDownloads());
1603 // Check that the cookie policy is correctly updated when downloading a file
1604 // that redirects cross origin.
1605 IN_PROC_BROWSER_TEST_F(DownloadContentTest, CookiePolicy) {
1606 ASSERT_TRUE(test_server()->Start());
1607 net::HostPortPair host_port = test_server()->host_port_pair();
1608 DCHECK_EQ(host_port.host(), std::string("127.0.0.1"));
1610 // Block third-party cookies.
1611 ShellNetworkDelegate::SetAcceptAllCookies(false);
1613 // |url| redirects to a different origin |download| which tries to set a
1614 // cookie.
1615 std::string download(base::StringPrintf(
1616 "http://localhost:%d/set-cookie?A=B", host_port.port()));
1617 GURL url(test_server()->GetURL("server-redirect?" + download));
1619 // Download the file.
1620 SetupEnsureNoPendingDownloads();
1621 scoped_ptr<DownloadUrlParameters> dl_params(
1622 DownloadUrlParameters::FromWebContents(shell()->web_contents(), url));
1623 scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
1624 DownloadManagerForShell(shell())->DownloadUrl(dl_params.Pass());
1625 observer->WaitForFinished();
1627 // Get the important info from other threads and check it.
1628 EXPECT_TRUE(EnsureNoPendingDownloads());
1630 std::vector<DownloadItem*> downloads;
1631 DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
1632 ASSERT_EQ(1u, downloads.size());
1633 ASSERT_EQ(DownloadItem::COMPLETE, downloads[0]->GetState());
1635 // Check that the cookies were correctly set.
1636 EXPECT_EQ("A=B",
1637 content::GetCookies(shell()->web_contents()->GetBrowserContext(),
1638 GURL(download)));
1641 } // namespace content