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.
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"
20 #if defined(ENABLE_EXTENSIONS)
21 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
25 using testing::Invoke;
26 using testing::Return;
27 using testing::ReturnRefOfCopy;
28 using testing::SetArgPointee;
29 using testing::WithArg;
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();
42 EXPECT_EQ(left.url_chain[i].spec(), right.url_chain[i].spec());
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);
61 typedef DownloadHistory::IdSet IdSet;
62 typedef std::vector<history::DownloadRow> InfoVector;
63 typedef testing::StrictMock<content::MockDownloadItem> StrictMockDownloadItem;
65 class FakeHistoryAdapter : public DownloadHistory::HistoryAdapter {
68 : DownloadHistory::HistoryAdapter(NULL),
69 slow_create_download_(false),
70 fail_create_download_(false) {
73 ~FakeHistoryAdapter() override {}
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));
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());
90 void set_slow_create_download(bool slow) { slow_create_download_ = slow; }
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();
105 void FinishCreateDownload() {
106 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
107 create_download_callback_.Run();
108 create_download_callback_.Reset();
111 void UpdateDownload(const history::DownloadRow& info) override {
112 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
113 update_download_ = info;
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);
124 void ExpectWillQueryDownloads(scoped_ptr<InfoVector> infos) {
125 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
126 expect_query_downloads_ = infos.Pass();
129 void ExpectQueryDownloadsDone() {
130 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
131 EXPECT_TRUE(NULL == expect_query_downloads_.get());
134 void FailCreateDownload() {
135 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
136 fail_create_download_ = true;
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();
147 void ExpectNoDownloadCreated() {
148 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
149 content::RunAllPendingInMessageLoop(content::BrowserThread::UI);
150 CheckInfoEqual(history::DownloadRow(), create_download_info_);
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();
160 void ExpectNoDownloadUpdated() {
161 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
162 content::RunAllPendingInMessageLoop(content::BrowserThread::UI);
163 CheckInfoEqual(history::DownloadRow(), update_download_);
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()));
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;
180 remove_downloads_.clear();
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_;
192 DISALLOW_COPY_AND_ASSIGN(FakeHistoryAdapter);
195 class DownloadHistoryTest : public testing::Test {
197 // Generic callback that receives a pointer to a StrictMockDownloadItem.
198 typedef base::Callback<void(content::MockDownloadItem*)> DownloadItemCallback;
200 DownloadHistoryTest()
201 : ui_thread_(content::BrowserThread::UI, &loop_),
202 manager_(new content::MockDownloadManager()),
204 manager_observer_(NULL),
205 download_created_index_(0) {}
206 ~DownloadHistoryTest() override { STLDeleteElements(&items_); }
209 void TearDown() override { download_history_.reset(); }
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(); }
215 void SetManagerObserver(
216 content::DownloadManager::Observer* manager_observer) {
217 manager_observer_ = manager_observer;
219 content::DownloadManager::Observer* manager_observer() {
220 return manager_observer_;
223 void CreateDownloadHistory(scoped_ptr<InfoVector> infos) {
224 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
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(
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))
252 this, &DownloadHistoryTest::CallOnDownloadCreatedInOrder),
253 Return(&item(index))));
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();
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));
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_++);
281 void set_slow_create_download(bool slow) {
282 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
283 history_->set_slow_create_download(slow);
286 void FinishCreateDownload() {
287 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
288 history_->FinishCreateDownload();
291 void FailCreateDownload() {
292 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
293 history_->FailCreateDownload();
296 void ExpectDownloadCreated(
297 const history::DownloadRow& info) {
298 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
299 history_->ExpectDownloadCreated(info);
302 void ExpectNoDownloadCreated() {
303 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
304 history_->ExpectNoDownloadCreated();
307 void ExpectDownloadUpdated(const history::DownloadRow& info) {
308 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
309 history_->ExpectDownloadUpdated(info);
312 void ExpectNoDownloadUpdated() {
313 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
314 history_->ExpectNoDownloadUpdated();
317 void ExpectNoDownloadsRemoved() {
318 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
319 history_->ExpectNoDownloadsRemoved();
322 void ExpectDownloadsRemoved(const IdSet& ids) {
323 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
324 history_->ExpectDownloadsRemoved(ids);
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),
333 post_on_create_handler_ =
334 base::Bind(&DownloadHistoryTest::CheckDownloadWasRestoredFromHistory,
335 base::Unretained(this),
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),
352 "application/octet-stream",
353 "application/octet-stream",
354 (base::Time::Now() - base::TimeDelta::FromMinutes(10)),
355 (base::Time::Now() - base::TimeDelta::FromMinutes(1)),
360 content::DownloadItem::COMPLETE,
361 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
362 content::DOWNLOAD_INTERRUPT_REASON_NONE,
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,
383 content::DownloadItem::DownloadState state,
384 content::DownloadDangerType danger_type,
385 content::DownloadInterruptReason interrupt_reason,
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));
392 size_t index = items_.size();
393 StrictMockDownloadItem* mock_item = new StrictMockDownloadItem();
394 items_.push_back(mock_item);
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;
405 info->last_modified = last_modified;
406 info->received_bytes = received_bytes;
407 info->total_bytes = total_bytes;
409 info->danger_type = danger_type;
410 info->interrupt_reason = interrupt_reason;
412 info->opened = opened;
413 info->by_ext_id = by_extension_id;
414 info->by_ext_name = by_extension_name;
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())
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);
457 std::vector<content::DownloadItem*> items;
458 for (size_t i = 0; i < items_.size(); ++i) {
459 items.push_back(&item(i));
461 EXPECT_CALL(*manager_.get(), GetAllDownloads(_))
462 .WillRepeatedly(SetArgPointee<0>(items));
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));
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_;
483 DISALLOW_COPY_AND_ASSIGN(DownloadHistoryTest);
486 // Test loading an item from the database, changing it, saving it back, removing
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",
497 scoped_ptr<InfoVector> infos(new InfoVector());
498 infos->push_back(info);
499 CreateDownloadHistory(infos.Pass());
500 ExpectNoDownloadCreated();
502 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
504 // Pretend that something changed on the item.
505 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true));
506 item(0).NotifyObserversDownloadUpdated();
508 ExpectDownloadUpdated(info);
510 // Pretend that the user removed the item.
513 item(0).NotifyObserversDownloadRemoved();
514 ExpectDownloadsRemoved(ids);
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
524 ExpectDownloadsRestoredFromHistory(true);
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",
535 scoped_ptr<InfoVector> infos(new InfoVector());
536 infos->push_back(info);
537 CreateDownloadHistory(infos.Pass());
539 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
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
549 ExpectDownloadsRestoredFromHistory(false);
551 // Create a DownloadHistory with no history downloads. No
552 // DownloadManager::CreateDownload() calls are expected.
553 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector()));
555 // Notify DownloadHistory that a new download was created. The above test
556 // expecation should verify that WasRestoredFromHistory is correct for this
558 history::DownloadRow info;
559 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
560 "http://example.com/bar.pdf",
561 "http://example.com/referrer.html",
563 CallOnDownloadCreated(0);
564 ExpectDownloadCreated(info);
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()));
574 history::DownloadRow info;
575 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
576 "http://example.com/bar.pdf",
577 "http://example.com/referrer.html",
580 // Pretend the manager just created |item|.
581 CallOnDownloadCreated(0);
582 ExpectDownloadCreated(info);
583 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
585 // Pretend that something changed on the item.
586 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true));
587 item(0).NotifyObserversDownloadUpdated();
589 ExpectDownloadUpdated(info);
591 // Pretend that the user removed the item.
594 item(0).NotifyObserversDownloadRemoved();
595 ExpectDownloadsRemoved(ids);
598 // Test that changes to persisted fields in a DownloadItem triggers database
600 TEST_F(DownloadHistoryTest, DownloadHistoryTest_Update) {
601 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector()));
603 history::DownloadRow info;
604 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
605 "http://example.com/bar.pdf",
606 "http://example.com/referrer.html",
608 CallOnDownloadCreated(0);
609 ExpectDownloadCreated(info);
610 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
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");
618 EXPECT_CALL(item(0), GetFullPath()).WillRepeatedly(ReturnRefOfCopy(new_path));
619 info.current_path = new_path;
620 item(0).NotifyObserversDownloadUpdated();
621 ExpectDownloadUpdated(info);
624 EXPECT_CALL(item(0), GetTargetFilePath())
625 .WillRepeatedly(ReturnRefOfCopy(new_path));
626 info.target_path = new_path;
627 item(0).NotifyObserversDownloadUpdated();
628 ExpectDownloadUpdated(info);
631 EXPECT_CALL(item(0), GetEndTime()).WillRepeatedly(Return(new_time));
632 info.end_time = new_time;
633 item(0).NotifyObserversDownloadUpdated();
634 ExpectDownloadUpdated(info);
637 EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(101));
638 info.received_bytes = 101;
639 item(0).NotifyObserversDownloadUpdated();
640 ExpectDownloadUpdated(info);
643 EXPECT_CALL(item(0), GetTotalBytes()).WillRepeatedly(Return(102));
644 info.total_bytes = 102;
645 item(0).NotifyObserversDownloadUpdated();
646 ExpectDownloadUpdated(info);
649 EXPECT_CALL(item(0), GetETag()).WillRepeatedly(ReturnRefOfCopy(new_etag));
650 info.etag = new_etag;
651 item(0).NotifyObserversDownloadUpdated();
652 ExpectDownloadUpdated(info);
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);
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);
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);
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);
683 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true));
685 item(0).NotifyObserversDownloadUpdated();
686 ExpectDownloadUpdated(info);
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()));
698 history::DownloadRow info;
699 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
700 "http://example.com/bar.pdf",
701 "http://example.com/referrer.html",
704 // Pretend the manager just created |item|.
705 CallOnDownloadCreated(0);
706 ExpectDownloadCreated(info);
707 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
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();
715 ExpectDownloadsRemoved(ids);
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();
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)));
731 EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(100));
732 item(0).NotifyObserversDownloadUpdated();
733 info.received_bytes = 100;
734 ExpectDownloadUpdated(info);
737 // Test removing downloads while they're still being added.
738 TEST_F(DownloadHistoryTest, DownloadHistoryTest_RemoveWhileAdding) {
739 CreateDownloadHistory(scoped_ptr<InfoVector>(new InfoVector()));
741 history::DownloadRow info;
742 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
743 "http://example.com/bar.pdf",
744 "http://example.com/referrer.html",
747 // Instruct CreateDownload() to not callback to DownloadHistory immediately,
748 // but to wait for FinishCreateDownload().
749 set_slow_create_download(true);
751 // Pretend the manager just created |item|.
752 CallOnDownloadCreated(0);
753 ExpectDownloadCreated(info);
754 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0)));
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)));
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();
771 ExpectDownloadsRemoved(ids);
772 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0)));
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",
784 InitBasicItem(FILE_PATH_LITERAL("/foo/qux.pdf"),
785 "http://example.com/qux.pdf",
786 "http://example.com/referrer1.html",
789 scoped_ptr<InfoVector> infos(new InfoVector());
790 infos->push_back(info0);
791 infos->push_back(info1);
792 CreateDownloadHistory(infos.Pass());
793 ExpectNoDownloadCreated();
796 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
797 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(1)));
799 // Pretend that the user removed both items.
801 ids.insert(info0.id);
802 ids.insert(info1.id);
803 item(0).NotifyObserversDownloadRemoved();
804 item(1).NotifyObserversDownloadRemoved();
805 ExpectDownloadsRemoved(ids);
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()));
814 history::DownloadRow info;
815 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
816 "http://example.com/bar.pdf",
817 "http://example.com/referrer.html",
820 FailCreateDownload();
821 // Pretend the manager just created |item|.
822 CallOnDownloadCreated(0);
823 ExpectDownloadCreated(info);
824 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0)));
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)));
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()));
838 history::DownloadRow info;
839 InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
840 "http://example.com/bar.pdf",
841 "http://example.com/referrer.html",
844 // Instruct CreateDownload() to not callback to DownloadHistory immediately,
845 // but to wait for FinishCreateDownload().
846 set_slow_create_download(true);
848 // Pretend the manager just created |item|.
849 CallOnDownloadCreated(0);
850 ExpectDownloadCreated(info);
851 EXPECT_FALSE(DownloadHistory::IsPersisted(&item(0)));
853 // Pretend that something changed on the item.
854 EXPECT_CALL(item(0), GetOpened()).WillRepeatedly(Return(true));
855 item(0).NotifyObserversDownloadUpdated();
857 FinishCreateDownload();
858 EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
860 // ItemAdded should call OnDownloadUpdated, which should detect that the item
861 // changed while it was being added and call UpdateDownload immediately.
863 ExpectDownloadUpdated(info);
866 } // anonymous namespace