| 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 |