- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / download / download_item_impl_unittest.cc
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
26 using ::testing::_;
27 using ::testing::NiceMock;
28 using ::testing::Property;
29 using ::testing::Return;
30 using ::testing::SaveArg;
31 using ::testing::StrictMock;
32
33 const int kDownloadChunkSize = 1000;
34 const int kDownloadSpeed = 1000;
35 const base::FilePath::CharType kDummyPath[] = FILE_PATH_LITERAL("/testpath");
36
37 namespace content {
38
39 namespace {
40
41 class 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
85 class 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));
101 ACTION_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
109 class 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
341 TEST_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
350 TEST_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
369 TEST_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
380 TEST_F(DownloadItemTest, NotificationAfterDownloadedFileRemoved) {
381   DownloadItemImpl* item = CreateDownloadItem();
382   MockObserver observer(item);
383
384   item->OnDownloadedFileRemoved();
385   ASSERT_TRUE(observer.CheckUpdated());
386 }
387
388 TEST_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
403 TEST_F(DownloadItemTest, NotificationAfterDestroyed) {
404   DownloadItemImpl* item = CreateDownloadItem();
405   MockObserver observer(item);
406
407   DestroyDownloadItem(item);
408   ASSERT_TRUE(observer.CheckDestroyed());
409 }
410
411 TEST_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.
439 TEST_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
462 TEST_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
526 TEST_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
538 TEST_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.
579 TEST_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
605 TEST_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
630 TEST_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.
654 TEST_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.
669 TEST_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.
705 TEST_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
728 TEST_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.
751 TEST_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.
784 TEST_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.
819 TEST_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
852 TEST_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
862 TEST_F(DownloadItemTest, FileRemoved) {
863   DownloadItemImpl* item = CreateDownloadItem();
864
865   EXPECT_FALSE(item->GetFileExternallyRemoved());
866   item->OnDownloadedFileRemoved();
867   EXPECT_TRUE(item->GetFileExternallyRemoved());
868 }
869
870 TEST_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
899 TEST_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
921 TEST_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
950 TEST_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
978 TEST_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
1008 TEST_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
1024 TEST_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.
1041 TEST_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.
1069 TEST_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.
1107 TEST_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.
1154 TEST_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
1198 TEST_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
1219 TEST_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
1245 TEST_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
1267 TEST(MockDownloadItem, Compiles) {
1268   MockDownloadItem mock_item;
1269 }
1270
1271 }  // namespace content