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

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: another win fix. Created 4 years, 2 months 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 void PrintTo(const ContentSuggestion& value, std::ostream* os) {
49 *os << "{ url: " << value.url() << ", publish_date: " << value.publish_date()
50 << "}";
51 }
52
53 void PrintTo(const CategoryStatus& value, std::ostream* os) {
Marc Treib 2016/10/17 10:18:41 If multiple tests need this, it's also okay to def
vitaliii 2016/10/26 00:07:55 I will do this as a part of clean up later.
54 *os << "CategoryStatus::";
55 switch (value) {
56 case CategoryStatus::INITIALIZING:
57 *os << "INITIALIZING";
58 break;
59 case CategoryStatus::AVAILABLE:
60 *os << "AVAILABLE";
61 break;
62 case CategoryStatus::AVAILABLE_LOADING:
63 *os << "AVAILABLE_LOADING";
64 break;
65 case CategoryStatus::NOT_PROVIDED:
66 *os << "NOT_PROVIDED";
67 break;
68 case CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED:
69 *os << "ALL_SUGGESTIONS_EXPLICITLY_DISABLED";
70 break;
71 case CategoryStatus::CATEGORY_EXPLICITLY_DISABLED:
72 *os << "CATEGORY_EXPLICITLY_DISABLED";
73 break;
74 case CategoryStatus::SIGNED_OUT:
75 *os << "SIGNED_OUT";
76 break;
77 case CategoryStatus::LOADING_ERROR:
78 *os << "LOADING_ERROR";
79 break;
80 }
81 }
82
83 } // namespace ntp_snippets
84
85 namespace {
86
87 // TODO(vitaliii): Move this and |PrintTo| above to common file and replace
88 // remaining |Property(&ContentSuggestion::url, GURL("some_url"))|.
89 // See crbug.com/655513.
90 MATCHER_P(HasUrl, url, "") {
91 *result_listener << "expected URL: " << url
92 << "has URL: " << arg.url().spec();
93 return arg.url().spec() == url;
94 }
95
96 OfflinePageItem CreateDummyOfflinePage(int id) {
97 return ntp_snippets::test::CreateDummyOfflinePageItem(
98 id, offline_pages::kAsyncNamespace);
99 }
100
101 std::vector<OfflinePageItem> CreateDummyOfflinePages(
102 const std::vector<int>& ids) {
103 std::vector<OfflinePageItem> result;
104 for (int id : ids) {
105 result.push_back(CreateDummyOfflinePage(id));
106 }
107 return result;
108 }
109
110 OfflinePageItem CreateDummyOfflinePage(int id, base::Time time) {
111 OfflinePageItem item = CreateDummyOfflinePage(id);
112 item.creation_time = time;
113 return item;
114 }
115
116 std::unique_ptr<FakeDownloadItem> CreateDummyAssetDownload(int id) {
117 std::unique_ptr<FakeDownloadItem> item = base::MakeUnique<FakeDownloadItem>();
118 item->SetId(id);
119 std::string id_string = base::IntToString(id);
120 item->SetTargetFilePath(
121 base::FilePath::FromUTF8Unsafe("folder/file" + id_string + ".mhtml"));
122 item->SetURL(GURL("http://dummy_file.com/" + id_string));
123 item->SetEndTime(base::Time::Now());
124 item->SetFileExternallyRemoved(false);
125 item->SetState(DownloadItem::DownloadState::COMPLETE);
126 return item;
127 }
128
129 std::unique_ptr<FakeDownloadItem> CreateDummyAssetDownload(
130 int id,
131 const base::Time end_time) {
132 std::unique_ptr<FakeDownloadItem> item = CreateDummyAssetDownload(id);
133 item->SetEndTime(end_time);
134 return item;
135 }
136
137 std::vector<std::unique_ptr<FakeDownloadItem>> CreateDummyAssetDownloads(
138 const std::vector<int>& ids) {
139 std::vector<std::unique_ptr<FakeDownloadItem>> result;
140 // The time is set to enforce the provider to cache the first items in the
141 // list first.
142 base::Time current_time = base::Time::Now();
143 for (int id : ids) {
144 result.push_back(CreateDummyAssetDownload(id, current_time));
145 current_time -= base::TimeDelta::FromDays(1);
146 }
147 return result;
148 }
149
150 class ObservedMockDownloadManager : public MockDownloadManager {
151 public:
152 ObservedMockDownloadManager() {}
153 ~ObservedMockDownloadManager() override {
154 for (auto& observer : observers_)
155 observer.ManagerGoingDown(this);
156 }
157
158 // Observer accessors.
159 void AddObserver(Observer* observer) override {
160 observers_.AddObserver(observer);
161 }
162
163 void RemoveObserver(Observer* observer) override {
164 observers_.RemoveObserver(observer);
165 }
166
167 void NotifyDownloadCreated(DownloadItem* item) {
168 for (auto& observer : observers_)
169 observer.OnDownloadCreated(this, item);
170 }
171
172 std::vector<std::unique_ptr<FakeDownloadItem>>* mutable_items() {
173 return &items_;
174 }
175
176 const std::vector<std::unique_ptr<FakeDownloadItem>>& items() const {
177 return items_;
178 }
179
180 void GetAllDownloads(std::vector<DownloadItem*>* all_downloads) override {
181 all_downloads->clear();
182 for (const auto& item : items_)
183 all_downloads->push_back(item.get());
184 }
185
186 private:
187 base::ObserverList<Observer> observers_;
188 std::vector<std::unique_ptr<FakeDownloadItem>> items_;
189 };
190
191 } // namespace
192
193 class DownloadSuggestionsProviderTest : public testing::Test {
194 public:
195 DownloadSuggestionsProviderTest()
196 : pref_service_(new TestingPrefServiceSimple()) {
197 DownloadSuggestionsProvider::RegisterProfilePrefs(
198 pref_service()->registry());
199 }
200
201 void IgnoreOnCategoryStatusChanged() {
Marc Treib 2016/10/17 10:18:41 nit: This sounds like it ignores all changes, but
vitaliii 2016/10/26 00:07:55 Done.
202 EXPECT_CALL(observer_, OnCategoryStatusChanged(_, downloads_category(),
203 CategoryStatus::AVAILABLE))
204 .Times(AnyNumber());
205 EXPECT_CALL(observer_,
206 OnCategoryStatusChanged(_, downloads_category(),
207 CategoryStatus::AVAILABLE_LOADING))
208 .Times(AnyNumber());
209 }
210
211 void IgnoreOnSuggestionInvalidated() {
212 EXPECT_CALL(observer_, OnSuggestionInvalidated(_, _)).Times(AnyNumber());
213 }
214
215 DownloadSuggestionsProvider* CreateProvider() {
216 scoped_refptr<OfflinePageProxy> proxy(
Marc Treib 2016/10/17 10:18:41 DCHECK(!provider_) ?
vitaliii 2016/10/26 00:07:55 Done.
217 new OfflinePageProxy(&offline_pages_model_));
218 provider_ = base::MakeUnique<DownloadSuggestionsProvider>(
219 &observer_, &category_factory_, proxy, &downloads_manager_,
220 pref_service(),
221 /*download_manager_ui_enabled=*/false);
222 return provider_.get();
223 }
224
225 void DestroyProvider() { provider_.release(); }
Marc Treib 2016/10/17 10:18:41 This will leak memory - it gives up ownership and
vitaliii 2016/10/26 00:07:55 I misunderstood what |release()| does, I meant |re
226
227 Category downloads_category() {
228 return category_factory_.FromKnownCategory(
229 ntp_snippets::KnownCategories::DOWNLOADS);
230 }
231
232 void FireOfflinePageModelChanged(const std::vector<OfflinePageItem>& items) {
233 DCHECK(provider_.get());
Marc Treib 2016/10/17 10:18:41 nit: I think the ".get()" isn't required
vitaliii 2016/10/26 00:07:55 Done.
234 provider_->OfflinePageModelChanged(items);
235 }
236
237 void FireOfflinePageDeleted(const OfflinePageItem& item) {
238 DCHECK(provider_.get());
239 provider_->OfflinePageDeleted(item.offline_id, item.client_id);
240 }
241
242 void FireDownloadCreated(DownloadItem* item) {
243 DCHECK(provider_.get());
244 downloads_manager_.NotifyDownloadCreated(item);
245 }
246
247 void FireDownloadsCreated(
248 const std::vector<std::unique_ptr<FakeDownloadItem>>& items) {
249 for (const auto& item : items)
250 FireDownloadCreated(item.get());
251 }
252
253 ContentSuggestion::ID GetDummySuggestionId(int id, bool is_offline_page) {
254 return ContentSuggestion::ID(
255 downloads_category(),
256 (is_offline_page ? "O" : "D") + base::IntToString(id));
257 }
258
259 std::vector<ContentSuggestion> GetDismissedSuggestions() {
260 std::vector<ContentSuggestion> dismissed_suggestions;
261 provider()->GetDismissedSuggestionsForDebugging(
262 downloads_category(),
263 base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
Marc Treib 2016/10/17 10:18:41 Does this always return synchronously? If so, that
vitaliii 2016/10/26 00:07:55 FakeOfflinePageModel (which we own) returns items
264 return dismissed_suggestions;
265 }
266
267 ContentSuggestionsProvider* provider() {
268 DCHECK(provider_.get());
269 return provider_.get();
270 }
271 ObservedMockDownloadManager* downloads_manager() {
272 return &downloads_manager_;
273 }
274 FakeOfflinePageModel* offline_pages_model() { return &offline_pages_model_; }
275 StrictMock<MockContentSuggestionsProviderObserver>* observer() {
Marc Treib 2016/10/17 10:18:41 I think just returning MockContentSuggestionsProvi
vitaliii 2016/10/26 00:07:55 Done.
276 return &observer_;
277 }
278 TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
279
280 private:
281 ObservedMockDownloadManager downloads_manager_;
282 FakeOfflinePageModel offline_pages_model_;
283 StrictMock<MockContentSuggestionsProviderObserver> observer_;
284 CategoryFactory category_factory_;
285 std::unique_ptr<TestingPrefServiceSimple> pref_service_;
286 // Last so that the dependencies are deleted after the provider.
287 std::unique_ptr<DownloadSuggestionsProvider> provider_;
288
289 DISALLOW_COPY_AND_ASSIGN(DownloadSuggestionsProviderTest);
290 };
291
292 TEST_F(DownloadSuggestionsProviderTest,
293 ShouldConvertOfflinePagesToSuggestions) {
294 IgnoreOnCategoryStatusChanged();
295
296 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
297 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(),
298 UnorderedElementsAre(
299 HasUrl("http://dummy.com/1"),
300 HasUrl("http://dummy.com/2"))));
301 CreateProvider();
302 }
303
304 TEST_F(DownloadSuggestionsProviderTest,
305 ShouldConvertDownloadItemsToSuggestions) {
306 IgnoreOnCategoryStatusChanged();
307 IgnoreOnSuggestionInvalidated();
308
309 EXPECT_CALL(*observer(),
310 OnNewSuggestions(_, downloads_category(), SizeIs(0)));
311 CreateProvider();
312
313 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads =
314 CreateDummyAssetDownloads({1, 2});
315
316 EXPECT_CALL(*observer(),
317 OnNewSuggestions(
318 _, downloads_category(),
319 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"))));
320 FireDownloadCreated(asset_downloads[0].get());
321
322 EXPECT_CALL(*observer(),
323 OnNewSuggestions(
324 _, downloads_category(),
325 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
326 HasUrl("file:///folder/file2.mhtml"))));
327 FireDownloadCreated(asset_downloads[1].get());
328 }
329
330 TEST_F(DownloadSuggestionsProviderTest, ShouldMixInBothSources) {
331 IgnoreOnCategoryStatusChanged();
332 IgnoreOnSuggestionInvalidated();
333
334 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
335 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(),
336 UnorderedElementsAre(
337 HasUrl("http://dummy.com/1"),
338 HasUrl("http://dummy.com/2"))));
339 CreateProvider();
340
341 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads =
342 CreateDummyAssetDownloads({1, 2});
343
344 EXPECT_CALL(*observer(),
345 OnNewSuggestions(
346 _, downloads_category(),
347 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
348 HasUrl("http://dummy.com/2"),
349 HasUrl("file:///folder/file1.mhtml"))));
350 FireDownloadCreated(asset_downloads[0].get());
351
352 EXPECT_CALL(*observer(),
353 OnNewSuggestions(
354 _, downloads_category(),
355 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
356 HasUrl("http://dummy.com/2"),
357 HasUrl("file:///folder/file1.mhtml"),
358 HasUrl("file:///folder/file2.mhtml"))));
359 FireDownloadCreated(asset_downloads[1].get());
360 }
361
362 TEST_F(DownloadSuggestionsProviderTest, ShouldSortSuggestions) {
363 IgnoreOnCategoryStatusChanged();
364 IgnoreOnSuggestionInvalidated();
365
366 base::Time now = base::Time::Now();
367 base::Time yesterday = now - base::TimeDelta::FromDays(1);
368 base::Time tomorrow = now + base::TimeDelta::FromDays(1);
369 base::Time next_week = now + base::TimeDelta::FromDays(7);
370
371 (*offline_pages_model()->mutable_items())
372 .push_back(CreateDummyOfflinePage(1, yesterday));
373 (*offline_pages_model()->mutable_items())
374 .push_back(CreateDummyOfflinePage(2, tomorrow));
375
376 EXPECT_CALL(*observer(),
377 OnNewSuggestions(_, downloads_category(),
378 ElementsAre(HasUrl("http://dummy.com/2"),
379 HasUrl("http://dummy.com/1"))));
380 CreateProvider();
381
382 std::vector<std::unique_ptr<FakeDownloadItem>> asset_downloads;
383 asset_downloads.push_back(CreateDummyAssetDownload(3, next_week));
384 asset_downloads.push_back(CreateDummyAssetDownload(4, now));
385
386 EXPECT_CALL(*observer(),
387 OnNewSuggestions(_, downloads_category(),
388 ElementsAre(HasUrl("file:///folder/file3.mhtml"),
389 HasUrl("http://dummy.com/2"),
390 HasUrl("http://dummy.com/1"))));
391 FireDownloadCreated(asset_downloads[0].get());
392
393 EXPECT_CALL(*observer(),
394 OnNewSuggestions(_, downloads_category(),
395 ElementsAre(HasUrl("file:///folder/file3.mhtml"),
396 HasUrl("http://dummy.com/2"),
397 HasUrl("file:///folder/file4.mhtml"),
398 HasUrl("http://dummy.com/1"))));
399 FireDownloadCreated(asset_downloads[1].get());
400 }
401
402 TEST_F(DownloadSuggestionsProviderTest,
403 ShouldDismissWithoutNotifyingObservers) {
404 IgnoreOnCategoryStatusChanged();
405
406 EXPECT_CALL(*observer(),
Marc Treib 2016/10/17 10:18:41 optional: If you expect calls in a particular orde
vitaliii 2016/10/26 00:07:55 It breaks my |IgnoreOn*| functions.
Marc Treib 2016/10/26 08:54:08 Interesting - why?
vitaliii 2016/10/27 15:49:19 I do not know precise reason, but I speculate that
407 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
408 .Times(2);
409 EXPECT_CALL(*observer(),
410 OnNewSuggestions(
411 _, downloads_category(),
412 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
413 HasUrl("http://dummy.com/2"),
414 HasUrl("file:///folder/file1.mhtml"),
415 HasUrl("file:///folder/file2.mhtml"))));
416
417 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
418 CreateProvider();
419 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
420 FireDownloadsCreated(downloads_manager()->items());
421
422 EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
423 EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, _)).Times(0);
424 provider()->DismissSuggestion(
425 GetDummySuggestionId(1, /*is_offline_page=*/true));
426 provider()->DismissSuggestion(
427 GetDummySuggestionId(1, /*is_offline_page=*/false));
428
429 IgnoreOnSuggestionInvalidated();
Marc Treib 2016/10/17 10:18:41 Does this do anything here? If so, worth a comment
vitaliii 2016/10/26 00:07:55 No, but the reason is quite nontrivial. Basically,
430 }
431
432 TEST_F(DownloadSuggestionsProviderTest,
433 ShouldNotReportDismissedSuggestionsOnNewData) {
434 IgnoreOnCategoryStatusChanged();
435 IgnoreOnSuggestionInvalidated();
436
437 EXPECT_CALL(*observer(),
438 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
439 .Times(2);
440 EXPECT_CALL(*observer(),
441 OnNewSuggestions(
442 _, downloads_category(),
443 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
444 HasUrl("http://dummy.com/2"),
445 HasUrl("file:///folder/file1.mhtml"),
446 HasUrl("file:///folder/file2.mhtml"))));
447 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
448 CreateProvider();
449 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
450 FireDownloadsCreated(downloads_manager()->items());
451
452 provider()->DismissSuggestion(
453 GetDummySuggestionId(1, /*is_offline_page=*/true));
454 provider()->DismissSuggestion(
455 GetDummySuggestionId(1, /*is_offline_page=*/false));
456
457 EXPECT_CALL(*observer(),
458 OnNewSuggestions(
459 _, downloads_category(),
460 UnorderedElementsAre(HasUrl("http://dummy.com/2"),
461 HasUrl("file:///folder/file2.mhtml"))));
462 FireOfflinePageModelChanged(offline_pages_model()->items());
463 }
464
465 TEST_F(DownloadSuggestionsProviderTest, ShouldReturnDismissedSuggestions) {
466 IgnoreOnCategoryStatusChanged();
467 IgnoreOnSuggestionInvalidated();
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 IgnoreOnCategoryStatusChanged();
496 IgnoreOnSuggestionInvalidated();
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 IgnoreOnCategoryStatusChanged();
532 IgnoreOnSuggestionInvalidated();
533
534 EXPECT_CALL(*observer(),
535 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(4ul))))
536 .Times(2);
537 EXPECT_CALL(*observer(),
538 OnNewSuggestions(
539 _, downloads_category(),
540 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
541 HasUrl("http://dummy.com/2"),
542 HasUrl("file:///folder/file1.mhtml"),
543 HasUrl("file:///folder/file2.mhtml"))));
544 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
545 CreateProvider();
546 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
547 FireDownloadsCreated(downloads_manager()->items());
548
549 provider()->DismissSuggestion(
550 GetDummySuggestionId(1, /*is_offline_page=*/true));
551
552 EXPECT_CALL(*observer(),
553 OnNewSuggestions(
554 _, downloads_category(),
555 UnorderedElementsAre(HasUrl("http://dummy.com/2"),
556 HasUrl("file:///folder/file1.mhtml"),
557 HasUrl("file:///folder/file2.mhtml"))));
558 FireOfflinePageModelChanged(offline_pages_model()->items());
559 }
560
561 TEST_F(DownloadSuggestionsProviderTest, ShouldReplaceDismissedItemWithNewData) {
562 IgnoreOnCategoryStatusChanged();
563 IgnoreOnSuggestionInvalidated();
564
565 EXPECT_CALL(*observer(),
566 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(5ul))))
567 .Times(5);
568 EXPECT_CALL(*observer(),
569 OnNewSuggestions(
570 _, downloads_category(),
571 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
572 HasUrl("file:///folder/file2.mhtml"),
573 HasUrl("file:///folder/file3.mhtml"),
574 HasUrl("file:///folder/file4.mhtml"),
575 HasUrl("file:///folder/file5.mhtml"))));
576 CreateProvider();
577 // Currently the provider stores five items in its internal cache, so six
578 // items are needed to check whether all downloads are fetched on dismissal.
579 *(downloads_manager()->mutable_items()) =
580 CreateDummyAssetDownloads({1, 2, 3, 4, 5, 6});
581 FireDownloadsCreated(downloads_manager()->items());
582
583 provider()->DismissSuggestion(
584 GetDummySuggestionId(1, /*is_offline_page=*/false));
585
586 // The provider is not notified about the 6th item, however, it must report
587 // it now.
588 EXPECT_CALL(*observer(),
589 OnNewSuggestions(
590 _, downloads_category(),
591 UnorderedElementsAre(HasUrl("file:///folder/file2.mhtml"),
592 HasUrl("file:///folder/file3.mhtml"),
593 HasUrl("file:///folder/file4.mhtml"),
594 HasUrl("file:///folder/file5.mhtml"),
595 HasUrl("file:///folder/file6.mhtml"))));
596 FireOfflinePageModelChanged(offline_pages_model()->items());
597 }
598
599 TEST_F(DownloadSuggestionsProviderTest,
600 ShouldInvalidateWhenUnderlyingItemDeleted) {
601 IgnoreOnCategoryStatusChanged();
602
603 EXPECT_CALL(*observer(),
604 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(3ul))));
605 EXPECT_CALL(*observer(),
606 OnNewSuggestions(
607 _, downloads_category(),
608 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
609 HasUrl("http://dummy.com/2"),
610 HasUrl("file:///folder/file1.mhtml"))));
611 *(offline_pages_model()->mutable_items()) = CreateDummyOfflinePages({1, 2});
612 CreateProvider();
613 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1});
614 FireDownloadsCreated(downloads_manager()->items());
615
616 // We add another item manually, so that when it gets deleted it is not
617 // present in DownloadsManager list.
618 std::unique_ptr<FakeDownloadItem> removed_item = CreateDummyAssetDownload(2);
619 EXPECT_CALL(*observer(),
620 OnNewSuggestions(
621 _, downloads_category(),
622 UnorderedElementsAre(HasUrl("http://dummy.com/1"),
623 HasUrl("http://dummy.com/2"),
624 HasUrl("file:///folder/file1.mhtml"),
625 HasUrl("file:///folder/file2.mhtml"))));
626 FireDownloadCreated(removed_item.get());
627
628 EXPECT_CALL(*observer(),
629 OnSuggestionInvalidated(
630 _, GetDummySuggestionId(1, /*is_offline_page=*/true)));
631 FireOfflinePageDeleted(offline_pages_model()->items()[0]);
632
633 EXPECT_CALL(*observer(),
634 OnSuggestionInvalidated(
635 _, GetDummySuggestionId(2, /*is_offline_page=*/false)));
636 // |OnDownloadItemDestroyed| is called from its destructor.
Marc Treib 2016/10/17 10:18:41 nit: s/its/|removed_item|'s/
vitaliii 2016/10/26 00:07:55 Done.
637 removed_item.reset();
638
639 IgnoreOnSuggestionInvalidated();
Marc Treib 2016/10/17 10:18:41 Is this necessary?
vitaliii 2016/10/26 00:07:55 The answer is the same as for the case above. No,
640 }
641
642 TEST_F(DownloadSuggestionsProviderTest, ShouldReplaceRemovedItemWithNewData) {
643 IgnoreOnCategoryStatusChanged();
644 IgnoreOnSuggestionInvalidated();
645
646 EXPECT_CALL(*observer(),
647 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(5ul))))
648 .Times(5);
649 EXPECT_CALL(*observer(),
650 OnNewSuggestions(
651 _, downloads_category(),
652 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
653 HasUrl("file:///folder/file2.mhtml"),
654 HasUrl("file:///folder/file3.mhtml"),
655 HasUrl("file:///folder/file4.mhtml"),
656 HasUrl("file:///folder/file5.mhtml"))));
657 CreateProvider();
658 *(downloads_manager()->mutable_items()) =
659 CreateDummyAssetDownloads({1, 2, 3, 4, 5});
660 FireDownloadsCreated(downloads_manager()->items());
661
662 // Note that |CreateDummyAssetDownloads| creates items "downloaded" before
663 // |base::Time::Now()|, so for a new item the time is set in future to enforce
664 // the provider to show the new item.
665 std::unique_ptr<FakeDownloadItem> removed_item = CreateDummyAssetDownload(
666 100, base::Time::Now() + base::TimeDelta::FromDays(1));
667 EXPECT_CALL(*observer(),
668 OnNewSuggestions(_, downloads_category(),
669 UnorderedElementsAre(
670 HasUrl("file:///folder/file1.mhtml"),
671 HasUrl("file:///folder/file2.mhtml"),
672 HasUrl("file:///folder/file3.mhtml"),
673 HasUrl("file:///folder/file4.mhtml"),
674 HasUrl("file:///folder/file100.mhtml"))));
675 FireDownloadCreated(removed_item.get());
676
677 // |OnDownloadDestroyed| notification is called in |DownloadItem|'s
678 // destructor.
679 removed_item.reset();
680
681 EXPECT_CALL(*observer(),
682 OnNewSuggestions(
683 _, downloads_category(),
684 UnorderedElementsAre(HasUrl("file:///folder/file1.mhtml"),
685 HasUrl("file:///folder/file2.mhtml"),
686 HasUrl("file:///folder/file3.mhtml"),
687 HasUrl("file:///folder/file4.mhtml"),
688 HasUrl("file:///folder/file5.mhtml"))));
689 FireOfflinePageModelChanged(offline_pages_model()->items());
Marc Treib 2016/10/17 10:18:41 Is the FireOfflinePageModelChanged needed here? Sh
vitaliii 2016/10/26 00:07:55 Yes, it is.
Marc Treib 2016/10/26 08:54:08 Ah yes, you're right. Destroying the download shou
vitaliii 2016/10/27 15:49:19 Acknowledged.
690 }
691
692 TEST_F(DownloadSuggestionsProviderTest, ShouldPruneOfflinePagesDismissedIDs) {
693 IgnoreOnCategoryStatusChanged();
694 IgnoreOnSuggestionInvalidated();
695
696 *(offline_pages_model()->mutable_items()) =
697 CreateDummyOfflinePages({1, 2, 3});
698 EXPECT_CALL(*observer(), OnNewSuggestions(_, downloads_category(),
699 UnorderedElementsAre(
700 HasUrl("http://dummy.com/1"),
701 HasUrl("http://dummy.com/2"),
702 HasUrl("http://dummy.com/3"))));
703 CreateProvider();
704
705 provider()->DismissSuggestion(
706 GetDummySuggestionId(1, /*is_offline_page=*/true));
707 provider()->DismissSuggestion(
708 GetDummySuggestionId(2, /*is_offline_page=*/true));
709 provider()->DismissSuggestion(
710 GetDummySuggestionId(3, /*is_offline_page=*/true));
711 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(3));
712
713 // Prune on getting all offline pages. Note that the first suggestion is not
714 // removed from |offline_pages_model| storage, because otherwise
715 // |GetDismissedSuggestions| cannot return it.
716 EXPECT_CALL(*observer(),
717 OnNewSuggestions(_, downloads_category(), IsEmpty()));
718 FireOfflinePageModelChanged(CreateDummyOfflinePages({2, 3}));
719 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(2));
720
721 // Prune when offline page is deleted.
722 FireOfflinePageDeleted(offline_pages_model()->items()[1]);
723 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(1));
724 }
725
726 TEST_F(DownloadSuggestionsProviderTest, ShouldPruneAssetDownloadsDismissedIDs) {
727 IgnoreOnCategoryStatusChanged();
728 IgnoreOnSuggestionInvalidated();
729
730 EXPECT_CALL(*observer(),
731 OnNewSuggestions(_, downloads_category(), SizeIs(Lt(3ul))))
732 .Times(3);
733 CreateProvider();
734 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
735 FireDownloadsCreated(downloads_manager()->items());
736
737 provider()->DismissSuggestion(
738 GetDummySuggestionId(1, /*is_offline_page=*/false));
739 provider()->DismissSuggestion(
740 GetDummySuggestionId(2, /*is_offline_page=*/false));
741 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(2));
742
743 downloads_manager()->items()[0]->NotifyDownloadDestroyed();
744 EXPECT_THAT(GetDismissedSuggestions(), SizeIs(1));
745 }
746
747 TEST_F(DownloadSuggestionsProviderTest, ShouldNotFetchAssetDownloadsOnStartup) {
748 IgnoreOnCategoryStatusChanged();
749
750 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1, 2});
751 EXPECT_CALL(*observer(),
752 OnNewSuggestions(_, downloads_category(), IsEmpty()));
753 CreateProvider();
754 }
755
756 TEST_F(DownloadSuggestionsProviderTest,
757 ShouldInvalidateAssetDownloadWhenItsFileRemoved) {
758 IgnoreOnCategoryStatusChanged();
759
760 EXPECT_CALL(*observer(),
761 OnNewSuggestions(_, downloads_category(), IsEmpty()));
762 EXPECT_CALL(*observer(),
763 OnNewSuggestions(_, downloads_category(), SizeIs(1)));
764 CreateProvider();
765 *(downloads_manager()->mutable_items()) = CreateDummyAssetDownloads({1});
766 FireDownloadsCreated(downloads_manager()->items());
767
768 EXPECT_CALL(*observer(),
769 OnSuggestionInvalidated(
770 _, GetDummySuggestionId(1, /*is_offline_page=*/false)));
771 (*downloads_manager()->mutable_items())[0]->SetFileExternallyRemoved(true);
772 (*downloads_manager()->mutable_items())[0]->NotifyDownloadUpdated();
773 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698