| Index: chrome/browser/download/download_history_unittest.cc | 
| diff --git a/chrome/browser/download/download_history_unittest.cc b/chrome/browser/download/download_history_unittest.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..00b2629e7e3669949210c2cdbe1b63491805c9f4 | 
| --- /dev/null | 
| +++ b/chrome/browser/download/download_history_unittest.cc | 
| @@ -0,0 +1,480 @@ | 
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "base/rand_util.h" | 
| +#include "chrome/browser/download/download_history.h" | 
| +#include "chrome/browser/download/download_persistent_store_info.h" | 
| +#include "chrome/browser/history/history.h" | 
| +#include "chrome/test/base/in_process_browser_test.h" | 
| +#include "content/public/test/mock_download_item.h" | 
| +#include "content/public/test/mock_download_manager.h" | 
| +#include "content/public/test/test_utils.h" | 
| + | 
| +using content::BrowserThread; | 
| +using content::DownloadItem; | 
| +using content::DownloadManager; | 
| +using content::MockDownloadItem; | 
| +using content::MockDownloadManager; | 
| +using testing::DoAll; | 
| +using testing::Invoke; | 
| +using testing::NiceMock; | 
| +using testing::Return; | 
| +using testing::ReturnRef; | 
| +using testing::_; | 
| + | 
| +namespace { | 
| + | 
| +bool InfoEqual(const DownloadPersistentStoreInfo& left, | 
| +               const DownloadPersistentStoreInfo& right) { | 
| +  if (left.path != right.path) { | 
| +    LOG(ERROR) << left.path.value() << " != " << right.path.value(); | 
| +    return false; | 
| +  } else if (left.url != right.url) { | 
| +    LOG(ERROR) << left.url.spec() << " != " << right.url.spec(); | 
| +    return false; | 
| +  } else if (left.referrer_url != right.referrer_url) { | 
| +    LOG(ERROR) << left.referrer_url.spec() << " != " | 
| +               << right.referrer_url.spec(); | 
| +    return false; | 
| +  } else if (left.start_time != right.start_time) { | 
| +    LOG(ERROR) << left.start_time.ToTimeT() << " != " | 
| +               << right.start_time.ToTimeT(); | 
| +    return false; | 
| +  } else if (left.end_time != right.end_time) { | 
| +    LOG(ERROR) << left.end_time.ToTimeT() << " != " << right.end_time.ToTimeT(); | 
| +    return false; | 
| +  } else if (left.received_bytes != right.received_bytes) { | 
| +    LOG(ERROR) << left.received_bytes << " != " << right.received_bytes; | 
| +    return false; | 
| +  } else if (left.total_bytes != right.total_bytes) { | 
| +    LOG(ERROR) << left.total_bytes << " != " << right.total_bytes; | 
| +    return false; | 
| +  } else if (left.state != right.state) { | 
| +    LOG(ERROR) << left.state << " != " << right.state; | 
| +    return false; | 
| +  } else if (left.db_handle != right.db_handle) { | 
| +    LOG(ERROR) << left.db_handle << " != " << right.db_handle; | 
| +    return false; | 
| +  } else if (left.opened != right.opened) { | 
| +    LOG(ERROR) << left.opened << " != " << right.opened; | 
| +    return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| +class DownloadHistoryTest : public InProcessBrowserTest, | 
| +                            public HistoryServiceDownloadAdapter { | 
| + public: | 
| +  DownloadHistoryTest() | 
| +    : HistoryServiceDownloadAdapter(NULL), | 
| +      manager_(new MockDownloadManager()), | 
| +      download_history_(NULL), | 
| +      expect_query_downloads_(NULL), | 
| +      slow_create_download_(false), | 
| +      handle_counter_(0), | 
| +      create_download_id_(-1) { | 
| +  } | 
| +  virtual ~DownloadHistoryTest() {} | 
| + | 
| +  // HistoryServiceDownloadAdapter | 
| +  virtual void QueryDownloads( | 
| +      const HistoryService::DownloadQueryCallback& callback) OVERRIDE { | 
| +    CHECK(expect_query_downloads_); | 
| +    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 
| +        base::Bind(&DownloadHistoryTest::QueryDownloadsDone, this, callback)); | 
| +  } | 
| + | 
| +  void QueryDownloadsDone( | 
| +      const HistoryService::DownloadQueryCallback& callback) { | 
| +    callback.Run(expect_query_downloads_); | 
| +    expect_query_downloads_ = NULL; | 
| +  } | 
| + | 
| +  virtual HistoryService::Handle GetVisibleVisitCountToHost( | 
| +      const GURL& referrer_url, | 
| +      const HistoryService::GetVisibleVisitCountToHostCallback& | 
| +        callback) OVERRIDE { | 
| +    NOTIMPLEMENTED(); | 
| +    return 0; | 
| +  } | 
| + | 
| +  void set_slow_create_download(bool slow) { slow_create_download_ = slow; } | 
| + | 
| +  virtual void CreateDownload( | 
| +      int32 id, | 
| +      const DownloadPersistentStoreInfo& info, | 
| +      const HistoryService::DownloadCreateCallback& callback) OVERRIDE { | 
| +    create_download_id_ = id; | 
| +    create_download_info_ = info; | 
| +    create_download_callback_ = base::Bind(callback, id, handle_counter_++); | 
| +    if (!slow_create_download_) { | 
| +      FinishCreateDownload(); | 
| +    } | 
| +  } | 
| + | 
| +  void FinishCreateDownload() { | 
| +    create_download_callback_.Run(); | 
| +    create_download_callback_.Reset(); | 
| +  } | 
| + | 
| +  virtual void UpdateDownload( | 
| +      const DownloadPersistentStoreInfo& info) OVERRIDE { | 
| +    update_download_ = info; | 
| +  } | 
| + | 
| +  virtual void RemoveDownloads( | 
| +      const DownloadHistory::HandleSet& handles) OVERRIDE { | 
| +    for (DownloadHistory::HandleSet::const_iterator it = handles.begin(); | 
| +         it != handles.end(); ++it) { | 
| +      remove_downloads_.insert(*it); | 
| +    } | 
| +  } | 
| + | 
| +  virtual void OnDownloadHistoryDestroyed() OVERRIDE { | 
| +  } | 
| + | 
| + protected: | 
| +  virtual void CleanUpOnMainThread() OVERRIDE { | 
| +    download_history_.reset(); | 
| +  } | 
| + | 
| +  DownloadHistory* download_history() { return download_history_.get(); } | 
| + | 
| +  MockDownloadManager& manager() { return *manager_.get(); } | 
| +  MockDownloadItem& item() { return item_; } | 
| + | 
| +  HistoryService::DownloadQueryCallback query_callback() { | 
| +    return base::Bind(&DownloadHistoryTest::QueryCallback, | 
| +                      base::Unretained(this)); | 
| +  } | 
| + | 
| +  void ExpectQueryDownloads(DownloadHistory::InfoVector* infos) { | 
| +    expect_query_downloads_ = infos; | 
| +    EXPECT_CALL(manager(), AddObserver(_)); | 
| +    EXPECT_CALL(manager(), RemoveObserver(_)); | 
| +    if (infos->size() != 0) { | 
| +      EXPECT_EQ(1, static_cast<int>(infos->size())); | 
| +      EXPECT_CALL(manager(), CreateDownloadItem( | 
| +          infos->at(0).path, | 
| +          infos->at(0).url, | 
| +          infos->at(0).referrer_url, | 
| +          infos->at(0).start_time, | 
| +          infos->at(0).end_time, | 
| +          infos->at(0).received_bytes, | 
| +          infos->at(0).total_bytes, | 
| +          infos->at(0).state, | 
| +          infos->at(0).opened)) | 
| +        .WillOnce(DoAll( | 
| +            InvokeWithoutArgs( | 
| +                this, &DownloadHistoryTest::CallOnDownloadCreated), | 
| +            Return(&item()))); | 
| +    } | 
| +    download_history_.reset(new DownloadHistory(&manager(), this)); | 
| +    content::RunAllPendingInMessageLoop(content::BrowserThread::UI); | 
| +    CHECK(NULL == expect_query_downloads_); | 
| +  } | 
| + | 
| +  void CallOnDownloadCreated() { | 
| +    download_history_->OnDownloadCreated(&manager(), &item()); | 
| +  } | 
| + | 
| +  void ExpectCreateDownload( | 
| +      const DownloadPersistentStoreInfo& info) { | 
| +    content::RunAllPendingInMessageLoop(content::BrowserThread::UI); | 
| +    CHECK_EQ(item().GetId(), create_download_id_); | 
| +    create_download_id_ = -1; | 
| +    CHECK(InfoEqual(info, create_download_info_)); | 
| +    create_download_info_ = DownloadPersistentStoreInfo(); | 
| +  } | 
| + | 
| +  void ExpectNoCreateDownload() { | 
| +    content::RunAllPendingInMessageLoop(content::BrowserThread::UI); | 
| +    CHECK_EQ(-1, create_download_id_); | 
| +    CHECK(InfoEqual(DownloadPersistentStoreInfo(), create_download_info_)); | 
| +  } | 
| + | 
| +  void ExpectUpdateDownload(const DownloadPersistentStoreInfo& info) { | 
| +    content::RunAllPendingInMessageLoop(content::BrowserThread::UI); | 
| +    CHECK(InfoEqual(update_download_, info)); | 
| +    update_download_ = DownloadPersistentStoreInfo(); | 
| +  } | 
| + | 
| +  void ExpectNoUpdateDownload() { | 
| +    content::RunAllPendingInMessageLoop(content::BrowserThread::UI); | 
| +    CHECK(InfoEqual(DownloadPersistentStoreInfo(), update_download_)); | 
| +  } | 
| + | 
| +  void ExpectNoRemoveDownloads() { | 
| +    content::RunAllPendingInMessageLoop(content::BrowserThread::UI); | 
| +    CHECK_EQ(0, static_cast<int>(remove_downloads_.size())); | 
| +  } | 
| + | 
| +  void ExpectRemoveDownloads(const DownloadHistory::HandleSet& handles) { | 
| +    content::RunAllPendingInMessageLoop(content::BrowserThread::UI); | 
| +    DownloadHistory::HandleSet difference; | 
| +    std::insert_iterator<DownloadHistory::HandleSet> insert_it( | 
| +        difference, difference.begin()); | 
| +    std::set_difference(handles.begin(), handles.end(), | 
| +                        remove_downloads_.begin(), | 
| +                        remove_downloads_.end(), | 
| +                        insert_it); | 
| +    CHECK(difference.empty()); | 
| +    remove_downloads_.clear(); | 
| +  } | 
| + | 
| +  void InitItem( | 
| +      int32 id, | 
| +      const FilePath& path, | 
| +      const GURL& url, | 
| +      const GURL& referrer, | 
| +      const base::Time& start_time, | 
| +      const base::Time& end_time, | 
| +      int64 received_bytes, | 
| +      int64 total_bytes, | 
| +      DownloadItem::DownloadState state, | 
| +      int64 db_handle, | 
| +      bool opened, | 
| +      DownloadPersistentStoreInfo* info) { | 
| +    info->path = path; | 
| +    info->url = url; | 
| +    info->referrer_url = referrer; | 
| +    info->start_time = start_time; | 
| +    info->end_time = end_time; | 
| +    info->received_bytes = received_bytes; | 
| +    info->total_bytes = total_bytes; | 
| +    info->state = state; | 
| +    info->db_handle = db_handle; | 
| +    info->opened = opened; | 
| +    EXPECT_CALL(item(), GetId()).WillRepeatedly(Return(id)); | 
| +    EXPECT_CALL(item(), GetFullPath()).WillRepeatedly(ReturnRef(path)); | 
| +    EXPECT_CALL(item(), GetURL()).WillRepeatedly(ReturnRef(url)); | 
| +    EXPECT_CALL(item(), GetReferrerUrl()).WillRepeatedly(ReturnRef(referrer)); | 
| +    EXPECT_CALL(item(), GetStartTime()).WillRepeatedly(Return(start_time)); | 
| +    EXPECT_CALL(item(), GetEndTime()).WillRepeatedly(Return(end_time)); | 
| +    EXPECT_CALL(item(), GetReceivedBytes()) | 
| +      .WillRepeatedly(Return(received_bytes)); | 
| +    EXPECT_CALL(item(), GetTotalBytes()).WillRepeatedly(Return(total_bytes)); | 
| +    EXPECT_CALL(item(), GetState()).WillRepeatedly(Return(state)); | 
| +    EXPECT_CALL(item(), GetOpened()).WillRepeatedly(Return(opened)); | 
| +    EXPECT_CALL(manager(), GetDownload(id)) | 
| +      .WillRepeatedly(Return(&item())); | 
| +    EXPECT_CALL(item(), AddObserver(_)); | 
| +    EXPECT_CALL(item(), RemoveObserver(_)); | 
| +  } | 
| + | 
| + private: | 
| +  void QueryCallback(DownloadHistory::InfoVector* infos) { | 
| +  } | 
| + | 
| +  testing::NiceMock<content::MockDownloadItem> item_; | 
| +  scoped_refptr<content::MockDownloadManager> manager_; | 
| +  scoped_ptr<DownloadHistory> download_history_; | 
| +  DownloadHistory::InfoVector* expect_query_downloads_; | 
| +  bool slow_create_download_; | 
| +  base::Closure create_download_callback_; | 
| +  int handle_counter_; | 
| +  DownloadPersistentStoreInfo update_download_; | 
| +  int32 create_download_id_; | 
| +  DownloadPersistentStoreInfo create_download_info_; | 
| +  DownloadHistory::HandleSet remove_downloads_; | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(DownloadHistoryTest); | 
| +}; | 
| + | 
| +}  // anonymous namespace | 
| + | 
| +IN_PROC_BROWSER_TEST_F(DownloadHistoryTest, | 
| +    DownloadHistoryTest_Load) { | 
| +  // Load a download from history, create the item, OnDownloadCreated, | 
| +  // OnDownloadUpdated, OnDownloadRemoved, OnDownloadDestroyed. | 
| +  DownloadPersistentStoreInfo info; | 
| +  InitItem(base::RandInt(0, 1 << 20), | 
| +           FilePath(FILE_PATH_LITERAL("/foo/bar.pdf")), | 
| +           GURL("http://example.com/bar.pdf"), | 
| +           GURL("http://example.com/referrer.html"), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(10)), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(1)), | 
| +           100, | 
| +           100, | 
| +           DownloadItem::COMPLETE, | 
| +           base::RandInt(0, 1 << 20), | 
| +           false, | 
| +           &info); | 
| +  DownloadHistory::InfoVector infos; | 
| +  infos.push_back(info); | 
| +  ExpectQueryDownloads(&infos); | 
| +  ExpectNoCreateDownload(); | 
| + | 
| +  // Pretend that something changed on the item. | 
| +  EXPECT_CALL(item(), GetOpened()).WillRepeatedly(Return(true)); | 
| +  download_history()->OnDownloadUpdated(&item()); | 
| +  info.opened = true; | 
| +  ExpectUpdateDownload(info); | 
| + | 
| +  // Pretend that the user removed the item. | 
| +  DownloadHistory::HandleSet handles; | 
| +  handles.insert(info.db_handle); | 
| +  download_history()->OnDownloadRemoved(&item()); | 
| +  ExpectRemoveDownloads(handles); | 
| + | 
| +  // Pretend that the browser is closing. | 
| +  download_history()->ManagerGoingDown(&manager()); | 
| +  download_history()->OnDownloadDestroyed(&item()); | 
| +} | 
| + | 
| +IN_PROC_BROWSER_TEST_F(DownloadHistoryTest, | 
| +    DownloadHistoryTest_Create) { | 
| +  // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated, | 
| +  // OnDownloadRemoved, OnDownloadDestroyed. | 
| +  DownloadHistory::InfoVector infos; | 
| +  ExpectQueryDownloads(&infos); | 
| + | 
| +  // Note that db_handle must be -1 at first because it isn't in the db yet. | 
| +  DownloadPersistentStoreInfo info; | 
| +  InitItem(base::RandInt(0, 1 << 20), | 
| +           FilePath(FILE_PATH_LITERAL("/foo/bar.pdf")), | 
| +           GURL("http://example.com/bar.pdf"), | 
| +           GURL("http://example.com/referrer.html"), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(10)), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(1)), | 
| +           100, | 
| +           100, | 
| +           DownloadItem::COMPLETE, | 
| +           -1, | 
| +           false, | 
| +           &info); | 
| + | 
| +  // Pretend the manager just created |item|. | 
| +  download_history()->OnDownloadCreated(&manager(), &item()); | 
| +  // CreateDownload() always gets db_handle=-1. | 
| +  ExpectCreateDownload(info); | 
| +  info.db_handle = 0; | 
| + | 
| +  // Pretend that something changed on the item. | 
| +  EXPECT_CALL(item(), GetOpened()).WillRepeatedly(Return(true)); | 
| +  download_history()->OnDownloadUpdated(&item()); | 
| +  info.opened = true; | 
| +  ExpectUpdateDownload(info); | 
| + | 
| +  // Pretend that the user removed the item. | 
| +  DownloadHistory::HandleSet handles; | 
| +  handles.insert(info.db_handle); | 
| +  download_history()->OnDownloadRemoved(&item()); | 
| +  ExpectRemoveDownloads(handles); | 
| + | 
| +  // Pretend that the browser is closing. | 
| +  download_history()->ManagerGoingDown(&manager()); | 
| +  download_history()->OnDownloadDestroyed(&item()); | 
| +} | 
| + | 
| +IN_PROC_BROWSER_TEST_F(DownloadHistoryTest, | 
| +    DownloadHistoryTest_Temporary) { | 
| +  // Create a fresh item not from history, OnDownloadCreated, OnDownloadUpdated, | 
| +  // OnDownloadRemoved, OnDownloadDestroyed. | 
| +  DownloadHistory::InfoVector infos; | 
| +  ExpectQueryDownloads(&infos); | 
| + | 
| +  // Note that db_handle must be -1 at first because it isn't in the db yet. | 
| +  DownloadPersistentStoreInfo info; | 
| +  InitItem(base::RandInt(0, 1 << 20), | 
| +           FilePath(FILE_PATH_LITERAL("/foo/bar.pdf")), | 
| +           GURL("http://example.com/bar.pdf"), | 
| +           GURL("http://example.com/referrer.html"), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(10)), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(1)), | 
| +           100, | 
| +           100, | 
| +           DownloadItem::COMPLETE, | 
| +           -1, | 
| +           false, | 
| +           &info); | 
| + | 
| +  // Pretend the manager just created |item|. | 
| +  download_history()->OnDownloadCreated(&manager(), &item()); | 
| +  // CreateDownload() always gets db_handle=-1. | 
| +  ExpectCreateDownload(info); | 
| +  info.db_handle = 0; | 
| + | 
| +  // Pretend the item was marked temporary. DownloadHistory should remove it | 
| +  // from history and start ignoring it. | 
| +  EXPECT_CALL(item(), IsTemporary()).WillRepeatedly(Return(true)); | 
| +  download_history()->OnDownloadUpdated(&item()); | 
| +  DownloadHistory::HandleSet handles; | 
| +  handles.insert(info.db_handle); | 
| +  ExpectRemoveDownloads(handles); | 
| + | 
| +  // Change something that would make DownloadHistory call UpdateDownload if the | 
| +  // item weren't temporary. | 
| +  EXPECT_CALL(item(), GetReceivedBytes()).WillRepeatedly(Return(4200)); | 
| +  download_history()->OnDownloadUpdated(&item()); | 
| +  ExpectNoUpdateDownload(); | 
| + | 
| +  // Changing a temporary item back to a non-temporary item should make | 
| +  // DownloadHistory call CreateDownload. | 
| +  EXPECT_CALL(item(), IsTemporary()).WillRepeatedly(Return(false)); | 
| +  download_history()->OnDownloadUpdated(&item()); | 
| +  info.received_bytes = 4200; | 
| +  info.db_handle = -1; | 
| +  // CreateDownload() always gets db_handle=-1. | 
| +  ExpectCreateDownload(info); | 
| +  info.db_handle = 1; | 
| + | 
| +  EXPECT_CALL(item(), GetReceivedBytes()).WillRepeatedly(Return(100)); | 
| +  download_history()->OnDownloadUpdated(&item()); | 
| +  info.received_bytes = 100; | 
| +  ExpectUpdateDownload(info); | 
| + | 
| +  // Pretend that the browser is closing. | 
| +  download_history()->ManagerGoingDown(&manager()); | 
| +  download_history()->OnDownloadDestroyed(&item()); | 
| +} | 
| + | 
| +IN_PROC_BROWSER_TEST_F(DownloadHistoryTest, | 
| +    DownloadHistoryTest_RemoveWhileAdding) { | 
| +  DownloadHistory::InfoVector infos; | 
| +  ExpectQueryDownloads(&infos); | 
| + | 
| +  // Note that db_handle must be -1 at first because it isn't in the db yet. | 
| +  DownloadPersistentStoreInfo info; | 
| +  InitItem(base::RandInt(0, 1 << 20), | 
| +           FilePath(FILE_PATH_LITERAL("/foo/bar.pdf")), | 
| +           GURL("http://example.com/bar.pdf"), | 
| +           GURL("http://example.com/referrer.html"), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(10)), | 
| +           (base::Time::Now() - base::TimeDelta::FromMinutes(1)), | 
| +           100, | 
| +           100, | 
| +           DownloadItem::COMPLETE, | 
| +           -1, | 
| +           false, | 
| +           &info); | 
| + | 
| +  // Instruct CreateDownload() to not callback to DownloadHistory immediately, | 
| +  // but to wait for FinishCreateDownload(). | 
| +  set_slow_create_download(true); | 
| + | 
| +  // Pretend the manager just created |item|. | 
| +  download_history()->OnDownloadCreated(&manager(), &item()); | 
| +  // CreateDownload() always gets db_handle=-1. | 
| +  ExpectCreateDownload(info); | 
| +  info.db_handle = 0; | 
| + | 
| +  // Call OnDownloadRemoved before calling back to DownloadHistory::ItemAdded(). | 
| +  // Instead of calling RemoveDownloads() immediately, it should | 
| +  download_history()->OnDownloadRemoved(&item()); | 
| +  EXPECT_CALL(manager(), GetDownload(item().GetId())) | 
| +    .WillRepeatedly(Return(static_cast<DownloadItem*>(NULL))); | 
| +  ExpectNoRemoveDownloads(); | 
| + | 
| +  // Now callback to DownloadHistory::ItemAdded(), and expect a call to | 
| +  // RemoveDownloads() for the item that was removed while it was being added. | 
| +  FinishCreateDownload(); | 
| +  DownloadHistory::HandleSet handles; | 
| +  handles.insert(info.db_handle); | 
| +  ExpectRemoveDownloads(handles); | 
| + | 
| +  // Pretend that the browser is closing. | 
| +  download_history()->ManagerGoingDown(&manager()); | 
| +  download_history()->OnDownloadDestroyed(&item()); | 
| +} | 
|  |