Update To 11.40.268.0
[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     ~MockObserver() override {
125       if (item_) item_->RemoveObserver(this);
126     }
127
128     void OnDownloadRemoved(DownloadItem* download) override {
129       DVLOG(20) << " " << __FUNCTION__
130                 << " download = " << download->DebugString(false);
131       removed_ = true;
132     }
133
134     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     void OnDownloadOpened(DownloadItem* download) override {
151       DVLOG(20) << " " << __FUNCTION__
152                 << " download = " << download->DebugString(false);
153     }
154
155     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   base::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   base::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 // Check we do correct cleanup for RESUME_MODE_INVALID interrupts.
463 TEST_F(DownloadItemTest, UnresumableInterrupt) {
464   base::CommandLine::ForCurrentProcess()->AppendSwitch(
465       switches::kEnableDownloadResumption);
466
467   DownloadItemImpl* item = CreateDownloadItem();
468   MockObserver observer(item);
469   DownloadItemImplDelegate::DownloadTargetCallback callback;
470   MockDownloadFile* download_file =
471       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
472
473   // Fail final rename with unresumable reason.
474   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
475       .WillOnce(Return(true));
476   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
477       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED,
478                                        base::FilePath(kDummyPath)));
479   EXPECT_CALL(*download_file, Cancel());
480
481   // Complete download to trigger final rename.
482   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
483   RunAllPendingInMessageLoops();
484
485   ASSERT_TRUE(observer.CheckUpdated());
486   // Should not try to auto-resume.
487   ASSERT_EQ(1, observer.GetInterruptCount());
488   ASSERT_EQ(0, observer.GetResumeCount());
489
490   CleanupItem(item, download_file, DownloadItem::INTERRUPTED);
491 }
492
493 TEST_F(DownloadItemTest, LimitRestartsAfterInterrupted) {
494   base::CommandLine::ForCurrentProcess()->AppendSwitch(
495       switches::kEnableDownloadResumption);
496
497   DownloadItemImpl* item = CreateDownloadItem();
498   base::WeakPtr<DownloadDestinationObserver> as_observer(
499       item->DestinationObserverAsWeakPtr());
500   MockObserver observer(item);
501   MockDownloadFile* mock_download_file(NULL);
502   scoped_ptr<DownloadFile> download_file;
503   MockRequestHandle* mock_request_handle(NULL);
504   scoped_ptr<DownloadRequestHandleInterface> request_handle;
505   DownloadItemImplDelegate::DownloadTargetCallback callback;
506
507   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _))
508       .WillRepeatedly(SaveArg<1>(&callback));
509   for (int i = 0; i < (DownloadItemImpl::kMaxAutoResumeAttempts + 1); ++i) {
510     DVLOG(20) << "Loop iteration " << i;
511
512     mock_download_file = new NiceMock<MockDownloadFile>;
513     download_file.reset(mock_download_file);
514     mock_request_handle = new NiceMock<MockRequestHandle>;
515     request_handle.reset(mock_request_handle);
516
517     ON_CALL(*mock_download_file, FullPath())
518         .WillByDefault(Return(base::FilePath()));
519
520     // It's too complicated to set up a WebContents instance that would cause
521     // the MockDownloadItemDelegate's ResumeInterruptedDownload() function
522     // to be callled, so we simply verify that GetWebContents() is called.
523     if (i < (DownloadItemImpl::kMaxAutoResumeAttempts - 1)) {
524       EXPECT_CALL(*mock_request_handle, GetWebContents())
525           .WillRepeatedly(Return(static_cast<WebContents*>(NULL)));
526     }
527
528     // Copied key parts of DoIntermediateRename & AddDownloadFileToDownloadItem
529     // to allow for holding onto the request handle.
530     item->Start(download_file.Pass(), request_handle.Pass());
531     RunAllPendingInMessageLoops();
532     if (i == 0) {
533       // Target determination is only done the first time through.
534       base::FilePath target_path(kDummyPath);
535       base::FilePath intermediate_path(
536           target_path.InsertBeforeExtensionASCII("x"));
537       EXPECT_CALL(*mock_download_file, RenameAndUniquify(intermediate_path, _))
538           .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
539                                            intermediate_path));
540       callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
541                    DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
542       RunAllPendingInMessageLoops();
543     }
544     ASSERT_EQ(i, observer.GetResumeCount());
545
546     // Use a continuable interrupt.
547     item->DestinationObserverAsWeakPtr()->DestinationError(
548         DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR);
549
550     ASSERT_EQ(i + 1, observer.GetInterruptCount());
551     ::testing::Mock::VerifyAndClearExpectations(mock_download_file);
552   }
553
554   CleanupItem(item, mock_download_file, DownloadItem::INTERRUPTED);
555 }
556
557 TEST_F(DownloadItemTest, NotificationAfterRemove) {
558   DownloadItemImpl* item = CreateDownloadItem();
559   MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
560   EXPECT_CALL(*download_file, Cancel());
561   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
562   MockObserver observer(item);
563
564   item->Remove();
565   ASSERT_TRUE(observer.CheckUpdated());
566   ASSERT_TRUE(observer.CheckRemoved());
567 }
568
569 TEST_F(DownloadItemTest, NotificationAfterOnContentCheckCompleted) {
570   // Setting to NOT_DANGEROUS does not trigger a notification.
571   DownloadItemImpl* safe_item = CreateDownloadItem();
572   MockObserver safe_observer(safe_item);
573
574   safe_item->OnAllDataSaved(std::string());
575   EXPECT_TRUE(safe_observer.CheckUpdated());
576   safe_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
577   EXPECT_TRUE(safe_observer.CheckUpdated());
578
579   // Setting to unsafe url or unsafe file should trigger a notification.
580   DownloadItemImpl* unsafeurl_item =
581       CreateDownloadItem();
582   MockObserver unsafeurl_observer(unsafeurl_item);
583
584   unsafeurl_item->OnAllDataSaved(std::string());
585   EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
586   unsafeurl_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_URL);
587   EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
588
589   unsafeurl_item->ValidateDangerousDownload();
590   EXPECT_TRUE(unsafeurl_observer.CheckUpdated());
591
592   DownloadItemImpl* unsafefile_item =
593       CreateDownloadItem();
594   MockObserver unsafefile_observer(unsafefile_item);
595
596   unsafefile_item->OnAllDataSaved(std::string());
597   EXPECT_TRUE(unsafefile_observer.CheckUpdated());
598   unsafefile_item->OnContentCheckCompleted(DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
599   EXPECT_TRUE(unsafefile_observer.CheckUpdated());
600
601   unsafefile_item->ValidateDangerousDownload();
602   EXPECT_TRUE(unsafefile_observer.CheckUpdated());
603 }
604
605 // DownloadItemImpl::OnDownloadTargetDetermined will schedule a task to run
606 // DownloadFile::Rename(). Once the rename
607 // completes, DownloadItemImpl receives a notification with the new file
608 // name. Check that observers are updated when the new filename is available and
609 // not before.
610 TEST_F(DownloadItemTest, NotificationAfterOnDownloadTargetDetermined) {
611   DownloadItemImpl* item = CreateDownloadItem();
612   DownloadItemImplDelegate::DownloadTargetCallback callback;
613   MockDownloadFile* download_file =
614       AddDownloadFileToDownloadItem(item, &callback);
615   MockObserver observer(item);
616   base::FilePath target_path(kDummyPath);
617   base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
618   base::FilePath new_intermediate_path(
619       target_path.InsertBeforeExtensionASCII("y"));
620   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
621       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
622                                        new_intermediate_path));
623
624   // Currently, a notification would be generated if the danger type is anything
625   // other than NOT_DANGEROUS.
626   callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
627                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
628   EXPECT_FALSE(observer.CheckUpdated());
629   RunAllPendingInMessageLoops();
630   EXPECT_TRUE(observer.CheckUpdated());
631   EXPECT_EQ(new_intermediate_path, item->GetFullPath());
632
633   CleanupItem(item, download_file, DownloadItem::IN_PROGRESS);
634 }
635
636 TEST_F(DownloadItemTest, NotificationAfterTogglePause) {
637   DownloadItemImpl* item = CreateDownloadItem();
638   MockObserver observer(item);
639   MockDownloadFile* mock_download_file(new MockDownloadFile);
640   scoped_ptr<DownloadFile> download_file(mock_download_file);
641   scoped_ptr<DownloadRequestHandleInterface> request_handle(
642       new NiceMock<MockRequestHandle>);
643
644   EXPECT_CALL(*mock_download_file, Initialize(_));
645   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _));
646   item->Start(download_file.Pass(), request_handle.Pass());
647
648   item->Pause();
649   ASSERT_TRUE(observer.CheckUpdated());
650
651   ASSERT_TRUE(item->IsPaused());
652
653   item->Resume();
654   ASSERT_TRUE(observer.CheckUpdated());
655
656   RunAllPendingInMessageLoops();
657
658   CleanupItem(item, mock_download_file, DownloadItem::IN_PROGRESS);
659 }
660
661 TEST_F(DownloadItemTest, DisplayName) {
662   DownloadItemImpl* item = CreateDownloadItem();
663   DownloadItemImplDelegate::DownloadTargetCallback callback;
664   MockDownloadFile* download_file =
665       AddDownloadFileToDownloadItem(item, &callback);
666   base::FilePath target_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
667   base::FilePath intermediate_path(target_path.InsertBeforeExtensionASCII("x"));
668   EXPECT_EQ(FILE_PATH_LITERAL(""),
669             item->GetFileNameToReportUser().value());
670   EXPECT_CALL(*download_file, RenameAndUniquify(_, _))
671       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
672                                        intermediate_path));
673   callback.Run(target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
674                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
675   RunAllPendingInMessageLoops();
676   EXPECT_EQ(FILE_PATH_LITERAL("foo.bar"),
677             item->GetFileNameToReportUser().value());
678   item->SetDisplayName(base::FilePath(FILE_PATH_LITERAL("new.name")));
679   EXPECT_EQ(FILE_PATH_LITERAL("new.name"),
680             item->GetFileNameToReportUser().value());
681   CleanupItem(item, download_file, DownloadItem::IN_PROGRESS);
682 }
683
684 // Test to make sure that Start method calls DF initialize properly.
685 TEST_F(DownloadItemTest, Start) {
686   MockDownloadFile* mock_download_file(new MockDownloadFile);
687   scoped_ptr<DownloadFile> download_file(mock_download_file);
688   DownloadItemImpl* item = CreateDownloadItem();
689   EXPECT_CALL(*mock_download_file, Initialize(_));
690   scoped_ptr<DownloadRequestHandleInterface> request_handle(
691       new NiceMock<MockRequestHandle>);
692   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
693   item->Start(download_file.Pass(), request_handle.Pass());
694   RunAllPendingInMessageLoops();
695
696   CleanupItem(item, mock_download_file, DownloadItem::IN_PROGRESS);
697 }
698
699 // Test that the delegate is invoked after the download file is renamed.
700 TEST_F(DownloadItemTest, CallbackAfterRename) {
701   DownloadItemImpl* item = CreateDownloadItem();
702   DownloadItemImplDelegate::DownloadTargetCallback callback;
703   MockDownloadFile* download_file =
704       AddDownloadFileToDownloadItem(item, &callback);
705   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
706   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
707   base::FilePath new_intermediate_path(
708       final_path.InsertBeforeExtensionASCII("y"));
709   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
710       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
711                                        new_intermediate_path));
712
713   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
714                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
715   RunAllPendingInMessageLoops();
716   // All the callbacks should have happened by now.
717   ::testing::Mock::VerifyAndClearExpectations(download_file);
718   mock_delegate()->VerifyAndClearExpectations();
719
720   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
721       .WillOnce(Return(true));
722   EXPECT_CALL(*download_file, RenameAndAnnotate(final_path, _))
723       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
724                                        final_path));
725   EXPECT_CALL(*download_file, FullPath())
726       .WillOnce(Return(base::FilePath()));
727   EXPECT_CALL(*download_file, Detach());
728   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
729   RunAllPendingInMessageLoops();
730   ::testing::Mock::VerifyAndClearExpectations(download_file);
731   mock_delegate()->VerifyAndClearExpectations();
732 }
733
734 // Test that the delegate is invoked after the download file is renamed and the
735 // download item is in an interrupted state.
736 TEST_F(DownloadItemTest, CallbackAfterInterruptedRename) {
737   DownloadItemImpl* item = CreateDownloadItem();
738   DownloadItemImplDelegate::DownloadTargetCallback callback;
739   MockDownloadFile* download_file =
740       AddDownloadFileToDownloadItem(item, &callback);
741   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
742   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
743   base::FilePath new_intermediate_path(
744       final_path.InsertBeforeExtensionASCII("y"));
745   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
746       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
747                                        new_intermediate_path));
748   EXPECT_CALL(*download_file, Cancel())
749       .Times(1);
750
751   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
752                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
753   RunAllPendingInMessageLoops();
754   // All the callbacks should have happened by now.
755   ::testing::Mock::VerifyAndClearExpectations(download_file);
756   mock_delegate()->VerifyAndClearExpectations();
757 }
758
759 TEST_F(DownloadItemTest, Interrupted) {
760   DownloadItemImpl* item = CreateDownloadItem();
761   MockDownloadFile* download_file =
762       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
763
764   const DownloadInterruptReason reason(
765       DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
766
767   // Confirm interrupt sets state properly.
768   EXPECT_CALL(*download_file, Cancel());
769   item->DestinationObserverAsWeakPtr()->DestinationError(reason);
770   RunAllPendingInMessageLoops();
771   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
772   EXPECT_EQ(reason, item->GetLastReason());
773
774   // Cancel should kill it.
775   item->Cancel(true);
776   EXPECT_EQ(DownloadItem::CANCELLED, item->GetState());
777   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, item->GetLastReason());
778 }
779
780 // Destination errors that occur before the intermediate rename shouldn't cause
781 // the download to be marked as interrupted until after the intermediate rename.
782 TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Restart) {
783   DownloadItemImpl* item = CreateDownloadItem();
784   DownloadItemImplDelegate::DownloadTargetCallback callback;
785   MockDownloadFile* download_file =
786       AddDownloadFileToDownloadItem(item, &callback);
787   item->DestinationObserverAsWeakPtr()->DestinationError(
788       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
789   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
790
791   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
792   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
793   base::FilePath new_intermediate_path(
794       final_path.InsertBeforeExtensionASCII("y"));
795   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
796       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
797                                        new_intermediate_path));
798   EXPECT_CALL(*download_file, Cancel())
799       .Times(1);
800
801   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
802                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
803   RunAllPendingInMessageLoops();
804   // All the callbacks should have happened by now.
805   ::testing::Mock::VerifyAndClearExpectations(download_file);
806   mock_delegate()->VerifyAndClearExpectations();
807   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
808   EXPECT_TRUE(item->GetFullPath().empty());
809   EXPECT_EQ(final_path, item->GetTargetFilePath());
810 }
811
812 // As above. But if the download can be resumed by continuing, then the
813 // intermediate path should be retained when the download is interrupted after
814 // the intermediate rename succeeds.
815 TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Continue) {
816   base::CommandLine::ForCurrentProcess()->AppendSwitch(
817       switches::kEnableDownloadResumption);
818   DownloadItemImpl* item = CreateDownloadItem();
819   DownloadItemImplDelegate::DownloadTargetCallback callback;
820   MockDownloadFile* download_file =
821       AddDownloadFileToDownloadItem(item, &callback);
822   item->DestinationObserverAsWeakPtr()->DestinationError(
823       DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
824   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
825
826   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
827   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
828   base::FilePath new_intermediate_path(
829       final_path.InsertBeforeExtensionASCII("y"));
830   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
831       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
832                                        new_intermediate_path));
833   EXPECT_CALL(*download_file, FullPath())
834       .WillOnce(Return(base::FilePath(new_intermediate_path)));
835   EXPECT_CALL(*download_file, Detach());
836
837   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
838                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
839   RunAllPendingInMessageLoops();
840   // All the callbacks should have happened by now.
841   ::testing::Mock::VerifyAndClearExpectations(download_file);
842   mock_delegate()->VerifyAndClearExpectations();
843   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
844   EXPECT_EQ(new_intermediate_path, item->GetFullPath());
845   EXPECT_EQ(final_path, item->GetTargetFilePath());
846 }
847
848 // As above. If the intermediate rename fails, then the interrupt reason should
849 // be set to the destination error and the intermediate path should be empty.
850 TEST_F(DownloadItemTest, InterruptedBeforeIntermediateRename_Failed) {
851   base::CommandLine::ForCurrentProcess()->AppendSwitch(
852       switches::kEnableDownloadResumption);
853   DownloadItemImpl* item = CreateDownloadItem();
854   DownloadItemImplDelegate::DownloadTargetCallback callback;
855   MockDownloadFile* download_file =
856       AddDownloadFileToDownloadItem(item, &callback);
857   item->DestinationObserverAsWeakPtr()->DestinationError(
858       DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
859   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
860
861   base::FilePath final_path(base::FilePath(kDummyPath).AppendASCII("foo.bar"));
862   base::FilePath intermediate_path(final_path.InsertBeforeExtensionASCII("x"));
863   base::FilePath new_intermediate_path(
864       final_path.InsertBeforeExtensionASCII("y"));
865   EXPECT_CALL(*download_file, RenameAndUniquify(intermediate_path, _))
866       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED,
867                                        new_intermediate_path));
868   EXPECT_CALL(*download_file, Cancel())
869       .Times(1);
870
871   callback.Run(final_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
872                DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, intermediate_path);
873   RunAllPendingInMessageLoops();
874   // All the callbacks should have happened by now.
875   ::testing::Mock::VerifyAndClearExpectations(download_file);
876   mock_delegate()->VerifyAndClearExpectations();
877   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
878   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED, item->GetLastReason());
879   EXPECT_TRUE(item->GetFullPath().empty());
880   EXPECT_EQ(final_path, item->GetTargetFilePath());
881 }
882
883 TEST_F(DownloadItemTest, Canceled) {
884   DownloadItemImpl* item = CreateDownloadItem();
885   MockDownloadFile* download_file = AddDownloadFileToDownloadItem(item, NULL);
886
887   // Confirm cancel sets state properly.
888   EXPECT_CALL(*download_file, Cancel());
889   item->Cancel(true);
890   EXPECT_EQ(DownloadItem::CANCELLED, item->GetState());
891 }
892
893 TEST_F(DownloadItemTest, FileRemoved) {
894   DownloadItemImpl* item = CreateDownloadItem();
895
896   EXPECT_FALSE(item->GetFileExternallyRemoved());
897   item->OnDownloadedFileRemoved();
898   EXPECT_TRUE(item->GetFileExternallyRemoved());
899 }
900
901 TEST_F(DownloadItemTest, DestinationUpdate) {
902   DownloadItemImpl* item = CreateDownloadItem();
903   base::WeakPtr<DownloadDestinationObserver> as_observer(
904       item->DestinationObserverAsWeakPtr());
905   MockObserver observer(item);
906
907   EXPECT_EQ(0l, item->CurrentSpeed());
908   EXPECT_EQ("", item->GetHashState());
909   EXPECT_EQ(0l, item->GetReceivedBytes());
910   EXPECT_EQ(0l, item->GetTotalBytes());
911   EXPECT_FALSE(observer.CheckUpdated());
912   item->SetTotalBytes(100l);
913   EXPECT_EQ(100l, item->GetTotalBytes());
914
915   as_observer->DestinationUpdate(10, 20, "deadbeef");
916   EXPECT_EQ(20l, item->CurrentSpeed());
917   EXPECT_EQ("deadbeef", item->GetHashState());
918   EXPECT_EQ(10l, item->GetReceivedBytes());
919   EXPECT_EQ(100l, item->GetTotalBytes());
920   EXPECT_TRUE(observer.CheckUpdated());
921
922   as_observer->DestinationUpdate(200, 20, "livebeef");
923   EXPECT_EQ(20l, item->CurrentSpeed());
924   EXPECT_EQ("livebeef", item->GetHashState());
925   EXPECT_EQ(200l, item->GetReceivedBytes());
926   EXPECT_EQ(0l, item->GetTotalBytes());
927   EXPECT_TRUE(observer.CheckUpdated());
928 }
929
930 TEST_F(DownloadItemTest, DestinationError) {
931   DownloadItemImpl* item = CreateDownloadItem();
932   MockDownloadFile* download_file =
933       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
934   base::WeakPtr<DownloadDestinationObserver> as_observer(
935       item->DestinationObserverAsWeakPtr());
936   MockObserver observer(item);
937
938   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
939   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, item->GetLastReason());
940   EXPECT_FALSE(observer.CheckUpdated());
941
942   EXPECT_CALL(*download_file, Cancel());
943   as_observer->DestinationError(
944       DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
945   mock_delegate()->VerifyAndClearExpectations();
946   EXPECT_TRUE(observer.CheckUpdated());
947   EXPECT_EQ(DownloadItem::INTERRUPTED, item->GetState());
948   EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED,
949             item->GetLastReason());
950 }
951
952 TEST_F(DownloadItemTest, DestinationCompleted) {
953   DownloadItemImpl* item = CreateDownloadItem();
954   base::WeakPtr<DownloadDestinationObserver> as_observer(
955       item->DestinationObserverAsWeakPtr());
956   MockObserver observer(item);
957
958   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
959   EXPECT_EQ("", item->GetHash());
960   EXPECT_EQ("", item->GetHashState());
961   EXPECT_FALSE(item->AllDataSaved());
962   EXPECT_FALSE(observer.CheckUpdated());
963
964   as_observer->DestinationUpdate(10, 20, "deadbeef");
965   EXPECT_TRUE(observer.CheckUpdated());
966   EXPECT_FALSE(observer.CheckUpdated()); // Confirm reset.
967   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
968   EXPECT_EQ("", item->GetHash());
969   EXPECT_EQ("deadbeef", item->GetHashState());
970   EXPECT_FALSE(item->AllDataSaved());
971
972   as_observer->DestinationCompleted("livebeef");
973   mock_delegate()->VerifyAndClearExpectations();
974   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
975   EXPECT_TRUE(observer.CheckUpdated());
976   EXPECT_EQ("livebeef", item->GetHash());
977   EXPECT_EQ("", item->GetHashState());
978   EXPECT_TRUE(item->AllDataSaved());
979 }
980
981 TEST_F(DownloadItemTest, EnabledActionsForNormalDownload) {
982   DownloadItemImpl* item = CreateDownloadItem();
983   MockDownloadFile* download_file =
984       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
985
986   // InProgress
987   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
988   ASSERT_FALSE(item->GetTargetFilePath().empty());
989   EXPECT_TRUE(item->CanShowInFolder());
990   EXPECT_TRUE(item->CanOpenDownload());
991
992   // Complete
993   EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
994       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
995                                        base::FilePath(kDummyPath)));
996   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
997       .WillOnce(Return(true));
998   EXPECT_CALL(*download_file, FullPath())
999       .WillOnce(Return(base::FilePath()));
1000   EXPECT_CALL(*download_file, Detach());
1001   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1002   RunAllPendingInMessageLoops();
1003
1004   ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
1005   EXPECT_TRUE(item->CanShowInFolder());
1006   EXPECT_TRUE(item->CanOpenDownload());
1007 }
1008
1009 TEST_F(DownloadItemTest, EnabledActionsForTemporaryDownload) {
1010   DownloadItemImpl* item = CreateDownloadItem();
1011   MockDownloadFile* download_file =
1012       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1013   item->SetIsTemporary(true);
1014
1015   // InProgress Temporary
1016   ASSERT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1017   ASSERT_FALSE(item->GetTargetFilePath().empty());
1018   ASSERT_TRUE(item->IsTemporary());
1019   EXPECT_FALSE(item->CanShowInFolder());
1020   EXPECT_FALSE(item->CanOpenDownload());
1021
1022   // Complete Temporary
1023   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1024       .WillOnce(Return(true));
1025   EXPECT_CALL(*download_file, RenameAndAnnotate(_, _))
1026       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1027                                        base::FilePath(kDummyPath)));
1028   EXPECT_CALL(*download_file, FullPath())
1029       .WillOnce(Return(base::FilePath()));
1030   EXPECT_CALL(*download_file, Detach());
1031   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1032   RunAllPendingInMessageLoops();
1033
1034   ASSERT_EQ(DownloadItem::COMPLETE, item->GetState());
1035   EXPECT_FALSE(item->CanShowInFolder());
1036   EXPECT_FALSE(item->CanOpenDownload());
1037 }
1038
1039 TEST_F(DownloadItemTest, EnabledActionsForInterruptedDownload) {
1040   DownloadItemImpl* item = CreateDownloadItem();
1041   MockDownloadFile* download_file =
1042       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1043
1044   EXPECT_CALL(*download_file, Cancel());
1045   item->DestinationObserverAsWeakPtr()->DestinationError(
1046       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
1047   RunAllPendingInMessageLoops();
1048
1049   ASSERT_EQ(DownloadItem::INTERRUPTED, item->GetState());
1050   ASSERT_FALSE(item->GetTargetFilePath().empty());
1051   EXPECT_FALSE(item->CanShowInFolder());
1052   EXPECT_FALSE(item->CanOpenDownload());
1053 }
1054
1055 TEST_F(DownloadItemTest, EnabledActionsForCancelledDownload) {
1056   DownloadItemImpl* item = CreateDownloadItem();
1057   MockDownloadFile* download_file =
1058       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1059
1060   EXPECT_CALL(*download_file, Cancel());
1061   item->Cancel(true);
1062   RunAllPendingInMessageLoops();
1063
1064   ASSERT_EQ(DownloadItem::CANCELLED, item->GetState());
1065   EXPECT_FALSE(item->CanShowInFolder());
1066   EXPECT_FALSE(item->CanOpenDownload());
1067 }
1068
1069 // Test various aspects of the delegate completion blocker.
1070
1071 // Just allowing completion.
1072 TEST_F(DownloadItemTest, CompleteDelegate_ReturnTrue) {
1073   // Test to confirm that if we have a callback that returns true,
1074   // we complete immediately.
1075   DownloadItemImpl* item = CreateDownloadItem();
1076   MockDownloadFile* download_file =
1077       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1078
1079   // Drive the delegate interaction.
1080   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1081       .WillOnce(Return(true));
1082   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1083   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1084   EXPECT_FALSE(item->IsDangerous());
1085
1086   // Make sure the download can complete.
1087   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1088       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1089                                        base::FilePath(kDummyPath)));
1090   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1091       .WillOnce(Return(true));
1092   EXPECT_CALL(*download_file, FullPath())
1093       .WillOnce(Return(base::FilePath()));
1094   EXPECT_CALL(*download_file, Detach());
1095   RunAllPendingInMessageLoops();
1096   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1097 }
1098
1099 // Just delaying completion.
1100 TEST_F(DownloadItemTest, CompleteDelegate_BlockOnce) {
1101   // Test to confirm that if we have a callback that returns true,
1102   // we complete immediately.
1103   DownloadItemImpl* item = CreateDownloadItem();
1104   MockDownloadFile* download_file =
1105       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1106
1107   // Drive the delegate interaction.
1108   base::Closure delegate_callback;
1109   base::Closure copy_delegate_callback;
1110   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1111       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1112                       Return(false)))
1113       .WillOnce(Return(true));
1114   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1115   ASSERT_FALSE(delegate_callback.is_null());
1116   copy_delegate_callback = delegate_callback;
1117   delegate_callback.Reset();
1118   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1119   copy_delegate_callback.Run();
1120   ASSERT_TRUE(delegate_callback.is_null());
1121   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1122   EXPECT_FALSE(item->IsDangerous());
1123
1124   // Make sure the download can complete.
1125   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1126       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1127                                        base::FilePath(kDummyPath)));
1128   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1129       .WillOnce(Return(true));
1130   EXPECT_CALL(*download_file, FullPath())
1131       .WillOnce(Return(base::FilePath()));
1132   EXPECT_CALL(*download_file, Detach());
1133   RunAllPendingInMessageLoops();
1134   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1135 }
1136
1137 // Delay and set danger.
1138 TEST_F(DownloadItemTest, CompleteDelegate_SetDanger) {
1139   // Test to confirm that if we have a callback that returns true,
1140   // we complete immediately.
1141   DownloadItemImpl* item = CreateDownloadItem();
1142   MockDownloadFile* download_file =
1143       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1144
1145   // Drive the delegate interaction.
1146   base::Closure delegate_callback;
1147   base::Closure copy_delegate_callback;
1148   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1149       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1150                       Return(false)))
1151       .WillOnce(Return(true));
1152   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1153   ASSERT_FALSE(delegate_callback.is_null());
1154   copy_delegate_callback = delegate_callback;
1155   delegate_callback.Reset();
1156   EXPECT_FALSE(item->IsDangerous());
1157   item->OnContentCheckCompleted(
1158       content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1159   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1160   copy_delegate_callback.Run();
1161   ASSERT_TRUE(delegate_callback.is_null());
1162   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1163   EXPECT_TRUE(item->IsDangerous());
1164
1165   // Make sure the download doesn't complete until we've validated it.
1166   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1167       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1168                                        base::FilePath(kDummyPath)));
1169   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1170       .WillOnce(Return(true));
1171   EXPECT_CALL(*download_file, FullPath())
1172       .WillOnce(Return(base::FilePath()));
1173   EXPECT_CALL(*download_file, Detach());
1174   RunAllPendingInMessageLoops();
1175   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1176   EXPECT_TRUE(item->IsDangerous());
1177
1178   item->ValidateDangerousDownload();
1179   EXPECT_EQ(DOWNLOAD_DANGER_TYPE_USER_VALIDATED, item->GetDangerType());
1180   RunAllPendingInMessageLoops();
1181   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1182 }
1183
1184 // Just delaying completion twice.
1185 TEST_F(DownloadItemTest, CompleteDelegate_BlockTwice) {
1186   // Test to confirm that if we have a callback that returns true,
1187   // we complete immediately.
1188   DownloadItemImpl* item = CreateDownloadItem();
1189   MockDownloadFile* download_file =
1190       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
1191
1192   // Drive the delegate interaction.
1193   base::Closure delegate_callback;
1194   base::Closure copy_delegate_callback;
1195   EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
1196       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1197                       Return(false)))
1198       .WillOnce(DoAll(SaveArg<1>(&delegate_callback),
1199                       Return(false)))
1200       .WillOnce(Return(true));
1201   item->DestinationObserverAsWeakPtr()->DestinationCompleted(std::string());
1202   ASSERT_FALSE(delegate_callback.is_null());
1203   copy_delegate_callback = delegate_callback;
1204   delegate_callback.Reset();
1205   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1206   copy_delegate_callback.Run();
1207   ASSERT_FALSE(delegate_callback.is_null());
1208   copy_delegate_callback = delegate_callback;
1209   delegate_callback.Reset();
1210   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1211   copy_delegate_callback.Run();
1212   ASSERT_TRUE(delegate_callback.is_null());
1213   EXPECT_EQ(DownloadItem::IN_PROGRESS, item->GetState());
1214   EXPECT_FALSE(item->IsDangerous());
1215
1216   // Make sure the download can complete.
1217   EXPECT_CALL(*download_file, RenameAndAnnotate(base::FilePath(kDummyPath), _))
1218       .WillOnce(ScheduleRenameCallback(DOWNLOAD_INTERRUPT_REASON_NONE,
1219                                        base::FilePath(kDummyPath)));
1220   EXPECT_CALL(*mock_delegate(), ShouldOpenDownload(item, _))
1221       .WillOnce(Return(true));
1222   EXPECT_CALL(*download_file, FullPath())
1223       .WillOnce(Return(base::FilePath()));
1224   EXPECT_CALL(*download_file, Detach());
1225   RunAllPendingInMessageLoops();
1226   EXPECT_EQ(DownloadItem::COMPLETE, item->GetState());
1227 }
1228
1229 TEST_F(DownloadItemTest, StealDangerousDownload) {
1230   DownloadItemImpl* item = CreateDownloadItem();
1231   MockDownloadFile* download_file =
1232       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1233   ASSERT_TRUE(item->IsDangerous());
1234   base::FilePath full_path(FILE_PATH_LITERAL("foo.txt"));
1235   base::FilePath returned_path;
1236
1237   EXPECT_CALL(*download_file, FullPath())
1238       .WillOnce(Return(full_path));
1239   EXPECT_CALL(*download_file, Detach());
1240   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
1241   base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
1242   item->StealDangerousDownload(
1243       base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
1244                  weak_ptr_factory.GetWeakPtr(),
1245                  base::Unretained(&returned_path)));
1246   RunAllPendingInMessageLoops();
1247   EXPECT_EQ(full_path, returned_path);
1248 }
1249
1250 TEST_F(DownloadItemTest, StealInterruptedDangerousDownload) {
1251   base::CommandLine::ForCurrentProcess()->AppendSwitch(
1252       switches::kEnableDownloadResumption);
1253   base::FilePath returned_path;
1254   DownloadItemImpl* item = CreateDownloadItem();
1255   MockDownloadFile* download_file =
1256       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1257   base::FilePath full_path = item->GetFullPath();
1258   EXPECT_FALSE(full_path.empty());
1259   EXPECT_CALL(*download_file, FullPath())
1260       .WillOnce(Return(full_path));
1261   EXPECT_CALL(*download_file, Detach());
1262   item->DestinationObserverAsWeakPtr()->DestinationError(
1263       DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED);
1264   ASSERT_TRUE(item->IsDangerous());
1265
1266   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
1267   base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
1268   item->StealDangerousDownload(
1269       base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
1270                  weak_ptr_factory.GetWeakPtr(),
1271                  base::Unretained(&returned_path)));
1272   RunAllPendingInMessageLoops();
1273   EXPECT_EQ(full_path, returned_path);
1274 }
1275
1276 TEST_F(DownloadItemTest, StealInterruptedNonResumableDangerousDownload) {
1277   base::CommandLine::ForCurrentProcess()->AppendSwitch(
1278       switches::kEnableDownloadResumption);
1279   base::FilePath returned_path;
1280   DownloadItemImpl* item = CreateDownloadItem();
1281   MockDownloadFile* download_file =
1282       DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE);
1283   EXPECT_CALL(*download_file, Cancel());
1284   item->DestinationObserverAsWeakPtr()->DestinationError(
1285       DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
1286   ASSERT_TRUE(item->IsDangerous());
1287
1288   EXPECT_CALL(*mock_delegate(), DownloadRemoved(_));
1289   base::WeakPtrFactory<DownloadItemTest> weak_ptr_factory(this);
1290   item->StealDangerousDownload(
1291       base::Bind(&DownloadItemTest::OnDownloadFileAcquired,
1292                  weak_ptr_factory.GetWeakPtr(),
1293                  base::Unretained(&returned_path)));
1294   RunAllPendingInMessageLoops();
1295   EXPECT_TRUE(returned_path.empty());
1296 }
1297
1298 TEST(MockDownloadItem, Compiles) {
1299   MockDownloadItem mock_item;
1300 }
1301
1302 }  // namespace content