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