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