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