Home | History | Annotate | Download | only in download
      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