Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(287)

Side by Side Diff: chrome/browser/ntp_snippets/download_suggestions_provider_unittest.cc

Issue 2360263002: [NTPSnippets] Show all downloads on the NTP (3/3): Downloads provider. (Closed)
Patch Set: rebase + Marc's comments. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "chrome/browser/ntp_snippets/download_suggestions_provider.h"
6
7 #include "base/bind.h"
8 #include "base/observer_list.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "chrome/browser/ntp_snippets/fake_download_item.h"
11 #include "components/ntp_snippets/category.h"
12 #include "components/ntp_snippets/category_factory.h"
13 #include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
14 #include "components/ntp_snippets/offline_pages/offline_pages_test_utils.h"
15 #include "components/offline_pages/client_namespace_constants.h"
16 #include "components/prefs/testing_pref_service.h"
17 #include "content/public/test/mock_download_item.h"
18 #include "content/public/test/mock_download_manager.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 using content::DownloadItem;
22 using content::MockDownloadManager;
23 using ntp_snippets::Category;
24 using ntp_snippets::CategoryFactory;
25 using ntp_snippets::ContentSuggestion;
26 using ntp_snippets::ContentSuggestionsProvider;
27 using ntp_snippets::MockContentSuggestionsProviderObserver;
28 using ntp_snippets::OfflinePageProxy;
29 using ntp_snippets::test::CaptureDismissedSuggestions;
30 using ntp_snippets::test::FakeOfflinePageModel;
31 using ntp_snippets::CategoryStatus;
32 using offline_pages::ClientId;
33 using offline_pages::OfflinePageItem;
34 using test::FakeDownloadItem;
35 using testing::_;
36 using testing::AnyNumber;
37 using testing::ElementsAre;
38 using testing::IsEmpty;
39 using testing::Mock;
40 using testing::Return;
41 using testing::SizeIs;
42 using testing::StrictMock;
43 using testing::UnorderedElementsAre;
44 using testing::Lt;
45
46 namespace ntp_snippets {
47 // These functions are implicitly used to print out values during the tests.
48 std::ostream& operator<<(std::ostream& os, const ContentSuggestion& value) {
49 os << "{ url: " << value.url() << ", publish_date: " << value.publish_date()
50 << "}";
51 return os;
52 }
53
54 std::ostream& operator<<(std::ostream& os, const CategoryStatus& value) {
55 os << "CategoryStatus::";
56 switch (value) {
57 case CategoryStatus::INITIALIZING:
58 os << "INITIALIZING";
59 break;
60 case CategoryStatus::AVAILABLE:
61 os << "AVAILABLE";
62 break;
63 case CategoryStatus::AVAILABLE_LOADING:
64 os << "AVAILABLE_LOADING";
65 break;
66 case CategoryStatus::NOT_PROVIDED:
67 os << "NOT_PROVIDED";
68 break;
69 case CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED:
70 os << "ALL_SUGGESTIONS_EXPLICITLY_DISABLED";
71 break;
72 case CategoryStatus::CATEGORY_EXPLICITLY_DISABLED:
73 os << "CATEGORY_EXPLICITLY_DISABLED";
74 break;
75 case CategoryStatus::SIGNED_OUT:
76 os << "SIGNED_OUT";
77 break;
78 case CategoryStatus::LOADING_ERROR:
79 os << "LOADING_ERROR";
80 break;
81 }
82 return os;
83 }
84
85 } // namespace ntp_snippets
86
87 namespace {
88
89 // TODO(vitaliii): Move this and outputting functions above to common file and
90 // replace remaining |Property(&ContentSuggestion::url, GURL("some_url"))|.
91 // See crbug.com/655513.
92 MATCHER_P(HasUrl, url, "") {
93 *result_listener << "expected URL: " << url
94 << "has URL: " << arg.url().spec();
95 return arg.url().spec() == url;
96 }
97
98 OfflinePageItem CreateDummyOfflinePage(int id) {
99 return ntp_snippets::test::CreateDummyOfflinePageItem(
100 id, offline_pages::kAsyncNamespace);
101 }
102
103 std::vector<OfflinePageItem> CreateDummyOfflinePages(
104 const std::vector<int>& ids) {
105 std::vector<OfflinePageItem> result;
106 for (int id : ids) {
107 result.push_back(CreateDummyOfflinePage(id));
108 }
109 return result;
110 }
111
112 OfflinePageItem CreateDummyOfflinePage(int id, base::Time time) {
113 OfflinePageItem item = CreateDummyOfflinePage(id);
114 item.creation_time = time;
115 return item;
116 }
117
118 std::unique_ptr<FakeDownloadItem> CreateDummyAssetDownload(int id) {
119 std::unique_ptr<FakeDownloadItem> item = base::MakeUnique<FakeDownloadItem>();
120 item->SetId(id);
121 std::string id_string = base::IntToString(id);
122 item->SetTargetFilePath(
123 base::FilePath::FromUTF8Unsafe("folder/file" + id_string + ".mhtml"));
124 item->SetURL(GURL("http://dummy_file.com/" + id_string));
125 item->SetEndTime(base::Time::Now());
126 item->SetFileExternallyRemoved(false);
127 item->SetState(DownloadItem::DownloadState::COMPLETE);
128 return item;
129 }
130
131 std::unique_ptr<FakeDownloadItem> CreateDummyAssetDownload(
132 int id,
133 const base::Time end_time) {
134 std::unique_ptr<FakeDownloadItem> item = CreateDummyAssetDownload(id);
135 item->SetEndTime(end_time);
136 return item;
137 }
138
139 std::vector<std::unique_ptr<FakeDownloadItem>> CreateDummyAssetDownloads(
140 const std::vector<int>& ids) {
141 std::vector<std::unique_ptr<FakeDownloadItem>> result;
142 // The time is set to enforce the provider to cache the first items in the
143 // list first.
144 base::Time current_time = base::Time::Now();
145 for (int id : ids) {
146 result.push_back(CreateDummyAssetDownload(id, current_time));
147 current_time -= base::TimeDelta::FromDays(1);
148 }
149 return result;
150 }
151
152 class ObservedMockDownloadManager : public MockDownloadManager {
153 public:
154 ObservedMockDownloadManager() {}
155 ~ObservedMockDownloadManager() override {
156 for (auto& observer : observers_)
157 observer.ManagerGoingDown(this);
158 }
159
160 // Observer accessors.
161 void AddObserver(Observer* observer) override {
162 observers_.AddObserver(observer);
163 }
164
165 void RemoveObserver(Observer* observer) override {
166 observers_.RemoveObserver(observer);
167 }
168
169 void NotifyDownloadCreated(DownloadItem* item) {
170 for (auto& observer : observers_)
171 observer.OnDownloadCreated(this, item);
172 }
173
174 std::vector<std::unique_ptr<FakeDownloadItem>>* mutable_items() {
175 return &items_;
176 }
177
178 const std::vector<std::unique_ptr<FakeDownloadItem>>& items() const {
179 return items_;
180 }
181
182 void GetAllDownloads(std::vector<DownloadItem*>* all_downloads) override {
183 all_downloads->clear();
184 for (const auto& item : items_)
185 all_downloads->push_back(item.get());
186 }
187
188 private:
189 base::ObserverList<Observer> observers_;
190 std::vector<std::unique_ptr<FakeDownloadItem>> items_;
191 };
192
193 } // namespace
194
195 class DownloadSuggestionsProviderTest : public testing::Test {
196 public:
197 DownloadSuggestionsProviderTest()
198 : pref_service_(new TestingPrefServiceSimple()) {
199 DownloadSuggestionsProvider::RegisterProfilePrefs(
200 pref_service()->registry());
201 }
202
203 void IgnoreOnCategoryStatusChangedToAvailable() {
204 EXPECT_CALL(observer_, OnCategoryStatusChanged(_, downloads_category(),
205 CategoryStatus::AVAILABLE))
206 .Times(AnyNumber());
207 EXPECT_CALL(observer_,
208 OnCategoryStatusChanged(_, downloads_category(),
209 CategoryStatus::AVAILABLE_LOADING))
210 .Times(AnyNumber());
211 }
212
213 void IgnoreOnSuggestionInvalidated() {
214 EXPECT_CALL(observer_, OnSuggestionInvalidated(_, _)).Times(AnyNumber());
215 }
216
217 DownloadSuggestionsProvider* CreateProvider() {
218 DCHECK(!provider_);
219 scoped_refptr<OfflinePageProxy> proxy(
220 new OfflinePageProxy(&offline_pages_model_));
221 provider_ = base::MakeUnique<DownloadSuggestionsProvider>(
222 &observer_, &category_factory_, proxy, &downloads_manager_,
223 pref_service(),
224 /*download_manager_ui_enabled=*/false);
225 return provider_.get();
226 }
227
228 void DestroyProvider() { provider_.reset(); }
229
230 Category downloads_category() {
231 return category_factory_.FromKnownCategory(
232 ntp_snippets::KnownCategories::DOWNLOADS);
233 }
234
235 void FireOfflinePageModelChanged(const std::vector<OfflinePageItem>& items) {
236 DCHECK(provider_);
237 provider_->OfflinePageModelChanged(items);
238 }
239
240 void FireOfflinePageDeleted(const OfflinePageItem& item) {
241 DCHECK(provider_);
242 provider_->OfflinePageDeleted(item.offline_id, item.client_id);
243 }
244
245 void FireDownloadCreated(DownloadItem* item) {
246 DCHECK(provider_);
247 downloads_manager_.NotifyDownloadCreated(item);
248 }
249
250 void FireDownloadsCreated(
251 const std::vector<std::unique_ptr<FakeDownloadItem>>& items) {
252 for (const auto& item : items)
253 FireDownloadCreated(item.get());
254 }
255
256 ContentSuggestion::ID GetDummySuggestionId(int id, bool is_offline_page) {
257 return ContentSuggestion::ID(
258 downloads_category(),
259 (is_offline_page ? "O" : "D") + base::IntToString(id));
260 }
261
262 std::vector<ContentSuggestion> GetDismissedSuggestions() {
263 std::vector<ContentSuggestion> dismissed_suggestions;
264 // This works synchronously because both fake data sources were designed so.
265 provider()->GetDismissedSuggestionsForDebugging(
266 downloads_category(),
267 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
268 return dismissed_suggestions;
269 }
270
271 ContentSuggestionsProvider* provider() {
272 DCHECK(provider_);
273 return provider_.get();
274 }
275 ObservedMockDownloadManager* downloads_manager() {
276 return &downloads_manager_;
277 }
278 FakeOfflinePageModel* offline_pages_model() { return &offline_pages_model_; }
279 MockContentSuggestionsProviderObserver* observer() { return &observer_; }
280 TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
281
282 private:
283 ObservedMockDownloadManager downloads_manager_;
284 FakeOfflinePageModel offline_pages_model_;
285 StrictMock<MockContentSuggestionsProviderObserver> observer_;
286 CategoryFactory category_factory_;
287 std::unique_ptr<TestingPrefServiceSimple> pref_service_;
288 // Last so that the dependencies are deleted after the provider.
289 std::unique_ptr<DownloadSuggestionsProvider> provider_;
290
291 DISALLOW_COPY_AND_ASSIGN(DownloadSuggestionsProviderTest);
292 };
293
294 TEST_F(DownloadSuggestionsProviderTest,
295 ShouldConvertOfflinePagesToSuggestions) {
296 IgnoreOnCategoryStatusChangedToAvailable();
297
298 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
299 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(),
300 UnorderedElementsAre(
301 HasUrl("http://dummy.com/1"),
302 HasUrl("http://dummy.com/2"))));
303 CreateProvider();
304 }
305
306 TEST_F(DownloadSuggestionsProviderTest,
307 ShouldConvertDownloadItemsToSuggestions) {
308 IgnoreOnCategoryStatusChangedToAvailable();
309 IgnoreOnSuggestionInvalidated();
310
311 EXPECT_CALL(*observer(),
312 OnNewSuggestions(_, downloads_category(), SizeIs(0)));
313 CreateProvider();
314
315 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads =
316 CreateDummyAssetDownloads({1, 2});
317
318 EXPECT_CALL(*observer(),
319 OnNewSuggestions(
320 _, downloads_category(),
321 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"))));
322 FireDownloadCreated(asset_downloads[0].get());
323
324 EXPECT_CALL(*observer(),
325 OnNewSuggestions(
326 _, downloads_category(),
327 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
328 HasUrl("file:///folder/file2.mhtml"))));
329 FireDownloadCreated(asset_downloads[1].get());
330 }
331
332 TEST_F(DownloadSuggestionsProviderTest, ShouldMixInBothSources) {
333 IgnoreOnCategoryStatusChangedToAvailable();
334 IgnoreOnSuggestionInvalidated();
335
336 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
337 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(),
338 UnorderedElementsAre(
339 HasUrl("http://dummy.com/1"),
340 HasUrl("http://dummy.com/2"))));
341 CreateProvider();
342
343 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads =
344 CreateDummyAssetDownloads({1, 2});
345
346 EXPECT_CALL(*observer(),
347 OnNewSuggestions(
348 _, downloads_category(),
349 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
350 HasUrl("http://dummy.com/2"),
351 HasUrl("file:///folder/file1.mhtml"))));
352 FireDownloadCreated(asset_downloads[0].get());
353
354 EXPECT_CALL(*observer(),
355 OnNewSuggestions(
356 _, downloads_category(),
357 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
358 HasUrl("http://dummy.com/2"),
359 HasUrl("file:///folder/file1.mhtml"),
360 HasUrl("file:///folder/file2.mhtml"))));
361 FireDownloadCreated(asset_downloads[1].get());
362 }
363
364 TEST_F(DownloadSuggestionsProviderTest, ShouldSortSuggestions) {
365 IgnoreOnCategoryStatusChangedToAvailable();
366 IgnoreOnSuggestionInvalidated();
367
368 base::Time now = base::Time::Now();
369 base::Time yesterday = now - base::TimeDelta::FromDays(1);
370 base::Time tomorrow = now + base::TimeDelta::FromDays(1);
371 base::Time next_week = now + base::TimeDelta::FromDays(7);
372
373 (*offline_pages_model()->mutable_items())
374 .push_back(CreateDummyOfflinePage(1, yesterday));
375 (*offline_pages_model()->mutable_items())
376 .push_back(CreateDummyOfflinePage(2, tomorrow));
377
378 EXPECT_CALL(*observer(),
379 OnNewSuggestions(_, downloads_category(),
380 ElementsAre(HasUrl("http://dummy.com/2"),
381 HasUrl("http://dummy.com/1"))));
382 CreateProvider();
383
384 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads;
385 asset_downloads.push_back(CreateDummyAssetDownload(3, next_week));
386 asset_downloads.push_back(CreateDummyAssetDownload(4, now));
387
388 EXPECT_CALL(*observer(),
389 OnNewSuggestions(_, downloads_category(),
390 ElementsAre(HasUrl("file:///folder/file3.mhtml"),
391 HasUrl("http://dummy.com/2"),
392 HasUrl("http://dummy.com/1"))));
393 FireDownloadCreated(asset_downloads[0].get());
394
395 EXPECT_CALL(*observer(),
396 OnNewSuggestions(_, downloads_category(),
397 ElementsAre(HasUrl("file:///folder/file3.mhtml"),
398 HasUrl("http://dummy.com/2"),
399 HasUrl("file:///folder/file4.mhtml"),
400 HasUrl("http://dummy.com/1"))));
401 FireDownloadCreated(asset_downloads[1].get());
402 }
403
404 TEST_F(DownloadSuggestionsProviderTest,
405 ShouldDismissWithoutNotifyingObservers) {
406 IgnoreOnCategoryStatusChangedToAvailable();
407
408 EXPECT_CALL(*observer(),
409 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
410 .Times(2);
411 EXPECT_CALL(*observer(),
412 OnNewSuggestions(
413 _, downloads_category(),
414 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
415 HasUrl("http://dummy.com/2"),
416 HasUrl("file:///folder/file1.mhtml"),
417 HasUrl("file:///folder/file2.mhtml"))));
418
419 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
420 CreateProvider();
421 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
422 FireDownloadsCreated(downloads_manager()->items());
423
424 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
425 EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, _)).Times(0);
426 provider()->DismissSuggestion(
427 GetDummySuggestionId(1, /*is_offline_page=*/true));
428 provider()->DismissSuggestion(
429 GetDummySuggestionId(1, /*is_offline_page=*/false));
430
431 // |downloads_manager_| is destroyed after the |provider_|, so the provider
432 // will not observe download items being destroyed.
433 }
434
435 TEST_F(DownloadSuggestionsProviderTest,
436 ShouldNotReportDismissedSuggestionsOnNewData) {
437 IgnoreOnCategoryStatusChangedToAvailable();
438
439 EXPECT_CALL(*observer(),
440 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
441 .Times(2);
442 EXPECT_CALL(*observer(),
443 OnNewSuggestions(
444 _, downloads_category(),
445 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
446 HasUrl("http://dummy.com/2"),
447 HasUrl("file:///folder/file1.mhtml"),
448 HasUrl("file:///folder/file2.mhtml"))));
449 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
450 CreateProvider();
451 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
452 FireDownloadsCreated(downloads_manager()->items());
453
454 provider()->DismissSuggestion(
455 GetDummySuggestionId(1, /*is_offline_page=*/true));
456 provider()->DismissSuggestion(
457 GetDummySuggestionId(1, /*is_offline_page=*/false));
458
459 EXPECT_CALL(*observer(),
460 OnNewSuggestions(
461 _, downloads_category(),
462 UnorderedElementsAre(HasUrl("http://dummy.com/2"),
463 HasUrl("file:///folder/file2.mhtml"))));
464 FireOfflinePageModelChanged(offline_pages_model()->items());
465 }
466
467 TEST_F(DownloadSuggestionsProviderTest, ShouldReturnDismissedSuggestions) {
468 IgnoreOnCategoryStatusChangedToAvailable();
469
470 EXPECT_CALL(*observer(),
471 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
472 .Times(2);
473 EXPECT_CALL(*observer(),
474 OnNewSuggestions(
475 _, downloads_category(),
476 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
477 HasUrl("http://dummy.com/2"),
478 HasUrl("file:///folder/file1.mhtml"),
479 HasUrl("file:///folder/file2.mhtml"))));
480 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
481 CreateProvider();
482 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
483 FireDownloadsCreated(downloads_manager()->items());
484
485 provider()->DismissSuggestion(
486 GetDummySuggestionId(1, /*is_offline_page=*/true));
487 provider()->DismissSuggestion(
488 GetDummySuggestionId(1, /*is_offline_page=*/false));
489
490 EXPECT_THAT(GetDismissedSuggestions(),
491 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
492 HasUrl("file:///folder/file1.mhtml")));
493 }
494
495 TEST_F(DownloadSuggestionsProviderTest, ShouldClearDismissedSuggestions) {
496 IgnoreOnCategoryStatusChangedToAvailable();
497
498 EXPECT_CALL(*observer(),
499 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
500 .Times(2);
501 EXPECT_CALL(*observer(),
502 OnNewSuggestions(
503 _, downloads_category(),
504 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
505 HasUrl("http://dummy.com/2"),
506 HasUrl("file:///folder/file1.mhtml"),
507 HasUrl("file:///folder/file2.mhtml"))));
508 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
509 CreateProvider();
510 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
511 FireDownloadsCreated(downloads_manager()->items());
512
513 provider()->DismissSuggestion(
514 GetDummySuggestionId(1, /*is_offline_page=*/true));
515 provider()->DismissSuggestion(
516 GetDummySuggestionId(1, /*is_offline_page=*/false));
517
518 EXPECT_CALL(*observer(),
519 OnNewSuggestions(
520 _, downloads_category(),
521 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
522 HasUrl("http://dummy.com/2"),
523 HasUrl("file:///folder/file1.mhtml"),
524 HasUrl("file:///folder/file2.mhtml"))));
525 provider()->ClearDismissedSuggestionsForDebugging(downloads_category());
526 EXPECT_THAT(GetDismissedSuggestions(), IsEmpty());
527 }
528
529 TEST_F(DownloadSuggestionsProviderTest,
530 ShouldNotDismissOtherTypeWithTheSameID) {
531 IgnoreOnCategoryStatusChangedToAvailable();
532
533 EXPECT_CALL(*observer(),
534 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
535 .Times(2);
536 EXPECT_CALL(*observer(),
537 OnNewSuggestions(
538 _, downloads_category(),
539 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
540 HasUrl("http://dummy.com/2"),
541 HasUrl("file:///folder/file1.mhtml"),
542 HasUrl("file:///folder/file2.mhtml"))));
543 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
544 CreateProvider();
545 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
546 FireDownloadsCreated(downloads_manager()->items());
547
548 provider()->DismissSuggestion(
549 GetDummySuggestionId(1, /*is_offline_page=*/true));
550
551 EXPECT_CALL(*observer(),
552 OnNewSuggestions(
553 _, downloads_category(),
554 UnorderedElementsAre(HasUrl("http://dummy.com/2"),
555 HasUrl("file:///folder/file1.mhtml"),
556 HasUrl("file:///folder/file2.mhtml"))));
557 FireOfflinePageModelChanged(offline_pages_model()->items());
558 }
559
560 TEST_F(DownloadSuggestionsProviderTest, ShouldReplaceDismissedItemWithNewData) {
561 IgnoreOnCategoryStatusChangedToAvailable();
562
563 EXPECT_CALL(*observer(),
564 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(5ul))))
565 .Times(5);
566 EXPECT_CALL(*observer(),
567 OnNewSuggestions(
568 _, downloads_category(),
569 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
570 HasUrl("file:///folder/file2.mhtml"),
571 HasUrl("file:///folder/file3.mhtml"),
572 HasUrl("file:///folder/file4.mhtml"),
573 HasUrl("file:///folder/file5.mhtml"))));
574 CreateProvider();
575 // Currently the provider stores five items in its internal cache, so six
576 // items are needed to check whether all downloads are fetched on dismissal.
577 *(downloads_manager()->mutable_items()) =
578 CreateDummyAssetDownloads({1, 2, 3, 4, 5, 6});
579 FireDownloadsCreated(downloads_manager()->items());
580
581 provider()->DismissSuggestion(
582 GetDummySuggestionId(1, /*is_offline_page=*/false));
583
584 // The provider is not notified about the 6th item, however, it must report
585 // it now.
586 EXPECT_CALL(*observer(),
587 OnNewSuggestions(
588 _, downloads_category(),
589 UnorderedElementsAre(HasUrl("file:///folder/file2.mhtml"),
590 HasUrl("file:///folder/file3.mhtml"),
591 HasUrl("file:///folder/file4.mhtml"),
592 HasUrl("file:///folder/file5.mhtml"),
593 HasUrl("file:///folder/file6.mhtml"))));
594 FireOfflinePageModelChanged(offline_pages_model()->items());
595 }
596
597 TEST_F(DownloadSuggestionsProviderTest,
598 ShouldInvalidateWhenUnderlyingItemDeleted) {
599 IgnoreOnCategoryStatusChangedToAvailable();
600
601 EXPECT_CALL(*observer(),
602 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(3ul))));
603 EXPECT_CALL(*observer(),
604 OnNewSuggestions(
605 _, downloads_category(),
606 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
607 HasUrl("http://dummy.com/2"),
608 HasUrl("file:///folder/file1.mhtml"))));
609 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
610 CreateProvider();
611 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1});
612 FireDownloadsCreated(downloads_manager()->items());
613
614 // We add another item manually, so that when it gets deleted it is not
615 // present in DownloadsManager list.
616 std::unique_ptr<FakeDownloadItem> removed_item = CreateDummyAssetDownload(2);
617 EXPECT_CALL(*observer(),
618 OnNewSuggestions(
619 _, downloads_category(),
620 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
621 HasUrl("http://dummy.com/2"),
622 HasUrl("file:///folder/file1.mhtml"),
623 HasUrl("file:///folder/file2.mhtml"))));
624 FireDownloadCreated(removed_item.get());
625
626 EXPECT_CALL(*observer(),
627 OnSuggestionInvalidated(
628 _, GetDummySuggestionId(1, /*is_offline_page=*/true)));
629 FireOfflinePageDeleted(offline_pages_model()->items()[0]);
630
631 EXPECT_CALL(*observer(),
632 OnSuggestionInvalidated(
633 _, GetDummySuggestionId(2, /*is_offline_page=*/false)));
634 // |OnDownloadItemDestroyed| is called from |removed_item|'s destructor.
635 removed_item.reset();
636 }
637
638 TEST_F(DownloadSuggestionsProviderTest, ShouldReplaceRemovedItemWithNewData) {
639 IgnoreOnCategoryStatusChangedToAvailable();
640 IgnoreOnSuggestionInvalidated();
641
642 EXPECT_CALL(*observer(),
643 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(5ul))))
644 .Times(5);
645 EXPECT_CALL(*observer(),
646 OnNewSuggestions(
647 _, downloads_category(),
648 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
649 HasUrl("file:///folder/file2.mhtml"),
650 HasUrl("file:///folder/file3.mhtml"),
651 HasUrl("file:///folder/file4.mhtml"),
652 HasUrl("file:///folder/file5.mhtml"))));
653 CreateProvider();
654 *(downloads_manager()->mutable_items()) =
655 CreateDummyAssetDownloads({1, 2, 3, 4, 5});
656 FireDownloadsCreated(downloads_manager()->items());
657
658 // Note that |CreateDummyAssetDownloads| creates items "downloaded" before
659 // |base::Time::Now()|, so for a new item the time is set in future to enforce
660 // the provider to show the new item.
661 std::unique_ptr<FakeDownloadItem> removed_item = CreateDummyAssetDownload(
662 100, base::Time::Now() + base::TimeDelta::FromDays(1));
663 EXPECT_CALL(*observer(),
664 OnNewSuggestions(_, downloads_category(),
665 UnorderedElementsAre(
666 HasUrl("file:///folder/file1.mhtml"),
667 HasUrl("file:///folder/file2.mhtml"),
668 HasUrl("file:///folder/file3.mhtml"),
669 HasUrl("file:///folder/file4.mhtml"),
670 HasUrl("file:///folder/file100.mhtml"))));
671 FireDownloadCreated(removed_item.get());
672
673 // |OnDownloadDestroyed| notification is called in |DownloadItem|'s
674 // destructor.
675 removed_item.reset();
676
677 EXPECT_CALL(*observer(),
678 OnNewSuggestions(
679 _, downloads_category(),
680 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
681 HasUrl("file:///folder/file2.mhtml"),
682 HasUrl("file:///folder/file3.mhtml"),
683 HasUrl("file:///folder/file4.mhtml"),
684 HasUrl("file:///folder/file5.mhtml"))));
685 FireOfflinePageModelChanged(offline_pages_model()->items());
686 }
687
688 TEST_F(DownloadSuggestionsProviderTest, ShouldPruneOfflinePagesDismissedIDs) {
689 IgnoreOnCategoryStatusChangedToAvailable();
690 IgnoreOnSuggestionInvalidated();
691
692 *(offline_pages_model()->mutable_items()) =
693 CreateDummyOfflinePages({1, 2, 3});
694 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(),
695 UnorderedElementsAre(
696 HasUrl("http://dummy.com/1"),
697 HasUrl("http://dummy.com/2"),
698 HasUrl("http://dummy.com/3"))));
699 CreateProvider();
700
701 provider()->DismissSuggestion(
702 GetDummySuggestionId(1, /*is_offline_page=*/true));
703 provider()->DismissSuggestion(
704 GetDummySuggestionId(2, /*is_offline_page=*/true));
705 provider()->DismissSuggestion(
706 GetDummySuggestionId(3, /*is_offline_page=*/true));
707 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(3));
708
709 // Prune on getting all offline pages. Note that the first suggestion is not
710 // removed from |offline_pages_model| storage, because otherwise
711 // |GetDismissedSuggestions| cannot return it.
712 EXPECT_CALL(*observer(),
713 OnNewSuggestions(_, downloads_category(), IsEmpty()));
714 FireOfflinePageModelChanged(CreateDummyOfflinePages({2, 3}));
715 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(2));
716
717 // Prune when offline page is deleted.
718 FireOfflinePageDeleted(offline_pages_model()->items()[1]);
719 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(1));
720 }
721
722 TEST_F(DownloadSuggestionsProviderTest, ShouldPruneAssetDownloadsDismissedIDs) {
723 IgnoreOnCategoryStatusChangedToAvailable();
724 IgnoreOnSuggestionInvalidated();
725
726 EXPECT_CALL(*observer(),
727 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(3ul))))
728 .Times(3);
729 CreateProvider();
730 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
731 FireDownloadsCreated(downloads_manager()->items());
732
733 provider()->DismissSuggestion(
734 GetDummySuggestionId(1, /*is_offline_page=*/false));
735 provider()->DismissSuggestion(
736 GetDummySuggestionId(2, /*is_offline_page=*/false));
737 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(2));
738
739 downloads_manager()->items()[0]->NotifyDownloadDestroyed();
740 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(1));
741 }
742
743 TEST_F(DownloadSuggestionsProviderTest, ShouldNotFetchAssetDownloadsOnStartup) {
744 IgnoreOnCategoryStatusChangedToAvailable();
745
746 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
747 EXPECT_CALL(*observer(),
748 OnNewSuggestions(_, downloads_category(), IsEmpty()));
749 CreateProvider();
750 }
751
752 TEST_F(DownloadSuggestionsProviderTest,
753 ShouldInvalidateAssetDownloadWhenItsFileRemoved) {
754 IgnoreOnCategoryStatusChangedToAvailable();
755
756 EXPECT_CALL(*observer(),
757 OnNewSuggestions(_, downloads_category(), IsEmpty()));
758 EXPECT_CALL(*observer(),
759 OnNewSuggestions(_, downloads_category(), SizeIs(1)));
760 CreateProvider();
761 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1});
762 FireDownloadsCreated(downloads_manager()->items());
763
764 EXPECT_CALL(*observer(),
765 OnSuggestionInvalidated(
766 _, GetDummySuggestionId(1, /*is_offline_page=*/false)));
767 (*downloads_manager()->mutable_items())[0]->SetFileExternallyRemoved(true);
768 (*downloads_manager()->mutable_items())[0]->NotifyDownloadUpdated();
769 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698