OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/ntp_snippets/content_suggestions_service.h" | 5 #include "components/ntp_snippets/content_suggestions_service.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 | 80 |
81 void FireSuggestionsChanged(Category category, std::vector<int> numbers) { | 81 void FireSuggestionsChanged(Category category, std::vector<int> numbers) { |
82 observer()->OnNewSuggestions(this, category, CreateSuggestions(numbers)); | 82 observer()->OnNewSuggestions(this, category, CreateSuggestions(numbers)); |
83 } | 83 } |
84 | 84 |
85 void FireCategoryStatusChanged(Category category, CategoryStatus new_status) { | 85 void FireCategoryStatusChanged(Category category, CategoryStatus new_status) { |
86 statuses_[category.id()] = new_status; | 86 statuses_[category.id()] = new_status; |
87 observer()->OnCategoryStatusChanged(this, category, new_status); | 87 observer()->OnCategoryStatusChanged(this, category, new_status); |
88 } | 88 } |
89 | 89 |
| 90 void FireSuggestionInvalidated(Category category, |
| 91 const std::string& suggestion_id) { |
| 92 observer()->OnSuggestionInvalidated(this, category, suggestion_id); |
| 93 } |
| 94 |
90 MOCK_METHOD1(ClearCachedSuggestionsForDebugging, void(Category category)); | 95 MOCK_METHOD1(ClearCachedSuggestionsForDebugging, void(Category category)); |
91 MOCK_METHOD1(GetDismissedSuggestionsForDebugging, | 96 MOCK_METHOD1(GetDismissedSuggestionsForDebugging, |
92 std::vector<ContentSuggestion>(Category category)); | 97 std::vector<ContentSuggestion>(Category category)); |
93 MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category)); | 98 MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category)); |
94 MOCK_METHOD1(DismissSuggestion, void(const std::string& suggestion_id)); | 99 MOCK_METHOD1(DismissSuggestion, void(const std::string& suggestion_id)); |
95 MOCK_METHOD2(FetchSuggestionImage, | 100 MOCK_METHOD2(FetchSuggestionImage, |
96 void(const std::string& suggestion_id, | 101 void(const std::string& suggestion_id, |
97 const ImageFetchedCallback& callback)); | 102 const ImageFetchedCallback& callback)); |
98 | 103 |
99 private: | 104 private: |
100 std::vector<Category> provided_categories_; | 105 std::vector<Category> provided_categories_; |
101 std::map<int, CategoryStatus> statuses_; | 106 std::map<int, CategoryStatus> statuses_; |
102 }; | 107 }; |
103 | 108 |
104 class MockServiceObserver : public ContentSuggestionsService::Observer { | 109 class MockServiceObserver : public ContentSuggestionsService::Observer { |
105 public: | 110 public: |
106 MOCK_METHOD1(OnNewSuggestions, void(Category category)); | 111 MOCK_METHOD1(OnNewSuggestions, void(Category category)); |
107 MOCK_METHOD2(OnCategoryStatusChanged, | 112 MOCK_METHOD2(OnCategoryStatusChanged, |
108 void(Category changed_category, CategoryStatus new_status)); | 113 void(Category changed_category, CategoryStatus new_status)); |
| 114 MOCK_METHOD2(OnSuggestionInvalidated, |
| 115 void(Category category, const std::string& suggestion_id)); |
109 MOCK_METHOD0(ContentSuggestionsServiceShutdown, void()); | 116 MOCK_METHOD0(ContentSuggestionsServiceShutdown, void()); |
110 ~MockServiceObserver() override {} | 117 ~MockServiceObserver() override {} |
111 }; | 118 }; |
112 | 119 |
113 } // namespace | 120 } // namespace |
114 | 121 |
115 class ContentSuggestionsServiceTest : public testing::Test { | 122 class ContentSuggestionsServiceTest : public testing::Test { |
116 public: | 123 public: |
117 ContentSuggestionsServiceTest() {} | 124 ContentSuggestionsServiceTest() {} |
118 | 125 |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectFetchSuggestionImage) { | 261 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectFetchSuggestionImage) { |
255 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); | 262 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
256 Category offline_pages_category = | 263 Category offline_pages_category = |
257 FromKnownCategory(KnownCategories::BOOKMARKS); | 264 FromKnownCategory(KnownCategories::BOOKMARKS); |
258 MockProvider* provider1 = MakeProvider(articles_category); | 265 MockProvider* provider1 = MakeProvider(articles_category); |
259 MockProvider* provider2 = MakeProvider(offline_pages_category); | 266 MockProvider* provider2 = MakeProvider(offline_pages_category); |
260 | 267 |
261 provider1->FireSuggestionsChanged(articles_category, {1}); | 268 provider1->FireSuggestionsChanged(articles_category, {1}); |
262 std::string suggestion_id = CreateSuggestion(1).id(); | 269 std::string suggestion_id = CreateSuggestion(1).id(); |
263 | 270 |
264 EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _)).Times(1); | 271 EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _)); |
265 EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0); | 272 EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0); |
266 service()->FetchSuggestionImage( | 273 service()->FetchSuggestionImage( |
267 suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched, | 274 suggestion_id, base::Bind(&ContentSuggestionsServiceTest::OnImageFetched, |
268 base::Unretained(this))); | 275 base::Unretained(this))); |
269 } | 276 } |
270 | 277 |
271 TEST_F(ContentSuggestionsServiceTest, | 278 TEST_F(ContentSuggestionsServiceTest, |
272 ShouldCallbackEmptyImageForUnavailableProvider) { | 279 ShouldCallbackEmptyImageForUnavailableProvider) { |
273 // Setup the current thread's MessageLoop. | 280 // Setup the current thread's MessageLoop. |
274 base::MessageLoop message_loop; | 281 base::MessageLoop message_loop; |
(...skipping 13 matching lines...) Expand all Loading... |
288 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); | 295 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
289 Category offline_pages_category = | 296 Category offline_pages_category = |
290 FromKnownCategory(KnownCategories::BOOKMARKS); | 297 FromKnownCategory(KnownCategories::BOOKMARKS); |
291 MockProvider* provider1 = MakeProvider(articles_category); | 298 MockProvider* provider1 = MakeProvider(articles_category); |
292 MockProvider* provider2 = MakeProvider(offline_pages_category); | 299 MockProvider* provider2 = MakeProvider(offline_pages_category); |
293 | 300 |
294 provider2->FireSuggestionsChanged(offline_pages_category, {11}); | 301 provider2->FireSuggestionsChanged(offline_pages_category, {11}); |
295 std::string suggestion_id = CreateSuggestion(11).id(); | 302 std::string suggestion_id = CreateSuggestion(11).id(); |
296 | 303 |
297 EXPECT_CALL(*provider1, DismissSuggestion(_)).Times(0); | 304 EXPECT_CALL(*provider1, DismissSuggestion(_)).Times(0); |
298 EXPECT_CALL(*provider2, DismissSuggestion(suggestion_id)).Times(1); | 305 EXPECT_CALL(*provider2, DismissSuggestion(suggestion_id)); |
299 service()->DismissSuggestion(suggestion_id); | 306 service()->DismissSuggestion(suggestion_id); |
300 } | 307 } |
301 | 308 |
| 309 TEST_F(ContentSuggestionsServiceTest, ShouldRedirectSuggestionInvalidated) { |
| 310 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
| 311 |
| 312 MockProvider* provider = MakeProvider(articles_category); |
| 313 MockServiceObserver observer; |
| 314 service()->AddObserver(&observer); |
| 315 |
| 316 provider->FireSuggestionsChanged(articles_category, {11, 12, 13}); |
| 317 ExpectThatSuggestionsAre(articles_category, {11, 12, 13}); |
| 318 |
| 319 std::string suggestion_id = CreateSuggestion(12).id(); |
| 320 EXPECT_CALL(observer, |
| 321 OnSuggestionInvalidated(articles_category, suggestion_id)); |
| 322 provider->FireSuggestionInvalidated(articles_category, suggestion_id); |
| 323 ExpectThatSuggestionsAre(articles_category, {11, 13}); |
| 324 Mock::VerifyAndClearExpectations(&observer); |
| 325 |
| 326 // Unknown IDs must be forwarded (though no change happens to the service's |
| 327 // internal data structures) because previously opened UIs, which can still |
| 328 // show the invalidated suggestion, must be notified. |
| 329 std::string unknown_id = CreateSuggestion(1234).id(); |
| 330 EXPECT_CALL(observer, OnSuggestionInvalidated(articles_category, unknown_id)); |
| 331 provider->FireSuggestionInvalidated(articles_category, unknown_id); |
| 332 ExpectThatSuggestionsAre(articles_category, {11, 13}); |
| 333 Mock::VerifyAndClearExpectations(&observer); |
| 334 |
| 335 service()->RemoveObserver(&observer); |
| 336 } |
| 337 |
302 TEST_F(ContentSuggestionsServiceTest, ShouldForwardSuggestions) { | 338 TEST_F(ContentSuggestionsServiceTest, ShouldForwardSuggestions) { |
303 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); | 339 Category articles_category = FromKnownCategory(KnownCategories::ARTICLES); |
304 Category offline_pages_category = | 340 Category offline_pages_category = |
305 FromKnownCategory(KnownCategories::BOOKMARKS); | 341 FromKnownCategory(KnownCategories::BOOKMARKS); |
306 | 342 |
307 // Create and register providers | 343 // Create and register providers |
308 MockProvider* provider1 = MakeProvider(articles_category); | 344 MockProvider* provider1 = MakeProvider(articles_category); |
309 MockProvider* provider2 = MakeProvider(offline_pages_category); | 345 MockProvider* provider2 = MakeProvider(offline_pages_category); |
310 EXPECT_THAT(providers().at(articles_category), Eq(provider1)); | 346 EXPECT_THAT(providers().at(articles_category), Eq(provider1)); |
311 EXPECT_THAT(providers().at(offline_pages_category), Eq(provider2)); | 347 EXPECT_THAT(providers().at(offline_pages_category), Eq(provider2)); |
312 | 348 |
313 // Create and register observer | 349 // Create and register observer |
314 MockServiceObserver observer; | 350 MockServiceObserver observer; |
315 service()->AddObserver(&observer); | 351 service()->AddObserver(&observer); |
316 | 352 |
317 // Send suggestions 1 and 2 | 353 // Send suggestions 1 and 2 |
318 EXPECT_CALL(observer, OnNewSuggestions(articles_category)).Times(1); | 354 EXPECT_CALL(observer, OnNewSuggestions(articles_category)); |
319 provider1->FireSuggestionsChanged(articles_category, {1, 2}); | 355 provider1->FireSuggestionsChanged(articles_category, {1, 2}); |
320 ExpectThatSuggestionsAre(articles_category, {1, 2}); | 356 ExpectThatSuggestionsAre(articles_category, {1, 2}); |
321 Mock::VerifyAndClearExpectations(&observer); | 357 Mock::VerifyAndClearExpectations(&observer); |
322 | 358 |
323 // Send them again, make sure they're not reported twice | 359 // Send them again, make sure they're not reported twice |
324 EXPECT_CALL(observer, OnNewSuggestions(articles_category)).Times(1); | 360 EXPECT_CALL(observer, OnNewSuggestions(articles_category)); |
325 provider1->FireSuggestionsChanged(articles_category, {1, 2}); | 361 provider1->FireSuggestionsChanged(articles_category, {1, 2}); |
326 ExpectThatSuggestionsAre(articles_category, {1, 2}); | 362 ExpectThatSuggestionsAre(articles_category, {1, 2}); |
327 ExpectThatSuggestionsAre(offline_pages_category, std::vector<int>()); | 363 ExpectThatSuggestionsAre(offline_pages_category, std::vector<int>()); |
328 Mock::VerifyAndClearExpectations(&observer); | 364 Mock::VerifyAndClearExpectations(&observer); |
329 | 365 |
330 // Send suggestions 13 and 14 | 366 // Send suggestions 13 and 14 |
331 EXPECT_CALL(observer, OnNewSuggestions(offline_pages_category)).Times(1); | 367 EXPECT_CALL(observer, OnNewSuggestions(offline_pages_category)); |
332 provider2->FireSuggestionsChanged(offline_pages_category, {13, 14}); | 368 provider2->FireSuggestionsChanged(offline_pages_category, {13, 14}); |
333 ExpectThatSuggestionsAre(articles_category, {1, 2}); | 369 ExpectThatSuggestionsAre(articles_category, {1, 2}); |
334 ExpectThatSuggestionsAre(offline_pages_category, {13, 14}); | 370 ExpectThatSuggestionsAre(offline_pages_category, {13, 14}); |
335 Mock::VerifyAndClearExpectations(&observer); | 371 Mock::VerifyAndClearExpectations(&observer); |
336 | 372 |
337 // Send suggestion 1 only | 373 // Send suggestion 1 only |
338 EXPECT_CALL(observer, OnNewSuggestions(articles_category)).Times(1); | 374 EXPECT_CALL(observer, OnNewSuggestions(articles_category)); |
339 provider1->FireSuggestionsChanged(articles_category, {1}); | 375 provider1->FireSuggestionsChanged(articles_category, {1}); |
340 ExpectThatSuggestionsAre(articles_category, {1}); | 376 ExpectThatSuggestionsAre(articles_category, {1}); |
341 ExpectThatSuggestionsAre(offline_pages_category, {13, 14}); | 377 ExpectThatSuggestionsAre(offline_pages_category, {13, 14}); |
342 Mock::VerifyAndClearExpectations(&observer); | 378 Mock::VerifyAndClearExpectations(&observer); |
343 | 379 |
344 // provider2 reports BOOKMARKS as unavailable | 380 // provider2 reports BOOKMARKS as unavailable |
345 EXPECT_CALL(observer, OnCategoryStatusChanged( | 381 EXPECT_CALL(observer, OnCategoryStatusChanged( |
346 offline_pages_category, | 382 offline_pages_category, |
347 CategoryStatus::CATEGORY_EXPLICITLY_DISABLED)) | 383 CategoryStatus::CATEGORY_EXPLICITLY_DISABLED)); |
348 .Times(1); | |
349 provider2->FireCategoryStatusChanged( | 384 provider2->FireCategoryStatusChanged( |
350 offline_pages_category, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); | 385 offline_pages_category, CategoryStatus::CATEGORY_EXPLICITLY_DISABLED); |
351 EXPECT_THAT(service()->GetCategoryStatus(articles_category), | 386 EXPECT_THAT(service()->GetCategoryStatus(articles_category), |
352 Eq(CategoryStatus::AVAILABLE)); | 387 Eq(CategoryStatus::AVAILABLE)); |
353 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), | 388 EXPECT_THAT(service()->GetCategoryStatus(offline_pages_category), |
354 Eq(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED)); | 389 Eq(CategoryStatus::CATEGORY_EXPLICITLY_DISABLED)); |
355 ExpectThatSuggestionsAre(articles_category, {1}); | 390 ExpectThatSuggestionsAre(articles_category, {1}); |
356 ExpectThatSuggestionsAre(offline_pages_category, std::vector<int>()); | 391 ExpectThatSuggestionsAre(offline_pages_category, std::vector<int>()); |
357 Mock::VerifyAndClearExpectations(&observer); | 392 Mock::VerifyAndClearExpectations(&observer); |
358 | 393 |
359 // Shutdown the service | 394 // Shutdown the service |
360 EXPECT_CALL(observer, ContentSuggestionsServiceShutdown()); | 395 EXPECT_CALL(observer, ContentSuggestionsServiceShutdown()); |
361 service()->Shutdown(); | 396 service()->Shutdown(); |
362 service()->RemoveObserver(&observer); | 397 service()->RemoveObserver(&observer); |
363 // The service will receive two Shutdown() calls. | 398 // The service will receive two Shutdown() calls. |
364 } | 399 } |
365 | 400 |
366 } // namespace ntp_snippets | 401 } // namespace ntp_snippets |
OLD | NEW |