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