Home | History | Annotate | Download | only in download
      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 // Check we do correct cleanup for RESUME_MODE_INVALID interrupts.
    463 TEST_F(DownloadItemTest, UnresumableInterrupt) {
    464   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   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   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   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   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   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
   1303