Chromium Code Reviews| 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 <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 13 #include "base/files/scoped_temp_dir.h" | 13 #include "base/files/scoped_temp_dir.h" |
| 14 #include "base/json/json_reader.h" | 14 #include "base/json/json_reader.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 18 #include "base/run_loop.h" | 18 #include "base/run_loop.h" |
| 19 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 22 #include "base/test/histogram_tester.h" | 22 #include "base/test/histogram_tester.h" |
| 23 #include "base/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
| 24 #include "base/time/time.h" | 24 #include "base/time/time.h" |
| 25 #include "components/image_fetcher/image_decoder.h" | 25 #include "components/image_fetcher/image_decoder.h" |
| 26 #include "components/image_fetcher/image_fetcher.h" | 26 #include "components/image_fetcher/image_fetcher.h" |
| 27 #include "components/image_fetcher/image_fetcher_delegate.h" | 27 #include "components/image_fetcher/image_fetcher_delegate.h" |
| 28 #include "components/ntp_snippets/category_factory.h" | 28 #include "components/ntp_snippets/category_factory.h" |
| 29 #include "components/ntp_snippets/mock_content_suggestions_provider_observer.h" | |
| 30 #include "components/ntp_snippets/ntp_snippet.h" | 29 #include "components/ntp_snippets/ntp_snippet.h" |
| 30 #include "components/ntp_snippets/ntp_snippets_constants.h" | |
| 31 #include "components/ntp_snippets/ntp_snippets_database.h" | 31 #include "components/ntp_snippets/ntp_snippets_database.h" |
| 32 #include "components/ntp_snippets/ntp_snippets_fetcher.h" | 32 #include "components/ntp_snippets/ntp_snippets_fetcher.h" |
| 33 #include "components/ntp_snippets/ntp_snippets_scheduler.h" | 33 #include "components/ntp_snippets/ntp_snippets_scheduler.h" |
| 34 #include "components/ntp_snippets/ntp_snippets_test_utils.h" | 34 #include "components/ntp_snippets/ntp_snippets_test_utils.h" |
| 35 #include "components/ntp_snippets/switches.h" | 35 #include "components/ntp_snippets/switches.h" |
| 36 #include "components/prefs/testing_pref_service.h" | 36 #include "components/prefs/testing_pref_service.h" |
| 37 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" | 37 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" |
| 38 #include "components/signin/core/browser/fake_signin_manager.h" | 38 #include "components/signin/core/browser/fake_signin_manager.h" |
| 39 #include "components/variations/variations_associated_data.h" | |
| 39 #include "google_apis/google_api_keys.h" | 40 #include "google_apis/google_api_keys.h" |
| 40 #include "net/url_request/test_url_fetcher_factory.h" | 41 #include "net/url_request/test_url_fetcher_factory.h" |
| 41 #include "net/url_request/url_request_test_util.h" | 42 #include "net/url_request/url_request_test_util.h" |
| 42 #include "testing/gmock/include/gmock/gmock.h" | 43 #include "testing/gmock/include/gmock/gmock.h" |
| 43 #include "testing/gtest/include/gtest/gtest.h" | 44 #include "testing/gtest/include/gtest/gtest.h" |
| 44 #include "ui/gfx/image/image.h" | 45 #include "ui/gfx/image/image.h" |
| 45 #include "ui/gfx/image/image_unittest_util.h" | 46 #include "ui/gfx/image/image_unittest_util.h" |
| 46 | 47 |
| 47 using image_fetcher::ImageFetcher; | 48 using image_fetcher::ImageFetcher; |
| 48 using image_fetcher::ImageFetcherDelegate; | 49 using image_fetcher::ImageFetcherDelegate; |
| 49 using testing::ElementsAre; | 50 using testing::ElementsAre; |
| 50 using testing::Eq; | 51 using testing::Eq; |
| 52 using testing::InSequence; | |
| 51 using testing::Invoke; | 53 using testing::Invoke; |
| 52 using testing::IsEmpty; | 54 using testing::IsEmpty; |
| 53 using testing::Mock; | 55 using testing::Mock; |
| 56 using testing::MockFunction; | |
| 54 using testing::Return; | 57 using testing::Return; |
| 55 using testing::SizeIs; | 58 using testing::SizeIs; |
| 56 using testing::StartsWith; | 59 using testing::StartsWith; |
| 57 using testing::_; | 60 using testing::_; |
| 58 | 61 |
| 59 namespace ntp_snippets { | 62 namespace ntp_snippets { |
| 60 | 63 |
| 61 namespace { | 64 namespace { |
| 62 | 65 |
| 63 MATCHER_P(IdEq, value, "") { | 66 MATCHER_P(IdEq, value, "") { |
| 64 return arg->id() == value; | 67 return arg->id() == value; |
| 65 } | 68 } |
| 66 | 69 |
| 67 const base::Time::Exploded kDefaultCreationTime = {2015, 11, 4, 25, 13, 46, 45}; | 70 const base::Time::Exploded kDefaultCreationTime = {2015, 11, 4, 25, 13, 46, 45}; |
| 68 const char kTestContentSnippetsServerFormat[] = | 71 const char kTestContentSuggestionsServerFormat[] = |
| 69 "https://chromereader-pa.googleapis.com/v1/fetch?key=%s"; | 72 "https://chromecontentsuggestions-pa.googleapis.com/v1/suggestions/" |
|
tschumann
2016/08/30 06:57:21
reading this test, you might think that we're actu
sfiera
2016/08/30 13:16:44
Done.
| |
| 73 "fetch?key=%s"; | |
| 70 | 74 |
| 71 const char kSnippetUrl[] = "http://localhost/foobar"; | 75 const char kSnippetUrl[] = "http://localhost/foobar"; |
| 72 const char kSnippetTitle[] = "Title"; | 76 const char kSnippetTitle[] = "Title"; |
| 73 const char kSnippetText[] = "Snippet"; | 77 const char kSnippetText[] = "Snippet"; |
| 74 const char kSnippetSalientImage[] = "http://localhost/salient_image"; | 78 const char kSnippetSalientImage[] = "http://localhost/salient_image"; |
| 75 const char kSnippetPublisherName[] = "Foo News"; | 79 const char kSnippetPublisherName[] = "Foo News"; |
| 76 const char kSnippetAmpUrl[] = "http://localhost/amp"; | 80 const char kSnippetAmpUrl[] = "http://localhost/amp"; |
| 77 const float kSnippetScore = 5.0; | |
| 78 | 81 |
| 79 const char kSnippetUrl2[] = "http://foo.com/bar"; | 82 const char kSnippetUrl2[] = "http://foo.com/bar"; |
| 80 | 83 |
| 81 base::Time GetDefaultCreationTime() { | 84 base::Time GetDefaultCreationTime() { |
| 82 base::Time out_time; | 85 base::Time out_time; |
| 83 EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time)); | 86 EXPECT_TRUE(base::Time::FromUTCExploded(kDefaultCreationTime, &out_time)); |
| 84 return out_time; | 87 return out_time; |
| 85 } | 88 } |
| 86 | 89 |
| 87 base::Time GetDefaultExpirationTime() { | 90 base::Time GetDefaultExpirationTime() { |
| 88 return base::Time::Now() + base::TimeDelta::FromHours(1); | 91 return base::Time::Now() + base::TimeDelta::FromHours(1); |
| 89 } | 92 } |
| 90 | 93 |
| 91 std::string GetTestJson(const std::vector<std::string>& snippets) { | 94 std::string GetTestJson(const std::vector<std::string>& snippets) { |
| 92 return base::StringPrintf("{\"recos\":[%s]}", | 95 return base::StringPrintf( |
| 93 base::JoinString(snippets, ", ").c_str()); | 96 "{\n" |
| 97 " \"categories\": [{\n" | |
| 98 " \"id\": 1,\n" | |
| 99 " \"localizedTitle\": \"Articles for You\",\n" | |
| 100 " \"suggestions\": [%s]\n" | |
| 101 " }]\n" | |
| 102 "}\n", | |
| 103 base::JoinString(snippets, ", ").c_str()); | |
| 104 } | |
| 105 | |
| 106 std::string FormatTime(const base::Time& t) { | |
| 107 base::Time::Exploded x; | |
| 108 t.UTCExplode(&x); | |
| 109 return base::StringPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ", x.year, x.month, | |
| 110 x.day_of_month, x.hour, x.minute, x.second); | |
| 94 } | 111 } |
| 95 | 112 |
| 96 std::string GetSnippetWithUrlAndTimesAndSources( | 113 std::string GetSnippetWithUrlAndTimesAndSources( |
|
Marc Treib
2016/08/30 09:29:29
"Sources" isn't accurate anymore, there's only one
sfiera
2016/08/30 13:16:43
Done.
| |
| 114 const std::vector<std::string>& ids, | |
| 97 const std::string& url, | 115 const std::string& url, |
| 98 const std::string& content_creation_time_str, | 116 const base::Time& creation_time, |
| 99 const std::string& expiry_time_str, | 117 const base::Time& expiry_time, |
| 100 const std::vector<std::string>& source_urls, | 118 const std::string& publisher, |
| 101 const std::vector<std::string>& publishers, | 119 const std::string& amp_url) { |
| 102 const std::vector<std::string>& amp_urls) { | 120 std::string ids_string; |
|
tschumann
2016/08/30 06:57:21
ids_string = base::JoinStrings(ids, "\",\n \"
sfiera
2016/08/30 13:16:44
Done.
| |
| 103 char json_str_format[] = | 121 for (const std::string& id : ids) { |
| 104 "{ \"contentInfo\": {" | 122 if (!ids_string.empty()) |
| 105 "\"url\" : \"%s\"," | 123 ids_string += "\",\n \""; |
| 106 "\"title\" : \"%s\"," | 124 ids_string += id; |
| 107 "\"snippet\" : \"%s\"," | 125 } |
| 108 "\"thumbnailUrl\" : \"%s\"," | |
| 109 "\"creationTimestampSec\" : \"%s\"," | |
| 110 "\"expiryTimestampSec\" : \"%s\"," | |
| 111 "\"sourceCorpusInfo\" : [%s]" | |
| 112 "}, " | |
| 113 "\"score\" : %f}"; | |
| 114 | 126 |
| 115 char source_corpus_info_format[] = | 127 return base::StringPrintf( |
| 116 "{\"corpusId\": \"%s\"," | 128 "{\n" |
|
Marc Treib
2016/08/30 09:29:29
nit: indentation?
sfiera
2016/08/30 13:16:44
Do you mean in the JSON? It's indented so that it
| |
| 117 "\"publisherData\": {" | 129 " \"ids\": [\n" |
| 118 "\"sourceName\": \"%s\"" | 130 " \"%s\"\n" |
| 119 "}," | 131 " ],\n" |
| 120 "\"ampUrl\": \"%s\"}"; | 132 " \"title\": \"%s\",\n" |
| 121 | 133 " \"snippet\": \"%s\",\n" |
| 122 std::string source_corpus_info_list_str; | 134 " \"fullPageUrl\": \"%s\",\n" |
| 123 for (size_t i = 0; i < source_urls.size(); ++i) { | 135 " \"creationTime\": \"%s\",\n" |
| 124 std::string source_corpus_info_str = | 136 " \"expirationTime\": \"%s\",\n" |
| 125 base::StringPrintf(source_corpus_info_format, | 137 " \"attribution\": \"%s\",\n" |
| 126 source_urls[i].empty() ? "" : source_urls[i].c_str(), | 138 " \"imageUrl\": \"%s\",\n" |
| 127 publishers[i].empty() ? "" : publishers[i].c_str(), | 139 " \"ampUrl\": \"%s\"\n" |
| 128 amp_urls[i].empty() ? "" : amp_urls[i].c_str()); | 140 " }", |
| 129 source_corpus_info_list_str.append(source_corpus_info_str); | 141 ids_string.c_str(), kSnippetTitle, kSnippetText, url.c_str(), |
| 130 source_corpus_info_list_str.append(","); | 142 FormatTime(creation_time).c_str(), FormatTime(expiry_time).c_str(), |
| 131 } | 143 publisher.c_str(), kSnippetSalientImage, amp_url.c_str()); |
| 132 // Remove the last comma | |
| 133 source_corpus_info_list_str.erase(source_corpus_info_list_str.size()-1, 1); | |
| 134 return base::StringPrintf(json_str_format, url.c_str(), kSnippetTitle, | |
| 135 kSnippetText, kSnippetSalientImage, | |
| 136 content_creation_time_str.c_str(), | |
| 137 expiry_time_str.c_str(), | |
| 138 source_corpus_info_list_str.c_str(), kSnippetScore); | |
| 139 } | 144 } |
| 140 | 145 |
| 141 std::string GetSnippetWithSources(const std::vector<std::string>& source_urls, | 146 std::string GetSnippetWithSources(const std::vector<std::string>& source_urls, |
| 142 const std::vector<std::string>& publishers, | 147 const std::string& publisher, |
| 143 const std::vector<std::string>& amp_urls) { | 148 const std::string& amp_url) { |
| 144 return GetSnippetWithUrlAndTimesAndSources( | 149 return GetSnippetWithUrlAndTimesAndSources( |
| 145 kSnippetUrl, NTPSnippet::TimeToJsonString(GetDefaultCreationTime()), | 150 {kSnippetUrl}, source_urls[0], GetDefaultCreationTime(), |
|
Marc Treib
2016/08/30 09:29:29
This seems wrong - why pass in a vector of source_
sfiera
2016/08/30 13:16:44
Not sure. I think this was used for the tests that
| |
| 146 NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()), source_urls, | 151 GetDefaultExpirationTime(), publisher, amp_url); |
| 147 publishers, amp_urls); | |
| 148 } | 152 } |
| 149 | 153 |
| 150 std::string GetSnippetWithUrlAndTimes( | 154 std::string GetSnippetWithUrlAndTimes(const std::string& url, |
| 151 const std::string& url, | 155 const base::Time& content_creation_time, |
| 152 const std::string& content_creation_time_str, | 156 const base::Time& expiry_time) { |
| 153 const std::string& expiry_time_str) { | 157 return GetSnippetWithUrlAndTimesAndSources({url}, url, content_creation_time, |
| 154 return GetSnippetWithUrlAndTimesAndSources( | 158 expiry_time, kSnippetPublisherName, |
| 155 url, content_creation_time_str, expiry_time_str, | 159 kSnippetAmpUrl); |
| 156 {std::string(url)}, {std::string(kSnippetPublisherName)}, | |
| 157 {std::string(kSnippetAmpUrl)}); | |
| 158 } | 160 } |
| 159 | 161 |
| 160 std::string GetSnippetWithTimes(const std::string& content_creation_time_str, | 162 std::string GetSnippetWithTimes(const base::Time& content_creation_time, |
| 161 const std::string& expiry_time_str) { | 163 const base::Time& expiry_time) { |
| 162 return GetSnippetWithUrlAndTimes(kSnippetUrl, content_creation_time_str, | 164 return GetSnippetWithUrlAndTimes(kSnippetUrl, content_creation_time, |
| 163 expiry_time_str); | 165 expiry_time); |
| 164 } | 166 } |
| 165 | 167 |
| 166 std::string GetSnippetWithUrl(const std::string& url) { | 168 std::string GetSnippetWithUrl(const std::string& url) { |
| 167 return GetSnippetWithUrlAndTimes( | 169 return GetSnippetWithUrlAndTimes(url, GetDefaultCreationTime(), |
| 168 url, NTPSnippet::TimeToJsonString(GetDefaultCreationTime()), | 170 GetDefaultExpirationTime()); |
| 169 NTPSnippet::TimeToJsonString(GetDefaultExpirationTime())); | |
| 170 } | 171 } |
| 171 | 172 |
| 172 std::string GetSnippet() { | 173 std::string GetSnippet() { |
| 173 return GetSnippetWithUrlAndTimes( | 174 return GetSnippetWithUrlAndTimes(kSnippetUrl, GetDefaultCreationTime(), |
| 174 kSnippetUrl, NTPSnippet::TimeToJsonString(GetDefaultCreationTime()), | 175 GetDefaultExpirationTime()); |
| 175 NTPSnippet::TimeToJsonString(GetDefaultExpirationTime())); | |
| 176 } | 176 } |
| 177 | 177 |
| 178 std::string GetExpiredSnippet() { | 178 std::string GetExpiredSnippet() { |
| 179 return GetSnippetWithTimes( | 179 return GetSnippetWithTimes(GetDefaultCreationTime(), base::Time::Now()); |
| 180 NTPSnippet::TimeToJsonString(GetDefaultCreationTime()), | |
| 181 NTPSnippet::TimeToJsonString(base::Time::Now())); | |
| 182 } | 180 } |
| 183 | 181 |
| 184 std::string GetInvalidSnippet() { | 182 std::string GetInvalidSnippet() { |
| 185 std::string json_str = GetSnippet(); | 183 std::string json_str = GetSnippet(); |
| 186 // Make the json invalid by removing the final closing brace. | 184 // Make the json invalid by removing the final closing brace. |
| 187 return json_str.substr(0, json_str.size() - 1); | 185 return json_str.substr(0, json_str.size() - 1); |
| 188 } | 186 } |
| 189 | 187 |
| 190 std::string GetIncompleteSnippet() { | 188 std::string GetIncompleteSnippet() { |
| 191 std::string json_str = GetSnippet(); | 189 std::string json_str = GetSnippet(); |
| 192 // Rename the "url" entry. The result is syntactically valid json that will | 190 // Rename the "url" entry. The result is syntactically valid json that will |
| 193 // fail to parse as snippets. | 191 // fail to parse as snippets. |
| 194 size_t pos = json_str.find("\"url\""); | 192 size_t pos = json_str.find("\"fullPageUrl\""); |
| 195 if (pos == std::string::npos) { | 193 if (pos == std::string::npos) { |
|
tschumann
2016/08/30 06:57:21
couldn't we just CHECK() then?
tschumann
2016/08/30 14:01:39
In this particular case, CHECK() would be cleaner
| |
| 196 NOTREACHED(); | 194 NOTREACHED(); |
| 197 return std::string(); | 195 return std::string(); |
| 198 } | 196 } |
| 199 json_str[pos + 1] = 'x'; | 197 json_str[pos + 1] = 'x'; |
| 200 return json_str; | 198 return json_str; |
| 201 } | 199 } |
| 202 | 200 |
| 203 void ServeOneByOneImage( | 201 void ServeOneByOneImage( |
| 204 const std::string& id, | 202 const std::string& id, |
| 205 base::Callback<void(const std::string&, const gfx::Image&)> callback) { | 203 base::Callback<void(const std::string&, const gfx::Image&)> callback) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 235 class MockScheduler : public NTPSnippetsScheduler { | 233 class MockScheduler : public NTPSnippetsScheduler { |
| 236 public: | 234 public: |
| 237 MOCK_METHOD4(Schedule, | 235 MOCK_METHOD4(Schedule, |
| 238 bool(base::TimeDelta period_wifi_charging, | 236 bool(base::TimeDelta period_wifi_charging, |
| 239 base::TimeDelta period_wifi, | 237 base::TimeDelta period_wifi, |
| 240 base::TimeDelta period_fallback, | 238 base::TimeDelta period_fallback, |
| 241 base::Time reschedule_time)); | 239 base::Time reschedule_time)); |
| 242 MOCK_METHOD0(Unschedule, bool()); | 240 MOCK_METHOD0(Unschedule, bool()); |
| 243 }; | 241 }; |
| 244 | 242 |
| 245 class WaitForDBLoad { | |
| 246 public: | |
| 247 WaitForDBLoad(MockContentSuggestionsProviderObserver* observer, | |
| 248 NTPSnippetsService* service) | |
| 249 : observer_(observer) { | |
| 250 EXPECT_CALL(*observer_, OnCategoryStatusChanged(_, _, _)) | |
| 251 .WillOnce(Invoke(this, &WaitForDBLoad::OnCategoryStatusChanged)); | |
| 252 if (!service->ready()) | |
| 253 run_loop_.Run(); | |
| 254 } | |
| 255 | |
| 256 ~WaitForDBLoad() { Mock::VerifyAndClearExpectations(observer_); } | |
| 257 | |
| 258 private: | |
| 259 void OnCategoryStatusChanged(ContentSuggestionsProvider* provider, | |
| 260 Category category, | |
| 261 CategoryStatus new_status) { | |
| 262 EXPECT_EQ(new_status, CategoryStatus::AVAILABLE_LOADING); | |
| 263 run_loop_.Quit(); | |
| 264 } | |
| 265 | |
| 266 MockContentSuggestionsProviderObserver* observer_; | |
| 267 base::RunLoop run_loop_; | |
| 268 | |
| 269 DISALLOW_COPY_AND_ASSIGN(WaitForDBLoad); | |
| 270 }; | |
| 271 | |
| 272 class MockImageFetcher : public ImageFetcher { | 243 class MockImageFetcher : public ImageFetcher { |
| 273 public: | 244 public: |
| 274 MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*)); | 245 MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*)); |
| 275 MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName)); | 246 MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName)); |
| 276 MOCK_METHOD3( | 247 MOCK_METHOD3( |
| 277 StartOrQueueNetworkRequest, | 248 StartOrQueueNetworkRequest, |
| 278 void(const std::string&, | 249 void(const std::string&, |
| 279 const GURL&, | 250 const GURL&, |
| 280 base::Callback<void(const std::string&, const gfx::Image&)>)); | 251 base::Callback<void(const std::string&, const gfx::Image&)>)); |
| 281 }; | 252 }; |
| 282 | 253 |
| 254 class FakeContentSuggestionsProviderObserver | |
|
tschumann
2016/08/30 06:57:21
nice!
| |
| 255 : public ContentSuggestionsProvider::Observer { | |
| 256 public: | |
| 257 FakeContentSuggestionsProviderObserver() | |
| 258 : loaded_(base::WaitableEvent::ResetPolicy::MANUAL, | |
| 259 base::WaitableEvent::InitialState::NOT_SIGNALED) {} | |
| 260 | |
| 261 void OnNewSuggestions(ContentSuggestionsProvider* provider, | |
| 262 Category category, | |
| 263 std::vector<ContentSuggestion> suggestions) override { | |
| 264 suggestions_[category].insert(suggestions_[category].begin(), | |
|
Marc Treib
2016/08/30 09:29:29
Shouldn't you clear suggestions_[category_] first?
sfiera
2016/08/30 13:16:43
Oh, apparently. Done.
| |
| 265 std::make_move_iterator(suggestions.begin()), | |
| 266 std::make_move_iterator(suggestions.end())); | |
| 267 } | |
| 268 | |
| 269 void OnCategoryStatusChanged(ContentSuggestionsProvider* provider, | |
| 270 Category category, | |
| 271 CategoryStatus new_status) override { | |
| 272 loaded_.Signal(); | |
| 273 statuses_[category] = new_status; | |
| 274 } | |
| 275 | |
| 276 void OnSuggestionInvalidated(ContentSuggestionsProvider* provider, | |
| 277 Category category, | |
| 278 const std::string& suggestion_id) override {} | |
| 279 | |
| 280 CategoryStatus StatusForCategory(Category category) const { | |
| 281 auto it = statuses_.find(category); | |
| 282 if (it == statuses_.end()) { | |
| 283 return CategoryStatus::NOT_PROVIDED; | |
| 284 } | |
| 285 return it->second; | |
| 286 } | |
| 287 | |
| 288 const std::vector<ContentSuggestion>& SuggestionsForCategory( | |
| 289 Category category) { | |
| 290 return suggestions_[category]; | |
| 291 } | |
| 292 | |
| 293 void WaitForLoad() { loaded_.Wait(); } | |
| 294 | |
| 295 void Reset() { | |
| 296 loaded_.Reset(); | |
| 297 statuses_.clear(); | |
| 298 } | |
| 299 | |
| 300 private: | |
| 301 base::WaitableEvent loaded_; | |
| 302 std::map<Category, CategoryStatus, Category::CompareByID> statuses_; | |
| 303 std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID> | |
| 304 suggestions_; | |
| 305 | |
| 306 DISALLOW_COPY_AND_ASSIGN(FakeContentSuggestionsProviderObserver); | |
| 307 }; | |
| 308 | |
| 283 class MockDismissedSuggestionsCallback | 309 class MockDismissedSuggestionsCallback |
| 284 : public ContentSuggestionsProvider::DismissedSuggestionsCallback { | 310 : public ContentSuggestionsProvider::DismissedSuggestionsCallback { |
| 285 public: | 311 public: |
| 286 MOCK_METHOD2(MockRun, | 312 MOCK_METHOD2(MockRun, |
| 287 void(Category category, | 313 void(Category category, |
| 288 std::vector<ContentSuggestion>* dismissed_suggestions)); | 314 std::vector<ContentSuggestion>* dismissed_suggestions)); |
| 289 void Run(Category category, | 315 void Run(Category category, |
| 290 std::vector<ContentSuggestion> dismissed_suggestions) { | 316 std::vector<ContentSuggestion> dismissed_suggestions) { |
| 291 MockRun(category, &dismissed_suggestions); | 317 MockRun(category, &dismissed_suggestions); |
| 292 } | 318 } |
| 293 }; | 319 }; |
| 294 | 320 |
| 295 } // namespace | 321 } // namespace |
| 296 | 322 |
| 297 class NTPSnippetsServiceTest : public test::NTPSnippetsTestBase { | 323 class NTPSnippetsServiceTest : public ::testing::Test { |
|
tschumann
2016/08/30 06:57:21
yay!
| |
| 298 public: | 324 public: |
| 299 NTPSnippetsServiceTest() | 325 NTPSnippetsServiceTest() |
| 300 : fake_url_fetcher_factory_( | 326 : params_manager_( |
| 327 ntp_snippets::kStudyName, | |
| 328 {{"content_suggestions_backend", kContentSuggestionsServer}}), | |
| 329 fake_url_fetcher_factory_( | |
| 301 /*default_factory=*/&failing_url_fetcher_factory_), | 330 /*default_factory=*/&failing_url_fetcher_factory_), |
| 302 test_url_(base::StringPrintf(kTestContentSnippetsServerFormat, | 331 test_url_(base::StringPrintf(kTestContentSuggestionsServerFormat, |
| 303 google_apis::GetAPIKey().c_str())) { | 332 google_apis::GetAPIKey().c_str())), |
|
Marc Treib
2016/08/30 09:29:29
I don't think the actual API key matters here? We
sfiera
2016/08/30 13:16:43
We're using a real fetcher, which will use a real
Marc Treib
2016/08/30 13:43:38
Aah, I remember now. Carry on then :)
tschumann
2016/08/30 14:01:39
but please tell me we're not making an actual fetc
| |
| 304 NTPSnippetsService::RegisterProfilePrefs(pref_service()->registry()); | 333 |
| 305 RequestThrottler::RegisterProfilePrefs(pref_service()->registry()); | 334 observer_(base::MakeUnique<FakeContentSuggestionsProviderObserver>()) { |
| 335 NTPSnippetsService::RegisterProfilePrefs(utils_.pref_service()->registry()); | |
| 336 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); | |
| 306 | 337 |
| 307 // Since no SuggestionsService is injected in tests, we need to force the | 338 // Since no SuggestionsService is injected in tests, we need to force the |
| 308 // service to fetch from all hosts. | 339 // service to fetch from all hosts. |
| 309 base::CommandLine::ForCurrentProcess()->AppendSwitch( | 340 base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| 310 switches::kDontRestrict); | 341 switches::kDontRestrict); |
| 311 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); | 342 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); |
| 312 } | 343 } |
| 313 | 344 |
| 314 ~NTPSnippetsServiceTest() override { | 345 ~NTPSnippetsServiceTest() override { |
| 315 // We need to run the message loop after deleting the database, because | 346 // We need to run the message loop after deleting the database, because |
| 316 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task | 347 // ProtoDatabaseImpl deletes the actual LevelDB asynchronously on the task |
| 317 // runner. Without this, we'd get reports of memory leaks. | 348 // runner. Without this, we'd get reports of memory leaks. |
| 318 Mock::VerifyAndClear(&mock_scheduler()); | |
| 319 service_.reset(); | |
| 320 base::RunLoop().RunUntilIdle(); | 349 base::RunLoop().RunUntilIdle(); |
| 321 } | 350 } |
| 322 | 351 |
| 323 void SetUp() override { | 352 std::unique_ptr<NTPSnippetsService> MakeSnippetsService() { |
| 324 test::NTPSnippetsTestBase::SetUp(); | |
| 325 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1); | |
| 326 CreateSnippetsService(); | |
| 327 } | |
| 328 | |
| 329 void RecreateSnippetsService() { | |
| 330 Mock::VerifyAndClear(&mock_scheduler()); | |
| 331 service_.reset(); | |
| 332 base::RunLoop().RunUntilIdle(); | |
| 333 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1); | |
| 334 CreateSnippetsService(); | |
| 335 } | |
| 336 | |
| 337 void CreateSnippetsService() { | |
| 338 DCHECK(!service_); | |
| 339 | |
| 340 scoped_refptr<base::SingleThreadTaskRunner> task_runner( | 353 scoped_refptr<base::SingleThreadTaskRunner> task_runner( |
| 341 base::ThreadTaskRunnerHandle::Get()); | 354 base::ThreadTaskRunnerHandle::Get()); |
| 342 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = | 355 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter = |
| 343 new net::TestURLRequestContextGetter(task_runner.get()); | 356 new net::TestURLRequestContextGetter(task_runner.get()); |
| 344 | 357 |
| 345 ResetSigninManager(); | 358 utils_.ResetSigninManager(); |
|
Marc Treib
2016/08/30 09:29:29
So if you call MakeSnippetsService twice in a row,
Marc Treib
2016/08/30 13:43:39
Not addressed yet.
sfiera
2016/08/30 16:33:09
Checked !observer.Loaded() above (which is reset f
| |
| 346 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = | 359 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher = |
| 347 base::MakeUnique<NTPSnippetsFetcher>( | 360 base::MakeUnique<NTPSnippetsFetcher>( |
| 348 fake_signin_manager(), fake_token_service_.get(), | 361 utils_.fake_signin_manager(), fake_token_service_.get(), |
| 349 std::move(request_context_getter), pref_service(), | 362 std::move(request_context_getter), utils_.pref_service(), |
| 350 &category_factory_, base::Bind(&ParseJson), | 363 &category_factory_, base::Bind(&ParseJson), |
| 351 /*is_stable_channel=*/true); | 364 /*is_stable_channel=*/true); |
| 352 | 365 |
| 353 fake_signin_manager()->SignIn("foo@bar.com"); | 366 utils_.fake_signin_manager()->SignIn("foo@bar.com"); |
| 354 snippets_fetcher->SetPersonalizationForTesting( | 367 snippets_fetcher->SetPersonalizationForTesting( |
| 355 NTPSnippetsFetcher::Personalization::kNonPersonal); | 368 NTPSnippetsFetcher::Personalization::kNonPersonal); |
| 356 | 369 |
| 357 auto image_fetcher = | 370 auto image_fetcher = |
| 358 base::MakeUnique<testing::NiceMock<MockImageFetcher>>(); | 371 base::MakeUnique<testing::NiceMock<MockImageFetcher>>(); |
| 359 image_fetcher_ = image_fetcher.get(); | 372 image_fetcher_ = image_fetcher.get(); |
| 360 | 373 |
| 361 // Add an initial fetch response, as the service tries to fetch when there | 374 // Add an initial fetch response, as the service tries to fetch when there |
| 362 // is nothing in the DB. | 375 // is nothing in the DB. |
| 363 SetUpFetchResponse(GetTestJson({GetSnippet()})); | 376 SetUpFetchResponse(GetTestJson({})); |
| 364 | 377 |
| 365 service_.reset(new NTPSnippetsService( | 378 auto service = base::MakeUnique<NTPSnippetsService>( |
| 366 &observer_, &category_factory_, pref_service(), nullptr, nullptr, "fr", | 379 observer_.get(), &category_factory_, utils_.pref_service(), nullptr, |
| 367 &scheduler_, std::move(snippets_fetcher), | 380 nullptr, "fr", &scheduler_, std::move(snippets_fetcher), |
| 368 std::move(image_fetcher), /*image_decoder=*/nullptr, | 381 std::move(image_fetcher), /*image_decoder=*/nullptr, |
| 369 base::MakeUnique<NTPSnippetsDatabase>(database_dir_.path(), | 382 base::MakeUnique<NTPSnippetsDatabase>(database_dir_.path(), |
| 370 task_runner), | 383 task_runner), |
| 371 base::MakeUnique<NTPSnippetsStatusService>(fake_signin_manager(), | 384 base::MakeUnique<NTPSnippetsStatusService>(utils_.fake_signin_manager(), |
| 372 pref_service()))); | 385 utils_.pref_service())); |
| 373 | 386 |
| 374 WaitForDBLoad(&observer_, service_.get()); | 387 base::RunLoop().RunUntilIdle(); |
| 388 observer_->WaitForLoad(); | |
| 389 return service; | |
| 375 } | 390 } |
| 376 | 391 |
| 377 std::string MakeUniqueID(const std::string& within_category_id) { | 392 void ResetSnippetsService(std::unique_ptr<NTPSnippetsService>* service) { |
| 378 return service()->MakeUniqueID(articles_category(), within_category_id); | 393 service->reset(); |
| 394 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); | |
| 395 *service = MakeSnippetsService(); | |
| 396 } | |
| 397 | |
| 398 std::string MakeUniqueID(const NTPSnippetsService& service, | |
| 399 const std::string& within_category_id) { | |
| 400 return service.MakeUniqueID(articles_category(), within_category_id); | |
| 379 } | 401 } |
| 380 | 402 |
| 381 Category articles_category() { | 403 Category articles_category() { |
| 382 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); | 404 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES); |
| 383 } | 405 } |
| 384 | 406 |
| 385 protected: | 407 protected: |
| 386 const GURL& test_url() { return test_url_; } | 408 const GURL& test_url() { return test_url_; } |
| 387 NTPSnippetsService* service() { return service_.get(); } | 409 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } |
| 388 MockContentSuggestionsProviderObserver& observer() { return observer_; } | |
| 389 MockScheduler& mock_scheduler() { return scheduler_; } | 410 MockScheduler& mock_scheduler() { return scheduler_; } |
| 390 testing::NiceMock<MockImageFetcher>* image_fetcher() { | 411 testing::NiceMock<MockImageFetcher>* image_fetcher() { |
| 391 return image_fetcher_; | 412 return image_fetcher_; |
| 392 } | 413 } |
| 393 | 414 |
| 394 // Provide the json to be returned by the fake fetcher. | 415 // Provide the json to be returned by the fake fetcher. |
| 395 void SetUpFetchResponse(const std::string& json) { | 416 void SetUpFetchResponse(const std::string& json) { |
| 396 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK, | 417 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK, |
| 397 net::URLRequestStatus::SUCCESS); | 418 net::URLRequestStatus::SUCCESS); |
| 398 } | 419 } |
| 399 | 420 |
| 400 void LoadFromJSONString(const std::string& json) { | 421 void LoadFromJSONString(NTPSnippetsService* service, |
| 422 const std::string& json) { | |
| 401 SetUpFetchResponse(json); | 423 SetUpFetchResponse(json); |
| 402 service()->FetchSnippets(true); | 424 service->FetchSnippets(true); |
| 403 base::RunLoop().RunUntilIdle(); | 425 base::RunLoop().RunUntilIdle(); |
| 404 } | 426 } |
| 405 | 427 |
| 406 private: | 428 private: |
| 429 variations::testing::VariationParamsManager params_manager_; | |
| 430 test::NTPSnippetsTestUtils utils_; | |
| 407 base::MessageLoop message_loop_; | 431 base::MessageLoop message_loop_; |
| 408 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; | 432 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; |
| 409 // Instantiation of factory automatically sets itself as URLFetcher's factory. | 433 // Instantiation of factory automatically sets itself as URLFetcher's factory. |
| 410 net::FakeURLFetcherFactory fake_url_fetcher_factory_; | 434 net::FakeURLFetcherFactory fake_url_fetcher_factory_; |
| 411 const GURL test_url_; | 435 const GURL test_url_; |
| 412 std::unique_ptr<OAuth2TokenService> fake_token_service_; | 436 std::unique_ptr<OAuth2TokenService> fake_token_service_; |
| 413 MockScheduler scheduler_; | 437 MockScheduler scheduler_; |
|
tschumann
2016/08/30 06:57:21
consider making this a ::testing::NiceMock<MockSch
sfiera
2016/08/30 13:16:44
I see your NiceMock<> and raise you a StrictMock<>
tschumann
2016/08/30 14:01:39
but please make sure the test doesn't get too brit
| |
| 414 MockContentSuggestionsProviderObserver observer_; | 438 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; |
| 415 CategoryFactory category_factory_; | 439 CategoryFactory category_factory_; |
| 416 testing::NiceMock<MockImageFetcher>* image_fetcher_; | 440 testing::NiceMock<MockImageFetcher>* image_fetcher_; |
| 417 // Last so that the dependencies are deleted after the service. | |
| 418 std::unique_ptr<NTPSnippetsService> service_; | |
| 419 | 441 |
| 420 base::ScopedTempDir database_dir_; | 442 base::ScopedTempDir database_dir_; |
| 421 | 443 |
| 422 DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest); | 444 DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest); |
| 423 }; | 445 }; |
| 424 | 446 |
| 425 TEST_F(NTPSnippetsServiceTest, ScheduleOnStart) { | 447 TEST_F(NTPSnippetsServiceTest, ScheduleOnStart) { |
| 426 // SetUp() checks that Schedule is called. | 448 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 449 auto service = MakeSnippetsService(); | |
| 427 | 450 |
| 428 // When we have no snippets are all, loading the service initiates a fetch. | 451 // When we have no snippets are all, loading the service initiates a fetch. |
| 429 base::RunLoop().RunUntilIdle(); | 452 base::RunLoop().RunUntilIdle(); |
| 430 ASSERT_EQ("OK", service()->snippets_fetcher()->last_status()); | 453 ASSERT_EQ("OK", service->snippets_fetcher()->last_status()); |
| 431 } | 454 } |
| 432 | 455 |
| 433 TEST_F(NTPSnippetsServiceTest, Full) { | 456 TEST_F(NTPSnippetsServiceTest, Full) { |
| 434 std::string json_str(GetTestJson({GetSnippet()})); | 457 std::string json_str(GetTestJson({GetSnippet()})); |
| 435 | 458 |
| 436 LoadFromJSONString(json_str); | 459 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 437 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 460 auto service = MakeSnippetsService(); |
| 438 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | |
| 439 | 461 |
| 440 EXPECT_EQ(snippet.id(), kSnippetUrl); | 462 LoadFromJSONString(service.get(), json_str); |
| 441 EXPECT_EQ(snippet.title(), kSnippetTitle); | 463 ASSERT_THAT(observer().SuggestionsForCategory(articles_category()), |
| 442 EXPECT_EQ(snippet.snippet(), kSnippetText); | 464 SizeIs(1)); |
| 443 EXPECT_EQ(snippet.salient_image_url(), GURL(kSnippetSalientImage)); | 465 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); |
| 466 const ContentSuggestion& snippet = | |
|
Marc Treib
2016/08/30 09:29:29
Can we rename this to |suggestion| please?
sfiera
2016/08/30 13:16:43
Done.
| |
| 467 observer().SuggestionsForCategory(articles_category()).front(); | |
| 468 | |
| 469 EXPECT_EQ(MakeUniqueID(*service, kSnippetUrl), snippet.id()); | |
| 470 EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(snippet.title())); | |
| 471 EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(snippet.snippet_text())); | |
| 472 // EXPECT_EQ(GURL(kSnippetSalientImage), snippet.salient_image_url()); | |
|
tschumann
2016/08/30 06:57:21
why is this commented out?
sfiera
2016/08/30 13:16:43
Right now ContentSuggestion::salient_image_url_ ha
Marc Treib
2016/08/30 13:43:39
Because it shouldn't be there :) Mind removing it
tschumann
2016/08/30 14:01:39
+1 for removing it. Commented out code tends to ro
Marc Treib
2016/08/30 14:04:39
I mostly meant removing that member, which is comp
| |
| 444 EXPECT_EQ(GetDefaultCreationTime(), snippet.publish_date()); | 473 EXPECT_EQ(GetDefaultCreationTime(), snippet.publish_date()); |
| 445 EXPECT_EQ(snippet.best_source().publisher_name, kSnippetPublisherName); | 474 EXPECT_EQ(kSnippetPublisherName, base::UTF16ToUTF8(snippet.publisher_name())); |
| 446 EXPECT_EQ(snippet.best_source().amp_url, GURL(kSnippetAmpUrl)); | 475 EXPECT_EQ(GURL(kSnippetAmpUrl), snippet.amp_url()); |
| 447 } | 476 } |
| 448 | 477 |
| 449 TEST_F(NTPSnippetsServiceTest, Clear) { | 478 TEST_F(NTPSnippetsServiceTest, Clear) { |
| 479 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); | |
| 480 auto service = MakeSnippetsService(); | |
| 481 | |
| 450 std::string json_str(GetTestJson({GetSnippet()})); | 482 std::string json_str(GetTestJson({GetSnippet()})); |
| 451 | 483 |
| 452 LoadFromJSONString(json_str); | 484 LoadFromJSONString(service.get(), json_str); |
| 453 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 485 EXPECT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); |
| 454 | 486 |
| 455 service()->ClearCachedSuggestions(articles_category()); | 487 service->ClearCachedSuggestions(articles_category()); |
| 456 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 488 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 457 } | 489 } |
| 458 | 490 |
| 459 TEST_F(NTPSnippetsServiceTest, InsertAtFront) { | 491 TEST_F(NTPSnippetsServiceTest, InsertAtFront) { |
| 492 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); | |
| 493 auto service = MakeSnippetsService(); | |
| 494 | |
| 460 std::string first("http://first"); | 495 std::string first("http://first"); |
| 461 LoadFromJSONString(GetTestJson({GetSnippetWithUrl(first)})); | 496 LoadFromJSONString(service.get(), GetTestJson({GetSnippetWithUrl(first)})); |
| 462 EXPECT_THAT(service()->GetSnippetsForTesting(), ElementsAre(IdEq(first))); | 497 EXPECT_THAT(service->GetSnippetsForTesting(), ElementsAre(IdEq(first))); |
| 463 | 498 |
| 464 std::string second("http://second"); | 499 std::string second("http://second"); |
| 465 LoadFromJSONString(GetTestJson({GetSnippetWithUrl(second)})); | 500 LoadFromJSONString(service.get(), GetTestJson({GetSnippetWithUrl(second)})); |
| 466 // The snippet loaded last should be at the first position in the list now. | 501 // The snippet loaded last should be at the first position in the list now. |
| 467 EXPECT_THAT(service()->GetSnippetsForTesting(), | 502 EXPECT_THAT(service->GetSnippetsForTesting(), |
| 468 ElementsAre(IdEq(second), IdEq(first))); | 503 ElementsAre(IdEq(second), IdEq(first))); |
| 469 } | 504 } |
| 470 | 505 |
| 471 TEST_F(NTPSnippetsServiceTest, LimitNumSnippets) { | 506 TEST_F(NTPSnippetsServiceTest, LimitNumSnippets) { |
| 507 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); | |
| 508 auto service = MakeSnippetsService(); | |
| 509 | |
| 472 int max_snippet_count = NTPSnippetsService::GetMaxSnippetCountForTesting(); | 510 int max_snippet_count = NTPSnippetsService::GetMaxSnippetCountForTesting(); |
| 473 int snippets_per_load = max_snippet_count / 2 + 1; | 511 int snippets_per_load = max_snippet_count / 2 + 1; |
| 474 char url_format[] = "http://localhost/%i"; | 512 char url_format[] = "http://localhost/%i"; |
| 475 | 513 |
| 476 std::vector<std::string> snippets1; | 514 std::vector<std::string> snippets1; |
| 477 std::vector<std::string> snippets2; | 515 std::vector<std::string> snippets2; |
| 478 for (int i = 0; i < snippets_per_load; i++) { | 516 for (int i = 0; i < snippets_per_load; i++) { |
| 479 snippets1.push_back(GetSnippetWithUrl(base::StringPrintf(url_format, i))); | 517 snippets1.push_back(GetSnippetWithUrl(base::StringPrintf(url_format, i))); |
| 480 snippets2.push_back(GetSnippetWithUrl( | 518 snippets2.push_back(GetSnippetWithUrl( |
| 481 base::StringPrintf(url_format, snippets_per_load + i))); | 519 base::StringPrintf(url_format, snippets_per_load + i))); |
| 482 } | 520 } |
| 483 | 521 |
| 484 LoadFromJSONString(GetTestJson(snippets1)); | 522 LoadFromJSONString(service.get(), GetTestJson(snippets1)); |
| 485 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(snippets1.size())); | 523 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(snippets1.size())); |
| 486 | 524 |
| 487 LoadFromJSONString(GetTestJson(snippets2)); | 525 LoadFromJSONString(service.get(), GetTestJson(snippets2)); |
| 488 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(max_snippet_count)); | 526 EXPECT_THAT(service->GetSnippetsForTesting(), SizeIs(max_snippet_count)); |
| 489 } | 527 } |
| 490 | 528 |
| 491 TEST_F(NTPSnippetsServiceTest, LoadInvalidJson) { | 529 TEST_F(NTPSnippetsServiceTest, LoadInvalidJson) { |
| 492 LoadFromJSONString(GetTestJson({GetInvalidSnippet()})); | 530 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 493 EXPECT_THAT(service()->snippets_fetcher()->last_status(), | 531 auto service = MakeSnippetsService(); |
| 532 | |
| 533 LoadFromJSONString(service.get(), GetTestJson({GetInvalidSnippet()})); | |
| 534 EXPECT_THAT(service->snippets_fetcher()->last_status(), | |
| 494 StartsWith("Received invalid JSON")); | 535 StartsWith("Received invalid JSON")); |
| 495 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 536 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 496 } | 537 } |
| 497 | 538 |
| 498 TEST_F(NTPSnippetsServiceTest, LoadInvalidJsonWithExistingSnippets) { | 539 TEST_F(NTPSnippetsServiceTest, LoadInvalidJsonWithExistingSnippets) { |
| 499 LoadFromJSONString(GetTestJson({GetSnippet()})); | 540 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 500 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 541 auto service = MakeSnippetsService(); |
| 501 ASSERT_EQ("OK", service()->snippets_fetcher()->last_status()); | |
| 502 | 542 |
| 503 LoadFromJSONString(GetTestJson({GetInvalidSnippet()})); | 543 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); |
| 504 EXPECT_THAT(service()->snippets_fetcher()->last_status(), | 544 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); |
| 545 ASSERT_EQ("OK", service->snippets_fetcher()->last_status()); | |
| 546 | |
| 547 LoadFromJSONString(service.get(), GetTestJson({GetInvalidSnippet()})); | |
| 548 EXPECT_THAT(service->snippets_fetcher()->last_status(), | |
| 505 StartsWith("Received invalid JSON")); | 549 StartsWith("Received invalid JSON")); |
| 506 // This should not have changed the existing snippets. | 550 // This should not have changed the existing snippets. |
| 507 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 551 EXPECT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); |
| 508 } | 552 } |
| 509 | 553 |
| 510 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJson) { | 554 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJson) { |
| 511 LoadFromJSONString(GetTestJson({GetIncompleteSnippet()})); | 555 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 556 auto service = MakeSnippetsService(); | |
| 557 | |
| 558 LoadFromJSONString(service.get(), GetTestJson({GetIncompleteSnippet()})); | |
| 512 EXPECT_EQ("Invalid / empty list.", | 559 EXPECT_EQ("Invalid / empty list.", |
| 513 service()->snippets_fetcher()->last_status()); | 560 service->snippets_fetcher()->last_status()); |
| 514 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 561 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 515 } | 562 } |
| 516 | 563 |
| 517 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJsonWithExistingSnippets) { | 564 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJsonWithExistingSnippets) { |
| 518 LoadFromJSONString(GetTestJson({GetSnippet()})); | 565 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 519 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 566 auto service = MakeSnippetsService(); |
| 520 | 567 |
| 521 LoadFromJSONString(GetTestJson({GetIncompleteSnippet()})); | 568 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); |
| 569 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); | |
| 570 | |
| 571 LoadFromJSONString(service.get(), GetTestJson({GetIncompleteSnippet()})); | |
| 522 EXPECT_EQ("Invalid / empty list.", | 572 EXPECT_EQ("Invalid / empty list.", |
| 523 service()->snippets_fetcher()->last_status()); | 573 service->snippets_fetcher()->last_status()); |
| 524 // This should not have changed the existing snippets. | 574 // This should not have changed the existing snippets. |
| 525 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 575 EXPECT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); |
| 526 } | 576 } |
| 527 | 577 |
| 528 TEST_F(NTPSnippetsServiceTest, Dismiss) { | 578 TEST_F(NTPSnippetsServiceTest, Dismiss) { |
| 529 std::vector<std::string> source_urls, publishers, amp_urls; | 579 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(2); |
| 530 source_urls.push_back(std::string("http://site.com")); | 580 auto service = MakeSnippetsService(); |
| 531 publishers.push_back(std::string("Source 1")); | |
| 532 amp_urls.push_back(std::string()); | |
| 533 std::string json_str( | |
| 534 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); | |
| 535 | 581 |
| 536 LoadFromJSONString(json_str); | 582 std::string json_str(GetTestJson( |
| 583 {GetSnippetWithSources({"http://site.com"}, "Source 1", "")})); | |
| 537 | 584 |
| 538 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 585 LoadFromJSONString(service.get(), json_str); |
| 586 | |
| 587 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); | |
| 539 | 588 |
| 540 // Dismissing a non-existent snippet shouldn't do anything. | 589 // Dismissing a non-existent snippet shouldn't do anything. |
| 541 service()->DismissSuggestion(MakeUniqueID("http://othersite.com")); | 590 service->DismissSuggestion(MakeUniqueID(*service, "http://othersite.com")); |
| 542 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 591 EXPECT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); |
| 543 | 592 |
| 544 // Dismiss the snippet. | 593 // Dismiss the snippet. |
| 545 service()->DismissSuggestion(MakeUniqueID(kSnippetUrl)); | 594 service->DismissSuggestion(MakeUniqueID(*service, kSnippetUrl)); |
| 546 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 595 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 547 | 596 |
| 548 // Make sure that fetching the same snippet again does not re-add it. | 597 // Make sure that fetching the same snippet again does not re-add it. |
| 549 LoadFromJSONString(json_str); | 598 LoadFromJSONString(service.get(), json_str); |
| 550 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 599 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 551 | 600 |
| 552 // The snippet should stay dismissed even after re-creating the service. | 601 // The snippet should stay dismissed even after re-creating the service. |
| 553 RecreateSnippetsService(); | 602 ResetSnippetsService(&service); |
| 554 LoadFromJSONString(json_str); | 603 LoadFromJSONString(service.get(), json_str); |
| 555 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 604 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 556 | 605 |
| 557 // The snippet can be added again after clearing dismissed snippets. | 606 // The snippet can be added again after clearing dismissed snippets. |
| 558 service()->ClearDismissedSuggestionsForDebugging(articles_category()); | 607 service->ClearDismissedSuggestionsForDebugging(articles_category()); |
| 559 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 608 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 560 LoadFromJSONString(json_str); | 609 LoadFromJSONString(service.get(), json_str); |
| 561 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 610 EXPECT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); |
| 562 } | 611 } |
| 563 | 612 |
| 564 TEST_F(NTPSnippetsServiceTest, GetDismissed) { | 613 TEST_F(NTPSnippetsServiceTest, GetDismissed) { |
| 565 LoadFromJSONString(GetTestJson({GetSnippet()})); | 614 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 615 auto service = MakeSnippetsService(); | |
| 566 | 616 |
| 567 service()->DismissSuggestion(MakeUniqueID(kSnippetUrl)); | 617 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); |
| 568 | 618 |
| 569 MockDismissedSuggestionsCallback callback; | 619 service->DismissSuggestion(MakeUniqueID(*service, kSnippetUrl)); |
| 570 | 620 |
| 571 EXPECT_CALL(callback, MockRun(_, _)) | 621 { |
| 572 .WillOnce( | 622 MockDismissedSuggestionsCallback callback; |
| 573 Invoke([this](Category category, | 623 EXPECT_CALL(callback, MockRun(_, _)) |
|
tschumann
2016/08/30 06:57:21
not now, but this mock usage also has a pretty bad
sfiera
2016/08/30 13:16:43
This is actually doable just with a lambda, which
tschumann
2016/08/30 14:01:39
Actually, it would be even nice as a standalone fu
| |
| 574 std::vector<ContentSuggestion>* dismissed_suggestions) { | 624 .WillOnce(Invoke([this, &service]( |
| 575 EXPECT_EQ(1u, dismissed_suggestions->size()); | 625 Category category, |
| 576 for (auto& suggestion : *dismissed_suggestions) { | 626 std::vector<ContentSuggestion>* dismissed_suggestions) { |
| 577 EXPECT_EQ(MakeUniqueID(kSnippetUrl), suggestion.id()); | 627 EXPECT_EQ(1u, dismissed_suggestions->size()); |
| 578 } | 628 for (auto& suggestion : *dismissed_suggestions) { |
| 579 })); | 629 EXPECT_EQ(MakeUniqueID(*service, kSnippetUrl), suggestion.id()); |
| 580 service()->GetDismissedSuggestionsForDebugging( | 630 } |
| 581 articles_category(), | 631 })); |
| 582 base::Bind(&MockDismissedSuggestionsCallback::Run, | |
| 583 base::Unretained(&callback), articles_category())); | |
| 584 Mock::VerifyAndClearExpectations(&callback); | |
| 585 | 632 |
| 586 // There should be no dismissed snippet after clearing the list. | 633 service->GetDismissedSuggestionsForDebugging( |
| 587 EXPECT_CALL(callback, MockRun(_, _)) | 634 articles_category(), |
| 588 .WillOnce( | 635 base::Bind(&MockDismissedSuggestionsCallback::Run, |
| 589 Invoke([this](Category category, | 636 base::Unretained(&callback), articles_category())); |
| 590 std::vector<ContentSuggestion>* dismissed_suggestions) { | 637 } |
| 591 EXPECT_EQ(0u, dismissed_suggestions->size()); | 638 |
| 592 })); | 639 { |
| 593 service()->ClearDismissedSuggestionsForDebugging(articles_category()); | 640 MockDismissedSuggestionsCallback callback; |
| 594 service()->GetDismissedSuggestionsForDebugging( | 641 EXPECT_CALL(callback, MockRun(_, _)) |
| 595 articles_category(), | 642 .WillOnce(Invoke( |
| 596 base::Bind(&MockDismissedSuggestionsCallback::Run, | 643 [this](Category category, |
| 597 base::Unretained(&callback), articles_category())); | 644 std::vector<ContentSuggestion>* dismissed_suggestions) { |
| 645 EXPECT_EQ(0u, dismissed_suggestions->size()); | |
| 646 })); | |
| 647 | |
| 648 // There should be no dismissed snippet after clearing the list. | |
| 649 service->ClearDismissedSuggestionsForDebugging(articles_category()); | |
| 650 service->GetDismissedSuggestionsForDebugging( | |
| 651 articles_category(), | |
| 652 base::Bind(&MockDismissedSuggestionsCallback::Run, | |
| 653 base::Unretained(&callback), articles_category())); | |
| 654 } | |
| 598 } | 655 } |
| 599 | 656 |
| 600 TEST_F(NTPSnippetsServiceTest, CreationTimestampParseFail) { | 657 TEST_F(NTPSnippetsServiceTest, CreationTimestampParseFail) { |
| 601 std::string json_str(GetTestJson({GetSnippetWithTimes( | 658 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 602 "aaa1448459205", | 659 auto service = MakeSnippetsService(); |
| 603 NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()))})); | |
| 604 | 660 |
| 605 LoadFromJSONString(json_str); | 661 std::string json = |
| 606 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 662 GetSnippetWithTimes(GetDefaultCreationTime(), GetDefaultExpirationTime()); |
| 607 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | 663 base::ReplaceFirstSubstringAfterOffset( |
| 608 EXPECT_EQ(snippet.id(), kSnippetUrl); | 664 &json, 0, FormatTime(GetDefaultCreationTime()), "aaa1448459205"); |
| 609 EXPECT_EQ(snippet.title(), kSnippetTitle); | 665 std::string json_str(GetTestJson({json})); |
| 610 EXPECT_EQ(snippet.snippet(), kSnippetText); | 666 |
| 611 EXPECT_EQ(base::Time::UnixEpoch(), snippet.publish_date()); | 667 LoadFromJSONString(service.get(), json_str); |
| 668 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(0)); | |
|
Marc Treib
2016/08/30 09:29:29
Why has the behavior changed here?
Also, this shou
sfiera
2016/08/30 13:16:43
NTPSnippet::CreateFromContentSuggestionsDictionary
| |
| 612 } | 669 } |
| 613 | 670 |
| 614 TEST_F(NTPSnippetsServiceTest, RemoveExpiredContent) { | 671 TEST_F(NTPSnippetsServiceTest, RemoveExpiredContent) { |
| 672 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); | |
| 673 auto service = MakeSnippetsService(); | |
| 674 | |
| 615 std::string json_str(GetTestJson({GetExpiredSnippet()})); | 675 std::string json_str(GetTestJson({GetExpiredSnippet()})); |
| 616 | 676 |
| 617 LoadFromJSONString(json_str); | 677 LoadFromJSONString(service.get(), json_str); |
| 618 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 678 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 619 } | 679 } |
| 620 | 680 |
| 621 TEST_F(NTPSnippetsServiceTest, TestSingleSource) { | 681 TEST_F(NTPSnippetsServiceTest, TestSingleSource) { |
| 622 std::vector<std::string> source_urls, publishers, amp_urls; | 682 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 623 source_urls.push_back(std::string("http://source1.com")); | 683 auto service = MakeSnippetsService(); |
| 624 publishers.push_back(std::string("Source 1")); | |
| 625 amp_urls.push_back(std::string("http://source1.amp.com")); | |
| 626 std::string json_str( | |
| 627 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); | |
| 628 | 684 |
| 629 LoadFromJSONString(json_str); | 685 std::string json_str(GetTestJson({GetSnippetWithSources( |
| 630 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 686 {"http://source1.com"}, "Source 1", "http://source1.amp.com")})); |
| 631 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | 687 |
| 688 LoadFromJSONString(service.get(), json_str); | |
| 689 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); | |
| 690 const NTPSnippet& snippet = *service->GetSnippetsForTesting().front(); | |
| 632 EXPECT_EQ(snippet.sources().size(), 1u); | 691 EXPECT_EQ(snippet.sources().size(), 1u); |
| 633 EXPECT_EQ(snippet.id(), kSnippetUrl); | 692 EXPECT_EQ(snippet.id(), kSnippetUrl); |
| 634 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); | 693 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); |
| 635 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); | 694 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); |
| 636 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com")); | 695 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com")); |
| 637 } | 696 } |
| 638 | 697 |
| 639 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMalformedUrl) { | 698 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMalformedUrl) { |
| 640 std::vector<std::string> source_urls, publishers, amp_urls; | 699 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 641 source_urls.push_back(std::string("aaaa")); | 700 auto service = MakeSnippetsService(); |
| 642 publishers.push_back(std::string("Source 1")); | |
| 643 amp_urls.push_back(std::string("http://source1.amp.com")); | |
| 644 std::string json_str( | |
| 645 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); | |
| 646 | 701 |
| 647 LoadFromJSONString(json_str); | 702 std::string json_str(GetTestJson( |
| 648 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 703 {GetSnippetWithSources({"aaaa"}, "Source 1", "http://source1.amp.com")})); |
|
Marc Treib
2016/08/30 09:29:29
nit: s/aaaa/not a url/ ?
sfiera
2016/08/30 13:16:44
Done (for locale fr)
| |
| 704 | |
| 705 LoadFromJSONString(service.get(), json_str); | |
| 706 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); | |
| 649 } | 707 } |
| 650 | 708 |
| 651 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMissingData) { | 709 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMissingData) { |
| 652 std::vector<std::string> source_urls, publishers, amp_urls; | 710 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 653 source_urls.push_back(std::string("http://source1.com")); | 711 auto service = MakeSnippetsService(); |
| 654 publishers.push_back(std::string()); | 712 |
| 655 amp_urls.push_back(std::string()); | |
| 656 std::string json_str( | 713 std::string json_str( |
| 657 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); | 714 GetTestJson({GetSnippetWithSources({"http://source1.com"}, "", "")})); |
| 658 | 715 |
| 659 LoadFromJSONString(json_str); | 716 LoadFromJSONString(service.get(), json_str); |
| 660 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 717 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 661 } | |
| 662 | |
| 663 TEST_F(NTPSnippetsServiceTest, TestMultipleSources) { | |
| 664 std::vector<std::string> source_urls, publishers, amp_urls; | |
| 665 source_urls.push_back(std::string("http://source1.com")); | |
| 666 source_urls.push_back(std::string("http://source2.com")); | |
| 667 publishers.push_back(std::string("Source 1")); | |
| 668 publishers.push_back(std::string("Source 2")); | |
| 669 amp_urls.push_back(std::string("http://source1.amp.com")); | |
| 670 amp_urls.push_back(std::string("http://source2.amp.com")); | |
| 671 std::string json_str( | |
| 672 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); | |
| 673 | |
| 674 LoadFromJSONString(json_str); | |
| 675 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | |
| 676 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | |
| 677 // Expect the first source to be chosen | |
| 678 EXPECT_EQ(snippet.sources().size(), 2u); | |
| 679 EXPECT_EQ(snippet.id(), kSnippetUrl); | |
| 680 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); | |
| 681 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); | |
| 682 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com")); | |
| 683 } | |
| 684 | |
| 685 TEST_F(NTPSnippetsServiceTest, TestMultipleIncompleteSources) { | |
| 686 // Set Source 2 to have no AMP url, and Source 1 to have no publisher name | |
| 687 // Source 2 should win since we favor publisher name over amp url | |
| 688 std::vector<std::string> source_urls, publishers, amp_urls; | |
| 689 source_urls.push_back(std::string("http://source1.com")); | |
| 690 source_urls.push_back(std::string("http://source2.com")); | |
| 691 publishers.push_back(std::string()); | |
| 692 publishers.push_back(std::string("Source 2")); | |
| 693 amp_urls.push_back(std::string("http://source1.amp.com")); | |
| 694 amp_urls.push_back(std::string()); | |
| 695 std::string json_str( | |
| 696 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); | |
| 697 | |
| 698 LoadFromJSONString(json_str); | |
| 699 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | |
| 700 { | |
| 701 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | |
| 702 EXPECT_EQ(snippet.sources().size(), 2u); | |
| 703 EXPECT_EQ(snippet.id(), kSnippetUrl); | |
| 704 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); | |
| 705 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2")); | |
| 706 EXPECT_EQ(snippet.best_source().amp_url, GURL()); | |
| 707 } | |
| 708 | |
| 709 service()->ClearCachedSuggestions(articles_category()); | |
| 710 // Set Source 1 to have no AMP url, and Source 2 to have no publisher name | |
| 711 // Source 1 should win in this case since we prefer publisher name to AMP url | |
| 712 source_urls.clear(); | |
| 713 source_urls.push_back(std::string("http://source1.com")); | |
| 714 source_urls.push_back(std::string("http://source2.com")); | |
| 715 publishers.clear(); | |
| 716 publishers.push_back(std::string("Source 1")); | |
| 717 publishers.push_back(std::string()); | |
| 718 amp_urls.clear(); | |
| 719 amp_urls.push_back(std::string()); | |
| 720 amp_urls.push_back(std::string("http://source2.amp.com")); | |
| 721 json_str = | |
| 722 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); | |
| 723 | |
| 724 LoadFromJSONString(json_str); | |
| 725 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | |
| 726 { | |
| 727 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | |
| 728 EXPECT_EQ(snippet.sources().size(), 2u); | |
| 729 EXPECT_EQ(snippet.id(), kSnippetUrl); | |
| 730 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); | |
| 731 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); | |
| 732 EXPECT_EQ(snippet.best_source().amp_url, GURL()); | |
| 733 } | |
| 734 | |
| 735 service()->ClearCachedSuggestions(articles_category()); | |
| 736 // Set source 1 to have no AMP url and no source, and source 2 to only have | |
| 737 // amp url. There should be no snippets since we only add sources we consider | |
| 738 // complete | |
| 739 source_urls.clear(); | |
| 740 source_urls.push_back(std::string("http://source1.com")); | |
| 741 source_urls.push_back(std::string("http://source2.com")); | |
| 742 publishers.clear(); | |
| 743 publishers.push_back(std::string()); | |
| 744 publishers.push_back(std::string()); | |
| 745 amp_urls.clear(); | |
| 746 amp_urls.push_back(std::string()); | |
| 747 amp_urls.push_back(std::string("http://source2.amp.com")); | |
| 748 json_str = | |
| 749 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); | |
| 750 | |
| 751 LoadFromJSONString(json_str); | |
| 752 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | |
| 753 } | |
| 754 | |
| 755 TEST_F(NTPSnippetsServiceTest, TestMultipleCompleteSources) { | |
| 756 // Test 2 complete sources, we should choose the first complete source | |
| 757 std::vector<std::string> source_urls, publishers, amp_urls; | |
| 758 source_urls.push_back(std::string("http://source1.com")); | |
| 759 source_urls.push_back(std::string("http://source2.com")); | |
| 760 source_urls.push_back(std::string("http://source3.com")); | |
| 761 publishers.push_back(std::string("Source 1")); | |
| 762 publishers.push_back(std::string()); | |
| 763 publishers.push_back(std::string("Source 3")); | |
| 764 amp_urls.push_back(std::string("http://source1.amp.com")); | |
| 765 amp_urls.push_back(std::string("http://source2.amp.com")); | |
| 766 amp_urls.push_back(std::string("http://source3.amp.com")); | |
| 767 std::string json_str( | |
| 768 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); | |
| 769 | |
| 770 LoadFromJSONString(json_str); | |
| 771 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | |
| 772 { | |
| 773 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | |
| 774 EXPECT_EQ(snippet.sources().size(), 3u); | |
| 775 EXPECT_EQ(snippet.id(), kSnippetUrl); | |
| 776 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); | |
| 777 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); | |
| 778 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com")); | |
| 779 } | |
| 780 | |
| 781 // Test 2 complete sources, we should choose the first complete source | |
| 782 service()->ClearCachedSuggestions(articles_category()); | |
| 783 source_urls.clear(); | |
| 784 source_urls.push_back(std::string("http://source1.com")); | |
| 785 source_urls.push_back(std::string("http://source2.com")); | |
| 786 source_urls.push_back(std::string("http://source3.com")); | |
| 787 publishers.clear(); | |
| 788 publishers.push_back(std::string()); | |
| 789 publishers.push_back(std::string("Source 2")); | |
| 790 publishers.push_back(std::string("Source 3")); | |
| 791 amp_urls.clear(); | |
| 792 amp_urls.push_back(std::string("http://source1.amp.com")); | |
| 793 amp_urls.push_back(std::string("http://source2.amp.com")); | |
| 794 amp_urls.push_back(std::string("http://source3.amp.com")); | |
| 795 json_str = | |
| 796 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); | |
| 797 | |
| 798 LoadFromJSONString(json_str); | |
| 799 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | |
| 800 { | |
| 801 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | |
| 802 EXPECT_EQ(snippet.sources().size(), 3u); | |
| 803 EXPECT_EQ(snippet.id(), kSnippetUrl); | |
| 804 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); | |
| 805 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2")); | |
| 806 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com")); | |
| 807 } | |
| 808 | |
| 809 // Test 3 complete sources, we should choose the first complete source | |
| 810 service()->ClearCachedSuggestions(articles_category()); | |
| 811 source_urls.clear(); | |
| 812 source_urls.push_back(std::string("http://source1.com")); | |
| 813 source_urls.push_back(std::string("http://source2.com")); | |
| 814 source_urls.push_back(std::string("http://source3.com")); | |
| 815 publishers.clear(); | |
| 816 publishers.push_back(std::string("Source 1")); | |
| 817 publishers.push_back(std::string("Source 2")); | |
| 818 publishers.push_back(std::string("Source 3")); | |
| 819 amp_urls.clear(); | |
| 820 amp_urls.push_back(std::string()); | |
| 821 amp_urls.push_back(std::string("http://source2.amp.com")); | |
| 822 amp_urls.push_back(std::string("http://source3.amp.com")); | |
| 823 json_str = | |
| 824 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); | |
| 825 | |
| 826 LoadFromJSONString(json_str); | |
| 827 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | |
| 828 { | |
| 829 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front(); | |
| 830 EXPECT_EQ(snippet.sources().size(), 3u); | |
| 831 EXPECT_EQ(snippet.id(), kSnippetUrl); | |
| 832 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); | |
| 833 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2")); | |
| 834 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com")); | |
| 835 } | |
| 836 } | 718 } |
| 837 | 719 |
| 838 TEST_F(NTPSnippetsServiceTest, LogNumArticlesHistogram) { | 720 TEST_F(NTPSnippetsServiceTest, LogNumArticlesHistogram) { |
| 721 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(2); | |
| 722 auto service = MakeSnippetsService(); | |
| 723 | |
| 839 base::HistogramTester tester; | 724 base::HistogramTester tester; |
| 840 LoadFromJSONString(GetTestJson({GetInvalidSnippet()})); | 725 LoadFromJSONString(service.get(), GetTestJson({GetInvalidSnippet()})); |
| 841 | 726 |
| 842 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), | 727 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), |
| 843 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); | 728 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); |
| 844 // Invalid JSON shouldn't contribute to NumArticlesFetched. | 729 // Invalid JSON shouldn't contribute to NumArticlesFetched. |
| 845 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 730 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
| 846 IsEmpty()); | 731 IsEmpty()); |
| 847 // Valid JSON with empty list. | 732 // Valid JSON with empty list. |
| 848 LoadFromJSONString(GetTestJson(std::vector<std::string>())); | 733 LoadFromJSONString(service.get(), GetTestJson(std::vector<std::string>())); |
| 849 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), | 734 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), |
| 850 ElementsAre(base::Bucket(/*min=*/0, /*count=*/2))); | 735 ElementsAre(base::Bucket(/*min=*/0, /*count=*/2))); |
| 851 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 736 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
| 852 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); | 737 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1))); |
| 853 // Snippet list should be populated with size 1. | 738 // Snippet list should be populated with size 1. |
| 854 LoadFromJSONString(GetTestJson({GetSnippet()})); | 739 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); |
| 855 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), | 740 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), |
| 856 ElementsAre(base::Bucket(/*min=*/0, /*count=*/2), | 741 ElementsAre(base::Bucket(/*min=*/0, /*count=*/2), |
| 857 base::Bucket(/*min=*/1, /*count=*/1))); | 742 base::Bucket(/*min=*/1, /*count=*/1))); |
| 858 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 743 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
| 859 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), | 744 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), |
| 860 base::Bucket(/*min=*/1, /*count=*/1))); | 745 base::Bucket(/*min=*/1, /*count=*/1))); |
| 861 // Duplicate snippet shouldn't increase the list size. | 746 // Duplicate snippet shouldn't increase the list size. |
| 862 LoadFromJSONString(GetTestJson({GetSnippet()})); | 747 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); |
| 863 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), | 748 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), |
| 864 ElementsAre(base::Bucket(/*min=*/0, /*count=*/2), | 749 ElementsAre(base::Bucket(/*min=*/0, /*count=*/2), |
| 865 base::Bucket(/*min=*/1, /*count=*/2))); | 750 base::Bucket(/*min=*/1, /*count=*/2))); |
| 866 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 751 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
| 867 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), | 752 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), |
| 868 base::Bucket(/*min=*/1, /*count=*/2))); | 753 base::Bucket(/*min=*/1, /*count=*/2))); |
| 869 EXPECT_THAT( | 754 EXPECT_THAT( |
| 870 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 755 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
| 871 IsEmpty()); | 756 IsEmpty()); |
| 872 // Dismissing a snippet should decrease the list size. This will only be | 757 // Dismissing a snippet should decrease the list size. This will only be |
| 873 // logged after the next fetch. | 758 // logged after the next fetch. |
| 874 service()->DismissSuggestion(MakeUniqueID(kSnippetUrl)); | 759 service->DismissSuggestion(MakeUniqueID(*service, kSnippetUrl)); |
| 875 LoadFromJSONString(GetTestJson({GetSnippet()})); | 760 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); |
| 876 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), | 761 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"), |
| 877 ElementsAre(base::Bucket(/*min=*/0, /*count=*/3), | 762 ElementsAre(base::Bucket(/*min=*/0, /*count=*/3), |
| 878 base::Bucket(/*min=*/1, /*count=*/2))); | 763 base::Bucket(/*min=*/1, /*count=*/2))); |
| 879 // Dismissed snippets shouldn't influence NumArticlesFetched. | 764 // Dismissed snippets shouldn't influence NumArticlesFetched. |
| 880 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), | 765 EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticlesFetched"), |
| 881 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), | 766 ElementsAre(base::Bucket(/*min=*/0, /*count=*/1), |
| 882 base::Bucket(/*min=*/1, /*count=*/3))); | 767 base::Bucket(/*min=*/1, /*count=*/3))); |
| 883 EXPECT_THAT( | 768 EXPECT_THAT( |
| 884 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), | 769 tester.GetAllSamples("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded"), |
| 885 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); | 770 ElementsAre(base::Bucket(/*min=*/1, /*count=*/1))); |
| 771 | |
| 886 // Recreating the service and loading from prefs shouldn't count as fetched | 772 // Recreating the service and loading from prefs shouldn't count as fetched |
|
Marc Treib
2016/08/30 09:29:29
Yay outdated comments - "loading from prefs" isn't
| |
| 887 // articles. | 773 // articles. However, recreating the service does trigger one fetch. |
|
Marc Treib
2016/08/30 09:29:29
Why? If we get suggestions from the DB, we shouldn
sfiera
2016/08/30 13:16:44
We don't get suggestions from the DB. There's one
Marc Treib
2016/08/30 13:43:38
Yay! Thanks!
| |
| 888 RecreateSnippetsService(); | |
| 889 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); | 774 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 4); |
| 775 ResetSnippetsService(&service); | |
| 776 EXPECT_EQ(observer().StatusForCategory(articles_category()), | |
| 777 CategoryStatus::AVAILABLE); | |
| 778 tester.ExpectTotalCount("NewTabPage.Snippets.NumArticlesFetched", 5); | |
| 890 } | 779 } |
| 891 | 780 |
| 892 TEST_F(NTPSnippetsServiceTest, DismissShouldRespectAllKnownUrls) { | 781 TEST_F(NTPSnippetsServiceTest, DismissShouldRespectAllKnownUrls) { |
| 893 const std::string creation = | 782 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 894 NTPSnippet::TimeToJsonString(GetDefaultCreationTime()); | 783 auto service = MakeSnippetsService(); |
| 895 const std::string expiry = | 784 |
| 896 NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()); | 785 const base::Time creation = GetDefaultCreationTime(); |
| 786 const base::Time expiry = GetDefaultExpirationTime(); | |
| 897 const std::vector<std::string> source_urls = { | 787 const std::vector<std::string> source_urls = { |
| 898 "http://mashable.com/2016/05/11/stolen", | 788 "http://mashable.com/2016/05/11/stolen", |
| 899 "http://www.aol.com/article/2016/05/stolen-doggie", | 789 "http://www.aol.com/article/2016/05/stolen-doggie", |
| 900 "http://mashable.com/2016/05/11/stolen?utm_cid=1"}; | 790 "http://mashable.com/2016/05/11/stolen?utm_cid=1"}; |
| 901 const std::vector<std::string> publishers = {"Mashable", "AOL", "Mashable"}; | 791 const std::vector<std::string> publishers = {"Mashable", "AOL", "Mashable"}; |
|
Marc Treib
2016/08/30 09:29:29
The third entry is never used.
sfiera
2016/08/30 13:16:44
Removed.
| |
| 902 const std::vector<std::string> amp_urls = { | 792 const std::vector<std::string> amp_urls = { |
|
Marc Treib
2016/08/30 09:29:29
Only amp_urls[1] is ever used.
sfiera
2016/08/30 13:16:44
Removed third entry.
| |
| 903 "http://mashable-amphtml.googleusercontent.com/1", | 793 "http://mashable-amphtml.googleusercontent.com/1", |
| 904 "http://t2.gstatic.com/images?q=tbn:3", | 794 "http://t2.gstatic.com/images?q=tbn:3", |
| 905 "http://t2.gstatic.com/images?q=tbn:3"}; | 795 "http://t2.gstatic.com/images?q=tbn:3"}; |
| 906 | 796 |
| 907 // Add the snippet from the mashable domain. | 797 // Add the snippet from the mashable domain. |
| 908 LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources( | 798 LoadFromJSONString(service.get(), |
| 909 source_urls[0], creation, expiry, source_urls, publishers, amp_urls)})); | 799 GetTestJson({GetSnippetWithUrlAndTimesAndSources( |
| 910 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1)); | 800 source_urls, source_urls[0], creation, expiry, |
| 801 publishers[0], amp_urls[1])})); | |
|
Marc Treib
2016/08/30 09:29:29
Should this be amp_urls[0]?
sfiera
2016/08/30 13:16:44
I suppose so. Done.
| |
| 802 ASSERT_THAT(service->GetSnippetsForTesting(), SizeIs(1)); | |
| 911 // Dismiss the snippet via the mashable source corpus ID. | 803 // Dismiss the snippet via the mashable source corpus ID. |
| 912 service()->DismissSuggestion(MakeUniqueID(source_urls[0])); | 804 service->DismissSuggestion(MakeUniqueID(*service, source_urls[0])); |
| 913 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 805 EXPECT_THAT(service->GetSnippetsForTesting(), IsEmpty()); |
| 914 | 806 |
| 915 // The same article from the AOL domain should now be detected as dismissed. | 807 // The same article from the AOL domain should now be detected as dismissed. |
| 916 LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources( | 808 LoadFromJSONString(service.get(), |
| 917 source_urls[1], creation, expiry, source_urls, publishers, amp_urls)})); | 809 GetTestJson({GetSnippetWithUrlAndTimesAndSources( |
| 918 ASSERT_THAT(service()->GetSnippetsForTesting(), IsEmpty()); | 810 source_urls, source_urls[1], creation, expiry, |
| 811 publishers[1], amp_urls[1])})); | |
| 812 ASSERT_THAT(service->GetSnippetsForTesting(), IsEmpty()); | |
| 919 } | 813 } |
| 920 | 814 |
| 921 TEST_F(NTPSnippetsServiceTest, StatusChanges) { | 815 TEST_F(NTPSnippetsServiceTest, StatusChanges) { |
| 816 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(2); | |
| 817 auto service = MakeSnippetsService(); | |
| 818 | |
| 922 // Simulate user signed out | 819 // Simulate user signed out |
| 923 SetUpFetchResponse(GetTestJson({GetSnippet()})); | 820 SetUpFetchResponse(GetTestJson({GetSnippet()})); |
| 924 EXPECT_CALL(observer(), | 821 service->OnDisabledReasonChanged(DisabledReason::SIGNED_OUT); |
| 925 OnCategoryStatusChanged(_, _, CategoryStatus::SIGNED_OUT)); | 822 |
| 926 service()->OnDisabledReasonChanged(DisabledReason::SIGNED_OUT); | |
| 927 base::RunLoop().RunUntilIdle(); | 823 base::RunLoop().RunUntilIdle(); |
| 928 EXPECT_EQ(NTPSnippetsService::State::DISABLED, service()->state_); | 824 EXPECT_THAT(observer().StatusForCategory(articles_category()), |
| 929 EXPECT_THAT(service()->GetSnippetsForTesting(), | 825 Eq(CategoryStatus::SIGNED_OUT)); |
| 826 EXPECT_THAT(NTPSnippetsService::State::DISABLED, Eq(service->state_)); | |
| 827 EXPECT_THAT(service->GetSnippetsForTesting(), | |
| 930 IsEmpty()); // No fetch should be made. | 828 IsEmpty()); // No fetch should be made. |
| 931 | 829 |
| 932 // Simulate user sign in. The service should be ready again and load snippets. | 830 // Simulate user sign in. The service should be ready again and load snippets. |
| 933 SetUpFetchResponse(GetTestJson({GetSnippet()})); | 831 SetUpFetchResponse(GetTestJson({GetSnippet()})); |
| 934 EXPECT_CALL(observer(), | 832 service->OnDisabledReasonChanged(DisabledReason::NONE); |
| 935 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE_LOADING)); | 833 EXPECT_THAT(observer().StatusForCategory(articles_category()), |
| 936 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1); | 834 Eq(CategoryStatus::AVAILABLE_LOADING)); |
| 937 service()->OnDisabledReasonChanged(DisabledReason::NONE); | 835 |
| 938 EXPECT_CALL(observer(), | |
| 939 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE)); | |
| 940 base::RunLoop().RunUntilIdle(); | 836 base::RunLoop().RunUntilIdle(); |
| 941 EXPECT_EQ(NTPSnippetsService::State::READY, service()->state_); | 837 EXPECT_THAT(observer().StatusForCategory(articles_category()), |
| 942 EXPECT_FALSE(service()->GetSnippetsForTesting().empty()); | 838 Eq(CategoryStatus::AVAILABLE)); |
| 839 EXPECT_THAT(NTPSnippetsService::State::READY, Eq(service->state_)); | |
| 840 EXPECT_FALSE(service->GetSnippetsForTesting().empty()); | |
| 943 } | 841 } |
| 944 | 842 |
| 945 TEST_F(NTPSnippetsServiceTest, ImageReturnedWithTheSameId) { | 843 TEST_F(NTPSnippetsServiceTest, ImageReturnedWithTheSameId) { |
| 946 LoadFromJSONString(GetTestJson({GetSnippet()})); | 844 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); |
| 845 auto service = MakeSnippetsService(); | |
| 846 | |
| 847 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); | |
| 947 | 848 |
| 948 gfx::Image image; | 849 gfx::Image image; |
| 949 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | |
| 950 .WillOnce(testing::WithArgs<0, 2>(Invoke(ServeOneByOneImage))); | |
| 951 testing::MockFunction<void(const std::string&, const gfx::Image&)> | 850 testing::MockFunction<void(const std::string&, const gfx::Image&)> |
| 952 image_fetched; | 851 image_fetched; |
| 953 EXPECT_CALL(image_fetched, Call(MakeUniqueID(kSnippetUrl), _)) | 852 { |
| 954 .WillOnce(testing::SaveArg<1>(&image)); | 853 InSequence s; |
| 854 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | |
| 855 .WillOnce(testing::WithArgs<0, 2>(Invoke(ServeOneByOneImage))); | |
|
Marc Treib
2016/08/30 09:29:29
optional: You could add "using testing::..." state
sfiera
2016/08/30 13:16:43
Done (for several testing::)
| |
| 856 EXPECT_CALL(image_fetched, Call(MakeUniqueID(*service, kSnippetUrl), _)) | |
| 857 .WillOnce(testing::SaveArg<1>(&image)); | |
| 858 } | |
| 955 | 859 |
| 956 service()->FetchSuggestionImage( | 860 service->FetchSuggestionImage( |
| 957 MakeUniqueID(kSnippetUrl), | 861 MakeUniqueID(*service, kSnippetUrl), |
| 958 base::Bind(&testing::MockFunction<void(const std::string&, | 862 base::Bind(&testing::MockFunction<void(const std::string&, |
| 959 const gfx::Image&)>::Call, | 863 const gfx::Image&)>::Call, |
| 960 base::Unretained(&image_fetched))); | 864 base::Unretained(&image_fetched))); |
| 961 base::RunLoop().RunUntilIdle(); | 865 base::RunLoop().RunUntilIdle(); |
| 962 // Check that the image by ServeOneByOneImage is really served. | 866 // Check that the image by ServeOneByOneImage is really served. |
| 963 EXPECT_EQ(1, image.Width()); | 867 EXPECT_EQ(1, image.Width()); |
| 964 } | 868 } |
| 965 | 869 |
| 966 TEST_F(NTPSnippetsServiceTest, EmptyImageReturnedForNonExistentId) { | 870 TEST_F(NTPSnippetsServiceTest, EmptyImageReturnedForNonExistentId) { |
| 871 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)); | |
| 872 auto service = MakeSnippetsService(); | |
| 873 | |
| 967 // Create a non-empty image so that we can test the image gets updated. | 874 // Create a non-empty image so that we can test the image gets updated. |
| 968 gfx::Image image = gfx::test::CreateImage(1, 1); | 875 gfx::Image image = gfx::test::CreateImage(1, 1); |
| 969 testing::MockFunction<void(const std::string&, const gfx::Image&)> | 876 testing::MockFunction<void(const std::string&, const gfx::Image&)> |
| 970 image_fetched; | 877 image_fetched; |
| 971 EXPECT_CALL(image_fetched, | 878 EXPECT_CALL(image_fetched, Call(MakeUniqueID(*service, kSnippetUrl2), _)) |
| 972 Call(MakeUniqueID(kSnippetUrl2), _)) | |
| 973 .WillOnce(testing::SaveArg<1>(&image)); | 879 .WillOnce(testing::SaveArg<1>(&image)); |
| 974 | 880 |
| 975 service()->FetchSuggestionImage( | 881 service->FetchSuggestionImage( |
| 976 MakeUniqueID(kSnippetUrl2), | 882 MakeUniqueID(*service, kSnippetUrl2), |
| 977 base::Bind(&testing::MockFunction<void(const std::string&, | 883 base::Bind(&testing::MockFunction<void(const std::string&, |
| 978 const gfx::Image&)>::Call, | 884 const gfx::Image&)>::Call, |
| 979 base::Unretained(&image_fetched))); | 885 base::Unretained(&image_fetched))); |
| 980 | 886 |
| 981 base::RunLoop().RunUntilIdle(); | 887 base::RunLoop().RunUntilIdle(); |
| 982 EXPECT_TRUE(image.IsEmpty()); | 888 EXPECT_TRUE(image.IsEmpty()); |
| 983 } | 889 } |
| 984 | 890 |
| 985 } // namespace ntp_snippets | 891 } // namespace ntp_snippets |
| OLD | NEW |