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 <vector> 6 7 #include "base/memory/weak_ptr.h" 8 #include "base/rand_util.h" 9 #include "base/stl_util.h" 10 #include "chrome/browser/download/download_history.h" 11 #include "chrome/browser/history/download_database.h" 12 #include "chrome/browser/history/download_row.h" 13 #include "chrome/browser/history/history_service.h" 14 #include "content/public/test/mock_download_item.h" 15 #include "content/public/test/mock_download_manager.h" 16 #include "content/public/test/test_browser_thread.h" 17 #include "content/public/test/test_utils.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 #if defined(ENABLE_EXTENSIONS) 21 #include "chrome/browser/extensions/api/downloads/downloads_api.h" 22 #endif 23 24 using testing::DoAll; 25 using testing::Invoke; 26 using testing::Return; 27 using testing::ReturnRefOfCopy; 28 using testing::SetArgPointee; 29 using testing::WithArg; 30 using testing::_; 31 32 namespace { 33 34 void CheckInfoEqual(const history::DownloadRow& left, 35 const history::DownloadRow& right) { 36 EXPECT_EQ(left.current_path.value(), right.current_path.value()); 37 EXPECT_EQ(left.target_path.value(), right.target_path.value()); 38 EXPECT_EQ(left.url_chain.size(), right.url_chain.size()); 39 for (unsigned int i = 0; 40 i < left.url_chain.size() && i < right.url_chain.size(); 41 ++i) { 42 EXPECT_EQ(left.url_chain[i].spec(), right.url_chain[i].spec()); 43 } 44 EXPECT_EQ(left.referrer_url.spec(), right.referrer_url.spec()); 45 EXPECT_EQ(left.mime_type, right.mime_type); 46 EXPECT_EQ(left.original_mime_type, right.original_mime_type); 47 EXPECT_EQ(left.start_time.ToTimeT(), right.start_time.ToTimeT()); 48 EXPECT_EQ(left.end_time.ToTimeT(), right.end_time.ToTimeT()); 49 EXPECT_EQ(left.etag, right.etag); 50 EXPECT_EQ(left.last_modified, right.last_modified); 51 EXPECT_EQ(left.received_bytes, right.received_bytes); 52 EXPECT_EQ(left.total_bytes, right.total_bytes); 53 EXPECT_EQ(left.state, right.state); 54 EXPECT_EQ(left.danger_type, right.danger_type); 55 EXPECT_EQ(left.id, right.id); 56 EXPECT_EQ(left.opened, right.opened); 57 EXPECT_EQ(left.by_ext_id, right.by_ext_id); 58 EXPECT_EQ(left.by_ext_name, right.by_ext_name); 59 } 60 61 typedef DownloadHistory::IdSet IdSet; 62 typedef std::vector<history::DownloadRow> InfoVector; 63 typedef testing::StrictMock<content::MockDownloadItem> StrictMockDownloadItem; 64 65 class FakeHistoryAdapter : public DownloadHistory::HistoryAdapter { 66 public: 67 FakeHistoryAdapter() 68 : DownloadHistory::HistoryAdapter(NULL), 69 slow_create_download_(false), 70 fail_create_download_(false) { 71 } 72 73 virtual ~FakeHistoryAdapter() {} 74 75 virtual void QueryDownloads( 76 const HistoryService::DownloadQueryCallback& callback) OVERRIDE { 77 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 78 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 79 base::Bind(&FakeHistoryAdapter::QueryDownloadsDone, 80 base::Unretained(this), callback)); 81 } 82 83 void QueryDownloadsDone( 84 const HistoryService::DownloadQueryCallback& callback) { 85 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 86 CHECK(expect_query_downloads_.get()); 87 callback.Run(expect_query_downloads_.Pass()); 88 } 89 90 void set_slow_create_download(bool slow) { slow_create_download_ = slow; } 91 92 virtual void CreateDownload( 93 const history::DownloadRow& info, 94 const HistoryService::DownloadCreateCallback& callback) OVERRIDE { 95 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 96 create_download_info_ = info; 97 // Must not call CreateDownload() again before FinishCreateDownload()! 98 DCHECK(create_download_callback_.is_null()); 99 create_download_callback_ = base::Bind(callback, !fail_create_download_); 100 fail_create_download_ = false; 101 if (!slow_create_download_) 102 FinishCreateDownload(); 103 } 104 105 void FinishCreateDownload() { 106 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 107 create_download_callback_.Run(); 108 create_download_callback_.Reset(); 109 } 110 111 virtual void UpdateDownload( 112 const history::DownloadRow& info) OVERRIDE { 113 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 114 update_download_ = info; 115 } 116 117 virtual void RemoveDownloads(const IdSet& ids) OVERRIDE { 118 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 119 for (IdSet::const_iterator it = ids.begin(); 120 it != ids.end(); ++it) { 121 remove_downloads_.insert(*it); 122 } 123 } 124 125 void ExpectWillQueryDownloads(scoped_ptr<InfoVector> infos) { 126 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 127 expect_query_downloads_ = infos.Pass(); 128 } 129 130 void ExpectQueryDownloadsDone() { 131 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 132 EXPECT_TRUE(NULL == expect_query_downloads_.get()); 133 } 134 135 void FailCreateDownload() { 136 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 137 fail_create_download_ = true; 138 } 139 140 void ExpectDownloadCreated( 141 const history::DownloadRow& info) { 142 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 143 content::RunAllPendingInMessageLoop(content::BrowserThread::UI); 144 CheckInfoEqual(info, create_download_info_); 145 create_download_info_ = history::DownloadRow(); 146 } 147 148 void ExpectNoDownloadCreated() { 149 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 150 content::RunAllPendingInMessageLoop(content::BrowserThread::UI); 151 CheckInfoEqual(history::DownloadRow(), create_download_info_); 152 } 153 154 void ExpectDownloadUpdated(const history::DownloadRow& info) { 155 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 156 content::RunAllPendingInMessageLoop(content::BrowserThread::UI); 157 CheckInfoEqual(update_download_, info); 158 update_download_ = history::DownloadRow(); 159 } 160 161 void ExpectNoDownloadUpdated() { 162 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 163 content::RunAllPendingInMessageLoop(content::BrowserThread::UI); 164 CheckInfoEqual(history::DownloadRow(), update_download_); 165 } 166 167 void ExpectNoDownloadsRemoved() { 168 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 169 content::RunAllPendingInMessageLoop(content::BrowserThread::UI); 170 EXPECT_EQ(0, static_cast<int>(remove_downloads_.size())); 171 } 172 173 void ExpectDownloadsRemoved(const IdSet& ids) { 174 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 175 content::RunAllPendingInMessageLoop(content::BrowserThread::UI); 176 IdSet differences = base::STLSetDifference<IdSet>(ids, remove_downloads_); 177 for (IdSet::const_iterator different = differences.begin(); 178 different != differences.end(); ++different) { 179 EXPECT_TRUE(false) << *different; 180 } 181 remove_downloads_.clear(); 182 } 183 184 private: 185 bool slow_create_download_; 186 bool fail_create_download_; 187 base::Closure create_download_callback_; 188 history::DownloadRow update_download_; 189 scoped_ptr<InfoVector> expect_query_downloads_; 190 IdSet remove_downloads_; 191 history::DownloadRow create_download_info_; 192 193 DISALLOW_COPY_AND_ASSIGN(FakeHistoryAdapter); 194 }; 195 196 class DownloadHistoryTest : public testing::Test { 197 public: 198 // Generic callback that receives a pointer to a StrictMockDownloadItem. 199 typedef base::Callback<void(content::MockDownloadItem*)> DownloadItemCallback; 200 201 DownloadHistoryTest() 202 : ui_thread_(content::BrowserThread::UI, &loop_), 203 manager_(new content::MockDownloadManager()), 204 history_(NULL), 205 manager_observer_(NULL), 206 download_created_index_(0) {} 207 virtual ~DownloadHistoryTest() { 208 STLDeleteElements(&items_); 209 } 210 211 protected: 212 virtual void TearDown() OVERRIDE { 213 download_history_.reset(); 214 } 215 216 content::MockDownloadManager& manager() { return *manager_.get(); } 217 content::MockDownloadItem& item(size_t index) { return *items_[index]; } 218 DownloadHistory* download_history() { return download_history_.get(); } 219 220 void SetManagerObserver( 221 content::DownloadManager::Observer* manager_observer) { 222 manager_observer_ = manager_observer; 223 } 224 content::DownloadManager::Observer* manager_observer() { 225 return manager_observer_; 226 } 227 228 void CreateDownloadHistory(scoped_ptr<InfoVector> infos) { 229 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 230 CHECK(infos.get()); 231 EXPECT_CALL(manager(), AddObserver(_)).WillOnce(WithArg<0>(Invoke( 232 this, &DownloadHistoryTest::SetManagerObserver))); 233 EXPECT_CALL(manager(), RemoveObserver(_)); 234 download_created_index_ = 0; 235 for (size_t index = 0; index < infos->size(); ++index) { 236 content::MockDownloadManager::CreateDownloadItemAdapter adapter( 237 infos->at(index).id, 238 infos->at(index).current_path, 239 infos->at(index).target_path, 240 infos->at(index).url_chain, 241 infos->at(index).referrer_url, 242 infos->at(index).mime_type, 243 infos->at(index).original_mime_type, 244 infos->at(index).start_time, 245 infos->at(index).end_time, 246 infos->at(index).etag, 247 infos->at(index).last_modified, 248 infos->at(index).received_bytes, 249 infos->at(index).total_bytes, 250 infos->at(index).state, 251 infos->at(index).danger_type, 252 infos->at(index).interrupt_reason, 253 infos->at(index).opened); 254 EXPECT_CALL(manager(), MockCreateDownloadItem(adapter)) 255 .WillOnce(DoAll( 256 InvokeWithoutArgs( 257 this, &DownloadHistoryTest::CallOnDownloadCreatedInOrder), 258 Return(&item(index)))); 259 } 260 EXPECT_CALL(manager(), CheckForHistoryFilesRemoval()); 261 history_ = new FakeHistoryAdapter(); 262 history_->ExpectWillQueryDownloads(infos.Pass()); 263 EXPECT_CALL(*manager_.get(), GetAllDownloads(_)).WillRepeatedly(Return()); 264 download_history_.reset(new DownloadHistory( 265 &manager(), scoped_ptr<DownloadHistory::HistoryAdapter>(history_))); 266 content::RunAllPendingInMessageLoop(content::BrowserThread::UI); 267 history_->ExpectQueryDownloadsDone(); 268 } 269 270 void CallOnDownloadCreated(size_t index) { 271 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 272 if (!pre_on_create_handler_.is_null()) 273 pre_on_create_handler_.Run(&item(index)); 274 manager_observer()->OnDownloadCreated(&manager(), &item(index)); 275 if (!post_on_create_handler_.is_null()) 276 post_on_create_handler_.Run(&item(index)); 277 } 278 279 void CallOnDownloadCreatedInOrder() { 280 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 281 // Gmock doesn't appear to support something like InvokeWithTheseArgs. Maybe 282 // gmock needs to learn about base::Callback. 283 CallOnDownloadCreated(download_created_index_++); 284 } 285 286 void set_slow_create_download(bool slow) { 287 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 288 history_->set_slow_create_download(slow); 289 } 290 291 void FinishCreateDownload() { 292 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 293 history_->FinishCreateDownload(); 294 } 295 296 void FailCreateDownload() { 297 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 298 history_->FailCreateDownload(); 299 } 300 301 void ExpectDownloadCreated( 302 const history::DownloadRow& info) { 303 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 304 history_->ExpectDownloadCreated(info); 305 } 306 307 void ExpectNoDownloadCreated() { 308 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 309 history_->ExpectNoDownloadCreated(); 310 } 311 312 void ExpectDownloadUpdated(const history::DownloadRow& info) { 313 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 314 history_->ExpectDownloadUpdated(info); 315 } 316 317 void ExpectNoDownloadUpdated() { 318 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 319 history_->ExpectNoDownloadUpdated(); 320 } 321 322 void ExpectNoDownloadsRemoved() { 323 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 324 history_->ExpectNoDownloadsRemoved(); 325 } 326 327 void ExpectDownloadsRemoved(const IdSet& ids) { 328 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 329 history_->ExpectDownloadsRemoved(ids); 330 } 331 332 void ExpectDownloadsRestoredFromHistory(bool expected_value) { 333 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 334 pre_on_create_handler_ = 335 base::Bind(&DownloadHistoryTest::CheckDownloadWasRestoredFromHistory, 336 base::Unretained(this), 337 expected_value); 338 post_on_create_handler_ = 339 base::Bind(&DownloadHistoryTest::CheckDownloadWasRestoredFromHistory, 340 base::Unretained(this), 341 expected_value); 342 } 343 344 void InitBasicItem(const base::FilePath::CharType* path, 345 const char* url_string, 346 const char* referrer_string, 347 history::DownloadRow* info) { 348 GURL url(url_string); 349 GURL referrer(referrer_string); 350 std::vector<GURL> url_chain; 351 url_chain.push_back(url); 352 InitItem(static_cast<uint32>(items_.size() + 1), 353 base::FilePath(path), 354 base::FilePath(path), 355 url_chain, 356 referrer, 357 "application/octet-stream", 358 "application/octet-stream", 359 (base::Time::Now() - base::TimeDelta::FromMinutes(10)), 360 (base::Time::Now() - base::TimeDelta::FromMinutes(1)), 361 "Etag", 362 "abc", 363 100, 364 100, 365 content::DownloadItem::COMPLETE, 366 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, 367 content::DOWNLOAD_INTERRUPT_REASON_NONE, 368 false, 369 std::string(), 370 std::string(), 371 info); 372 } 373 374 void InitItem( 375 uint32 id, 376 const base::FilePath& current_path, 377 const base::FilePath& target_path, 378 const std::vector<GURL>& url_chain, 379 const GURL& referrer, 380 const std::string& mime_type, 381 const std::string& original_mime_type, 382 const base::Time& start_time, 383 const base::Time& end_time, 384 const std::string& etag, 385 const std::string& last_modified, 386 int64 received_bytes, 387 int64 total_bytes, 388 content::DownloadItem::DownloadState state, 389 content::DownloadDangerType danger_type, 390 content::DownloadInterruptReason interrupt_reason, 391 bool opened, 392 const std::string& by_extension_id, 393 const std::string& by_extension_name, 394 history::DownloadRow* info) { 395 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 396 397 size_t index = items_.size(); 398 StrictMockDownloadItem* mock_item = new StrictMockDownloadItem(); 399 items_.push_back(mock_item); 400 401 info->current_path = current_path; 402 info->target_path = target_path; 403 info->url_chain = url_chain; 404 info->referrer_url = referrer; 405 info->mime_type = mime_type; 406 info->original_mime_type = original_mime_type; 407 info->start_time = start_time; 408 info->end_time = end_time; 409 info->etag = etag; 410 info->last_modified = last_modified; 411 info->received_bytes = received_bytes; 412 info->total_bytes = total_bytes; 413 info->state = state; 414 info->danger_type = danger_type; 415 info->interrupt_reason = interrupt_reason; 416 info->id = id; 417 info->opened = opened; 418 info->by_ext_id = by_extension_id; 419 info->by_ext_name = by_extension_name; 420 421 EXPECT_CALL(item(index), GetId()).WillRepeatedly(Return(id)); 422 EXPECT_CALL(item(index), GetFullPath()) 423 .WillRepeatedly(ReturnRefOfCopy(current_path)); 424 EXPECT_CALL(item(index), GetTargetFilePath()) 425 .WillRepeatedly(ReturnRefOfCopy(target_path)); 426 DCHECK_LE(1u, url_chain.size()); 427 EXPECT_CALL(item(index), GetURL()) 428 .WillRepeatedly(ReturnRefOfCopy(url_chain[0])); 429 EXPECT_CALL(item(index), GetUrlChain()) 430 .WillRepeatedly(ReturnRefOfCopy(url_chain)); 431 EXPECT_CALL(item(index), GetMimeType()).WillRepeatedly(Return(mime_type)); 432 EXPECT_CALL(item(index), GetOriginalMimeType()).WillRepeatedly(Return( 433 original_mime_type)); 434 EXPECT_CALL(item(index), GetReferrerUrl()) 435 .WillRepeatedly(ReturnRefOfCopy(referrer)); 436 EXPECT_CALL(item(index), GetStartTime()).WillRepeatedly(Return(start_time)); 437 EXPECT_CALL(item(index), GetEndTime()).WillRepeatedly(Return(end_time)); 438 EXPECT_CALL(item(index), GetETag()).WillRepeatedly(ReturnRefOfCopy(etag)); 439 EXPECT_CALL(item(index), GetLastModifiedTime()) 440 .WillRepeatedly(ReturnRefOfCopy(last_modified)); 441 EXPECT_CALL(item(index), GetReceivedBytes()) 442 .WillRepeatedly(Return(received_bytes)); 443 EXPECT_CALL(item(index), GetTotalBytes()) 444 .WillRepeatedly(Return(total_bytes)); 445 EXPECT_CALL(item(index), GetState()).WillRepeatedly(Return(state)); 446 EXPECT_CALL(item(index), GetDangerType()) 447 .WillRepeatedly(Return(danger_type)); 448 EXPECT_CALL(item(index), GetLastReason()) 449 .WillRepeatedly(Return(interrupt_reason)); 450 EXPECT_CALL(item(index), GetOpened()).WillRepeatedly(Return(opened)); 451 EXPECT_CALL(item(index), GetTargetDisposition()) 452 .WillRepeatedly( 453 Return(content::DownloadItem::TARGET_DISPOSITION_OVERWRITE)); 454 EXPECT_CALL(manager(), GetDownload(id)) 455 .WillRepeatedly(Return(&item(index))); 456 EXPECT_CALL(item(index), IsTemporary()).WillRepeatedly(Return(false)); 457 #if defined(ENABLE_EXTENSIONS) 458 new extensions::DownloadedByExtension( 459 &item(index), by_extension_id, by_extension_name); 460 #endif 461 462 std::vector<content::DownloadItem*> items; 463 for (size_t i = 0; i < items_.size(); ++i) { 464 items.push_back(&item(i)); 465 } 466 EXPECT_CALL(*manager_.get(), GetAllDownloads(_)) 467 .WillRepeatedly(SetArgPointee<0>(items)); 468 } 469 470 private: 471 void CheckDownloadWasRestoredFromHistory(bool expected_value, 472 content::MockDownloadItem* item) { 473 ASSERT_TRUE(download_history_.get()); 474 EXPECT_EQ(expected_value, download_history_->WasRestoredFromHistory(item)); 475 } 476 477 base::MessageLoopForUI loop_; 478 content::TestBrowserThread ui_thread_; 479 std::vector<StrictMockDownloadItem*> items_; 480 scoped_ptr<content::MockDownloadManager> manager_; 481 FakeHistoryAdapter* history_; 482 scoped_ptr<DownloadHistory> download_history_; 483 content::DownloadManager::Observer* manager_observer_; 484 size_t download_created_index_; 485 DownloadItemCallback pre_on_create_handler_; 486 DownloadItemCallback post_on_create_handler_; 487 488 DISALLOW_COPY_AND_ASSIGN(DownloadHistoryTest); 489 }; 490 491 // Test loading an item from the database, changing it, saving it back, removing 492 // it. 493 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Load) { 494 // Load a download from history, create the item, OnDownloadCreated, 495 // OnDownloadUpdated, OnDownloadRemoved. 496 history::DownloadRow info; 497 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 498 "http://example.com/bar.pdf", 499 "http://example.com/referrer.html", 500 &info); 501 { 502 scoped_ptr<InfoVector> infos(new InfoVector()); 503 infos->push_back(info); 504 CreateDownloadHistory(infos.Pass()); 505 ExpectNoDownloadCreated(); 506 } 507 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 508 509 // Pretend that something changed on the item. 510 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true)); 511 item(0).NotifyObserversDownloadUpdated(); 512 info.opened = true; 513 ExpectDownloadUpdated(info); 514 515 // Pretend that the user removed the item. 516 IdSet ids; 517 ids.insert(info.id); 518 item(0).NotifyObserversDownloadRemoved(); 519 ExpectDownloadsRemoved(ids); 520 } 521 522 // Test that WasRestoredFromHistory accurately identifies downloads that were 523 // created from history, even during an OnDownloadCreated() handler. 524 TEST_F(DownloadHistoryTest, DownloadHistoryTest_WasRestoredFromHistory_True) { 525 // This sets DownloadHistoryTest to call DH::WasRestoredFromHistory() both 526 // before and after DH::OnDownloadCreated() is called. At each call, the 527 // expected return value is |true| since the download was restored from 528 // history. 529 ExpectDownloadsRestoredFromHistory(true); 530 531 // Construct a DownloadHistory with a single history download. This results in 532 // DownloadManager::CreateDownload() being called for the restored download. 533 // The above test expectation should verify that the value of 534 // WasRestoredFromHistory is correct for this download. 535 history::DownloadRow info; 536 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 537 "http://example.com/bar.pdf", 538 "http://example.com/referrer.html", 539 &info); 540 scoped_ptr<InfoVector> infos(new InfoVector()); 541 infos->push_back(info); 542 CreateDownloadHistory(infos.Pass()); 543 544 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 545 } 546 547 // Test that WasRestoredFromHistory accurately identifies downloads that were 548 // not created from history. 549 TEST_F(DownloadHistoryTest, DownloadHistoryTest_WasRestoredFromHistory_False) { 550 // This sets DownloadHistoryTest to call DH::WasRestoredFromHistory() both 551 // before and after DH::OnDownloadCreated() is called. At each call, the 552 // expected return value is |true| since the download was restored from 553 // history. 554 ExpectDownloadsRestoredFromHistory(false); 555 556 // Create a DownloadHistory with no history downloads. No 557 // DownloadManager::CreateDownload() calls are expected. 558 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector())); 559 560 // Notify DownloadHistory that a new download was created. The above test 561 // expecation should verify that WasRestoredFromHistory is correct for this 562 // download. 563 history::DownloadRow info; 564 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 565 "http://example.com/bar.pdf", 566 "http://example.com/referrer.html", 567 &info); 568 CallOnDownloadCreated(0); 569 ExpectDownloadCreated(info); 570 } 571 572 // Test creating an item, saving it to the database, changing it, saving it 573 // back, removing it. 574 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Create) { 575 // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated, 576 // OnDownloadRemoved. 577 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector())); 578 579 history::DownloadRow info; 580 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 581 "http://example.com/bar.pdf", 582 "http://example.com/referrer.html", 583 &info); 584 585 // Pretend the manager just created |item|. 586 CallOnDownloadCreated(0); 587 ExpectDownloadCreated(info); 588 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 589 590 // Pretend that something changed on the item. 591 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true)); 592 item(0).NotifyObserversDownloadUpdated(); 593 info.opened = true; 594 ExpectDownloadUpdated(info); 595 596 // Pretend that the user removed the item. 597 IdSet ids; 598 ids.insert(info.id); 599 item(0).NotifyObserversDownloadRemoved(); 600 ExpectDownloadsRemoved(ids); 601 } 602 603 // Test that changes to persisted fields in a DownloadItem triggers database 604 // updates. 605 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Update) { 606 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector())); 607 608 history::DownloadRow info; 609 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 610 "http://example.com/bar.pdf", 611 "http://example.com/referrer.html", 612 &info); 613 CallOnDownloadCreated(0); 614 ExpectDownloadCreated(info); 615 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 616 617 base::FilePath new_path(FILE_PATH_LITERAL("/foo/baz.txt")); 618 base::Time new_time(base::Time::Now()); 619 std::string new_etag("new etag"); 620 std::string new_last_modifed("new last modified"); 621 622 // current_path 623 EXPECT_CALL(item(0), GetFullPath()).WillRepeatedly(ReturnRefOfCopy(new_path)); 624 info.current_path = new_path; 625 item(0).NotifyObserversDownloadUpdated(); 626 ExpectDownloadUpdated(info); 627 628 // target_path 629 EXPECT_CALL(item(0), GetTargetFilePath()) 630 .WillRepeatedly(ReturnRefOfCopy(new_path)); 631 info.target_path = new_path; 632 item(0).NotifyObserversDownloadUpdated(); 633 ExpectDownloadUpdated(info); 634 635 // end_time 636 EXPECT_CALL(item(0), GetEndTime()).WillRepeatedly(Return(new_time)); 637 info.end_time = new_time; 638 item(0).NotifyObserversDownloadUpdated(); 639 ExpectDownloadUpdated(info); 640 641 // received_bytes 642 EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(101)); 643 info.received_bytes = 101; 644 item(0).NotifyObserversDownloadUpdated(); 645 ExpectDownloadUpdated(info); 646 647 // total_bytes 648 EXPECT_CALL(item(0), GetTotalBytes()).WillRepeatedly(Return(102)); 649 info.total_bytes = 102; 650 item(0).NotifyObserversDownloadUpdated(); 651 ExpectDownloadUpdated(info); 652 653 // etag 654 EXPECT_CALL(item(0), GetETag()).WillRepeatedly(ReturnRefOfCopy(new_etag)); 655 info.etag = new_etag; 656 item(0).NotifyObserversDownloadUpdated(); 657 ExpectDownloadUpdated(info); 658 659 // last_modified 660 EXPECT_CALL(item(0), GetLastModifiedTime()) 661 .WillRepeatedly(ReturnRefOfCopy(new_last_modifed)); 662 info.last_modified = new_last_modifed; 663 item(0).NotifyObserversDownloadUpdated(); 664 ExpectDownloadUpdated(info); 665 666 // state 667 EXPECT_CALL(item(0), GetState()) 668 .WillRepeatedly(Return(content::DownloadItem::INTERRUPTED)); 669 info.state = content::DownloadItem::INTERRUPTED; 670 item(0).NotifyObserversDownloadUpdated(); 671 ExpectDownloadUpdated(info); 672 673 // danger_type 674 EXPECT_CALL(item(0), GetDangerType()) 675 .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT)); 676 info.danger_type = content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT; 677 item(0).NotifyObserversDownloadUpdated(); 678 ExpectDownloadUpdated(info); 679 680 // interrupt_reason 681 EXPECT_CALL(item(0), GetLastReason()) 682 .WillRepeatedly(Return(content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED)); 683 info.interrupt_reason = content::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; 684 item(0).NotifyObserversDownloadUpdated(); 685 ExpectDownloadUpdated(info); 686 687 // opened 688 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true)); 689 info.opened = true; 690 item(0).NotifyObserversDownloadUpdated(); 691 ExpectDownloadUpdated(info); 692 } 693 694 // Test creating a new item, saving it, removing it by setting it Temporary, 695 // changing it without saving it back because it's Temporary, clearing 696 // IsTemporary, saving it back, changing it, saving it back because it isn't 697 // Temporary anymore. 698 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Temporary) { 699 // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated, 700 // OnDownloadRemoved. 701 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector())); 702 703 history::DownloadRow info; 704 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 705 "http://example.com/bar.pdf", 706 "http://example.com/referrer.html", 707 &info); 708 709 // Pretend the manager just created |item|. 710 CallOnDownloadCreated(0); 711 ExpectDownloadCreated(info); 712 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 713 714 // Pretend the item was marked temporary. DownloadHistory should remove it 715 // from history and start ignoring it. 716 EXPECT_CALL(item(0), IsTemporary()).WillRepeatedly(Return(true)); 717 item(0).NotifyObserversDownloadUpdated(); 718 IdSet ids; 719 ids.insert(info.id); 720 ExpectDownloadsRemoved(ids); 721 722 // Change something that would make DownloadHistory call UpdateDownload if the 723 // item weren't temporary. 724 EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(4200)); 725 item(0).NotifyObserversDownloadUpdated(); 726 ExpectNoDownloadUpdated(); 727 728 // Changing a temporary item back to a non-temporary item should make 729 // DownloadHistory call CreateDownload. 730 EXPECT_CALL(item(0), IsTemporary()).WillRepeatedly(Return(false)); 731 item(0).NotifyObserversDownloadUpdated(); 732 info.received_bytes = 4200; 733 ExpectDownloadCreated(info); 734 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 735 736 EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(100)); 737 item(0).NotifyObserversDownloadUpdated(); 738 info.received_bytes = 100; 739 ExpectDownloadUpdated(info); 740 } 741 742 // Test removing downloads while they're still being added. 743 TEST_F(DownloadHistoryTest, DownloadHistoryTest_RemoveWhileAdding) { 744 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector())); 745 746 history::DownloadRow info; 747 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 748 "http://example.com/bar.pdf", 749 "http://example.com/referrer.html", 750 &info); 751 752 // Instruct CreateDownload() to not callback to DownloadHistory immediately, 753 // but to wait for FinishCreateDownload(). 754 set_slow_create_download(true); 755 756 // Pretend the manager just created |item|. 757 CallOnDownloadCreated(0); 758 ExpectDownloadCreated(info); 759 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0))); 760 761 // Call OnDownloadRemoved before calling back to DownloadHistory::ItemAdded(). 762 // Instead of calling RemoveDownloads() immediately, DownloadHistory should 763 // add the item's id to removed_while_adding_. Then, ItemAdded should 764 // immediately remove the item's record from history. 765 item(0).NotifyObserversDownloadRemoved(); 766 EXPECT_CALL(manager(), GetDownload(item(0).GetId())) 767 .WillRepeatedly(Return(static_cast<content::DownloadItem*>(NULL))); 768 ExpectNoDownloadsRemoved(); 769 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0))); 770 771 // Now callback to DownloadHistory::ItemAdded(), and expect a call to 772 // RemoveDownloads() for the item that was removed while it was being added. 773 FinishCreateDownload(); 774 IdSet ids; 775 ids.insert(info.id); 776 ExpectDownloadsRemoved(ids); 777 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0))); 778 } 779 780 // Test loading multiple items from the database and removing them all. 781 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Multiple) { 782 // Load a download from history, create the item, OnDownloadCreated, 783 // OnDownloadUpdated, OnDownloadRemoved. 784 history::DownloadRow info0, info1; 785 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 786 "http://example.com/bar.pdf", 787 "http://example.com/referrer.html", 788 &info0); 789 InitBasicItem(FILE_PATH_LITERAL("/foo/qux.pdf"), 790 "http://example.com/qux.pdf", 791 "http://example.com/referrer1.html", 792 &info1); 793 { 794 scoped_ptr<InfoVector> infos(new InfoVector()); 795 infos->push_back(info0); 796 infos->push_back(info1); 797 CreateDownloadHistory(infos.Pass()); 798 ExpectNoDownloadCreated(); 799 } 800 801 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 802 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(1))); 803 804 // Pretend that the user removed both items. 805 IdSet ids; 806 ids.insert(info0.id); 807 ids.insert(info1.id); 808 item(0).NotifyObserversDownloadRemoved(); 809 item(1).NotifyObserversDownloadRemoved(); 810 ExpectDownloadsRemoved(ids); 811 } 812 813 // Test what happens when HistoryService/CreateDownload::CreateDownload() fails. 814 TEST_F(DownloadHistoryTest, DownloadHistoryTest_CreateFailed) { 815 // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated, 816 // OnDownloadRemoved. 817 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector())); 818 819 history::DownloadRow info; 820 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 821 "http://example.com/bar.pdf", 822 "http://example.com/referrer.html", 823 &info); 824 825 FailCreateDownload(); 826 // Pretend the manager just created |item|. 827 CallOnDownloadCreated(0); 828 ExpectDownloadCreated(info); 829 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0))); 830 831 EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(100)); 832 item(0).NotifyObserversDownloadUpdated(); 833 info.received_bytes = 100; 834 ExpectDownloadCreated(info); 835 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 836 } 837 838 TEST_F(DownloadHistoryTest, DownloadHistoryTest_UpdateWhileAdding) { 839 // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated, 840 // OnDownloadRemoved. 841 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector())); 842 843 history::DownloadRow info; 844 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), 845 "http://example.com/bar.pdf", 846 "http://example.com/referrer.html", 847 &info); 848 849 // Instruct CreateDownload() to not callback to DownloadHistory immediately, 850 // but to wait for FinishCreateDownload(). 851 set_slow_create_download(true); 852 853 // Pretend the manager just created |item|. 854 CallOnDownloadCreated(0); 855 ExpectDownloadCreated(info); 856 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0))); 857 858 // Pretend that something changed on the item. 859 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true)); 860 item(0).NotifyObserversDownloadUpdated(); 861 862 FinishCreateDownload(); 863 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0))); 864 865 // ItemAdded should call OnDownloadUpdated, which should detect that the item 866 // changed while it was being added and call UpdateDownload immediately. 867 info.opened = true; 868 ExpectDownloadUpdated(info); 869 } 870 871 } // anonymous namespace 872