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