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#include "base/callback.h"
6#include "base/command_line.h"
7#include "base/message_loop/message_loop.h"
8#include "base/stl_util.h"
9#include "base/threading/thread.h"
10#include "content/browser/byte_stream.h"
11#include "content/browser/download/download_create_info.h"
12#include "content/browser/download/download_file_factory.h"
13#include "content/browser/download/download_item_impl.h"
14#include "content/browser/download/download_item_impl_delegate.h"
15#include "content/browser/download/download_request_handle.h"
16#include "content/browser/download/mock_download_file.h"
17#include "content/public/browser/download_destination_observer.h"
18#include "content/public/browser/download_interrupt_reasons.h"
19#include "content/public/browser/download_url_parameters.h"
20#include "content/public/common/content_switches.h"
21#include "content/public/test/mock_download_item.h"
22#include "content/public/test/test_browser_thread.h"
23#include "testing/gmock/include/gmock/gmock.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26using ::testing::_;
27using ::testing::NiceMock;
28using ::testing::Property;
29using ::testing::Return;
30using ::testing::SaveArg;
31using ::testing::StrictMock;
32
33const int kDownloadChunkSize = 1000;
34const int kDownloadSpeed = 1000;
35const base::FilePath::CharType kDummyPath[] = FILE_PATH_LITERAL("/testpath");
36
37namespace content {
38
39namespace {
40
41class MockDelegate : public DownloadItemImplDelegate {
42 public:
43  MockDelegate() : DownloadItemImplDelegate() {
44    SetDefaultExpectations();
45  }
46
47  MOCK_METHOD2(DetermineDownloadTarget, void(
48      DownloadItemImpl*, const DownloadTargetCallback&));
49  MOCK_METHOD2(ShouldCompleteDownload,
50               bool(DownloadItemImpl*, const base::Closure&));
51  MOCK_METHOD2(ShouldOpenDownload,
52               bool(DownloadItemImpl*, const ShouldOpenDownloadCallback&));
53  MOCK_METHOD1(ShouldOpenFileBasedOnExtension, bool(const base::FilePath&));
54  MOCK_METHOD1(CheckForFileRemoval, void(DownloadItemImpl*));
55
56  virtual void ResumeInterruptedDownload(
57      scoped_ptr<DownloadUrlParameters> params, uint32 id) OVERRIDE {
58    MockResumeInterruptedDownload(params.get(), id);
59  }
60  MOCK_METHOD2(MockResumeInterruptedDownload,
61               void(DownloadUrlParameters* params, uint32 id));
62
63  MOCK_CONST_METHOD0(GetBrowserContext, BrowserContext*());
64  MOCK_METHOD1(UpdatePersistence, void(DownloadItemImpl*));
65  MOCK_METHOD1(DownloadOpened, void(DownloadItemImpl*));
66  MOCK_METHOD1(DownloadRemoved, void(DownloadItemImpl*));
67  MOCK_CONST_METHOD1(AssertStateConsistent, void(DownloadItemImpl*));
68
69  void VerifyAndClearExpectations() {
70    ::testing::Mock::VerifyAndClearExpectations(this);
71    SetDefaultExpectations();
72  }
73
74 private:
75  void SetDefaultExpectations() {
76    EXPECT_CALL(*this, AssertStateConsistent(_))
77        .WillRepeatedly(Return());
78    EXPECT_CALL(*this, ShouldOpenFileBasedOnExtension(_))
79        .WillRepeatedly(Return(false));
80    EXPECT_CALL(*this, ShouldOpenDownload(_, _))
81        .WillRepeatedly(Return(true));
82  }
83};
84
85class MockRequestHandle : public DownloadRequestHandleInterface {
86 public:
87  MOCK_CONST_METHOD0(GetWebContents, WebContents*());
88  MOCK_CONST_METHOD0(GetDownloadManager, DownloadManager*());
89  MOCK_CONST_METHOD0(PauseRequest, void());
90  MOCK_CONST_METHOD0(ResumeRequest, void());
91  MOCK_CONST_METHOD0(CancelRequest, void());
92  MOCK_CONST_METHOD0(DebugString, std::string());
93};
94
95// Schedules a task to invoke the RenameCompletionCallback with |new_path| on
96// the UI thread. Should only be used as the action for
97// MockDownloadFile::Rename as follows:
98//   EXPECT_CALL(download_file, Rename*(_,_))
99//       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
100//                                        new_path));
101ACTION_P2(ScheduleRenameCallback, interrupt_reason, new_path) {
102  BrowserThread::PostTask(
103      BrowserThread::UI, FROM_HERE,
104      base::Bind(arg1, interrupt_reason, new_path));
105}
106
107}  // namespace
108
109class DownloadItemTest : public testing::Test {
110 public:
111  class MockObserver : public DownloadItem::Observer {
112   public:
113    explicit MockObserver(DownloadItem* item)
114      : item_(item),
115        last_state_(item->GetState()),
116        removed_(false),
117        destroyed_(false),
118        updated_(false),
119        interrupt_count_(0),
120        resume_count_(0) {
121      item_->AddObserver(this);
122    }
123
124    virtual ~MockObserver() {
125      if (item_) item_->RemoveObserver(this);
126    }
127
128    virtual void OnDownloadRemoved(DownloadItem* download) OVERRIDE {
129      DVLOG(20) << " " << __FUNCTION__
130                << " download = " << download->DebugString(false);
131      removed_ = true;
132    }
133
134    virtual void OnDownloadUpdated(DownloadItem* download) OVERRIDE {
135      DVLOG(20) << " " << __FUNCTION__
136                << " download = " << download->DebugString(false);
137      updated_ = true;
138      DownloadItem::DownloadState new_state = download->GetState();
139      if (last_state_ == DownloadItem::IN_PROGRESS &&
140          new_state == DownloadItem::INTERRUPTED) {
141        interrupt_count_++;
142      }
143      if (last_state_ == DownloadItem::INTERRUPTED &&
144          new_state == DownloadItem::IN_PROGRESS) {
145        resume_count_++;
146      }
147      last_state_ = new_state;
148    }
149
150    virtual void OnDownloadOpened(DownloadItem* download) OVERRIDE {
151      DVLOG(20) << " " << __FUNCTION__
152                << " download = " << download->DebugString(false);
153    }
154
155    virtual void OnDownloadDestroyed(DownloadItem* download) OVERRIDE {
156      DVLOG(20) << " " << __FUNCTION__
157                << " download = " << download->DebugString(false);
158      destroyed_ = true;
159      item_->RemoveObserver(this);
160      item_ = NULL;
161    }
162
163    bool CheckRemoved() {
164      return removed_;
165    }
166
167    bool CheckDestroyed() {
168      return destroyed_;
169    }
170
171    bool CheckUpdated() {
172      bool was_updated = updated_;
173      updated_ = false;
174      return was_updated;
175    }
176
177    int GetInterruptCount() {
178      return interrupt_count_;
179    }
180
181    int GetResumeCount() {
182      return resume_count_;
183    }
184
185   private:
186    DownloadItem* item_;
187    DownloadItem::DownloadState last_state_;
188    bool removed_;
189    bool destroyed_;
190    bool updated_;
191    int interrupt_count_;
192    int resume_count_;
193  };
194
195  DownloadItemTest()
196      : ui_thread_(BrowserThread::UI, &loop_),
197        file_thread_(BrowserThread::FILE, &loop_),
198        delegate_() {
199  }
200
201  ~DownloadItemTest() {
202  }
203
204  virtual void SetUp() {
205  }
206
207  virtual void TearDown() {
208    ui_thread_.DeprecatedGetThreadObject()->message_loop()->RunUntilIdle();
209    STLDeleteElements(&allocated_downloads_);
210    allocated_downloads_.clear();
211  }
212
213  // This class keeps ownership of the created download item; it will
214  // be torn down at the end of the test unless DestroyDownloadItem is
215  // called.
216  DownloadItemImpl* CreateDownloadItem() {
217    // Normally, the download system takes ownership of info, and is
218    // responsible for deleting it.  In these unit tests, however, we
219    // don't call the function that deletes it, so we do so ourselves.
220    scoped_ptr<DownloadCreateInfo> info_;
221
222    info_.reset(new DownloadCreateInfo());
223    static uint32 next_id = DownloadItem::kInvalidId + 1;
224    info_->save_info = scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo());
225    info_->save_info->prompt_for_save_location = false;
226    info_->url_chain.push_back(GURL());
227    info_->etag = "SomethingToSatisfyResumption";
228
229    DownloadItemImpl* download =
230        new DownloadItemImpl(
231            &delegate_, next_id++, *(info_.get()), net::BoundNetLog());
232    allocated_downloads_.insert(download);
233    return download;
234  }
235
236  // Add DownloadFile to DownloadItem
237  MockDownloadFile* AddDownloadFileToDownloadItem(
238      DownloadItemImpl* item,
239      DownloadItemImplDelegate::DownloadTargetCallback *callback) {
240    MockDownloadFile* mock_download_file(new StrictMock<MockDownloadFile>);
241    scoped_ptr<DownloadFile> download_file(mock_download_file);
242    EXPECT_CALL(*mock_download_file, Initialize(_));
243    if (callback) {
244      // Save the callback.
245      EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
246          .WillOnce(SaveArg<1>(callback));
247    } else {
248      // Drop it on the floor.
249      EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
250    }
251
252    scoped_ptr<DownloadRequestHandleInterface> request_handle(
253        new NiceMock<MockRequestHandle>);
254    item->Start(download_file.Pass(), request_handle.Pass());
255    loop_.RunUntilIdle();
256
257    // So that we don't have a function writing to a stack variable
258    // lying around if the above failed.
259    mock_delegate()->VerifyAndClearExpectations();
260    EXPECT_CALL(*mock_delegate(), AssertStateConsistent(_))
261        .WillRepeatedly(Return());
262    EXPECT_CALL(*mock_delegate(), ShouldOpenFileBasedOnExtension(_))
263        .WillRepeatedly(Return(false));
264    EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(_, _))
265        .WillRepeatedly(Return(true));
266
267    return mock_download_file;
268  }
269
270  // Perform the intermediate rename for |item|. The target path for the
271  // download will be set to kDummyPath. Returns the MockDownloadFile* that was
272  // added to the DownloadItem.
273  MockDownloadFile* DoIntermediateRename(DownloadItemImpl* item,
274                                         DownloadDangerType danger_type) {
275    EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
276    EXPECT_TRUE(item->GetTargetFilePath().empty());
277    DownloadItemImplDelegate::DownloadTargetCallback callback;
278    MockDownloadFile* download_file =
279        AddDownloadFileToDownloadItem(item, &callback);
280    base::FilePath target_path(kDummyPath);
281    base::FilePath intermediate_path(
282        target_path.InsertBeforeExtensionASCII("x"));
283    EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
284        .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
285                                         intermediate_path));
286    callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
287                 danger_type, intermediate_path);
288    RunAllPendingInMessageLoops();
289    return download_file;
290  }
291
292  // Cleanup a download item (specifically get rid of the DownloadFile on it).
293  // The item must be in the expected state.
294  void CleanupItem(DownloadItemImpl* item,
295                   MockDownloadFile* download_file,
296                   DownloadItem::DownloadState expected_state) {
297    EXPECT_EQ(expected_state, item->GetState());
298
299    if (expected_state == DownloadItem::IN_PROGRESS) {
300      EXPECT_CALL(*download_file, Cancel());
301      item->Cancel(true);
302      loop_.RunUntilIdle();
303    }
304  }
305
306  // Destroy a previously created download item.
307  void DestroyDownloadItem(DownloadItem* item) {
308    allocated_downloads_.erase(item);
309    delete item;
310  }
311
312  void RunAllPendingInMessageLoops() {
313    loop_.RunUntilIdle();
314  }
315
316  MockDelegate* mock_delegate() {
317    return &delegate_;
318  }
319
320  void OnDownloadFileAcquired(base::FilePath* return_path,
321                              const base::FilePath& path) {
322    *return_path = path;
323  }
324
325 private:
326  base::MessageLoopForUI loop_;
327  TestBrowserThread ui_thread_;    // UI thread
328  TestBrowserThread file_thread_;  // FILE thread
329  StrictMock<MockDelegate> delegate_;
330  std::set<DownloadItem*> allocated_downloads_;
331};
332
333// Tests to ensure calls that change a DownloadItem generate an update to
334// observers.
335// State changing functions not tested:
336//  void OpenDownload();
337//  void ShowDownloadInShell();
338//  void CompleteDelayedDownload();
339//  set_* mutators
340
341TEST_F(DownloadItemTest, NotificationAfterUpdate) {
342  DownloadItemImpl* item = CreateDownloadItem();
343  MockObserver observer(item);
344
345  item->DestinationUpdate(kDownloadChunkSize, kDownloadSpeed, std::string());
346  ASSERT_TRUE(observer.CheckUpdated());
347  EXPECT_EQ(kDownloadSpeed, item->CurrentSpeed());
348}
349
350TEST_F(DownloadItemTest, NotificationAfterCancel) {
351  DownloadItemImpl* user_cancel = CreateDownloadItem();
352  MockDownloadFile* download_file =
353      AddDownloadFileToDownloadItem(user_cancel, NULL);
354  EXPECT_CALL(*download_file, Cancel());
355  MockObserver observer1(user_cancel);
356
357  user_cancel->Cancel(true);
358  ASSERT_TRUE(observer1.CheckUpdated());
359
360  DownloadItemImpl* system_cancel = CreateDownloadItem();
361  download_file = AddDownloadFileToDownloadItem(system_cancel, NULL);
362  EXPECT_CALL(*download_file, Cancel());
363  MockObserver observer2(system_cancel);
364
365  system_cancel->Cancel(false);
366  ASSERT_TRUE(observer2.CheckUpdated());
367}
368
369TEST_F(DownloadItemTest, NotificationAfterComplete) {
370  DownloadItemImpl* item = CreateDownloadItem();
371  MockObserver observer(item);
372
373  item->OnAllDataSaved(DownloadItem::kEmptyFileHash);
374  ASSERT_TRUE(observer.CheckUpdated());
375
376  item->MarkAsComplete();
377  ASSERT_TRUE(observer.CheckUpdated());
378}
379
380TEST_F(DownloadItemTest, NotificationAfterDownloadedFileRemoved) {
381  DownloadItemImpl* item = CreateDownloadItem();
382  MockObserver observer(item);
383
384  item->OnDownloadedFileRemoved();
385  ASSERT_TRUE(observer.CheckUpdated());
386}
387
388TEST_F(DownloadItemTest, NotificationAfterInterrupted) {
389  DownloadItemImpl* item = CreateDownloadItem();
390  MockDownloadFile* download_file =
391      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
392  EXPECT_CALL(*download_file, Cancel());
393  MockObserver observer(item);
394
395  EXPECT_CALL(*mock_delegate(), MockResumeInterruptedDownload(_,_))
396      .Times(0);
397
398  item->DestinationObserverAsWeakPtr()->DestinationError(
399      DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
400  ASSERT_TRUE(observer.CheckUpdated());
401}
402
403TEST_F(DownloadItemTest, NotificationAfterDestroyed) {
404  DownloadItemImpl* item = CreateDownloadItem();
405  MockObserver observer(item);
406
407  DestroyDownloadItem(item);
408  ASSERT_TRUE(observer.CheckDestroyed());
409}
410
411TEST_F(DownloadItemTest, ContinueAfterInterrupted) {
412  CommandLine::ForCurrentProcess()->AppendSwitch(
413      switches::kEnableDownloadResumption);
414
415  DownloadItemImpl* item = CreateDownloadItem();
416  MockObserver observer(item);
417  DownloadItemImplDelegate::DownloadTargetCallback callback;
418  MockDownloadFile* download_file =
419      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
420
421  // Interrupt the download, using a continuable interrupt.
422  EXPECT_CALL(*download_file, FullPath())
423      .WillOnce(Return(base::FilePath()));
424  EXPECT_CALL(*download_file, Detach());
425  item->DestinationObserverAsWeakPtr()->DestinationError(
426      DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
427  ASSERT_TRUE(observer.CheckUpdated());
428  // Should attempt to auto-resume.  Because we don't have a mock WebContents,
429  // ResumeInterruptedDownload() will abort early, with another interrupt,
430  // which will be ignored.
431  ASSERT_EQ(1, observer.GetInterruptCount());
432  ASSERT_EQ(0, observer.GetResumeCount());
433  RunAllPendingInMessageLoops();
434
435  CleanupItem(item, download_file, DownloadItem::INTERRUPTED);
436}
437
438// Same as above, but with a non-continuable interrupt.
439TEST_F(DownloadItemTest, RestartAfterInterrupted) {
440  CommandLine::ForCurrentProcess()->AppendSwitch(
441      switches::kEnableDownloadResumption);
442
443  DownloadItemImpl* item = CreateDownloadItem();
444  MockObserver observer(item);
445  DownloadItemImplDelegate::DownloadTargetCallback callback;
446  MockDownloadFile* download_file =
447      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
448
449  // Interrupt the download, using a restartable interrupt.
450  EXPECT_CALL(*download_file, Cancel());
451  item->DestinationObserverAsWeakPtr()->DestinationError(
452      DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
453  ASSERT_TRUE(observer.CheckUpdated());
454  // Should not try to auto-resume.
455  ASSERT_EQ(1, observer.GetInterruptCount());
456  ASSERT_EQ(0, observer.GetResumeCount());
457  RunAllPendingInMessageLoops();
458
459  CleanupItem(item, download_file, DownloadItem::INTERRUPTED);
460}
461
462TEST_F(DownloadItemTest, LimitRestartsAfterInterrupted) {
463  CommandLine::ForCurrentProcess()->AppendSwitch(
464      switches::kEnableDownloadResumption);
465
466  DownloadItemImpl* item = CreateDownloadItem();
467  base::WeakPtr<DownloadDestinationObserver> as_observer(
468      item->DestinationObserverAsWeakPtr());
469  MockObserver observer(item);
470  MockDownloadFile* mock_download_file(NULL);
471  scoped_ptr<DownloadFile> download_file;
472  MockRequestHandle* mock_request_handle(NULL);
473  scoped_ptr<DownloadRequestHandleInterface> request_handle;
474  DownloadItemImplDelegate::DownloadTargetCallback callback;
475
476  EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
477      .WillRepeatedly(SaveArg<1>(&callback));
478  for (int i = 0; i < (DownloadItemImpl::kMaxAutoResumeAttempts + 1); ++i) {
479    DVLOG(20) << "Loop iteration " << i;
480
481    mock_download_file = new NiceMock<MockDownloadFile>;
482    download_file.reset(mock_download_file);
483    mock_request_handle = new NiceMock<MockRequestHandle>;
484    request_handle.reset(mock_request_handle);
485
486    ON_CALL(*mock_download_file, FullPath())
487        .WillByDefault(Return(base::FilePath()));
488
489    // It's too complicated to set up a WebContents instance that would cause
490    // the MockDownloadItemDelegate's ResumeInterruptedDownload() function
491    // to be callled, so we simply verify that GetWebContents() is called.
492    if (i < (DownloadItemImpl::kMaxAutoResumeAttempts - 1)) {
493      EXPECT_CALL(*mock_request_handle, GetWebContents())
494          .WillRepeatedly(Return(static_cast<WebContents*>(NULL)));
495    }
496
497    // Copied key parts of DoIntermediateRename & AddDownloadFileToDownloadItem
498    // to allow for holding onto the request handle.
499    item->Start(download_file.Pass(), request_handle.Pass());
500    RunAllPendingInMessageLoops();
501    if (i == 0) {
502      // Target determination is only done the first time through.
503      base::FilePath target_path(kDummyPath);
504      base::FilePath intermediate_path(
505          target_path.InsertBeforeExtensionASCII("x"));
506      EXPECT_CALL(*mock_download_file, RenameAndUniquify(intermediate_path, _))
507          .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
508                                           intermediate_path));
509      callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
510                   DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
511      RunAllPendingInMessageLoops();
512    }
513    ASSERT_EQ(i, observer.GetResumeCount());
514
515    // Use a continuable interrupt.
516    item->DestinationObserverAsWeakPtr()->DestinationError(
517        DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
518
519    ASSERT_EQ(i + 1, observer.GetInterruptCount());
520    ::testing::Mock::VerifyAndClearExpectations(mock_download_file);
521  }
522
523  CleanupItem(item, mock_download_file, DownloadItem::INTERRUPTED);
524}
525
526TEST_F(DownloadItemTest, NotificationAfterRemove) {
527  DownloadItemImpl* item = CreateDownloadItem();
528  MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
529  EXPECT_CALL(*download_file, Cancel());
530  EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
531  MockObserver observer(item);
532
533  item->Remove();
534  ASSERT_TRUE(observer.CheckUpdated());
535  ASSERT_TRUE(observer.CheckRemoved());
536}
537
538TEST_F(DownloadItemTest, NotificationAfterOnContentCheckCompleted) {
539  // Setting to NOT_DANGEROUS does not trigger a notification.
540  DownloadItemImpl* safe_item = CreateDownloadItem();
541  MockObserver safe_observer(safe_item);
542
543  safe_item->OnAllDataSaved(std::string());
544  EXPECT_TRUE(safe_observer.CheckUpdated());
545  safe_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
546  EXPECT_TRUE(safe_observer.CheckUpdated());
547
548  // Setting to unsafe url or unsafe file should trigger a notification.
549  DownloadItemImpl* unsafeurl_item =
550      CreateDownloadItem();
551  MockObserver unsafeurl_observer(unsafeurl_item);
552
553  unsafeurl_item->OnAllDataSaved(std::string());
554  EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
555  unsafeurl_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
556  EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
557
558  unsafeurl_item->ValidateDangerousDownload();
559  EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
560
561  DownloadItemImpl* unsafefile_item =
562      CreateDownloadItem();
563  MockObserver unsafefile_observer(unsafefile_item);
564
565  unsafefile_item->OnAllDataSaved(std::string());
566  EXPECT_TRUE(unsafefile_observer.CheckUpdated());
567  unsafefile_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
568  EXPECT_TRUE(unsafefile_observer.CheckUpdated());
569
570  unsafefile_item->ValidateDangerousDownload();
571  EXPECT_TRUE(unsafefile_observer.CheckUpdated());
572}
573
574// DownloadItemImpl::OnDownloadTargetDetermined will schedule a task to run
575// DownloadFile::Rename(). Once the rename
576// completes, DownloadItemImpl receives a notification with the new file
577// name. Check that observers are updated when the new filename is available and
578// not before.
579TEST_F(DownloadItemTest, NotificationAfterOnDownloadTargetDetermined) {
580  DownloadItemImpl* item = CreateDownloadItem();
581  DownloadItemImplDelegate::DownloadTargetCallback callback;
582  MockDownloadFile* download_file =
583      AddDownloadFileToDownloadItem(item, &callback);
584  MockObserver observer(item);
585  base::FilePath target_path(kDummyPath);
586  base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
587  base::FilePath new_intermediate_path(
588      target_path.InsertBeforeExtensionASCII("y"));
589  EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
590      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
591                                       new_intermediate_path));
592
593  // Currently, a notification would be generated if the danger type is anything
594  // other than NOT_DANGEROUS.
595  callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
596               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
597  EXPECT_FALSE(observer.CheckUpdated());
598  RunAllPendingInMessageLoops();
599  EXPECT_TRUE(observer.CheckUpdated());
600  EXPECT_EQ(new_intermediate_path, item->GetFullPath());
601
602  CleanupItem(item, download_file, DownloadItem::IN_PROGRESS);
603}
604
605TEST_F(DownloadItemTest, NotificationAfterTogglePause) {
606  DownloadItemImpl* item = CreateDownloadItem();
607  MockObserver observer(item);
608  MockDownloadFile* mock_download_file(new MockDownloadFile);
609  scoped_ptr<DownloadFile> download_file(mock_download_file);
610  scoped_ptr<DownloadRequestHandleInterface> request_handle(
611      new NiceMock<MockRequestHandle>);
612
613  EXPECT_CALL(*mock_download_file, Initialize(_));
614  EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _));
615  item->Start(download_file.Pass(), request_handle.Pass());
616
617  item->Pause();
618  ASSERT_TRUE(observer.CheckUpdated());
619
620  ASSERT_TRUE(item->IsPaused());
621
622  item->Resume();
623  ASSERT_TRUE(observer.CheckUpdated());
624
625  RunAllPendingInMessageLoops();
626
627  CleanupItem(item, mock_download_file, DownloadItem::IN_PROGRESS);
628}
629
630TEST_F(DownloadItemTest, DisplayName) {
631  DownloadItemImpl* item = CreateDownloadItem();
632  DownloadItemImplDelegate::DownloadTargetCallback callback;
633  MockDownloadFile* download_file =
634      AddDownloadFileToDownloadItem(item, &callback);
635  base::FilePath target_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
636  base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
637  EXPECT_EQ(FILE_PATH_LITERAL(""),
638            item->GetFileNameToReportUser().value());
639  EXPECT_CALL(*download_file, RenameAndUniquify(_, _))
640      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
641                                       intermediate_path));
642  callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
643               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
644  RunAllPendingInMessageLoops();
645  EXPECT_EQ(FILE_PATH_LITERAL("foo.bar"),
646            item->GetFileNameToReportUser().value());
647  item->SetDisplayName(base::FilePath(FILE_PATH_LITERAL("new.name")));
648  EXPECT_EQ(FILE_PATH_LITERAL("new.name"),
649            item->GetFileNameToReportUser().value());
650  CleanupItem(item, download_file, DownloadItem::IN_PROGRESS);
651}
652
653// Test to make sure that Start method calls DF initialize properly.
654TEST_F(DownloadItemTest, Start) {
655  MockDownloadFile* mock_download_file(new MockDownloadFile);
656  scoped_ptr<DownloadFile> download_file(mock_download_file);
657  DownloadItemImpl* item = CreateDownloadItem();
658  EXPECT_CALL(*mock_download_file, Initialize(_));
659  scoped_ptr<DownloadRequestHandleInterface> request_handle(
660      new NiceMock<MockRequestHandle>);
661  EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
662  item->Start(download_file.Pass(), request_handle.Pass());
663  RunAllPendingInMessageLoops();
664
665  CleanupItem(item, mock_download_file, DownloadItem::IN_PROGRESS);
666}
667
668// Test that the delegate is invoked after the download file is renamed.
669TEST_F(DownloadItemTest, CallbackAfterRename) {
670  DownloadItemImpl* item = CreateDownloadItem();
671  DownloadItemImplDelegate::DownloadTargetCallback callback;
672  MockDownloadFile* download_file =
673      AddDownloadFileToDownloadItem(item, &callback);
674  base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
675  base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
676  base::FilePath new_intermediate_path(
677      final_path.InsertBeforeExtensionASCII("y"));
678  EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
679      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
680                                       new_intermediate_path));
681
682  callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
683               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
684  RunAllPendingInMessageLoops();
685  // All the callbacks should have happened by now.
686  ::testing::Mock::VerifyAndClearExpectations(download_file);
687  mock_delegate()->VerifyAndClearExpectations();
688
689  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
690      .WillOnce(Return(true));
691  EXPECT_CALL(*download_file, RenameAndAnnotate(final_path, _))
692      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
693                                       final_path));
694  EXPECT_CALL(*download_file, FullPath())
695      .WillOnce(Return(base::FilePath()));
696  EXPECT_CALL(*download_file, Detach());
697  item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
698  RunAllPendingInMessageLoops();
699  ::testing::Mock::VerifyAndClearExpectations(download_file);
700  mock_delegate()->VerifyAndClearExpectations();
701}
702
703// Test that the delegate is invoked after the download file is renamed and the
704// download item is in an interrupted state.
705TEST_F(DownloadItemTest, CallbackAfterInterruptedRename) {
706  DownloadItemImpl* item = CreateDownloadItem();
707  DownloadItemImplDelegate::DownloadTargetCallback callback;
708  MockDownloadFile* download_file =
709      AddDownloadFileToDownloadItem(item, &callback);
710  base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
711  base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
712  base::FilePath new_intermediate_path(
713      final_path.InsertBeforeExtensionASCII("y"));
714  EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
715      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
716                                       new_intermediate_path));
717  EXPECT_CALL(*download_file, Cancel())
718      .Times(1);
719
720  callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
721               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
722  RunAllPendingInMessageLoops();
723  // All the callbacks should have happened by now.
724  ::testing::Mock::VerifyAndClearExpectations(download_file);
725  mock_delegate()->VerifyAndClearExpectations();
726}
727
728TEST_F(DownloadItemTest, Interrupted) {
729  DownloadItemImpl* item = CreateDownloadItem();
730  MockDownloadFile* download_file =
731      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
732
733  const DownloadInterruptReason reason(
734      DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
735
736  // Confirm interrupt sets state properly.
737  EXPECT_CALL(*download_file, Cancel());
738  item->DestinationObserverAsWeakPtr()->DestinationError(reason);
739  RunAllPendingInMessageLoops();
740  EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
741  EXPECT_EQ(reason, item->GetLastReason());
742
743  // Cancel should kill it.
744  item->Cancel(true);
745  EXPECT_EQ(DownloadItem::CANCELLED, item->GetState());
746  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, item->GetLastReason());
747}
748
749// Destination errors that occur before the intermediate rename shouldn't cause
750// the download to be marked as interrupted until after the intermediate rename.
751TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Restart) {
752  DownloadItemImpl* item = CreateDownloadItem();
753  DownloadItemImplDelegate::DownloadTargetCallback callback;
754  MockDownloadFile* download_file =
755      AddDownloadFileToDownloadItem(item, &callback);
756  item->DestinationObserverAsWeakPtr()->DestinationError(
757      DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
758  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
759
760  base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
761  base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
762  base::FilePath new_intermediate_path(
763      final_path.InsertBeforeExtensionASCII("y"));
764  EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
765      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
766                                       new_intermediate_path));
767  EXPECT_CALL(*download_file, Cancel())
768      .Times(1);
769
770  callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
771               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
772  RunAllPendingInMessageLoops();
773  // All the callbacks should have happened by now.
774  ::testing::Mock::VerifyAndClearExpectations(download_file);
775  mock_delegate()->VerifyAndClearExpectations();
776  EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
777  EXPECT_TRUE(item->GetFullPath().empty());
778  EXPECT_EQ(final_path, item->GetTargetFilePath());
779}
780
781// As above. But if the download can be resumed by continuing, then the
782// intermediate path should be retained when the download is interrupted after
783// the intermediate rename succeeds.
784TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Continue) {
785  CommandLine::ForCurrentProcess()->AppendSwitch(
786      switches::kEnableDownloadResumption);
787  DownloadItemImpl* item = CreateDownloadItem();
788  DownloadItemImplDelegate::DownloadTargetCallback callback;
789  MockDownloadFile* download_file =
790      AddDownloadFileToDownloadItem(item, &callback);
791  item->DestinationObserverAsWeakPtr()->DestinationError(
792      DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
793  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
794
795  base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
796  base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
797  base::FilePath new_intermediate_path(
798      final_path.InsertBeforeExtensionASCII("y"));
799  EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
800      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
801                                       new_intermediate_path));
802  EXPECT_CALL(*download_file, FullPath())
803      .WillOnce(Return(base::FilePath(new_intermediate_path)));
804  EXPECT_CALL(*download_file, Detach());
805
806  callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
807               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
808  RunAllPendingInMessageLoops();
809  // All the callbacks should have happened by now.
810  ::testing::Mock::VerifyAndClearExpectations(download_file);
811  mock_delegate()->VerifyAndClearExpectations();
812  EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
813  EXPECT_EQ(new_intermediate_path, item->GetFullPath());
814  EXPECT_EQ(final_path, item->GetTargetFilePath());
815}
816
817// As above. If the intermediate rename fails, then the interrupt reason should
818// be set to the destination error and the intermediate path should be empty.
819TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Failed) {
820  CommandLine::ForCurrentProcess()->AppendSwitch(
821      switches::kEnableDownloadResumption);
822  DownloadItemImpl* item = CreateDownloadItem();
823  DownloadItemImplDelegate::DownloadTargetCallback callback;
824  MockDownloadFile* download_file =
825      AddDownloadFileToDownloadItem(item, &callback);
826  item->DestinationObserverAsWeakPtr()->DestinationError(
827      DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
828  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
829
830  base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
831  base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
832  base::FilePath new_intermediate_path(
833      final_path.InsertBeforeExtensionASCII("y"));
834  EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
835      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
836                                       new_intermediate_path));
837  EXPECT_CALL(*download_file, Cancel())
838      .Times(1);
839
840  callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
841               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
842  RunAllPendingInMessageLoops();
843  // All the callbacks should have happened by now.
844  ::testing::Mock::VerifyAndClearExpectations(download_file);
845  mock_delegate()->VerifyAndClearExpectations();
846  EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
847  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, item->GetLastReason());
848  EXPECT_TRUE(item->GetFullPath().empty());
849  EXPECT_EQ(final_path, item->GetTargetFilePath());
850}
851
852TEST_F(DownloadItemTest, Canceled) {
853  DownloadItemImpl* item = CreateDownloadItem();
854  MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
855
856  // Confirm cancel sets state properly.
857  EXPECT_CALL(*download_file, Cancel());
858  item->Cancel(true);
859  EXPECT_EQ(DownloadItem::CANCELLED, item->GetState());
860}
861
862TEST_F(DownloadItemTest, FileRemoved) {
863  DownloadItemImpl* item = CreateDownloadItem();
864
865  EXPECT_FALSE(item->GetFileExternallyRemoved());
866  item->OnDownloadedFileRemoved();
867  EXPECT_TRUE(item->GetFileExternallyRemoved());
868}
869
870TEST_F(DownloadItemTest, DestinationUpdate) {
871  DownloadItemImpl* item = CreateDownloadItem();
872  base::WeakPtr<DownloadDestinationObserver> as_observer(
873      item->DestinationObserverAsWeakPtr());
874  MockObserver observer(item);
875
876  EXPECT_EQ(0l, item->CurrentSpeed());
877  EXPECT_EQ("", item->GetHashState());
878  EXPECT_EQ(0l, item->GetReceivedBytes());
879  EXPECT_EQ(0l, item->GetTotalBytes());
880  EXPECT_FALSE(observer.CheckUpdated());
881  item->SetTotalBytes(100l);
882  EXPECT_EQ(100l, item->GetTotalBytes());
883
884  as_observer->DestinationUpdate(10, 20, "deadbeef");
885  EXPECT_EQ(20l, item->CurrentSpeed());
886  EXPECT_EQ("deadbeef", item->GetHashState());
887  EXPECT_EQ(10l, item->GetReceivedBytes());
888  EXPECT_EQ(100l, item->GetTotalBytes());
889  EXPECT_TRUE(observer.CheckUpdated());
890
891  as_observer->DestinationUpdate(200, 20, "livebeef");
892  EXPECT_EQ(20l, item->CurrentSpeed());
893  EXPECT_EQ("livebeef", item->GetHashState());
894  EXPECT_EQ(200l, item->GetReceivedBytes());
895  EXPECT_EQ(0l, item->GetTotalBytes());
896  EXPECT_TRUE(observer.CheckUpdated());
897}
898
899TEST_F(DownloadItemTest, DestinationError) {
900  DownloadItemImpl* item = CreateDownloadItem();
901  MockDownloadFile* download_file =
902      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
903  base::WeakPtr<DownloadDestinationObserver> as_observer(
904      item->DestinationObserverAsWeakPtr());
905  MockObserver observer(item);
906
907  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
908  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, item->GetLastReason());
909  EXPECT_FALSE(observer.CheckUpdated());
910
911  EXPECT_CALL(*download_file, Cancel());
912  as_observer->DestinationError(
913      DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
914  mock_delegate()->VerifyAndClearExpectations();
915  EXPECT_TRUE(observer.CheckUpdated());
916  EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
917  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
918            item->GetLastReason());
919}
920
921TEST_F(DownloadItemTest, DestinationCompleted) {
922  DownloadItemImpl* item = CreateDownloadItem();
923  base::WeakPtr<DownloadDestinationObserver> as_observer(
924      item->DestinationObserverAsWeakPtr());
925  MockObserver observer(item);
926
927  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
928  EXPECT_EQ("", item->GetHash());
929  EXPECT_EQ("", item->GetHashState());
930  EXPECT_FALSE(item->AllDataSaved());
931  EXPECT_FALSE(observer.CheckUpdated());
932
933  as_observer->DestinationUpdate(10, 20, "deadbeef");
934  EXPECT_TRUE(observer.CheckUpdated());
935  EXPECT_FALSE(observer.CheckUpdated()); // Confirm reset.
936  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
937  EXPECT_EQ("", item->GetHash());
938  EXPECT_EQ("deadbeef", item->GetHashState());
939  EXPECT_FALSE(item->AllDataSaved());
940
941  as_observer->DestinationCompleted("livebeef");
942  mock_delegate()->VerifyAndClearExpectations();
943  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
944  EXPECT_TRUE(observer.CheckUpdated());
945  EXPECT_EQ("livebeef", item->GetHash());
946  EXPECT_EQ("", item->GetHashState());
947  EXPECT_TRUE(item->AllDataSaved());
948}
949
950TEST_F(DownloadItemTest, EnabledActionsForNormalDownload) {
951  DownloadItemImpl* item = CreateDownloadItem();
952  MockDownloadFile* download_file =
953      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
954
955  // InProgress
956  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
957  ASSERT_FALSE(item->GetTargetFilePath().empty());
958  EXPECT_TRUE(item->CanShowInFolder());
959  EXPECT_TRUE(item->CanOpenDownload());
960
961  // Complete
962  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
963      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
964                                       base::FilePath(kDummyPath)));
965  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
966      .WillOnce(Return(true));
967  EXPECT_CALL(*download_file, FullPath())
968      .WillOnce(Return(base::FilePath()));
969  EXPECT_CALL(*download_file, Detach());
970  item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
971  RunAllPendingInMessageLoops();
972
973  ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
974  EXPECT_TRUE(item->CanShowInFolder());
975  EXPECT_TRUE(item->CanOpenDownload());
976}
977
978TEST_F(DownloadItemTest, EnabledActionsForTemporaryDownload) {
979  DownloadItemImpl* item = CreateDownloadItem();
980  MockDownloadFile* download_file =
981      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
982  item->SetIsTemporary(true);
983
984  // InProgress Temporary
985  ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
986  ASSERT_FALSE(item->GetTargetFilePath().empty());
987  ASSERT_TRUE(item->IsTemporary());
988  EXPECT_FALSE(item->CanShowInFolder());
989  EXPECT_FALSE(item->CanOpenDownload());
990
991  // Complete Temporary
992  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
993      .WillOnce(Return(true));
994  EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
995      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
996                                       base::FilePath(kDummyPath)));
997  EXPECT_CALL(*download_file, FullPath())
998      .WillOnce(Return(base::FilePath()));
999  EXPECT_CALL(*download_file, Detach());
1000  item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1001  RunAllPendingInMessageLoops();
1002
1003  ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
1004  EXPECT_FALSE(item->CanShowInFolder());
1005  EXPECT_FALSE(item->CanOpenDownload());
1006}
1007
1008TEST_F(DownloadItemTest, EnabledActionsForInterruptedDownload) {
1009  DownloadItemImpl* item = CreateDownloadItem();
1010  MockDownloadFile* download_file =
1011      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1012
1013  EXPECT_CALL(*download_file, Cancel());
1014  item->DestinationObserverAsWeakPtr()->DestinationError(
1015      DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
1016  RunAllPendingInMessageLoops();
1017
1018  ASSERT_EQ(DownloadItem::INTERRUPTED, item->GetState());
1019  ASSERT_FALSE(item->GetTargetFilePath().empty());
1020  EXPECT_FALSE(item->CanShowInFolder());
1021  EXPECT_FALSE(item->CanOpenDownload());
1022}
1023
1024TEST_F(DownloadItemTest, EnabledActionsForCancelledDownload) {
1025  DownloadItemImpl* item = CreateDownloadItem();
1026  MockDownloadFile* download_file =
1027      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1028
1029  EXPECT_CALL(*download_file, Cancel());
1030  item->Cancel(true);
1031  RunAllPendingInMessageLoops();
1032
1033  ASSERT_EQ(DownloadItem::CANCELLED, item->GetState());
1034  EXPECT_FALSE(item->CanShowInFolder());
1035  EXPECT_FALSE(item->CanOpenDownload());
1036}
1037
1038// Test various aspects of the delegate completion blocker.
1039
1040// Just allowing completion.
1041TEST_F(DownloadItemTest, CompleteDelegate_ReturnTrue) {
1042  // Test to confirm that if we have a callback that returns true,
1043  // we complete immediately.
1044  DownloadItemImpl* item = CreateDownloadItem();
1045  MockDownloadFile* download_file =
1046      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1047
1048  // Drive the delegate interaction.
1049  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1050      .WillOnce(Return(true));
1051  item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1052  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1053  EXPECT_FALSE(item->IsDangerous());
1054
1055  // Make sure the download can complete.
1056  EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1057      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1058                                       base::FilePath(kDummyPath)));
1059  EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1060      .WillOnce(Return(true));
1061  EXPECT_CALL(*download_file, FullPath())
1062      .WillOnce(Return(base::FilePath()));
1063  EXPECT_CALL(*download_file, Detach());
1064  RunAllPendingInMessageLoops();
1065  EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1066}
1067
1068// Just delaying completion.
1069TEST_F(DownloadItemTest, CompleteDelegate_BlockOnce) {
1070  // Test to confirm that if we have a callback that returns true,
1071  // we complete immediately.
1072  DownloadItemImpl* item = CreateDownloadItem();
1073  MockDownloadFile* download_file =
1074      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1075
1076  // Drive the delegate interaction.
1077  base::Closure delegate_callback;
1078  base::Closure copy_delegate_callback;
1079  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1080      .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1081                      Return(false)))
1082      .WillOnce(Return(true));
1083  item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1084  ASSERT_FALSE(delegate_callback.is_null());
1085  copy_delegate_callback = delegate_callback;
1086  delegate_callback.Reset();
1087  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1088  copy_delegate_callback.Run();
1089  ASSERT_TRUE(delegate_callback.is_null());
1090  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1091  EXPECT_FALSE(item->IsDangerous());
1092
1093  // Make sure the download can complete.
1094  EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1095      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1096                                       base::FilePath(kDummyPath)));
1097  EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1098      .WillOnce(Return(true));
1099  EXPECT_CALL(*download_file, FullPath())
1100      .WillOnce(Return(base::FilePath()));
1101  EXPECT_CALL(*download_file, Detach());
1102  RunAllPendingInMessageLoops();
1103  EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1104}
1105
1106// Delay and set danger.
1107TEST_F(DownloadItemTest, CompleteDelegate_SetDanger) {
1108  // Test to confirm that if we have a callback that returns true,
1109  // we complete immediately.
1110  DownloadItemImpl* item = CreateDownloadItem();
1111  MockDownloadFile* download_file =
1112      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1113
1114  // Drive the delegate interaction.
1115  base::Closure delegate_callback;
1116  base::Closure copy_delegate_callback;
1117  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1118      .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1119                      Return(false)))
1120      .WillOnce(Return(true));
1121  item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1122  ASSERT_FALSE(delegate_callback.is_null());
1123  copy_delegate_callback = delegate_callback;
1124  delegate_callback.Reset();
1125  EXPECT_FALSE(item->IsDangerous());
1126  item->OnContentCheckCompleted(
1127      content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1128  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1129  copy_delegate_callback.Run();
1130  ASSERT_TRUE(delegate_callback.is_null());
1131  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1132  EXPECT_TRUE(item->IsDangerous());
1133
1134  // Make sure the download doesn't complete until we've validated it.
1135  EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1136      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1137                                       base::FilePath(kDummyPath)));
1138  EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1139      .WillOnce(Return(true));
1140  EXPECT_CALL(*download_file, FullPath())
1141      .WillOnce(Return(base::FilePath()));
1142  EXPECT_CALL(*download_file, Detach());
1143  RunAllPendingInMessageLoops();
1144  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1145  EXPECT_TRUE(item->IsDangerous());
1146
1147  item->ValidateDangerousDownload();
1148  EXPECT_EQ(DOWNLOAD_DANGER_TYPE_USER_VALIDATED, item->GetDangerType());
1149  RunAllPendingInMessageLoops();
1150  EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1151}
1152
1153// Just delaying completion twice.
1154TEST_F(DownloadItemTest, CompleteDelegate_BlockTwice) {
1155  // Test to confirm that if we have a callback that returns true,
1156  // we complete immediately.
1157  DownloadItemImpl* item = CreateDownloadItem();
1158  MockDownloadFile* download_file =
1159      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1160
1161  // Drive the delegate interaction.
1162  base::Closure delegate_callback;
1163  base::Closure copy_delegate_callback;
1164  EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1165      .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1166                      Return(false)))
1167      .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1168                      Return(false)))
1169      .WillOnce(Return(true));
1170  item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1171  ASSERT_FALSE(delegate_callback.is_null());
1172  copy_delegate_callback = delegate_callback;
1173  delegate_callback.Reset();
1174  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1175  copy_delegate_callback.Run();
1176  ASSERT_FALSE(delegate_callback.is_null());
1177  copy_delegate_callback = delegate_callback;
1178  delegate_callback.Reset();
1179  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1180  copy_delegate_callback.Run();
1181  ASSERT_TRUE(delegate_callback.is_null());
1182  EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1183  EXPECT_FALSE(item->IsDangerous());
1184
1185  // Make sure the download can complete.
1186  EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1187      .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1188                                       base::FilePath(kDummyPath)));
1189  EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1190      .WillOnce(Return(true));
1191  EXPECT_CALL(*download_file, FullPath())
1192      .WillOnce(Return(base::FilePath()));
1193  EXPECT_CALL(*download_file, Detach());
1194  RunAllPendingInMessageLoops();
1195  EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1196}
1197
1198TEST_F(DownloadItemTest, StealDangerousDownload) {
1199  DownloadItemImpl* item = CreateDownloadItem();
1200  MockDownloadFile* download_file =
1201      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1202  ASSERT_TRUE(item->IsDangerous());
1203  base::FilePath full_path(FILE_PATH_LITERAL("foo.txt"));
1204  base::FilePath returned_path;
1205
1206  EXPECT_CALL(*download_file, FullPath())
1207      .WillOnce(Return(full_path));
1208  EXPECT_CALL(*download_file, Detach());
1209  EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
1210  base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
1211  item->StealDangerousDownload(
1212      base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
1213                 weak_ptr_factory.GetWeakPtr(),
1214                 base::Unretained(&returned_path)));
1215  RunAllPendingInMessageLoops();
1216  EXPECT_EQ(full_path, returned_path);
1217}
1218
1219TEST_F(DownloadItemTest, StealInterruptedDangerousDownload) {
1220  CommandLine::ForCurrentProcess()->AppendSwitch(
1221      switches::kEnableDownloadResumption);
1222  base::FilePath returned_path;
1223  DownloadItemImpl* item = CreateDownloadItem();
1224  MockDownloadFile* download_file =
1225      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1226  base::FilePath full_path = item->GetFullPath();
1227  EXPECT_FALSE(full_path.empty());
1228  EXPECT_CALL(*download_file, FullPath())
1229      .WillOnce(Return(full_path));
1230  EXPECT_CALL(*download_file, Detach());
1231  item->DestinationObserverAsWeakPtr()->DestinationError(
1232      DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
1233  ASSERT_TRUE(item->IsDangerous());
1234
1235  EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
1236  base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
1237  item->StealDangerousDownload(
1238      base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
1239                 weak_ptr_factory.GetWeakPtr(),
1240                 base::Unretained(&returned_path)));
1241  RunAllPendingInMessageLoops();
1242  EXPECT_EQ(full_path, returned_path);
1243}
1244
1245TEST_F(DownloadItemTest, StealInterruptedNonResumableDangerousDownload) {
1246  CommandLine::ForCurrentProcess()->AppendSwitch(
1247      switches::kEnableDownloadResumption);
1248  base::FilePath returned_path;
1249  DownloadItemImpl* item = CreateDownloadItem();
1250  MockDownloadFile* download_file =
1251      DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1252  EXPECT_CALL(*download_file, Cancel());
1253  item->DestinationObserverAsWeakPtr()->DestinationError(
1254      DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
1255  ASSERT_TRUE(item->IsDangerous());
1256
1257  EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
1258  base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
1259  item->StealDangerousDownload(
1260      base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
1261                 weak_ptr_factory.GetWeakPtr(),
1262                 base::Unretained(&returned_path)));
1263  RunAllPendingInMessageLoops();
1264  EXPECT_TRUE(returned_path.empty());
1265}
1266
1267TEST(MockDownloadItem, Compiles) {
1268  MockDownloadItem mock_item;
1269}
1270
1271}  // namespace content
1272