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/stringprintf.h" | |
12 #include "base/values.h" | |
13 #include "chrome/browser/history/history_types.h" | |
14 #include "chrome/browser/history/most_visited_tiles_experiment.h" | |
sky
2013/07/25 17:20:21
nit: this should be your first include (same order
annark1
2013/07/25 18:51:24
Done.
| |
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 DictionaryValue using |url| and appends to |list|. | |
46 void AppendURLToListValue(const std::string& url_string, | |
47 base::ListValue* list) { | |
sky
2013/07/25 17:20:21
nit: spacing
annark1
2013/07/25 18:51:24
Done.
| |
48 DictionaryValue* page_value = new DictionaryValue(); | |
49 page_value->SetString("url", url_string); | |
50 list->Append(page_value); | |
51 } | |
52 | |
53 // Creates an InstantMostVisitedItem using |url| and appends to |list|. | |
54 void AppendInstantURLToVector( | |
55 const std::string& url_string, | |
56 std::vector<InstantMostVisitedItem>* list) { | |
57 InstantMostVisitedItem item; | |
58 item.url = GURL(url_string); | |
59 list->push_back(item); | |
60 } | |
61 | |
62 // Creates an MostVisitedURL using |url| and appends to |list|. | |
63 void AppendMostVisitedURLToVector( | |
64 const std::string& url_string, | |
65 std::vector<history::MostVisitedURL>* list) { | |
66 history::MostVisitedURL most_visited; | |
67 most_visited.url = GURL(url_string); | |
68 list->push_back(most_visited); | |
69 } | |
70 | |
71 void SetUpMaybeShuffle(const int& max_urls, | |
72 MostVisitedURLList* most_visited_urls, | |
73 MostVisitedURLList* test_urls) { | |
74 // |most_visited_urls| must have > 8 MostVisitedURLs for any URLs to be | |
75 // flipped by experiment. | |
76 for (int i = 0; i < max_urls; ++i) { | |
77 std::string url; | |
78 base::SStringPrintf(&url, "http://www.test%d.com", i); | |
79 AppendMostVisitedURLToVector(url, most_visited_urls); | |
80 AppendMostVisitedURLToVector(url, test_urls); | |
81 } | |
82 } | |
83 | |
84 } // namespace | |
85 | |
86 class MostVisitedTilesExperimentTest : public testing::Test { | |
87 public: | |
88 MostVisitedTilesExperimentTest() : histogram_(NULL) { | |
89 } | |
90 | |
91 ~MostVisitedTilesExperimentTest() {} | |
92 | |
93 protected: | |
94 virtual void SetUp() OVERRIDE { | |
95 field_trial_list_.reset(new base::FieldTrialList( | |
96 new metrics::SHA1EntropyProvider("foo"))); | |
97 base::StatisticsRecorder::Initialize(); | |
98 previous_metrics_count_.resize(NUM_NTP_TILE_EXPERIMENT_ACTIONS, 0); | |
99 base::HistogramBase* histogram = GetHistogram(); | |
100 if (histogram) { | |
101 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples()); | |
102 if (samples.get()) { | |
103 for (int state = NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL; | |
104 state < NUM_NTP_TILE_EXPERIMENT_ACTIONS; | |
105 ++state) { | |
106 previous_metrics_count_[state] = samples->GetCount(state); | |
107 } | |
108 } | |
109 } | |
110 } | |
111 | |
112 void ValidateMetrics(const base::HistogramBase::Sample& value) { | |
113 base::HistogramBase* histogram = GetHistogram(); | |
114 ASSERT_TRUE(histogram != NULL); | |
115 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples()); | |
116 if (samples.get()) { | |
117 for (int state = NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL; | |
118 state < NUM_NTP_TILE_EXPERIMENT_ACTIONS; | |
119 ++state) { | |
120 if (state == value) { | |
121 EXPECT_EQ(previous_metrics_count_[state] + 1, | |
122 samples->GetCount(state)); | |
123 } else { | |
124 EXPECT_EQ(previous_metrics_count_[state], samples->GetCount(state)); | |
125 } | |
126 } | |
127 } | |
128 } | |
129 | |
130 private: | |
131 base::HistogramBase* GetHistogram() { | |
132 if (!histogram_) { | |
133 histogram_ = base::StatisticsRecorder::FindHistogram( | |
134 kMostVisitedExperimentHistogramName); | |
135 } | |
136 return histogram_; | |
137 } | |
138 | |
139 base::HistogramBase* histogram_; | |
sky
2013/07/25 17:20:21
document ownership.
annark1
2013/07/25 18:51:24
Done.
| |
140 scoped_ptr<base::FieldTrialList> field_trial_list_; | |
sky
2013/07/25 17:20:21
nit: AFAICT you don't need a scoped_ptr here. Decl
annark1
2013/07/25 18:51:24
Done.
| |
141 std::vector<int> previous_metrics_count_; | |
142 | |
143 DISALLOW_COPY_AND_ASSIGN(MostVisitedTilesExperimentTest); | |
144 }; | |
145 | |
146 // For pre-instant extended clients. | |
147 TEST_F(MostVisitedTilesExperimentTest, | |
148 RemovePageValuesMatchingOpenTabsTooFewURLs) { | |
149 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
150 kDontShowOpenURLsGroupName); | |
151 | |
152 // Ensure the field trial is created with the correct group. | |
153 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
154 | |
155 std::set<std::string> open_urls; | |
156 open_urls.insert(kGmailURL); | |
157 | |
158 scoped_ptr<base::ListValue> pages_value(new ListValue()); | |
sky
2013/07/25 17:20:21
nit: don't use scoped_ptr (same comment on 184).
annark1
2013/07/25 18:51:24
Done.
| |
159 AppendURLToListValue(kGmailURL, pages_value.get()); | |
160 | |
161 // Test the method when there are not enough URLs to force removal. | |
162 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs( | |
163 open_urls, pages_value.get()); | |
164 DictionaryValue gmail_value; | |
165 gmail_value.SetString("url", kGmailURL); | |
166 // Ensure the open url has not been removed from |pages_value|. | |
167 EXPECT_NE(pages_value.get()->end(), pages_value.get()->Find(gmail_value)); | |
168 | |
169 // Ensure counts have been incremented correctly. | |
170 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL); | |
sky
2013/07/25 17:20:21
I would wrap all calls to this in EXPECT_NO_FATAL_
annark1
2013/07/25 18:51:24
Done.
| |
171 } | |
172 | |
173 // For pre-instant extended clients. | |
174 TEST_F(MostVisitedTilesExperimentTest, RemovePageValuesMatchingOpenTabs) { | |
175 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
176 kDontShowOpenURLsGroupName); | |
177 | |
178 // Ensure the field trial is created with the correct group. | |
179 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
180 | |
181 std::set<std::string> open_urls; | |
182 open_urls.insert(kGmailURL); | |
183 | |
184 scoped_ptr<base::ListValue> pages_value(new ListValue()); | |
185 AppendURLToListValue(kGmailURL, pages_value.get()); | |
186 | |
187 // |pages_value| must have > 8 page values for any URLs to be removed by | |
188 // experiment. | |
189 for (size_t i = 0; i < kMinUrlSuggestions; ++i) { | |
190 std::string url; | |
191 base::SStringPrintf(&url, "http://www.test%d.com", static_cast<int>(i)); | |
192 AppendURLToListValue(url, pages_value.get()); | |
193 } | |
194 | |
195 // Call method with enough URLs to force removal. | |
196 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs( | |
197 open_urls, pages_value.get()); | |
198 // Ensure the open url has been removed from |pages_value|. | |
199 DictionaryValue gmail_value; | |
200 gmail_value.SetString("url", kGmailURL); | |
201 EXPECT_EQ(pages_value.get()->end(), pages_value.get()->Find(gmail_value)); | |
202 | |
203 // Ensure counts have been incremented correctly. | |
204 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL); | |
205 } | |
206 | |
207 // For instant extended clients. | |
208 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabsTooFewURLs) { | |
209 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
210 kDontShowOpenURLsGroupName); | |
211 | |
212 // Ensure the field trial is created with the correct group. | |
213 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
214 | |
215 std::set<std::string> open_urls; | |
216 open_urls.insert(kGmailURL); | |
217 std::vector<InstantMostVisitedItem> items; | |
218 AppendInstantURLToVector(kGmailURL, &items); | |
219 | |
220 // Call the method when there are not enough URLs to force removal. | |
221 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items); | |
222 | |
223 // Ensure the open url has not been removed from |items|. | |
224 for (size_t i = 0; i < items.size(); i++) { | |
225 const std::string& item_url = items[i].url.spec(); | |
226 EXPECT_NE(0u, open_urls.count(item_url)); | |
227 } | |
228 | |
229 // Ensure counts have been incremented correctly. | |
230 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL); | |
231 } | |
232 | |
233 // For instant extended clients. | |
234 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabs) { | |
235 base::FieldTrialList::CreateFieldTrial( | |
236 kMostVisitedFieldTrialName, | |
237 kDontShowOpenURLsGroupName); | |
238 | |
239 // Ensure the field trial is created with the correct group. | |
240 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled()); | |
241 | |
242 std::set<std::string> open_urls; | |
243 open_urls.insert(kGmailURL); | |
244 std::vector<InstantMostVisitedItem> items; | |
245 AppendInstantURLToVector(kGmailURL, &items); | |
246 | |
247 // |items| must have > 8 InstantMostVisitedItems for any URLs to be removed by | |
248 // experiment. | |
249 for (size_t i = 0; i < kMinUrlSuggestions; ++i) { | |
250 std::string url; | |
251 base::SStringPrintf(&url, "http://www.test%d.com", static_cast<int>(i)); | |
252 AppendInstantURLToVector(url, &items); | |
253 } | |
254 | |
255 // Call method with enough URLs to force removal. | |
256 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items); | |
257 | |
258 // Ensure the open URL has been removed from |items|. | |
259 for (size_t i = 0; i < items.size(); i++) { | |
260 const std::string& item_url = items[i].url.spec(); | |
261 EXPECT_EQ(0u, open_urls.count(item_url)); | |
262 } | |
263 | |
264 // Ensure counts have been incremented correctly. | |
265 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL); | |
266 } | |
267 | |
268 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEight) { | |
269 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
270 kOneEightAGroupName); | |
271 | |
272 // Ensure the field trial is created with the correct group. | |
273 EXPECT_EQ(kOneEightAGroupName, | |
274 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
275 | |
276 MostVisitedURLList most_visited_urls; | |
277 MostVisitedURLList test_urls; | |
278 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls); | |
279 | |
280 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
281 // Ensure the 1st and 8th URLs have been switched. | |
282 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
283 test_urls[TILE_EIGHT].url.spec()); | |
284 | |
285 // Ensure counts are correct. | |
286 ValidateMetrics(NUM_NTP_TILE_EXPERIMENT_ACTIONS); | |
287 } | |
288 | |
289 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEightTooFewURLs) { | |
290 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
291 kOneEightAGroupName); | |
292 | |
293 // Ensure the field trial is created with the correct group. | |
294 EXPECT_EQ(kOneEightAGroupName, | |
295 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
296 | |
297 MostVisitedURLList most_visited_urls; | |
298 MostVisitedURLList test_urls; | |
299 // If |most_visited_urls| has < 8 URLs, experiment will not flip any tiles. | |
300 SetUpMaybeShuffle(kMinUrlSuggestions - 1, &most_visited_urls, &test_urls); | |
301 | |
302 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
303 // Ensure no URLs have been switched. | |
304 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
305 test_urls[TILE_ONE].url.spec()); | |
306 EXPECT_EQ(most_visited_urls[TILE_EIGHT - 1].url.spec(), | |
307 test_urls[TILE_EIGHT - 1].url.spec()); | |
308 | |
309 // Ensure counts are correct. | |
310 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_8); | |
311 } | |
312 | |
313 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFour) { | |
314 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName, | |
315 kOneFourAGroupName); | |
316 | |
317 // Ensure the field trial is created with the correct group. | |
318 EXPECT_EQ(kOneFourAGroupName, | |
319 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
320 | |
321 MostVisitedURLList most_visited_urls; | |
322 MostVisitedURLList test_urls; | |
323 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls); | |
324 | |
325 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
326 // Ensure the 1st and 4th URLs have been switched. | |
327 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
328 test_urls[TILE_FOUR].url.spec()); | |
329 | |
330 // Ensure counts are correct. | |
331 ValidateMetrics(NUM_NTP_TILE_EXPERIMENT_ACTIONS); | |
332 } | |
333 | |
334 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFourTooFewURLs) { | |
335 base::FieldTrialList::CreateFieldTrial( | |
336 kMostVisitedFieldTrialName, | |
337 kOneFourAGroupName); | |
338 | |
339 // Ensure the field trial is created with the correct group. | |
340 EXPECT_EQ(kOneFourAGroupName, | |
341 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName)); | |
342 | |
343 MostVisitedURLList most_visited_urls; | |
344 MostVisitedURLList test_urls; | |
345 // If |most_visited_urls| has < 4 URLs, experiment will not flip any tiles. | |
346 SetUpMaybeShuffle(kMinUrlSuggestions - 5, &most_visited_urls, &test_urls); | |
347 | |
348 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls); | |
349 // Ensure no URLs have been switched. | |
350 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(), | |
351 test_urls[TILE_ONE].url.spec()); | |
352 EXPECT_EQ(most_visited_urls[TILE_FOUR-1].url.spec(), | |
353 test_urls[TILE_FOUR-1].url.spec()); | |
354 | |
355 // Ensure counts are correct. | |
356 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_4); | |
357 } | |
358 | |
359 } // namespace history | |
OLD | NEW |