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

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

Powered by Google App Engine
This is Rietveld 408576698