OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/ntp_snippets_service.h" | 5 #include "components/ntp_snippets/ntp_snippets_service.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | |
8 #include <vector> | 9 #include <vector> |
9 | 10 |
10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
12 #include "base/files/scoped_temp_dir.h" | 13 #include "base/files/scoped_temp_dir.h" |
13 #include "base/json/json_reader.h" | 14 #include "base/json/json_reader.h" |
14 #include "base/macros.h" | 15 #include "base/macros.h" |
15 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
16 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
17 #include "base/run_loop.h" | 18 #include "base/run_loop.h" |
18 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
19 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
20 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
21 #include "base/test/histogram_tester.h" | 22 #include "base/test/histogram_tester.h" |
22 #include "base/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
23 #include "base/time/time.h" | 24 #include "base/time/time.h" |
24 #include "components/image_fetcher/image_decoder.h" | 25 #include "components/image_fetcher/image_decoder.h" |
25 #include "components/image_fetcher/image_fetcher.h" | 26 #include "components/image_fetcher/image_fetcher.h" |
27 #include "components/image_fetcher/image_fetcher_delegate.h" | |
26 #include "components/ntp_snippets/category_factory.h" | 28 #include "components/ntp_snippets/category_factory.h" |
27 #include "components/ntp_snippets/ntp_snippet.h" | 29 #include "components/ntp_snippets/ntp_snippet.h" |
28 #include "components/ntp_snippets/ntp_snippets_database.h" | 30 #include "components/ntp_snippets/ntp_snippets_database.h" |
29 #include "components/ntp_snippets/ntp_snippets_fetcher.h" | 31 #include "components/ntp_snippets/ntp_snippets_fetcher.h" |
30 #include "components/ntp_snippets/ntp_snippets_scheduler.h" | 32 #include "components/ntp_snippets/ntp_snippets_scheduler.h" |
31 #include "components/ntp_snippets/ntp_snippets_test_utils.h" | 33 #include "components/ntp_snippets/ntp_snippets_test_utils.h" |
32 #include "components/ntp_snippets/switches.h" | 34 #include "components/ntp_snippets/switches.h" |
33 #include "components/prefs/testing_pref_service.h" | 35 #include "components/prefs/testing_pref_service.h" |
34 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" | 36 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" |
35 #include "components/signin/core/browser/fake_signin_manager.h" | 37 #include "components/signin/core/browser/fake_signin_manager.h" |
36 #include "google_apis/google_api_keys.h" | 38 #include "google_apis/google_api_keys.h" |
37 #include "net/url_request/test_url_fetcher_factory.h" | 39 #include "net/url_request/test_url_fetcher_factory.h" |
38 #include "net/url_request/url_request_test_util.h" | 40 #include "net/url_request/url_request_test_util.h" |
39 #include "testing/gmock/include/gmock/gmock.h" | 41 #include "testing/gmock/include/gmock/gmock.h" |
40 #include "testing/gtest/include/gtest/gtest.h" | 42 #include "testing/gtest/include/gtest/gtest.h" |
43 #include "ui/gfx/image/image.h" | |
44 #include "ui/gfx/image/image_unittest_util.h" | |
41 | 45 |
46 using image_fetcher::ImageFetcher; | |
47 using image_fetcher::ImageFetcherDelegate; | |
42 using testing::ElementsAre; | 48 using testing::ElementsAre; |
43 using testing::Eq; | 49 using testing::Eq; |
44 using testing::Invoke; | 50 using testing::Invoke; |
45 using testing::IsEmpty; | 51 using testing::IsEmpty; |
46 using testing::Mock; | 52 using testing::Mock; |
47 using testing::Return; | 53 using testing::Return; |
48 using testing::SizeIs; | 54 using testing::SizeIs; |
49 using testing::StartsWith; | 55 using testing::StartsWith; |
50 using testing::_; | 56 using testing::_; |
51 | 57 |
(...skipping 10 matching lines...) Expand all Loading... | |
62 "https://chromereader-pa.googleapis.com/v1/fetch?key=%s"; | 68 "https://chromereader-pa.googleapis.com/v1/fetch?key=%s"; |
63 | 69 |
64 const char kSnippetUrl[] = "http://localhost/foobar"; | 70 const char kSnippetUrl[] = "http://localhost/foobar"; |
65 const char kSnippetTitle[] = "Title"; | 71 const char kSnippetTitle[] = "Title"; |
66 const char kSnippetText[] = "Snippet"; | 72 const char kSnippetText[] = "Snippet"; |
67 const char kSnippetSalientImage[] = "http://localhost/salient_image"; | 73 const char kSnippetSalientImage[] = "http://localhost/salient_image"; |
68 const char kSnippetPublisherName[] = "Foo News"; | 74 const char kSnippetPublisherName[] = "Foo News"; |
69 const char kSnippetAmpUrl[] = "http://localhost/amp"; | 75 const char kSnippetAmpUrl[] = "http://localhost/amp"; |
70 const float kSnippetScore = 5.0; | 76 const float kSnippetScore = 5.0; |
71 | 77 |
78 const char kSnippetUrl2[] = "http://foo.com/bar"; | |
79 | |
72 base::Time GetDefaultCreationTime() { | 80 base::Time GetDefaultCreationTime() { |
73 base::Time out_time; | 81 base::Time out_time; |
74 EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time)); | 82 EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time)); |
75 return out_time; | 83 return out_time; |
76 } | 84 } |
77 | 85 |
78 base::Time GetDefaultExpirationTime() { | 86 base::Time GetDefaultExpirationTime() { |
79 return base::Time::Now() + base::TimeDelta::FromHours(1); | 87 return base::Time::Now() + base::TimeDelta::FromHours(1); |
80 } | 88 } |
81 | 89 |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 // fail to parse as snippets. | 192 // fail to parse as snippets. |
185 size_t pos = json_str.find("\"url\""); | 193 size_t pos = json_str.find("\"url\""); |
186 if (pos == std::string::npos) { | 194 if (pos == std::string::npos) { |
187 NOTREACHED(); | 195 NOTREACHED(); |
188 return std::string(); | 196 return std::string(); |
189 } | 197 } |
190 json_str[pos + 1] = 'x'; | 198 json_str[pos + 1] = 'x'; |
191 return json_str; | 199 return json_str; |
192 } | 200 } |
193 | 201 |
202 void ServeOneByOneImage( | |
203 const std::string& id, | |
204 base::Callback<void(const std::string&, const gfx::Image&)> callback) { | |
205 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
206 FROM_HERE, base::Bind(callback, id, gfx::test::CreateImage(1, 1))); | |
207 } | |
208 | |
194 void ParseJson( | 209 void ParseJson( |
195 const std::string& json, | 210 const std::string& json, |
196 const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback, | 211 const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback, |
197 const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) { | 212 const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) { |
198 base::JSONReader json_reader; | 213 base::JSONReader json_reader; |
199 std::unique_ptr<base::Value> value = json_reader.ReadToValue(json); | 214 std::unique_ptr<base::Value> value = json_reader.ReadToValue(json); |
200 if (value) { | 215 if (value) { |
201 success_callback.Run(std::move(value)); | 216 success_callback.Run(std::move(value)); |
202 } else { | 217 } else { |
203 error_callback.Run(json_reader.GetErrorMessage()); | 218 error_callback.Run(json_reader.GetErrorMessage()); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
256 EXPECT_EQ(new_status, CategoryStatus::AVAILABLE_LOADING); | 271 EXPECT_EQ(new_status, CategoryStatus::AVAILABLE_LOADING); |
257 run_loop_.Quit(); | 272 run_loop_.Quit(); |
258 } | 273 } |
259 | 274 |
260 MockProviderObserver* observer_; | 275 MockProviderObserver* observer_; |
261 base::RunLoop run_loop_; | 276 base::RunLoop run_loop_; |
262 | 277 |
263 DISALLOW_COPY_AND_ASSIGN(WaitForDBLoad); | 278 DISALLOW_COPY_AND_ASSIGN(WaitForDBLoad); |
264 }; | 279 }; |
265 | 280 |
281 class MockImageFetcher : public ImageFetcher { | |
282 public: | |
283 MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*)); | |
284 MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName)); | |
285 MOCK_METHOD3( | |
286 StartOrQueueNetworkRequest, | |
287 void(const std::string&, | |
288 const GURL&, | |
289 base::Callback<void(const std::string&, const gfx::Image&)>)); | |
290 }; | |
291 | |
266 } // namespace | 292 } // namespace |
267 | 293 |
268 class NTPSnippetsServiceTest : public test::NTPSnippetsTestBase { | 294 class NTPSnippetsServiceTest : public test::NTPSnippetsTestBase { |
269 public: | 295 public: |
270 NTPSnippetsServiceTest() | 296 NTPSnippetsServiceTest() |
271 : fake_url_fetcher_factory_( | 297 : fake_url_fetcher_factory_( |
272 /*default_factory=*/&failing_url_fetcher_factory_), | 298 /*default_factory=*/&failing_url_fetcher_factory_), |
273 test_url_(base::StringPrintf(kTestContentSnippetsServerFormat, | 299 test_url_(base::StringPrintf(kTestContentSnippetsServerFormat, |
274 google_apis::GetAPIKey().c_str())) { | 300 google_apis::GetAPIKey().c_str())) { |
275 NTPSnippetsService::RegisterProfilePrefs(pref_service()->registry()); | 301 NTPSnippetsService::RegisterProfilePrefs(pref_service()->registry()); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 base::MakeUnique<NTPSnippetsFetcher>( | 344 base::MakeUnique<NTPSnippetsFetcher>( |
319 fake_signin_manager(), fake_token_service_.get(), | 345 fake_signin_manager(), fake_token_service_.get(), |
320 std::move(request_context_getter), pref_service(), | 346 std::move(request_context_getter), pref_service(), |
321 &category_factory_, base::Bind(&ParseJson), | 347 &category_factory_, base::Bind(&ParseJson), |
322 /*is_stable_channel=*/true); | 348 /*is_stable_channel=*/true); |
323 | 349 |
324 fake_signin_manager()->SignIn("foo@bar.com"); | 350 fake_signin_manager()->SignIn("foo@bar.com"); |
325 snippets_fetcher->SetPersonalizationForTesting( | 351 snippets_fetcher->SetPersonalizationForTesting( |
326 NTPSnippetsFetcher::Personalization::kNonPersonal); | 352 NTPSnippetsFetcher::Personalization::kNonPersonal); |
327 | 353 |
354 auto image_fetcher = | |
355 base::MakeUnique<testing::NiceMock<MockImageFetcher>>(); | |
356 image_fetcher_ = image_fetcher.get(); | |
357 | |
328 // Add an initial fetch response, as the service tries to fetch when there | 358 // Add an initial fetch response, as the service tries to fetch when there |
329 // is nothing in the DB. | 359 // is nothing in the DB. |
330 SetUpFetchResponse(GetTestJson({GetSnippet()})); | 360 SetUpFetchResponse(GetTestJson({GetSnippet()})); |
331 | 361 |
332 service_.reset(new NTPSnippetsService( | 362 service_.reset(new NTPSnippetsService( |
333 &observer_, &category_factory_, pref_service(), nullptr, "fr", | 363 &observer_, &category_factory_, pref_service(), nullptr, "fr", |
334 &scheduler_, std::move(snippets_fetcher), /*image_fetcher=*/nullptr, | 364 &scheduler_, std::move(snippets_fetcher), |
335 /*image_fetcher=*/nullptr, base::MakeUnique<NTPSnippetsDatabase>( | 365 std::move(image_fetcher), /*image_decoder=*/nullptr, |
336 database_dir_.path(), task_runner), | 366 base::MakeUnique<NTPSnippetsDatabase>(database_dir_.path(), |
367 task_runner), | |
337 base::MakeUnique<NTPSnippetsStatusService>(fake_signin_manager(), | 368 base::MakeUnique<NTPSnippetsStatusService>(fake_signin_manager(), |
338 pref_service()))); | 369 pref_service()))); |
339 | 370 |
340 WaitForDBLoad(&observer_, service_.get()); | 371 WaitForDBLoad(&observer_, service_.get()); |
341 } | 372 } |
342 | 373 |
343 std::string MakeUniqueID(const std::string& within_category_id) { | 374 std::string MakeUniqueID(const std::string& within_category_id) { |
344 return service()->MakeUniqueID(articles_category(), within_category_id); | 375 return service()->MakeUniqueID(articles_category(), within_category_id); |
345 } | 376 } |
346 | 377 |
347 Category articles_category() { | 378 Category articles_category() { |
348 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); | 379 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); |
349 } | 380 } |
350 | 381 |
351 protected: | 382 protected: |
352 const GURL& test_url() { return test_url_; } | 383 const GURL& test_url() { return test_url_; } |
353 NTPSnippetsService* service() { return service_.get(); } | 384 NTPSnippetsService* service() { return service_.get(); } |
354 MockProviderObserver& observer() { return observer_; } | 385 MockProviderObserver& observer() { return observer_; } |
355 MockScheduler& mock_scheduler() { return scheduler_; } | 386 MockScheduler& mock_scheduler() { return scheduler_; } |
387 testing::NiceMock<MockImageFetcher>* image_fetcher() { | |
388 return image_fetcher_; | |
389 } | |
356 | 390 |
357 // Provide the json to be returned by the fake fetcher. | 391 // Provide the json to be returned by the fake fetcher. |
358 void SetUpFetchResponse(const std::string& json) { | 392 void SetUpFetchResponse(const std::string& json) { |
359 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK, | 393 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK, |
360 net::URLRequestStatus::SUCCESS); | 394 net::URLRequestStatus::SUCCESS); |
361 } | 395 } |
362 | 396 |
363 void LoadFromJSONString(const std::string& json) { | 397 void LoadFromJSONString(const std::string& json) { |
364 SetUpFetchResponse(json); | 398 SetUpFetchResponse(json); |
365 service()->FetchSnippets(true); | 399 service()->FetchSnippets(true); |
366 base::RunLoop().RunUntilIdle(); | 400 base::RunLoop().RunUntilIdle(); |
367 } | 401 } |
368 | 402 |
369 private: | 403 private: |
370 base::MessageLoop message_loop_; | 404 base::MessageLoop message_loop_; |
371 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; | 405 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; |
372 // Instantiation of factory automatically sets itself as URLFetcher's factory. | 406 // Instantiation of factory automatically sets itself as URLFetcher's factory. |
373 net::FakeURLFetcherFactory fake_url_fetcher_factory_; | 407 net::FakeURLFetcherFactory fake_url_fetcher_factory_; |
374 const GURL test_url_; | 408 const GURL test_url_; |
375 std::unique_ptr<OAuth2TokenService> fake_token_service_; | 409 std::unique_ptr<OAuth2TokenService> fake_token_service_; |
376 MockScheduler scheduler_; | 410 MockScheduler scheduler_; |
377 MockProviderObserver observer_; | 411 MockProviderObserver observer_; |
378 CategoryFactory category_factory_; | 412 CategoryFactory category_factory_; |
413 testing::NiceMock<MockImageFetcher>* image_fetcher_; | |
379 // Last so that the dependencies are deleted after the service. | 414 // Last so that the dependencies are deleted after the service. |
380 std::unique_ptr<NTPSnippetsService> service_; | 415 std::unique_ptr<NTPSnippetsService> service_; |
381 | 416 |
382 base::ScopedTempDir database_dir_; | 417 base::ScopedTempDir database_dir_; |
383 | 418 |
384 DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest); | 419 DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest); |
385 }; | 420 }; |
386 | 421 |
387 TEST_F(NTPSnippetsServiceTest, ScheduleOnStart) { | 422 TEST_F(NTPSnippetsServiceTest, ScheduleOnStart) { |
388 // SetUp() checks that Schedule is called. | 423 // SetUp() checks that Schedule is called. |
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
879 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE_LOADING)); | 914 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE_LOADING)); |
880 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1); | 915 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1); |
881 service()->OnDisabledReasonChanged(DisabledReason::NONE); | 916 service()->OnDisabledReasonChanged(DisabledReason::NONE); |
882 EXPECT_CALL(observer(), | 917 EXPECT_CALL(observer(), |
883 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE)); | 918 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE)); |
884 base::RunLoop().RunUntilIdle(); | 919 base::RunLoop().RunUntilIdle(); |
885 EXPECT_EQ(NTPSnippetsService::State::READY, service()->state_); | 920 EXPECT_EQ(NTPSnippetsService::State::READY, service()->state_); |
886 EXPECT_FALSE(service()->GetSnippetsForTesting().empty()); | 921 EXPECT_FALSE(service()->GetSnippetsForTesting().empty()); |
887 } | 922 } |
888 | 923 |
924 TEST_F(NTPSnippetsServiceTest, ImageReturnedWithTheSameId) { | |
925 LoadFromJSONString(GetTestJson({GetSnippet()})); | |
926 | |
927 gfx::Image image; | |
928 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | |
929 .WillOnce(testing::WithArgs<0, 2>(Invoke(ServeOneByOneImage))); | |
930 testing::MockFunction<void(const std::string&, const gfx::Image&)> | |
931 image_fetched; | |
932 EXPECT_CALL(image_fetched, Call(MakeUniqueID(kSnippetUrl), _)) | |
933 .WillOnce(testing::SaveArg<1>(&image)); | |
934 | |
935 service()->FetchSuggestionImage( | |
936 MakeUniqueID(kSnippetUrl), | |
937 base::Bind(&testing::MockFunction<void(const std::string&, | |
938 const gfx::Image&)>::Call, | |
939 base::Unretained(&image_fetched))); | |
940 base::RunLoop().RunUntilIdle(); | |
941 // Check that the image by ServeOneByOneImage is really served. | |
942 EXPECT_EQ(1, image.Width()); | |
943 } | |
944 | |
945 TEST_F(NTPSnippetsServiceTest, EmptyImageReturnedForNonExistentId) { | |
946 gfx::Image image = gfx::test::CreateImage(1, 1); | |
tschumann
2016/08/16 14:56:55
please add a comment explaining that we set up the
jkrcal
2016/12/06 08:30:25
Done.
| |
947 testing::MockFunction<void(const std::string&, const gfx::Image&)> | |
948 image_fetched; | |
949 EXPECT_CALL(image_fetched, | |
950 Call(MakeUniqueID(kSnippetUrl2), _)) | |
951 .WillOnce(testing::SaveArg<1>(&image)); | |
952 | |
953 service()->FetchSuggestionImage( | |
954 MakeUniqueID(kSnippetUrl2), | |
955 base::Bind(&testing::MockFunction<void(const std::string&, | |
956 const gfx::Image&)>::Call, | |
957 base::Unretained(&image_fetched))); | |
958 | |
959 base::RunLoop().RunUntilIdle(); | |
960 EXPECT_TRUE(image.IsEmpty()); | |
961 } | |
962 | |
889 } // namespace ntp_snippets | 963 } // namespace ntp_snippets |
OLD | NEW |