1 // Copyright 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.
5 #include "chrome/browser/history/most_visited_tiles_experiment.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h"
12 #include "base/metrics/statistics_recorder.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/history/history_types.h"
16 #include "chrome/common/instant_types.h"
17 #include "components/variations/entropy_provider.h"
18 #include "testing/gtest/include/gtest/gtest.h"
25 // Constants for the most visited tile placement field trial.
26 // See field trial config (MostVisitedTilePlacement.json) for details.
27 const char kMostVisitedFieldTrialName[] = "MostVisitedTilePlacement";
28 const char kOneEightAGroupName[] = "OneEight_A_Flipped";
29 const char kOneFourAGroupName[] = "OneFour_A_Flipped";
30 const char kDontShowOpenURLsGroupName[] = "DontShowOpenTabs";
31 const char kGmailURL[] = "http://www.gmail.com/";
32 // Name of histogram tracking types of actions carried out by the field trial.
33 const char kMostVisitedExperimentHistogramName[] =
34 "NewTabPage.MostVisitedTilePlacementExperiment";
35 // Minimum number of Most Visited suggestions required in order for the Most
36 // Visited Field Trial to remove a URL already open in the browser.
37 const size_t kMinUrlSuggestions = 8;
39 // The indexes of the tiles that are affected in the experiment.
46 // Creates a DictionaryValue using |url| and appends to |list|.
47 void AppendURLToListValue(const std::string& url_string,
48 base::ListValue* list) {
49 DictionaryValue* page_value = new DictionaryValue();
50 page_value->SetString("url", url_string);
51 list->Append(page_value);
54 // Creates an InstantMostVisitedItem using |url| and appends to |list|.
55 void AppendInstantURLToVector(const std::string& url_string,
56 std::vector<InstantMostVisitedItem>* list) {
57 InstantMostVisitedItem item;
58 item.url = GURL(url_string);
59 list->push_back(item);
62 // Creates an MostVisitedURL using |url| and appends to |list|.
63 void AppendMostVisitedURLToVector(const std::string& url_string,
64 std::vector<history::MostVisitedURL>* list) {
65 history::MostVisitedURL most_visited;
66 most_visited.url = GURL(url_string);
67 list->push_back(most_visited);
70 void SetUpMaybeShuffle(const int& max_urls,
71 MostVisitedURLList* most_visited_urls,
72 MostVisitedURLList* test_urls) {
73 // |most_visited_urls| must have > 8 MostVisitedURLs for any URLs to be
74 // flipped by experiment.
75 for (int i = 0; i < max_urls; ++i) {
77 base::SStringPrintf(&url, "http://www.test%d.com", i);
78 AppendMostVisitedURLToVector(url, most_visited_urls);
79 AppendMostVisitedURLToVector(url, test_urls);
85 class MostVisitedTilesExperimentTest : public testing::Test {
87 MostVisitedTilesExperimentTest()
89 field_trial_list_(new metrics::SHA1EntropyProvider("foo")) {}
91 virtual ~MostVisitedTilesExperimentTest() {}
94 virtual void SetUp() OVERRIDE {
95 base::StatisticsRecorder::Initialize();
96 previous_metrics_count_.resize(NUM_NTP_TILE_EXPERIMENT_ACTIONS, 0);
97 base::HistogramBase* histogram = GetHistogram();
99 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
101 for (int state = NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL;
102 state < NUM_NTP_TILE_EXPERIMENT_ACTIONS;
104 previous_metrics_count_[state] = samples->GetCount(state);
110 void ValidateMetrics(const base::HistogramBase::Sample& value) {
111 base::HistogramBase* histogram = GetHistogram();
112 ASSERT_TRUE(histogram != NULL);
113 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
115 for (int state = NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL;
116 state < NUM_NTP_TILE_EXPERIMENT_ACTIONS;
118 if (state == value) {
119 EXPECT_EQ(previous_metrics_count_[state] + 1,
120 samples->GetCount(state));
122 EXPECT_EQ(previous_metrics_count_[state], samples->GetCount(state));
129 base::HistogramBase* GetHistogram() {
131 histogram_ = base::StatisticsRecorder::FindHistogram(
132 kMostVisitedExperimentHistogramName);
137 // Owned by base::StatisticsRecorder
138 base::HistogramBase* histogram_;
139 base::FieldTrialList field_trial_list_;
140 std::vector<int> previous_metrics_count_;
142 DISALLOW_COPY_AND_ASSIGN(MostVisitedTilesExperimentTest);
145 // For pre-instant extended clients.
146 TEST_F(MostVisitedTilesExperimentTest,
147 RemovePageValuesMatchingOpenTabsTooFewURLs) {
148 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName,
149 kDontShowOpenURLsGroupName);
151 // Ensure the field trial is created with the correct group.
152 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled());
154 std::set<std::string> open_urls;
155 open_urls.insert(kGmailURL);
157 base::ListValue pages_value;
158 AppendURLToListValue(kGmailURL, &pages_value);
160 // Test the method when there are not enough URLs to force removal.
161 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs(
162 open_urls, &pages_value);
163 DictionaryValue gmail_value;
164 gmail_value.SetString("url", kGmailURL);
165 // Ensure the open url has not been removed from |pages_value|.
166 EXPECT_NE(pages_value.end(), pages_value.Find(gmail_value));
168 // Ensure counts have been incremented correctly.
169 EXPECT_NO_FATAL_FAILURE(
170 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL));
173 // For pre-instant extended clients.
174 TEST_F(MostVisitedTilesExperimentTest, RemovePageValuesMatchingOpenTabs) {
175 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName,
176 kDontShowOpenURLsGroupName);
178 // Ensure the field trial is created with the correct group.
179 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled());
181 std::set<std::string> open_urls;
182 open_urls.insert(kGmailURL);
184 base::ListValue pages_value;
185 AppendURLToListValue(kGmailURL, &pages_value);
187 // |pages_value| must have > 8 page values for any URLs to be removed by
189 for (size_t i = 0; i < kMinUrlSuggestions; ++i) {
191 base::SStringPrintf(&url, "http://www.test%d.com", static_cast<int>(i));
192 AppendURLToListValue(url, &pages_value);
195 // Call method with enough URLs to force removal.
196 MostVisitedTilesExperiment::RemovePageValuesMatchingOpenTabs(
197 open_urls, &pages_value);
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.end(), pages_value.Find(gmail_value));
203 // Ensure counts have been incremented correctly.
204 EXPECT_NO_FATAL_FAILURE(
205 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL));
208 // For instant extended clients.
209 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabsTooFewURLs) {
210 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName,
211 kDontShowOpenURLsGroupName);
213 // Ensure the field trial is created with the correct group.
214 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled());
216 std::set<std::string> open_urls;
217 open_urls.insert(kGmailURL);
218 std::vector<InstantMostVisitedItem> items;
219 AppendInstantURLToVector(kGmailURL, &items);
221 // Call the method when there are not enough URLs to force removal.
222 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items);
224 // Ensure the open url has not been removed from |items|.
225 for (size_t i = 0; i < items.size(); i++) {
226 const std::string& item_url = items[i].url.spec();
227 EXPECT_NE(0u, open_urls.count(item_url));
230 // Ensure counts have been incremented correctly.
231 EXPECT_NO_FATAL_FAILURE(
232 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_DID_NOT_REMOVE_URL));
235 // For instant extended clients.
236 TEST_F(MostVisitedTilesExperimentTest, RemoveItemsMatchingOpenTabs) {
237 base::FieldTrialList::CreateFieldTrial(
238 kMostVisitedFieldTrialName,
239 kDontShowOpenURLsGroupName);
241 // Ensure the field trial is created with the correct group.
242 EXPECT_TRUE(MostVisitedTilesExperiment::IsDontShowOpenURLsEnabled());
244 std::set<std::string> open_urls;
245 open_urls.insert(kGmailURL);
246 std::vector<InstantMostVisitedItem> items;
247 AppendInstantURLToVector(kGmailURL, &items);
249 // |items| must have > 8 InstantMostVisitedItems for any URLs to be removed by
251 for (size_t i = 0; i < kMinUrlSuggestions; ++i) {
253 base::SStringPrintf(&url, "http://www.test%d.com", static_cast<int>(i));
254 AppendInstantURLToVector(url, &items);
257 // Call method with enough URLs to force removal.
258 MostVisitedTilesExperiment::RemoveItemsMatchingOpenTabs(open_urls, &items);
260 // Ensure the open URL has been removed from |items|.
261 for (size_t i = 0; i < items.size(); i++) {
262 const std::string& item_url = items[i].url.spec();
263 EXPECT_EQ(0u, open_urls.count(item_url));
266 // Ensure counts have been incremented correctly.
267 EXPECT_NO_FATAL_FAILURE(
268 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_REMOVED_URL));
271 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEight) {
272 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName,
273 kOneEightAGroupName);
275 // Ensure the field trial is created with the correct group.
276 EXPECT_EQ(kOneEightAGroupName,
277 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName));
279 MostVisitedURLList most_visited_urls;
280 MostVisitedURLList test_urls;
281 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls);
283 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls);
284 // Ensure the 1st and 8th URLs have been switched.
285 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(),
286 test_urls[TILE_EIGHT].url.spec());
289 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneEightTooFewURLs) {
290 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName,
291 kOneEightAGroupName);
293 // Ensure the field trial is created with the correct group.
294 EXPECT_EQ(kOneEightAGroupName,
295 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName));
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);
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());
309 // Ensure counts are correct.
310 EXPECT_NO_FATAL_FAILURE(
311 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_8));
314 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFour) {
315 base::FieldTrialList::CreateFieldTrial(kMostVisitedFieldTrialName,
318 // Ensure the field trial is created with the correct group.
319 EXPECT_EQ(kOneFourAGroupName,
320 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName));
322 MostVisitedURLList most_visited_urls;
323 MostVisitedURLList test_urls;
324 SetUpMaybeShuffle(kMinUrlSuggestions, &most_visited_urls, &test_urls);
326 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls);
327 // Ensure the 1st and 4th URLs have been switched.
328 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(),
329 test_urls[TILE_FOUR].url.spec());
332 TEST_F(MostVisitedTilesExperimentTest, MaybeShuffleOneFourTooFewURLs) {
333 base::FieldTrialList::CreateFieldTrial(
334 kMostVisitedFieldTrialName,
337 // Ensure the field trial is created with the correct group.
338 EXPECT_EQ(kOneFourAGroupName,
339 base::FieldTrialList::FindFullName(kMostVisitedFieldTrialName));
341 MostVisitedURLList most_visited_urls;
342 MostVisitedURLList test_urls;
343 // If |most_visited_urls| has < 4 URLs, experiment will not flip any tiles.
344 SetUpMaybeShuffle(kMinUrlSuggestions - 5, &most_visited_urls, &test_urls);
346 history::MostVisitedTilesExperiment::MaybeShuffle(&most_visited_urls);
347 // Ensure no URLs have been switched.
348 EXPECT_EQ(most_visited_urls[TILE_ONE].url.spec(),
349 test_urls[TILE_ONE].url.spec());
350 EXPECT_EQ(most_visited_urls[TILE_FOUR-1].url.spec(),
351 test_urls[TILE_FOUR-1].url.spec());
353 // Ensure counts are correct.
354 EXPECT_NO_FATAL_FAILURE(
355 ValidateMetrics(NTP_TILE_EXPERIMENT_ACTION_TOO_FEW_URLS_TILES_1_4));
358 } // namespace history