OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <algorithm> | |
6 #include <sstream> | |
7 | |
8 #include "base/metrics/field_trial.h" | |
9 #include "base/metrics/histogram.h" | |
10 #include "base/metrics/statistics_recorder.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/values.h" | |
13 #include "chrome/browser/history/history_types.h" | |
14 #include "chrome/browser/history/most_visited_tiles_experiment.h" | |
15 #include "chrome/common/instant_types.h" | |
16 #include "chrome/common/metrics/entropy_provider.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "url/gurl.h" | |
19 | |
20 namespace history { | |
21 | |
22 namespace { | |
23 | |
24 // Constants for the most visited tile placement field trial. | |
25 // See field trial config (MostVisitedTilePlacement.json) for details. | |
26 const char kMostVisitedFieldTrialName[] = "MostVisitedTilePlacement"; | |
27 const char kOneEightAGroupName[] = "OneEight_A_Flipped"; | |
28 const char kOneFourAGroupName[] = "OneFour_A_Flipped"; | |
29 const char kDontShowOpenURLsGroupName[] = "DontShowOpenTabs"; | |
30 const char kGmailURL[] = "http://www.gmail.com/"; | |
31 // Name of histogram tracking types of actions carried out by the field trial. | |
32 const char kMostVisitedExperimentHistogramName[] = | |
33 "NewTabPage.MostVisitedTilePlacementExperiment"; | |
34 // Minimum number of Most Visited suggestions required in order for the Most | |
35 // Visited Field Trial to remove a URL already open in the browser. | |
36 const size_t kMinUrlSuggestions = 8; | |
37 | |
38 // The indexes of the tiles that are affected in the experiment. | |
39 enum FlippedIndexes { | |
40 TILE_ONE = 0, | |
41 TILE_FOUR = 3, | |
42 TILE_EIGHT = 7 | |
43 }; | |
44 | |
45 // Creates a test url string: "http://www.test" + |num| + ".com". | |
46 void MakeTestURLString(const int& num, std::string* url) { | |
Alexei Svitkine (slow)
2013/07/24 21:04:31
No need to pass num by ref.
annark1
2013/07/24 21:51:40
Done.
| |
47 std::stringstream out; | |
48 url->append("http://www.test"); | |
49 out << num; | |
50 url->append(out.str()); | |
51 url->append(".com"); | |
Alexei Svitkine (slow)
2013/07/24 21:04:31
Just use SStringPrintf.
annark1
2013/07/24 21:51:40
Done.
| |
52 } | |
53 | |
54 // Creates a DictionaryValue using |url| and appends to |list|. | |
55 void AppendURLToListValue(const std::string& url_string, | |
56 base::ListValue* list) { | |
57 DictionaryValue* page_value = new DictionaryValue(); | |
58 page_value->SetString("url", url_string); | |
59 list->Append(page_value); | |
60 } | |
61 | |
62 // Creates an InstantMostVisitedItem using |url| and appends to |list|. | |
63 void AppendInstantURLToVector( | |
64 const std::string& url_string, | |
65 std::vector<InstantMostVisitedItem>* list) { | |
66 InstantMostVisitedItem item; | |
67 item.url = GURL(url_string); | |
68 list->push_back(item); | |
69 } | |
70 | |
71 // Creates an MostVisitedURL using |url| and appends to |list|. | |
72 void AppendMostVisitedURLToVector( | |
73 const std::string& url_string, | |
74 std::vector<history::MostVisitedURL>* list) { | |
75 history::MostVisitedURL most_visited; | |
76 most_visited.url = GURL(url_string); | |
77 list->push_back(most_visited); | |
78 } | |
79 | |
80 void SetUpMaybeShuffle(const int& max_urls, | |
81 MostVisitedURLList* most_visited_urls, | |
82 MostVisitedURLList* test_urls) { | |
83 // |most_visited_urls| must have > 8 MostVisitedURLs for any URLs to be | |
84 // flipped by experiment. | |
85 for (int i = 0; i < max_urls; ++i) { | |
86 std::string url; | |
87 MakeTestURLString(i, &url); | |
88 AppendMostVisitedURLToVector(url, most_visited_urls); | |
89 AppendMostVisitedURLToVector(url, test_urls); | |
90 } | |
91 } | |
92 | |
93 } // namespace | |
94 | |
95 class MostVisitedTilesExperimentTest : public testing::Test { | |
96 public: | |
97 MostVisitedTilesExperimentTest() : histogram_(NULL) { | |
98 } | |
99 | |
100 ~MostVisitedTilesExperimentTest() {} | |
101 | |
102 protected: | |
103 virtual void SetUp() OVERRIDE { | |
104 field_trial_list_.reset(new base::FieldTrialList( | |
105 new metrics::SHA1EntropyProvider("foo"))); | |
106 base::StatisticsRecorder::Initialize(); | |
107 previous_metrics_count_.resize(NUM_NTP_TILE_EXPERIMENT_ACTIONS, 0); | |
108 base::HistogramBase* histogram = GetHistogram(); | |
109 if (histogram) { | |
110 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples()); | |
111 if (samples.get()) { | |
112 for (int state = NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL; | |
113 state < NUM_NTP_TILE_EXPERIMENT_ACTIONS; | |
114 ++state) { | |
115 previous_metrics_count_[state] = samples->GetCount(state); | |
116 } | |
117 } | |
118 } | |
119 } | |
120 | |
121 void ValidateMetrics(const base::HistogramBase::Sample& value) { | |
122 base::HistogramBase* histogram = GetHistogram(); | |
123 ASSERT_TRUE(histogram != NULL); | |
124 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples()); | |
125 if (samples.get()) { | |
126 for (int state = NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL; | |
127 state < NUM_NTP_TILE_EXPERIMENT_ACTIONS; | |
128 ++state) { | |
129 if (state == value) { | |
130 EXPECT_EQ(previous_metrics_count_[state] + 1, | |
131 samples->GetCount(state)); | |
132 } else { | |
133 EXPECT_EQ(previous_metrics_count_[state], samples->GetCount(state)); | |
134 } | |
135 } | |
136 } | |
137 } | |
138 | |
139 private: | |
140 base::HistogramBase* GetHistogram() { | |
141 if (!histogram_) { | |
142 histogram_ = base::StatisticsRecorder::FindHistogram( | |
143 kMostVisitedExperimentHistogramName); | |
144 } | |
145 return histogram_; | |
146 } | |
147 | |
148 base::HistogramBase* histogram_; | |
149 scoped_ptr<base::FieldTrialList> field_trial_list_; | |
150 std::vector<int> previous_metrics_count_; | |
151 | |
152 DISALLOW_COPY_AND_ASSIGN(MostVisitedTilesExperimentTest); | |
153 }; | |
154 | |
155 // For pre-instant extended clients. | |
156 TEST_F(MostVisitedTilesExperimentTest, | |
157 RemovePageValuesMatchingOpenTabsTooFewURLs) { | |
158 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
159 kDontShowOpenURLsGroupName); | |
160 | |
161 // Ensure the field trial is created with the correct group. | |
162 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
163 | |
164 std::set<std::string> open_urls; | |
165 open_urls.insert(kGmailURL); | |
166 | |
167 scoped_ptr<base::ListValue> pages_value(new ListValue()); | |
168 AppendURLToListValue(kGmailURL, pages_value.get()); | |
169 | |
170 // Test the method when there are not enough URLs to force removal. | |
171 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs( | |
172 open_urls, pages_value.get()); | |
173 DictionaryValue gmail_value; | |
174 gmail_value.SetString("url", kGmailURL); | |
175 // Ensure the open url has not been removed from |pages_value|. | |
176 EXPECT_NE(pages_value.get()->end(), pages_value.get()->Find(gmail_value)); | |
177 | |
178 // Ensure counts have been incremented correctly. | |
179 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL); | |
180 } | |
181 | |
182 // For pre-instant extended clients. | |
183 TEST_F(MostVisitedTilesExperimentTest, RemovePageValuesMatchingOpenTabs) { | |
184 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
185 kDontShowOpenURLsGroupName); | |
186 | |
187 // Ensure the field trial is created with the correct group. | |
188 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
189 | |
190 std::set<std::string> open_urls; | |
191 open_urls.insert(kGmailURL); | |
192 | |
193 scoped_ptr<base::ListValue> pages_value(new ListValue()); | |
194 AppendURLToListValue(kGmailURL, pages_value.get()); | |
195 | |
196 // |pages_value| must have > 8 page values for any URLs to be removed by | |
197 // experiment. | |
198 for (size_t i = 0; i < kMinUrlSuggestions; ++i) { | |
199 std::string url; | |
200 MakeTestURLString(i, &url); | |
201 AppendURLToListValue(url, pages_value.get()); | |
202 } | |
203 | |
204 // Call method with enough URLs to force removal. | |
205 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs( | |
206 open_urls, pages_value.get()); | |
207 // Ensure the open url has been removed from |pages_value|. | |
208 DictionaryValue gmail_value; | |
209 gmail_value.SetString("url", kGmailURL); | |
210 EXPECT_EQ(pages_value.get()->end(), pages_value.get()->Find(gmail_value)); | |
211 | |
212 // Ensure counts have been incremented correctly. | |
213 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL); | |
214 } | |
215 | |
216 // For instant extended clients. | |
217 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabsTooFewURLs) { | |
218 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
219 kDontShowOpenURLsGroupName); | |
220 | |
221 // Ensure the field trial is created with the correct group. | |
222 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
223 | |
224 std::set<std::string> open_urls; | |
225 open_urls.insert(kGmailURL); | |
226 std::vector<InstantMostVisitedItem> items; | |
227 AppendInstantURLToVector(kGmailURL, &items); | |
228 | |
229 // Call the method when there are not enough URLs to force removal. | |
230 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items); | |
231 | |
232 // Ensure the open url has not been removed from |items|. | |
233 for (size_t i = 0; i < items.size(); i++) { | |
234 const std::string& item_url = items[i].url.spec(); | |
235 EXPECT_NE(0u, open_urls.count(item_url)); | |
236 } | |
237 | |
238 // Ensure counts have been incremented correctly. | |
239 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL); | |
240 } | |
241 | |
242 // For instant extended clients. | |
243 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabs) { | |
244 base::FieldTrialList::CreateFieldTrial( | |
245 kMostVisitedFieldTrialName, | |
246 kDontShowOpenURLsGroupName); | |
247 | |
248 // Ensure the field trial is created with the correct group. | |
249 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
250 | |
251 std::set<std::string> open_urls; | |
252 open_urls.insert(kGmailURL); | |
253 std::vector<InstantMostVisitedItem> items; | |
254 AppendInstantURLToVector(kGmailURL, &items); | |
255 | |
256 // |items| must have > 8 InstantMostVisitedItems for any URLs to be removed by | |
257 // experiment. | |
258 for (size_t i = 0; i < kMinUrlSuggestions; ++i) { | |
259 std::string url; | |
260 MakeTestURLString(i, &url); | |
261 AppendInstantURLToVector(url, &items); | |
262 } | |
263 | |
264 // Call method with enough URLs to force removal. | |
265 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items); | |
266 | |
267 // Ensure the open URL has been removed from |items|. | |
268 for (size_t i = 0; i < items.size(); i++) { | |
269 const std::string& item_url = items[i].url.spec(); | |
270 EXPECT_EQ(0u, open_urls.count(item_url)); | |
271 } | |
272 | |
273 // Ensure counts have been incremented correctly. | |
274 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL); | |
275 } | |
276 | |
277 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEight) { | |
278 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
279 kOneEightAGroupName); | |
280 | |
281 // Ensure the field trial is created with the correct group. | |
282 EXPECT_EQ(kOneEightAGroupName, | |
283 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
284 | |
285 MostVisitedURLList most_visited_urls; | |
286 MostVisitedURLList test_urls; | |
287 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls); | |
288 | |
289 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
290 // Ensure the 1st and 8th URLs have been switched. | |
291 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
292 test_urls[TILE_EIGHT].url.spec()); | |
293 | |
294 // Ensure counts are correct. | |
295 ValidateMetrics(NUM_NTP_TILE_EXPERIMENT_ACTIONS); | |
296 } | |
297 | |
298 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEightTooFewURLs) { | |
299 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
300 kOneEightAGroupName); | |
301 | |
302 // Ensure the field trial is created with the correct group. | |
303 EXPECT_EQ(kOneEightAGroupName, | |
304 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
305 | |
306 MostVisitedURLList most_visited_urls; | |
307 MostVisitedURLList test_urls; | |
308 // If |most_visited_urls| has < 8 URLs, experiment will not flip any tiles. | |
309 SetUpMaybeShuffle(kMinUrlSuggestions - 1, &most_visited_urls, &test_urls); | |
310 | |
311 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
312 // Ensure no URLs have been switched. | |
313 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
314 test_urls[TILE_ONE].url.spec()); | |
315 EXPECT_EQ(most_visited_urls[TILE_EIGHT - 1].url.spec(), | |
316 test_urls[TILE_EIGHT - 1].url.spec()); | |
317 | |
318 // Ensure counts are correct. | |
319 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_8); | |
320 } | |
321 | |
322 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFour) { | |
323 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
324 kOneFourAGroupName); | |
325 | |
326 // Ensure the field trial is created with the correct group. | |
327 EXPECT_EQ(kOneFourAGroupName, | |
328 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
329 | |
330 MostVisitedURLList most_visited_urls; | |
331 MostVisitedURLList test_urls; | |
332 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls); | |
333 | |
334 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
335 // Ensure the 1st and 4th URLs have been switched. | |
336 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
337 test_urls[TILE_FOUR].url.spec()); | |
338 | |
339 // Ensure counts are correct. | |
340 ValidateMetrics(NUM_NTP_TILE_EXPERIMENT_ACTIONS); | |
341 } | |
342 | |
343 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFourTooFewURLs) { | |
344 base::FieldTrialList::CreateFieldTrial( | |
345 kMostVisitedFieldTrialName, | |
346 kOneFourAGroupName); | |
347 | |
348 // Ensure the field trial is created with the correct group. | |
349 EXPECT_EQ(kOneFourAGroupName, | |
350 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
351 | |
352 MostVisitedURLList most_visited_urls; | |
353 MostVisitedURLList test_urls; | |
354 // If |most_visited_urls| has < 4 URLs, experiment will not flip any tiles. | |
355 SetUpMaybeShuffle(kMinUrlSuggestions - 5, &most_visited_urls, &test_urls); | |
356 | |
357 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
358 // Ensure no URLs have been switched. | |
359 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
360 test_urls[TILE_ONE].url.spec()); | |
361 EXPECT_EQ(most_visited_urls[TILE_FOUR-1].url.spec(), | |
362 test_urls[TILE_FOUR-1].url.spec()); | |
363 | |
364 // Ensure counts are correct. | |
365 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_4); | |
366 } | |
367 | |
368 } // namespace history | |
OLD | NEW |