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