• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • 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 
CheckInfoEqual(const history::DownloadRow & left,const history::DownloadRow & right)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:
FakeHistoryAdapter()67   FakeHistoryAdapter()
68     : DownloadHistory::HistoryAdapter(NULL),
69       slow_create_download_(false),
70       fail_create_download_(false) {
71   }
72 
~FakeHistoryAdapter()73   virtual ~FakeHistoryAdapter() {}
74 
QueryDownloads(const HistoryService::DownloadQueryCallback & callback)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 
QueryDownloadsDone(const HistoryService::DownloadQueryCallback & callback)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 
set_slow_create_download(bool slow)90   void set_slow_create_download(bool slow) { slow_create_download_ = slow; }
91 
CreateDownload(const history::DownloadRow & info,const HistoryService::DownloadCreateCallback & callback)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 
FinishCreateDownload()105   void FinishCreateDownload() {
106     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
107     create_download_callback_.Run();
108     create_download_callback_.Reset();
109   }
110 
UpdateDownload(const history::DownloadRow & info)111   virtual void UpdateDownload(
112       const history::DownloadRow& info) OVERRIDE {
113     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
114     update_download_ = info;
115   }
116 
RemoveDownloads(const IdSet & ids)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 
ExpectWillQueryDownloads(scoped_ptr<InfoVector> infos)125   void ExpectWillQueryDownloads(scoped_ptr<InfoVector> infos) {
126     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
127     expect_query_downloads_ = infos.Pass();
128   }
129 
ExpectQueryDownloadsDone()130   void ExpectQueryDownloadsDone() {
131     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
132     EXPECT_TRUE(NULL == expect_query_downloads_.get());
133   }
134 
FailCreateDownload()135   void FailCreateDownload() {
136     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
137     fail_create_download_ = true;
138   }
139 
ExpectDownloadCreated(const history::DownloadRow & info)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 
ExpectNoDownloadCreated()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 
ExpectDownloadUpdated(const history::DownloadRow & info)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 
ExpectNoDownloadUpdated()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 
ExpectNoDownloadsRemoved()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 
ExpectDownloadsRemoved(const IdSet & ids)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 
DownloadHistoryTest()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) {}
~DownloadHistoryTest()207   virtual ~DownloadHistoryTest() {
208     STLDeleteElements(&items_);
209   }
210 
211  protected:
TearDown()212   virtual void TearDown() OVERRIDE {
213     download_history_.reset();
214   }
215 
manager()216   content::MockDownloadManager& manager() { return *manager_.get(); }
item(size_t index)217   content::MockDownloadItem& item(size_t index) { return *items_[index]; }
download_history()218   DownloadHistory* download_history() { return download_history_.get(); }
219 
SetManagerObserver(content::DownloadManager::Observer * manager_observer)220   void SetManagerObserver(
221       content::DownloadManager::Observer* manager_observer) {
222     manager_observer_ = manager_observer;
223   }
manager_observer()224   content::DownloadManager::Observer* manager_observer() {
225     return manager_observer_;
226   }
227 
CreateDownloadHistory(scoped_ptr<InfoVector> infos)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 
CallOnDownloadCreated(size_t index)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 
CallOnDownloadCreatedInOrder()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 
set_slow_create_download(bool slow)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 
FinishCreateDownload()291   void FinishCreateDownload() {
292     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
293     history_->FinishCreateDownload();
294   }
295 
FailCreateDownload()296   void FailCreateDownload() {
297     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
298     history_->FailCreateDownload();
299   }
300 
ExpectDownloadCreated(const history::DownloadRow & info)301   void ExpectDownloadCreated(
302       const history::DownloadRow& info) {
303     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
304     history_->ExpectDownloadCreated(info);
305   }
306 
ExpectNoDownloadCreated()307   void ExpectNoDownloadCreated() {
308     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
309     history_->ExpectNoDownloadCreated();
310   }
311 
ExpectDownloadUpdated(const history::DownloadRow & info)312   void ExpectDownloadUpdated(const history::DownloadRow& info) {
313     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
314     history_->ExpectDownloadUpdated(info);
315   }
316 
ExpectNoDownloadUpdated()317   void ExpectNoDownloadUpdated() {
318     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
319     history_->ExpectNoDownloadUpdated();
320   }
321 
ExpectNoDownloadsRemoved()322   void ExpectNoDownloadsRemoved() {
323     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
324     history_->ExpectNoDownloadsRemoved();
325   }
326 
ExpectDownloadsRemoved(const IdSet & ids)327   void ExpectDownloadsRemoved(const IdSet& ids) {
328     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
329     history_->ExpectDownloadsRemoved(ids);
330   }
331 
ExpectDownloadsRestoredFromHistory(bool expected_value)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 
InitBasicItem(const base::FilePath::CharType * path,const char * url_string,const char * referrer_string,history::DownloadRow * info)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 
InitItem(uint32 id,const base::FilePath & current_path,const base::FilePath & target_path,const std::vector<GURL> & url_chain,const GURL & referrer,const std::string & mime_type,const std::string & original_mime_type,const base::Time & start_time,const base::Time & end_time,const std::string & etag,const std::string & last_modified,int64 received_bytes,int64 total_bytes,content::DownloadItem::DownloadState state,content::DownloadDangerType danger_type,content::DownloadInterruptReason interrupt_reason,bool opened,const std::string & by_extension_id,const std::string & by_extension_name,history::DownloadRow * info)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:
CheckDownloadWasRestoredFromHistory(bool expected_value,content::MockDownloadItem * item)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_Load)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_WasRestoredFromHistory_True)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_WasRestoredFromHistory_False)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_Create)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_Update)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_Temporary)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_RemoveWhileAdding)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_Multiple)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.
TEST_F(DownloadHistoryTest,DownloadHistoryTest_CreateFailed)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 
TEST_F(DownloadHistoryTest,DownloadHistoryTest_UpdateWhileAdding)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