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