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 static void MakeTestURLString(const int& num, std::string* url) { | |
Alexei Svitkine (slow)
2013/07/23 20:10:51
No need for any of these functions to be static si
annark1
2013/07/24 01:23:58
Done.
| |
47 std::stringstream out; | |
48 url->append("http://www.test"); | |
49 out << num; | |
50 url->append(out.str()); | |
51 url->append(".com"); | |
52 } | |
53 | |
54 // Creates a DictionaryValue using |url| and appends to |list|. | |
55 static 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 static 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 static 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() { | |
Alexei Svitkine (slow)
2013/07/23 20:10:51
OVERRIDE
annark1
2013/07/24 01:23:58
Done.
| |
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 if (histogram) { | |
Alexei Svitkine (slow)
2013/07/23 20:10:51
Shouldn't it fail if the histogram doesn't exist?
annark1
2013/07/24 01:23:58
I've done this here, but not in SetUp, because for
| |
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 | |
140 private: | |
141 base::HistogramBase* GetHistogram() { | |
142 if (!histogram_) { | |
143 histogram_ = base::StatisticsRecorder::FindHistogram( | |
144 kMostVisitedExperimentHistogramName); | |
145 } | |
146 return histogram_; | |
147 } | |
148 | |
149 base::HistogramBase* histogram_; | |
150 scoped_ptr<base::FieldTrialList> field_trial_list_; | |
151 std::vector<int> previous_metrics_count_; | |
152 | |
153 DISALLOW_COPY_AND_ASSIGN(MostVisitedTilesExperimentTest); | |
154 }; | |
155 | |
156 // For pre-instant extended clients. | |
157 TEST_F(MostVisitedTilesExperimentTest, | |
158 RemovePageValuesMatchingOpenTabsTooFewURLs) { | |
159 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
160 kDontShowOpenURLsGroupName); | |
161 | |
162 // Ensure the field trial is created with the correct group. | |
163 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
164 | |
165 std::set<std::string> open_urls; | |
166 open_urls.insert(kGmailURL); | |
167 | |
168 scoped_ptr<base::ListValue> pages_value(new ListValue()); | |
169 AppendURLToListValue(kGmailURL, pages_value.get()); | |
170 | |
171 // Test the method when there are not enough URLs to force removal. | |
172 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs( | |
173 open_urls, pages_value.get()); | |
174 DictionaryValue gmail_value; | |
175 gmail_value.SetString("url", kGmailURL); | |
176 // Ensure the open url has not been removed from |pages_value|. | |
177 EXPECT_NE(pages_value.get()->end(), pages_value.get()->Find(gmail_value)); | |
178 | |
179 // Ensure counts have been incremented correctly. | |
180 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL); | |
181 } | |
182 | |
183 // For pre-instant extended clients. | |
184 TEST_F(MostVisitedTilesExperimentTest, RemovePageValuesMatchingOpenTabs) { | |
185 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
186 kDontShowOpenURLsGroupName); | |
187 | |
188 // Ensure the field trial is created with the correct group. | |
189 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
190 | |
191 std::set<std::string> open_urls; | |
192 open_urls.insert(kGmailURL); | |
193 | |
194 scoped_ptr<base::ListValue> pages_value(new ListValue()); | |
195 AppendURLToListValue(kGmailURL, pages_value.get()); | |
196 | |
197 // |pages_value| must have > 8 page values for any URLs to be removed by | |
198 // experiment. | |
199 for (size_t i = 0; i < kMinUrlSuggestions; ++i) { | |
200 std::string url; | |
201 MakeTestURLString(i, &url); | |
202 AppendURLToListValue(url, pages_value.get()); | |
203 } | |
204 | |
205 // Call method with enough URLs to force removal. | |
206 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs( | |
207 open_urls, pages_value.get()); | |
208 // Ensure the open url has been removed from |pages_value|. | |
209 DictionaryValue gmail_value; | |
210 gmail_value.SetString("url", kGmailURL); | |
211 EXPECT_EQ(pages_value.get()->end(), pages_value.get()->Find(gmail_value)); | |
212 | |
213 // Ensure counts have been incremented correctly. | |
214 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL); | |
215 } | |
216 | |
217 // For instant extended clients. | |
218 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabsTooFewURLs) { | |
219 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
220 kDontShowOpenURLsGroupName); | |
221 | |
222 // Ensure the field trial is created with the correct group. | |
223 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
224 | |
225 std::set<std::string> open_urls; | |
226 open_urls.insert(kGmailURL); | |
227 std::vector<InstantMostVisitedItem> items; | |
228 AppendInstantURLToVector(kGmailURL, &items); | |
229 | |
230 // Call the method when there are not enough URLs to force removal. | |
231 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items); | |
232 | |
233 // Ensure the open url has not been removed from |items|. | |
234 for (size_t i = 0; i < items.size(); i++) { | |
235 const std::string& item_url = items[i].url.spec(); | |
236 EXPECT_NE(0u, open_urls.count(item_url)); | |
237 } | |
238 | |
239 // Ensure counts have been incremented correctly. | |
240 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL); | |
241 } | |
242 | |
243 // For instant extended clients. | |
244 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabs) { | |
245 base::FieldTrialList::CreateFieldTrial( | |
246 kMostVisitedFieldTrialName, | |
247 kDontShowOpenURLsGroupName); | |
248 | |
249 // Ensure the field trial is created with the correct group. | |
250 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
251 | |
252 std::set<std::string> open_urls; | |
253 open_urls.insert(kGmailURL); | |
254 std::vector<InstantMostVisitedItem> items; | |
255 AppendInstantURLToVector(kGmailURL, &items); | |
256 | |
257 // |items| must have > 8 InstantMostVisitedItems for any URLs to be removed by | |
258 // experiment. | |
259 for (size_t i = 0; i < kMinUrlSuggestions; ++i) { | |
260 std::string url; | |
261 MakeTestURLString(i, &url); | |
262 AppendInstantURLToVector(url, &items); | |
263 } | |
264 | |
265 // Call method with enough URLs to force removal. | |
266 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items); | |
267 | |
268 // Ensure the open URL has been removed from |items|. | |
269 for (size_t i = 0; i < items.size(); i++) { | |
270 const std::string& item_url = items[i].url.spec(); | |
271 EXPECT_EQ(0u, open_urls.count(item_url)); | |
272 } | |
273 | |
274 // Ensure counts have been incremented correctly. | |
275 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL); | |
276 } | |
277 | |
278 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEight) { | |
279 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
280 kOneEightAGroupName); | |
281 | |
282 // Ensure the field trial is created with the correct group. | |
283 EXPECT_EQ(kOneEightAGroupName, | |
284 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
285 | |
286 MostVisitedURLList most_visited_urls; | |
287 MostVisitedURLList test_urls; | |
288 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls); | |
289 | |
290 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
291 // Ensure the 1st and 8th URLs have been switched. | |
292 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
293 test_urls[TILE_EIGHT].url.spec()); | |
294 | |
295 // Ensure counts are correct. | |
296 ValidateMetrics(NUM_NTP_TILE_EXPERIMENT_ACTIONS); | |
297 } | |
298 | |
299 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEightTooFewURLs) { | |
300 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
301 kOneEightAGroupName); | |
302 | |
303 // Ensure the field trial is created with the correct group. | |
304 EXPECT_EQ(kOneEightAGroupName, | |
305 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
306 | |
307 MostVisitedURLList most_visited_urls; | |
308 MostVisitedURLList test_urls; | |
309 // If |most_visited_urls| has < 8 URLs, experiment will not flip any tiles. | |
310 SetUpMaybeShuffle(kMinUrlSuggestions - 1, &most_visited_urls, &test_urls); | |
311 | |
312 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
313 // Ensure no URLs have been switched. | |
314 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
315 test_urls[TILE_ONE].url.spec()); | |
316 EXPECT_EQ(most_visited_urls[TILE_EIGHT - 1].url.spec(), | |
317 test_urls[TILE_EIGHT - 1].url.spec()); | |
318 | |
319 // Ensure counts are correct. | |
320 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_8); | |
321 } | |
322 | |
323 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFour) { | |
324 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
325 kOneFourAGroupName); | |
326 | |
327 // Ensure the field trial is created with the correct group. | |
328 EXPECT_EQ(kOneFourAGroupName, | |
329 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
330 | |
331 MostVisitedURLList most_visited_urls; | |
332 MostVisitedURLList test_urls; | |
333 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls); | |
334 | |
335 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
336 // Ensure the 1st and 4th URLs have been switched. | |
337 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
338 test_urls[TILE_FOUR].url.spec()); | |
339 | |
340 // Ensure counts are correct. | |
341 ValidateMetrics(NUM_NTP_TILE_EXPERIMENT_ACTIONS); | |
342 } | |
343 | |
344 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFourTooFewURLs) { | |
345 base::FieldTrialList::CreateFieldTrial( | |
346 kMostVisitedFieldTrialName, | |
347 kOneFourAGroupName); | |
348 | |
349 // Ensure the field trial is created with the correct group. | |
350 EXPECT_EQ(kOneFourAGroupName, | |
351 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
352 | |
353 MostVisitedURLList most_visited_urls; | |
354 MostVisitedURLList test_urls; | |
355 // If |most_visited_urls| has < 4 URLs, experiment will not flip any tiles. | |
356 SetUpMaybeShuffle(kMinUrlSuggestions - 5, &most_visited_urls, &test_urls); | |
357 | |
358 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
359 // Ensure no URLs have been switched. | |
360 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
361 test_urls[TILE_ONE].url.spec()); | |
362 EXPECT_EQ(most_visited_urls[TILE_FOUR-1].url.spec(), | |
363 test_urls[TILE_FOUR-1].url.spec()); | |
364 | |
365 // Ensure counts are correct. | |
366 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_4); | |
367 } | |
368 | |
369 } // namespace history | |
OLD | NEW |