| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/ntp_snippets/remote/ntp_snippet.h" | 5 #include "components/ntp_snippets/remote/ntp_snippet.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 11 #include "base/strings/utf_string_conversions.h" |
| 11 #include "base/values.h" | 12 #include "base/values.h" |
| 12 #include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h" | 13 #include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h" |
| 13 #include "testing/gmock/include/gmock/gmock.h" | 14 #include "testing/gmock/include/gmock/gmock.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 15 | 16 |
| 16 namespace ntp_snippets { | 17 namespace ntp_snippets { |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 19 using ::testing::ElementsAre; | 20 using ::testing::ElementsAre; |
| 21 using ::testing::Eq; |
| 20 using ::testing::IsNull; | 22 using ::testing::IsNull; |
| 21 using ::testing::NotNull; | 23 using ::testing::NotNull; |
| 22 | 24 |
| 23 std::unique_ptr<NTPSnippet> SnippetFromContentSuggestionJSON( | 25 std::unique_ptr<NTPSnippet> SnippetFromContentSuggestionJSON( |
| 24 const std::string& json) { | 26 const std::string& json) { |
| 25 auto json_value = base::JSONReader::Read(json); | 27 auto json_value = base::JSONReader::Read(json); |
| 26 base::DictionaryValue* json_dict; | 28 base::DictionaryValue* json_dict; |
| 27 if (!json_value->GetAsDictionary(&json_dict)) { | 29 if (!json_value->GetAsDictionary(&json_dict)) { |
| 28 return nullptr; | 30 return nullptr; |
| 29 } | 31 } |
| 30 return NTPSnippet::CreateFromContentSuggestionsDictionary(*json_dict, | 32 return NTPSnippet::CreateFromContentSuggestionsDictionary(*json_dict, |
| 31 kArticlesRemoteId); | 33 kArticlesRemoteId); |
| 32 } | 34 } |
| 33 | 35 |
| 34 TEST(NTPSnippetTest, FromChromeContentSuggestionsDictionary) { | 36 TEST(NTPSnippetTest, FromChromeContentSuggestionsDictionary) { |
| 35 const std::string kJsonStr = | 37 const std::string kJsonStr = |
| 36 "{" | 38 "{" |
| 37 " \"ids\" : [\"http://localhost/foobar\"]," | 39 " \"ids\" : [\"http://localhost/foobar\"]," |
| 38 " \"title\" : \"Foo Barred from Baz\"," | 40 " \"title\" : \"Foo Barred from Baz\"," |
| 39 " \"snippet\" : \"...\"," | 41 " \"snippet\" : \"...\"," |
| 40 " \"fullPageUrl\" : \"http://localhost/foobar\"," | 42 " \"fullPageUrl\" : \"http://localhost/foobar\"," |
| 41 " \"creationTime\" : \"2016-06-30T11:01:37.000Z\"," | 43 " \"creationTime\" : \"2016-06-30T11:01:37.000Z\"," |
| 42 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," | 44 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," |
| 43 " \"attribution\" : \"Foo News\"," | 45 " \"attribution\" : \"Foo News\"," |
| 44 " \"imageUrl\" : \"http://localhost/foobar.jpg\"," | 46 " \"imageUrl\" : \"http://localhost/foobar.jpg\"," |
| 45 " \"ampUrl\" : \"http://localhost/amp\"," | 47 " \"ampUrl\" : \"http://localhost/amp\"," |
| 46 " \"faviconUrl\" : \"http://localhost/favicon.ico\", " | 48 " \"faviconUrl\" : \"http://localhost/favicon.ico\", " |
| 47 " \"score\": 9001\n" | 49 " \"score\": 9001,\n" |
| 50 " \"notificationInfo\": {\n" |
| 51 " \"shouldNotify\": true," |
| 52 " \"deadline\": \"2016-06-30T13:01:37.000Z\"\n" |
| 53 " }\n" |
| 48 "}"; | 54 "}"; |
| 49 auto snippet = SnippetFromContentSuggestionJSON(kJsonStr); | 55 auto snippet = SnippetFromContentSuggestionJSON(kJsonStr); |
| 50 ASSERT_THAT(snippet, NotNull()); | 56 ASSERT_THAT(snippet, NotNull()); |
| 51 | 57 |
| 52 EXPECT_EQ(snippet->id(), "http://localhost/foobar"); | 58 EXPECT_EQ(snippet->id(), "http://localhost/foobar"); |
| 53 EXPECT_EQ(snippet->title(), "Foo Barred from Baz"); | 59 EXPECT_EQ(snippet->title(), "Foo Barred from Baz"); |
| 54 EXPECT_EQ(snippet->snippet(), "..."); | 60 EXPECT_EQ(snippet->snippet(), "..."); |
| 55 EXPECT_EQ(snippet->salient_image_url(), GURL("http://localhost/foobar.jpg")); | 61 EXPECT_EQ(snippet->salient_image_url(), GURL("http://localhost/foobar.jpg")); |
| 56 EXPECT_EQ(snippet->score(), 9001); | 62 EXPECT_EQ(snippet->score(), 9001); |
| 57 auto unix_publish_date = snippet->publish_date() - base::Time::UnixEpoch(); | 63 auto unix_publish_date = snippet->publish_date() - base::Time::UnixEpoch(); |
| 58 auto expiry_duration = snippet->expiry_date() - snippet->publish_date(); | 64 auto expiry_duration = snippet->expiry_date() - snippet->publish_date(); |
| 59 EXPECT_FLOAT_EQ(unix_publish_date.InSecondsF(), 1467284497.000000f); | 65 EXPECT_FLOAT_EQ(unix_publish_date.InSecondsF(), 1467284497.000000f); |
| 60 EXPECT_FLOAT_EQ(expiry_duration.InSecondsF(), 86400.000000f); | 66 EXPECT_FLOAT_EQ(expiry_duration.InSecondsF(), 86400.000000f); |
| 61 | 67 |
| 62 EXPECT_EQ(snippet->publisher_name(), "Foo News"); | 68 EXPECT_EQ(snippet->publisher_name(), "Foo News"); |
| 63 EXPECT_EQ(snippet->url(), GURL("http://localhost/foobar")); | 69 EXPECT_EQ(snippet->url(), GURL("http://localhost/foobar")); |
| 64 EXPECT_EQ(snippet->amp_url(), GURL("http://localhost/amp")); | 70 EXPECT_EQ(snippet->amp_url(), GURL("http://localhost/amp")); |
| 71 |
| 72 EXPECT_TRUE(snippet->should_notify()); |
| 73 auto notification_duration = |
| 74 snippet->notification_deadline() - snippet->publish_date(); |
| 75 EXPECT_EQ(7200.0f, notification_duration.InSecondsF()); |
| 65 } | 76 } |
| 66 | 77 |
| 67 std::unique_ptr<NTPSnippet> SnippetFromChromeReaderDict( | 78 std::unique_ptr<NTPSnippet> SnippetFromChromeReaderDict( |
| 68 std::unique_ptr<base::DictionaryValue> dict) { | 79 std::unique_ptr<base::DictionaryValue> dict) { |
| 69 if (!dict) { | 80 if (!dict) { |
| 70 return nullptr; | 81 return nullptr; |
| 71 } | 82 } |
| 72 return NTPSnippet::CreateFromChromeReaderDictionary(*dict); | 83 return NTPSnippet::CreateFromChromeReaderDictionary(*dict); |
| 73 } | 84 } |
| 74 | 85 |
| 75 const char kChromeReaderCreationTimestamp[] = "1234567890"; | 86 const char kChromeReaderCreationTimestamp[] = "1234567890"; |
| 76 const char kChromeReaderExpiryTimestamp[] = "2345678901"; | 87 const char kChromeReaderExpiryTimestamp[] = "2345678901"; |
| 77 | 88 |
| 78 std::unique_ptr<base::DictionaryValue> SnippetWithTwoSources() { | 89 // Old form, from chromereader-pa.googleapis.com. Two sources. |
| 90 std::unique_ptr<base::DictionaryValue> ChromeReaderSnippetWithTwoSources() { |
| 79 const std::string kJsonStr = base::StringPrintf( | 91 const std::string kJsonStr = base::StringPrintf( |
| 80 "{\n" | 92 "{\n" |
| 81 " \"contentInfo\": {\n" | 93 " \"contentInfo\": {\n" |
| 82 " \"url\": \"http://url.com\",\n" | 94 " \"url\": \"http://url.com\",\n" |
| 83 " \"title\": \"Source 1 Title\",\n" | 95 " \"title\": \"Source 1 Title\",\n" |
| 84 " \"snippet\": \"Source 1 Snippet\",\n" | 96 " \"snippet\": \"Source 1 Snippet\",\n" |
| 85 " \"thumbnailUrl\": \"http://url.com/thumbnail\",\n" | 97 " \"thumbnailUrl\": \"http://url.com/thumbnail\",\n" |
| 86 " \"creationTimestampSec\": \"%s\",\n" | 98 " \"creationTimestampSec\": \"%s\",\n" |
| 87 " \"expiryTimestampSec\": \"%s\",\n" | 99 " \"expiryTimestampSec\": \"%s\",\n" |
| 88 " \"sourceCorpusInfo\": [{\n" | 100 " \"sourceCorpusInfo\": [{\n" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 105 | 117 |
| 106 auto json_value = base::JSONReader::Read(kJsonStr); | 118 auto json_value = base::JSONReader::Read(kJsonStr); |
| 107 base::DictionaryValue* json_dict; | 119 base::DictionaryValue* json_dict; |
| 108 if (!json_value->GetAsDictionary(&json_dict)) { | 120 if (!json_value->GetAsDictionary(&json_dict)) { |
| 109 return nullptr; | 121 return nullptr; |
| 110 } | 122 } |
| 111 return json_dict->CreateDeepCopy(); | 123 return json_dict->CreateDeepCopy(); |
| 112 } | 124 } |
| 113 | 125 |
| 114 TEST(NTPSnippetTest, TestMultipleSources) { | 126 TEST(NTPSnippetTest, TestMultipleSources) { |
| 115 auto snippet = SnippetFromChromeReaderDict(SnippetWithTwoSources()); | 127 auto snippet = |
| 128 SnippetFromChromeReaderDict(ChromeReaderSnippetWithTwoSources()); |
| 116 ASSERT_THAT(snippet, NotNull()); | 129 ASSERT_THAT(snippet, NotNull()); |
| 117 | 130 |
| 118 // Expect the first source to be chosen. | 131 // Expect the first source to be chosen. |
| 119 EXPECT_EQ(snippet->id(), "http://url.com"); | 132 EXPECT_EQ(snippet->id(), "http://url.com"); |
| 120 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); | 133 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); |
| 121 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); | 134 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); |
| 122 EXPECT_EQ(snippet->amp_url(), GURL("http://source1.amp.com")); | 135 EXPECT_EQ(snippet->amp_url(), GURL("http://source1.amp.com")); |
| 123 } | 136 } |
| 124 | 137 |
| 125 TEST(NTPSnippetTest, TestMultipleIncompleteSources1) { | 138 TEST(NTPSnippetTest, TestMultipleIncompleteSources1) { |
| 126 // Set Source 2 to have no AMP url, and Source 1 to have no publisher name | 139 // Set Source 2 to have no AMP url, and Source 1 to have no publisher name |
| 127 // Source 2 should win since we favor publisher name over amp url | 140 // Source 2 should win since we favor publisher name over amp url |
| 128 auto dict = SnippetWithTwoSources(); | 141 auto dict = ChromeReaderSnippetWithTwoSources(); |
| 129 base::ListValue* sources; | 142 base::ListValue* sources; |
| 130 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); | 143 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); |
| 131 base::DictionaryValue* source; | 144 base::DictionaryValue* source; |
| 132 ASSERT_TRUE(sources->GetDictionary(0, &source)); | 145 ASSERT_TRUE(sources->GetDictionary(0, &source)); |
| 133 source->Remove("publisherData.sourceName", nullptr); | 146 source->Remove("publisherData.sourceName", nullptr); |
| 134 ASSERT_TRUE(sources->GetDictionary(1, &source)); | 147 ASSERT_TRUE(sources->GetDictionary(1, &source)); |
| 135 source->Remove("ampUrl", nullptr); | 148 source->Remove("ampUrl", nullptr); |
| 136 | 149 |
| 137 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 150 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 138 ASSERT_THAT(snippet, NotNull()); | 151 ASSERT_THAT(snippet, NotNull()); |
| 139 | 152 |
| 140 EXPECT_EQ(snippet->id(), "http://url.com"); | 153 EXPECT_EQ(snippet->id(), "http://url.com"); |
| 141 EXPECT_EQ(snippet->url(), GURL("http://source2.com")); | 154 EXPECT_EQ(snippet->url(), GURL("http://source2.com")); |
| 142 EXPECT_EQ(snippet->publisher_name(), std::string("Source 2")); | 155 EXPECT_EQ(snippet->publisher_name(), std::string("Source 2")); |
| 143 EXPECT_EQ(snippet->amp_url(), GURL()); | 156 EXPECT_EQ(snippet->amp_url(), GURL()); |
| 144 } | 157 } |
| 145 | 158 |
| 146 TEST(NTPSnippetTest, TestMultipleIncompleteSources2) { | 159 TEST(NTPSnippetTest, TestMultipleIncompleteSources2) { |
| 147 // Set Source 1 to have no AMP url, and Source 2 to have no publisher name | 160 // Set Source 1 to have no AMP url, and Source 2 to have no publisher name |
| 148 // Source 1 should win in this case since we prefer publisher name to AMP url | 161 // Source 1 should win in this case since we prefer publisher name to AMP url |
| 149 auto dict = SnippetWithTwoSources(); | 162 auto dict = ChromeReaderSnippetWithTwoSources(); |
| 150 base::ListValue* sources; | 163 base::ListValue* sources; |
| 151 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); | 164 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); |
| 152 base::DictionaryValue* source; | 165 base::DictionaryValue* source; |
| 153 ASSERT_TRUE(sources->GetDictionary(0, &source)); | 166 ASSERT_TRUE(sources->GetDictionary(0, &source)); |
| 154 source->Remove("ampUrl", nullptr); | 167 source->Remove("ampUrl", nullptr); |
| 155 ASSERT_TRUE(sources->GetDictionary(1, &source)); | 168 ASSERT_TRUE(sources->GetDictionary(1, &source)); |
| 156 source->Remove("publisherData.sourceName", nullptr); | 169 source->Remove("publisherData.sourceName", nullptr); |
| 157 | 170 |
| 158 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 171 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 159 ASSERT_THAT(snippet, NotNull()); | 172 ASSERT_THAT(snippet, NotNull()); |
| 160 | 173 |
| 161 EXPECT_EQ(snippet->id(), "http://url.com"); | 174 EXPECT_EQ(snippet->id(), "http://url.com"); |
| 162 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); | 175 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); |
| 163 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); | 176 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); |
| 164 EXPECT_EQ(snippet->amp_url(), GURL()); | 177 EXPECT_EQ(snippet->amp_url(), GURL()); |
| 165 } | 178 } |
| 166 | 179 |
| 167 TEST(NTPSnippetTest, TestMultipleIncompleteSources3) { | 180 TEST(NTPSnippetTest, TestMultipleIncompleteSources3) { |
| 168 // Set source 1 to have no AMP url and no source, and source 2 to only have | 181 // Set source 1 to have no AMP url and no source, and source 2 to only have |
| 169 // amp url. There should be no snippets since we only add sources we consider | 182 // amp url. There should be no snippets since we only add sources we consider |
| 170 // complete | 183 // complete |
| 171 auto dict = SnippetWithTwoSources(); | 184 auto dict = ChromeReaderSnippetWithTwoSources(); |
| 172 base::ListValue* sources; | 185 base::ListValue* sources; |
| 173 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); | 186 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); |
| 174 base::DictionaryValue* source; | 187 base::DictionaryValue* source; |
| 175 ASSERT_TRUE(sources->GetDictionary(0, &source)); | 188 ASSERT_TRUE(sources->GetDictionary(0, &source)); |
| 176 source->Remove("publisherData.sourceName", nullptr); | 189 source->Remove("publisherData.sourceName", nullptr); |
| 177 source->Remove("ampUrl", nullptr); | 190 source->Remove("ampUrl", nullptr); |
| 178 ASSERT_TRUE(sources->GetDictionary(1, &source)); | 191 ASSERT_TRUE(sources->GetDictionary(1, &source)); |
| 179 source->Remove("publisherData.sourceName", nullptr); | 192 source->Remove("publisherData.sourceName", nullptr); |
| 180 | 193 |
| 181 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 194 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 182 ASSERT_THAT(snippet, NotNull()); | 195 ASSERT_THAT(snippet, NotNull()); |
| 183 ASSERT_FALSE(snippet->is_complete()); | 196 ASSERT_FALSE(snippet->is_complete()); |
| 184 } | 197 } |
| 185 | 198 |
| 186 TEST(NTPSnippetTest, ShouldFillInCreation) { | 199 TEST(NTPSnippetTest, ShouldFillInCreation) { |
| 187 auto dict = SnippetWithTwoSources(); | 200 auto dict = ChromeReaderSnippetWithTwoSources(); |
| 188 ASSERT_TRUE(dict->Remove("contentInfo.creationTimestampSec", nullptr)); | 201 ASSERT_TRUE(dict->Remove("contentInfo.creationTimestampSec", nullptr)); |
| 189 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 202 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 190 ASSERT_THAT(snippet, NotNull()); | 203 ASSERT_THAT(snippet, NotNull()); |
| 191 | 204 |
| 192 // Publish date should have been filled with "now" - just make sure it's not | 205 // Publish date should have been filled with "now" - just make sure it's not |
| 193 // empty and not the test default value. | 206 // empty and not the test default value. |
| 194 base::Time publish_date = snippet->publish_date(); | 207 base::Time publish_date = snippet->publish_date(); |
| 195 EXPECT_FALSE(publish_date.is_null()); | 208 EXPECT_FALSE(publish_date.is_null()); |
| 196 EXPECT_NE(publish_date, | 209 EXPECT_NE(publish_date, |
| 197 NTPSnippet::TimeFromJsonString(kChromeReaderCreationTimestamp)); | 210 NTPSnippet::TimeFromJsonString(kChromeReaderCreationTimestamp)); |
| 198 // Expiry date should have kept the test default value. | 211 // Expiry date should have kept the test default value. |
| 199 base::Time expiry_date = snippet->expiry_date(); | 212 base::Time expiry_date = snippet->expiry_date(); |
| 200 EXPECT_FALSE(expiry_date.is_null()); | 213 EXPECT_FALSE(expiry_date.is_null()); |
| 201 EXPECT_EQ(expiry_date, | 214 EXPECT_EQ(expiry_date, |
| 202 NTPSnippet::TimeFromJsonString(kChromeReaderExpiryTimestamp)); | 215 NTPSnippet::TimeFromJsonString(kChromeReaderExpiryTimestamp)); |
| 203 } | 216 } |
| 204 | 217 |
| 205 TEST(NTPSnippetTest, ShouldFillInExpiry) { | 218 TEST(NTPSnippetTest, ShouldFillInExpiry) { |
| 206 auto dict = SnippetWithTwoSources(); | 219 auto dict = ChromeReaderSnippetWithTwoSources(); |
| 207 ASSERT_TRUE(dict->Remove("contentInfo.expiryTimestampSec", nullptr)); | 220 ASSERT_TRUE(dict->Remove("contentInfo.expiryTimestampSec", nullptr)); |
| 208 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 221 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 209 ASSERT_THAT(snippet, NotNull()); | 222 ASSERT_THAT(snippet, NotNull()); |
| 210 | 223 |
| 211 base::Time publish_date = snippet->publish_date(); | 224 base::Time publish_date = snippet->publish_date(); |
| 212 ASSERT_FALSE(publish_date.is_null()); | 225 ASSERT_FALSE(publish_date.is_null()); |
| 213 // Expiry date should have been filled with creation date + offset. | 226 // Expiry date should have been filled with creation date + offset. |
| 214 base::Time expiry_date = snippet->expiry_date(); | 227 base::Time expiry_date = snippet->expiry_date(); |
| 215 EXPECT_FALSE(expiry_date.is_null()); | 228 EXPECT_FALSE(expiry_date.is_null()); |
| 216 EXPECT_EQ(publish_date + base::TimeDelta::FromMinutes( | 229 EXPECT_EQ(publish_date + base::TimeDelta::FromMinutes( |
| 217 kChromeReaderDefaultExpiryTimeMins), | 230 kChromeReaderDefaultExpiryTimeMins), |
| 218 expiry_date); | 231 expiry_date); |
| 219 } | 232 } |
| 220 | 233 |
| 221 TEST(NTPSnippetTest, ShouldFillInCreationAndExpiry) { | 234 TEST(NTPSnippetTest, ShouldFillInCreationAndExpiry) { |
| 222 auto dict = SnippetWithTwoSources(); | 235 auto dict = ChromeReaderSnippetWithTwoSources(); |
| 223 ASSERT_TRUE(dict->Remove("contentInfo.creationTimestampSec", nullptr)); | 236 ASSERT_TRUE(dict->Remove("contentInfo.creationTimestampSec", nullptr)); |
| 224 ASSERT_TRUE(dict->Remove("contentInfo.expiryTimestampSec", nullptr)); | 237 ASSERT_TRUE(dict->Remove("contentInfo.expiryTimestampSec", nullptr)); |
| 225 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 238 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 226 ASSERT_THAT(snippet, NotNull()); | 239 ASSERT_THAT(snippet, NotNull()); |
| 227 | 240 |
| 228 // Publish date should have been filled with "now" - just make sure it's not | 241 // Publish date should have been filled with "now" - just make sure it's not |
| 229 // empty and not the test default value. | 242 // empty and not the test default value. |
| 230 base::Time publish_date = snippet->publish_date(); | 243 base::Time publish_date = snippet->publish_date(); |
| 231 EXPECT_FALSE(publish_date.is_null()); | 244 EXPECT_FALSE(publish_date.is_null()); |
| 232 EXPECT_NE(publish_date, | 245 EXPECT_NE(publish_date, |
| 233 NTPSnippet::TimeFromJsonString(kChromeReaderCreationTimestamp)); | 246 NTPSnippet::TimeFromJsonString(kChromeReaderCreationTimestamp)); |
| 234 // Expiry date should have been filled with creation date + offset. | 247 // Expiry date should have been filled with creation date + offset. |
| 235 base::Time expiry_date = snippet->expiry_date(); | 248 base::Time expiry_date = snippet->expiry_date(); |
| 236 EXPECT_FALSE(expiry_date.is_null()); | 249 EXPECT_FALSE(expiry_date.is_null()); |
| 237 EXPECT_EQ(publish_date + base::TimeDelta::FromMinutes( | 250 EXPECT_EQ(publish_date + base::TimeDelta::FromMinutes( |
| 238 kChromeReaderDefaultExpiryTimeMins), | 251 kChromeReaderDefaultExpiryTimeMins), |
| 239 expiry_date); | 252 expiry_date); |
| 240 } | 253 } |
| 241 | 254 |
| 242 TEST(NTPSnippetTest, ShouldNotOverwriteExpiry) { | 255 TEST(NTPSnippetTest, ShouldNotOverwriteExpiry) { |
| 243 auto dict = SnippetWithTwoSources(); | 256 auto dict = ChromeReaderSnippetWithTwoSources(); |
| 244 ASSERT_TRUE(dict->Remove("contentInfo.creationTimestampSec", nullptr)); | 257 ASSERT_TRUE(dict->Remove("contentInfo.creationTimestampSec", nullptr)); |
| 245 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 258 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 246 ASSERT_THAT(snippet, NotNull()); | 259 ASSERT_THAT(snippet, NotNull()); |
| 247 | 260 |
| 248 // Expiry date should have kept the test default value. | 261 // Expiry date should have kept the test default value. |
| 249 base::Time expiry_date = snippet->expiry_date(); | 262 base::Time expiry_date = snippet->expiry_date(); |
| 250 EXPECT_FALSE(expiry_date.is_null()); | 263 EXPECT_FALSE(expiry_date.is_null()); |
| 251 EXPECT_EQ(expiry_date, | 264 EXPECT_EQ(expiry_date, |
| 252 NTPSnippet::TimeFromJsonString(kChromeReaderExpiryTimestamp)); | 265 NTPSnippet::TimeFromJsonString(kChromeReaderExpiryTimestamp)); |
| 253 } | 266 } |
| 254 | 267 |
| 255 std::unique_ptr<base::DictionaryValue> SnippetWithThreeSources() { | 268 // Old form, from chromereader-pa.googleapis.com. Three sources. |
| 269 std::unique_ptr<base::DictionaryValue> ChromeReaderSnippetWithThreeSources() { |
| 256 const std::string kJsonStr = base::StringPrintf( | 270 const std::string kJsonStr = base::StringPrintf( |
| 257 "{\n" | 271 "{\n" |
| 258 " \"contentInfo\": {\n" | 272 " \"contentInfo\": {\n" |
| 259 " \"url\": \"http://url.com\",\n" | 273 " \"url\": \"http://url.com\",\n" |
| 260 " \"title\": \"Source 1 Title\",\n" | 274 " \"title\": \"Source 1 Title\",\n" |
| 261 " \"snippet\": \"Source 1 Snippet\",\n" | 275 " \"snippet\": \"Source 1 Snippet\",\n" |
| 262 " \"thumbnailUrl\": \"http://url.com/thumbnail\",\n" | 276 " \"thumbnailUrl\": \"http://url.com/thumbnail\",\n" |
| 263 " \"creationTimestampSec\": \"%s\",\n" | 277 " \"creationTimestampSec\": \"%s\",\n" |
| 264 " \"expiryTimestampSec\": \"%s\",\n" | 278 " \"expiryTimestampSec\": \"%s\",\n" |
| 265 " \"sourceCorpusInfo\": [{\n" | 279 " \"sourceCorpusInfo\": [{\n" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 289 auto json_value = base::JSONReader::Read(kJsonStr); | 303 auto json_value = base::JSONReader::Read(kJsonStr); |
| 290 base::DictionaryValue* json_dict; | 304 base::DictionaryValue* json_dict; |
| 291 if (!json_value->GetAsDictionary(&json_dict)) { | 305 if (!json_value->GetAsDictionary(&json_dict)) { |
| 292 return nullptr; | 306 return nullptr; |
| 293 } | 307 } |
| 294 return json_dict->CreateDeepCopy(); | 308 return json_dict->CreateDeepCopy(); |
| 295 } | 309 } |
| 296 | 310 |
| 297 TEST(NTPSnippetTest, TestMultipleCompleteSources1) { | 311 TEST(NTPSnippetTest, TestMultipleCompleteSources1) { |
| 298 // Test 2 complete sources, we should choose the first complete source | 312 // Test 2 complete sources, we should choose the first complete source |
| 299 auto dict = SnippetWithThreeSources(); | 313 auto dict = ChromeReaderSnippetWithThreeSources(); |
| 300 base::ListValue* sources; | 314 base::ListValue* sources; |
| 301 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); | 315 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); |
| 302 base::DictionaryValue* source; | 316 base::DictionaryValue* source; |
| 303 ASSERT_TRUE(sources->GetDictionary(1, &source)); | 317 ASSERT_TRUE(sources->GetDictionary(1, &source)); |
| 304 source->Remove("publisherData.sourceName", nullptr); | 318 source->Remove("publisherData.sourceName", nullptr); |
| 305 | 319 |
| 306 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 320 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 307 ASSERT_THAT(snippet, NotNull()); | 321 ASSERT_THAT(snippet, NotNull()); |
| 308 | 322 |
| 309 EXPECT_EQ(snippet->id(), "http://url.com"); | 323 EXPECT_EQ(snippet->id(), "http://url.com"); |
| 310 EXPECT_THAT(snippet->GetAllIDs(), | 324 EXPECT_THAT(snippet->GetAllIDs(), |
| 311 ElementsAre("http://url.com", "http://source1.com", | 325 ElementsAre("http://url.com", "http://source1.com", |
| 312 "http://source2.com", "http://source3.com")); | 326 "http://source2.com", "http://source3.com")); |
| 313 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); | 327 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); |
| 314 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); | 328 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); |
| 315 EXPECT_EQ(snippet->amp_url(), GURL("http://source1.amp.com")); | 329 EXPECT_EQ(snippet->amp_url(), GURL("http://source1.amp.com")); |
| 316 } | 330 } |
| 317 | 331 |
| 318 TEST(NTPSnippetTest, TestMultipleCompleteSources2) { | 332 TEST(NTPSnippetTest, TestMultipleCompleteSources2) { |
| 319 // Test 2 complete sources, we should choose the first complete source | 333 // Test 2 complete sources, we should choose the first complete source |
| 320 auto dict = SnippetWithThreeSources(); | 334 auto dict = ChromeReaderSnippetWithThreeSources(); |
| 321 base::ListValue* sources; | 335 base::ListValue* sources; |
| 322 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); | 336 ASSERT_TRUE(dict->GetList("contentInfo.sourceCorpusInfo", &sources)); |
| 323 base::DictionaryValue* source; | 337 base::DictionaryValue* source; |
| 324 ASSERT_TRUE(sources->GetDictionary(0, &source)); | 338 ASSERT_TRUE(sources->GetDictionary(0, &source)); |
| 325 source->Remove("publisherData.sourceName", nullptr); | 339 source->Remove("publisherData.sourceName", nullptr); |
| 326 | 340 |
| 327 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 341 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 328 ASSERT_THAT(snippet, NotNull()); | 342 ASSERT_THAT(snippet, NotNull()); |
| 329 | 343 |
| 330 EXPECT_EQ(snippet->id(), "http://url.com"); | 344 EXPECT_EQ(snippet->id(), "http://url.com"); |
| 331 EXPECT_EQ(snippet->url(), GURL("http://source2.com")); | 345 EXPECT_EQ(snippet->url(), GURL("http://source2.com")); |
| 332 EXPECT_EQ(snippet->publisher_name(), std::string("Source 2")); | 346 EXPECT_EQ(snippet->publisher_name(), std::string("Source 2")); |
| 333 EXPECT_EQ(snippet->amp_url(), GURL("http://source2.amp.com")); | 347 EXPECT_EQ(snippet->amp_url(), GURL("http://source2.amp.com")); |
| 334 } | 348 } |
| 335 | 349 |
| 336 TEST(NTPSnippetTest, TestMultipleCompleteSources3) { | 350 TEST(NTPSnippetTest, TestMultipleCompleteSources3) { |
| 337 // Test 3 complete sources, we should choose the first complete source | 351 // Test 3 complete sources, we should choose the first complete source |
| 338 auto dict = SnippetWithThreeSources(); | 352 auto dict = ChromeReaderSnippetWithThreeSources(); |
| 339 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); | 353 auto snippet = SnippetFromChromeReaderDict(std::move(dict)); |
| 340 ASSERT_THAT(snippet, NotNull()); | 354 ASSERT_THAT(snippet, NotNull()); |
| 341 | 355 |
| 342 EXPECT_EQ(snippet->id(), "http://url.com"); | 356 EXPECT_EQ(snippet->id(), "http://url.com"); |
| 343 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); | 357 EXPECT_EQ(snippet->url(), GURL("http://source1.com")); |
| 344 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); | 358 EXPECT_EQ(snippet->publisher_name(), std::string("Source 1")); |
| 345 EXPECT_EQ(snippet->amp_url(), GURL("http://source1.amp.com")); | 359 EXPECT_EQ(snippet->amp_url(), GURL("http://source1.amp.com")); |
| 346 } | 360 } |
| 347 | 361 |
| 348 TEST(NTPSnippetTest, ShouldSupportMultipleIdsFromContentSuggestionsServer) { | 362 TEST(NTPSnippetTest, ShouldSupportMultipleIdsFromContentSuggestionsServer) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 // Unfortunately, we only have MessageLite protocol buffers in Chrome, so | 406 // Unfortunately, we only have MessageLite protocol buffers in Chrome, so |
| 393 // comparing via DebugString() or MessageDifferencer is not working. | 407 // comparing via DebugString() or MessageDifferencer is not working. |
| 394 // So we either need to compare field-by-field (maintenance heavy) or | 408 // So we either need to compare field-by-field (maintenance heavy) or |
| 395 // compare the binary version (unusable diagnostic). Deciding for the latter. | 409 // compare the binary version (unusable diagnostic). Deciding for the latter. |
| 396 std::string proto_serialized, round_tripped_serialized; | 410 std::string proto_serialized, round_tripped_serialized; |
| 397 proto.SerializeToString(&proto_serialized); | 411 proto.SerializeToString(&proto_serialized); |
| 398 snippet->ToProto().SerializeToString(&round_tripped_serialized); | 412 snippet->ToProto().SerializeToString(&round_tripped_serialized); |
| 399 EXPECT_EQ(proto_serialized, round_tripped_serialized); | 413 EXPECT_EQ(proto_serialized, round_tripped_serialized); |
| 400 } | 414 } |
| 401 | 415 |
| 416 // New form, from chromecontentsuggestions-pa.googleapis.com. |
| 417 std::unique_ptr<base::DictionaryValue> ContentSuggestionSnippet() { |
| 418 const std::string kJsonStr = |
| 419 "{" |
| 420 " \"ids\" : [\"http://localhost/foobar\"]," |
| 421 " \"title\" : \"Foo Barred from Baz\"," |
| 422 " \"snippet\" : \"...\"," |
| 423 " \"fullPageUrl\" : \"http://localhost/foobar\"," |
| 424 " \"creationTime\" : \"2016-06-30T11:01:37.000Z\"," |
| 425 " \"expirationTime\" : \"2016-07-01T11:01:37.000Z\"," |
| 426 " \"attribution\" : \"Foo News\"," |
| 427 " \"imageUrl\" : \"http://localhost/foobar.jpg\"," |
| 428 " \"ampUrl\" : \"http://localhost/amp\"," |
| 429 " \"faviconUrl\" : \"http://localhost/favicon.ico\", " |
| 430 " \"score\": 9001\n" |
| 431 "}"; |
| 432 auto json_value = base::JSONReader::Read(kJsonStr); |
| 433 base::DictionaryValue* json_dict; |
| 434 CHECK(json_value->GetAsDictionary(&json_dict)); |
| 435 return json_dict->CreateDeepCopy(); |
| 436 } |
| 437 |
| 438 TEST(NTPSnippetTest, NotifcationInfoAllSpecified) { |
| 439 auto json = ContentSuggestionSnippet(); |
| 440 json->SetBoolean("notificationInfo.shouldNotify", true); |
| 441 json->SetString("notificationInfo.deadline", "2016-06-30T13:01:37.000Z"); |
| 442 auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json, 0); |
| 443 EXPECT_TRUE(snippet->should_notify()); |
| 444 EXPECT_EQ(7200.0f, |
| 445 (snippet->notification_deadline() - snippet->publish_date()) |
| 446 .InSecondsF()); |
| 447 } |
| 448 |
| 449 TEST(NTPSnippetTest, NotificationInfoDeadlineInvalid) { |
| 450 auto json = ContentSuggestionSnippet(); |
| 451 json->SetBoolean("notificationInfo.shouldNotify", true); |
| 452 json->SetInteger("notificationInfo.notificationDeadline", 0); |
| 453 auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json, 0); |
| 454 EXPECT_TRUE(snippet->should_notify()); |
| 455 EXPECT_EQ(base::Time::Max(), snippet->notification_deadline()); |
| 456 } |
| 457 |
| 458 TEST(NTPSnippetTest, NotificationInfoDeadlineAbsent) { |
| 459 auto json = ContentSuggestionSnippet(); |
| 460 json->SetBoolean("notificationInfo.shouldNotify", true); |
| 461 auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json, 0); |
| 462 EXPECT_TRUE(snippet->should_notify()); |
| 463 EXPECT_EQ(base::Time::Max(), snippet->notification_deadline()); |
| 464 } |
| 465 |
| 466 TEST(NTPSnippetTest, NotificationInfoShouldNotifyInvalid) { |
| 467 auto json = ContentSuggestionSnippet(); |
| 468 json->SetString("notificationInfo.shouldNotify", "non-bool"); |
| 469 auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json, 0); |
| 470 EXPECT_FALSE(snippet->should_notify()); |
| 471 } |
| 472 |
| 473 TEST(NTPSnippetTest, NotificationInfoAbsent) { |
| 474 auto json = ContentSuggestionSnippet(); |
| 475 auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json, 0); |
| 476 EXPECT_FALSE(snippet->should_notify()); |
| 477 } |
| 478 |
| 479 TEST(NTPSnippetTest, ToContentSuggestion) { |
| 480 auto json = ContentSuggestionSnippet(); |
| 481 auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json, 0); |
| 482 ASSERT_THAT(snippet, NotNull()); |
| 483 ContentSuggestion sugg = snippet->ToContentSuggestion( |
| 484 Category::FromKnownCategory(KnownCategories::ARTICLES)); |
| 485 |
| 486 EXPECT_THAT(sugg.id().category(), |
| 487 Eq(Category::FromKnownCategory(KnownCategories::ARTICLES))); |
| 488 EXPECT_THAT(sugg.id().id_within_category(), Eq("http://localhost/foobar")); |
| 489 EXPECT_THAT(sugg.url(), Eq(GURL("http://localhost/amp"))); |
| 490 EXPECT_THAT(sugg.title(), Eq(base::UTF8ToUTF16("Foo Barred from Baz"))); |
| 491 EXPECT_THAT(sugg.snippet_text(), Eq(base::UTF8ToUTF16("..."))); |
| 492 EXPECT_THAT(sugg.publish_date().ToJavaTime(), Eq(1467284497000)); |
| 493 EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News"))); |
| 494 EXPECT_THAT(sugg.score(), Eq(9001)); |
| 495 EXPECT_THAT(sugg.download_suggestion_extra(), IsNull()); |
| 496 EXPECT_THAT(sugg.recent_tab_suggestion_extra(), IsNull()); |
| 497 EXPECT_THAT(sugg.notification_extra(), IsNull()); |
| 498 } |
| 499 |
| 500 TEST(NTPSnippetTest, ToContentSuggestionWithNotificationInfo) { |
| 501 auto json = ContentSuggestionSnippet(); |
| 502 json->SetBoolean("notificationInfo.shouldNotify", true); |
| 503 json->SetString("notificationInfo.deadline", "2016-06-30T13:01:37.000Z"); |
| 504 auto snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*json, 0); |
| 505 ASSERT_THAT(snippet, NotNull()); |
| 506 ContentSuggestion sugg = snippet->ToContentSuggestion( |
| 507 Category::FromKnownCategory(KnownCategories::ARTICLES)); |
| 508 |
| 509 EXPECT_THAT(sugg.id().category(), |
| 510 Eq(Category::FromKnownCategory(KnownCategories::ARTICLES))); |
| 511 EXPECT_THAT(sugg.id().id_within_category(), Eq("http://localhost/foobar")); |
| 512 EXPECT_THAT(sugg.url(), Eq(GURL("http://localhost/amp"))); |
| 513 EXPECT_THAT(sugg.title(), Eq(base::UTF8ToUTF16("Foo Barred from Baz"))); |
| 514 EXPECT_THAT(sugg.snippet_text(), Eq(base::UTF8ToUTF16("..."))); |
| 515 EXPECT_THAT(sugg.publish_date().ToJavaTime(), Eq(1467284497000)); |
| 516 EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News"))); |
| 517 EXPECT_THAT(sugg.score(), Eq(9001)); |
| 518 EXPECT_THAT(sugg.download_suggestion_extra(), IsNull()); |
| 519 EXPECT_THAT(sugg.recent_tab_suggestion_extra(), IsNull()); |
| 520 ASSERT_THAT(sugg.notification_extra(), NotNull()); |
| 521 EXPECT_THAT(sugg.notification_extra()->deadline.ToJavaTime(), |
| 522 Eq(1467291697000)); |
| 523 } |
| 524 |
| 402 } // namespace | 525 } // namespace |
| 403 } // namespace ntp_snippets | 526 } // namespace ntp_snippets |
| OLD | NEW |