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.
5 #include "chrome/browser/omnibox/omnibox_field_trial.h"
7 #include "base/basictypes.h"
8 #include "base/command_line.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/strings/string16.h"
12 #include "chrome/browser/autocomplete/autocomplete_input.h"
13 #include "chrome/browser/search/search.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/metrics/variations/variations_util.h"
16 #include "components/variations/entropy_provider.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 class OmniboxFieldTrialTest
: public testing::Test
{
21 OmniboxFieldTrialTest() {
22 ResetFieldTrialList();
25 void ResetFieldTrialList() {
26 // Destroy the existing FieldTrialList before creating a new one to avoid
28 field_trial_list_
.reset();
29 field_trial_list_
.reset(new base::FieldTrialList(
30 new metrics::SHA1EntropyProvider("foo")));
31 chrome_variations::testing::ClearAllVariationParams();
32 OmniboxFieldTrial::ActivateDynamicTrials();
35 // Creates and activates a field trial.
36 static base::FieldTrial
* CreateTestTrial(const std::string
& name
,
37 const std::string
& group_name
) {
38 base::FieldTrial
* trial
= base::FieldTrialList::CreateFieldTrial(
44 // EXPECTS that demotions[match_type] exists with value expected_value.
45 static void VerifyDemotion(
46 const OmniboxFieldTrial::DemotionMultipliers
& demotions
,
47 AutocompleteMatchType::Type match_type
,
48 float expected_value
);
50 // EXPECT()s that OmniboxFieldTrial::GetValueForRuleInContext(|rule|,
51 // |page_classification|) returns |rule_value|.
52 static void ExpectRuleValue(
53 const std::string
& rule_value
,
54 const std::string
& rule
,
55 AutocompleteInput::PageClassification page_classification
);
58 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
60 DISALLOW_COPY_AND_ASSIGN(OmniboxFieldTrialTest
);
64 void OmniboxFieldTrialTest::VerifyDemotion(
65 const OmniboxFieldTrial::DemotionMultipliers
& demotions
,
66 AutocompleteMatchType::Type match_type
,
67 float expected_value
) {
68 OmniboxFieldTrial::DemotionMultipliers::const_iterator demotion_it
=
69 demotions
.find(match_type
);
70 ASSERT_TRUE(demotion_it
!= demotions
.end());
71 EXPECT_FLOAT_EQ(expected_value
, demotion_it
->second
);
75 void OmniboxFieldTrialTest::ExpectRuleValue(
76 const std::string
& rule_value
,
77 const std::string
& rule
,
78 AutocompleteInput::PageClassification page_classification
) {
80 OmniboxFieldTrial::GetValueForRuleInContext(
81 rule
, page_classification
));
84 // Test if GetDisabledProviderTypes() properly parses various field trial
86 TEST_F(OmniboxFieldTrialTest
, GetDisabledProviderTypes
) {
87 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
90 SCOPED_TRACE("Invalid groups");
91 CreateTestTrial("AutocompleteDynamicTrial_0", "DisabledProviders_");
92 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
93 ResetFieldTrialList();
94 CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_XXX");
95 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
96 ResetFieldTrialList();
97 CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_12abc");
98 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
102 SCOPED_TRACE("Valid group name, unsupported trial name.");
103 ResetFieldTrialList();
104 CreateTestTrial("UnsupportedTrialName", "DisabledProviders_20");
105 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
109 SCOPED_TRACE("Valid field and group name.");
110 ResetFieldTrialList();
111 CreateTestTrial("AutocompleteDynamicTrial_2", "DisabledProviders_3");
112 EXPECT_EQ(3, OmniboxFieldTrial::GetDisabledProviderTypes());
113 // Two groups should be OR-ed together.
114 CreateTestTrial("AutocompleteDynamicTrial_3", "DisabledProviders_6");
115 EXPECT_EQ(7, OmniboxFieldTrial::GetDisabledProviderTypes());
119 // Test if InZeroSuggestFieldTrial() properly parses various field trial
121 TEST_F(OmniboxFieldTrialTest
, ZeroSuggestFieldTrial
) {
122 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
125 SCOPED_TRACE("Valid group name, unsupported trial name.");
126 ResetFieldTrialList();
127 CreateTestTrial("UnsupportedTrialName", "EnableZeroSuggest");
128 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
130 ResetFieldTrialList();
131 CreateTestTrial("UnsupportedTrialName", "EnableZeroSuggest_Queries");
132 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
134 ResetFieldTrialList();
135 CreateTestTrial("UnsupportedTrialName", "EnableZeroSuggest_URLS");
136 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
140 SCOPED_TRACE("Valid trial name, unsupported group name.");
141 ResetFieldTrialList();
142 CreateTestTrial("AutocompleteDynamicTrial_2", "UnrelatedGroup");
143 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
147 SCOPED_TRACE("Valid field and group name.");
148 ResetFieldTrialList();
149 CreateTestTrial("AutocompleteDynamicTrial_2", "EnableZeroSuggest");
150 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
152 ResetFieldTrialList();
153 CreateTestTrial("AutocompleteDynamicTrial_2", "EnableZeroSuggest_Queries");
154 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
156 ResetFieldTrialList();
157 CreateTestTrial("AutocompleteDynamicTrial_3", "EnableZeroSuggest_URLs");
158 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
162 TEST_F(OmniboxFieldTrialTest
, GetDemotionsByTypeWithFallback
) {
164 std::map
<std::string
, std::string
> params
;
165 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":1:*"] =
167 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":3:*"] =
169 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":*:*"] = "1:25";
170 ASSERT_TRUE(chrome_variations::AssociateVariationParams(
171 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
173 base::FieldTrialList::CreateFieldTrial(
174 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
175 OmniboxFieldTrial::DemotionMultipliers demotions_by_type
;
176 OmniboxFieldTrial::GetDemotionsByType(
177 AutocompleteInput::NTP
, &demotions_by_type
);
178 ASSERT_EQ(2u, demotions_by_type
.size());
179 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_URL
, 0.5);
180 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_TITLE
, 0.0);
181 OmniboxFieldTrial::GetDemotionsByType(
182 AutocompleteInput::HOME_PAGE
, &demotions_by_type
);
183 ASSERT_EQ(1u, demotions_by_type
.size());
184 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::NAVSUGGEST
, 1.0);
185 OmniboxFieldTrial::GetDemotionsByType(
186 AutocompleteInput::BLANK
, &demotions_by_type
);
187 ASSERT_EQ(1u, demotions_by_type
.size());
188 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_URL
, 0.25);
191 TEST_F(OmniboxFieldTrialTest
, GetUndemotableTopTypes
) {
193 std::map
<std::string
, std::string
> params
;
194 const std::string
rule(OmniboxFieldTrial::kUndemotableTopTypeRule
);
195 params
[rule
+ ":1:*"] = "1,3";
196 params
[rule
+ ":3:*"] = "5";
197 params
[rule
+ ":*:*"] = "2";
198 ASSERT_TRUE(chrome_variations::AssociateVariationParams(
199 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
201 base::FieldTrialList::CreateFieldTrial(
202 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
203 OmniboxFieldTrial::UndemotableTopMatchTypes undemotable_types
;
204 undemotable_types
= OmniboxFieldTrial::GetUndemotableTopTypes(
205 AutocompleteInput::NTP
);
206 ASSERT_EQ(2u, undemotable_types
.size());
207 ASSERT_EQ(1u, undemotable_types
.count(AutocompleteMatchType::HISTORY_URL
));
208 ASSERT_EQ(1u, undemotable_types
.count(AutocompleteMatchType::HISTORY_BODY
));
209 undemotable_types
= OmniboxFieldTrial::GetUndemotableTopTypes(
210 AutocompleteInput::HOME_PAGE
);
211 ASSERT_EQ(1u, undemotable_types
.size());
212 ASSERT_EQ(1u, undemotable_types
.count(AutocompleteMatchType::NAVSUGGEST
));
213 undemotable_types
= OmniboxFieldTrial::GetUndemotableTopTypes(
214 AutocompleteInput::BLANK
);
215 ASSERT_EQ(1u, undemotable_types
.size());
216 ASSERT_EQ(1u, undemotable_types
.count(AutocompleteMatchType::HISTORY_TITLE
));
219 TEST_F(OmniboxFieldTrialTest
, GetValueForRuleInContext
) {
221 std::map
<std::string
, std::string
> params
;
222 // Rule 1 has some exact matches and fallbacks at every level.
223 params
["rule1:1:0"] = "rule1-1-0-value"; // NTP
224 params
["rule1:3:0"] = "rule1-3-0-value"; // HOME_PAGE
225 params
["rule1:4:1"] = "rule1-4-1-value"; // OTHER
226 params
["rule1:4:*"] = "rule1-4-*-value"; // OTHER
227 params
["rule1:*:1"] = "rule1-*-1-value"; // global
228 params
["rule1:*:*"] = "rule1-*-*-value"; // global
229 // Rule 2 has no exact matches but has fallbacks.
230 params
["rule2:*:0"] = "rule2-*-0-value"; // global
231 params
["rule2:1:*"] = "rule2-1-*-value"; // NTP
232 params
["rule2:*:*"] = "rule2-*-*-value"; // global
233 // Rule 3 has only a global fallback.
234 params
["rule3:*:*"] = "rule3-*-*-value"; // global
235 // Rule 4 has an exact match but no fallbacks.
236 params
["rule4:4:0"] = "rule4-4-0-value"; // OTHER
237 // Add a malformed rule to make sure it doesn't screw things up.
238 params
["unrecognized"] = "unrecognized-value";
239 ASSERT_TRUE(chrome_variations::AssociateVariationParams(
240 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
243 base::FieldTrialList::CreateFieldTrial(
244 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
246 if (chrome::IsInstantExtendedAPIEnabled()) {
247 // Tests with Instant Extended enabled.
249 ExpectRuleValue("rule1-4-1-value",
250 "rule1", AutocompleteInput::OTHER
); // exact match
251 ExpectRuleValue("rule1-*-1-value",
252 "rule1", AutocompleteInput::BLANK
); // partial fallback
253 ExpectRuleValue("rule1-*-1-value",
255 AutocompleteInput::NTP
); // partial fallback
258 ExpectRuleValue("rule2-1-*-value",
260 AutocompleteInput::NTP
); // partial fallback
261 ExpectRuleValue("rule2-*-*-value",
262 "rule2", AutocompleteInput::OTHER
); // global fallback
265 ExpectRuleValue("rule3-*-*-value",
267 AutocompleteInput::HOME_PAGE
); // global fallback
268 ExpectRuleValue("rule3-*-*-value",
270 AutocompleteInput::OTHER
); // global fallback
275 AutocompleteInput::BLANK
); // no global fallback
278 AutocompleteInput::HOME_PAGE
); // no global fallback
280 // Tests for rule 5 (a missing rule).
282 "rule5", AutocompleteInput::OTHER
); // no rule at all
285 ExpectRuleValue("rule1-1-0-value",
286 "rule1", AutocompleteInput::NTP
); // exact match
287 ExpectRuleValue("rule1-1-0-value",
288 "rule1", AutocompleteInput::NTP
); // exact match
289 ExpectRuleValue("rule1-*-*-value",
290 "rule1", AutocompleteInput::BLANK
); // fallback to global
291 ExpectRuleValue("rule1-3-0-value",
293 AutocompleteInput::HOME_PAGE
); // exact match
294 ExpectRuleValue("rule1-4-*-value",
295 "rule1", AutocompleteInput::OTHER
); // partial fallback
296 ExpectRuleValue("rule1-*-*-value",
298 AutocompleteInput:: // fallback to global
299 SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT
);
301 ExpectRuleValue("rule2-*-0-value",
303 AutocompleteInput::HOME_PAGE
); // partial fallback
304 ExpectRuleValue("rule2-*-0-value",
305 "rule2", AutocompleteInput::OTHER
); // partial fallback
308 ExpectRuleValue("rule3-*-*-value",
310 AutocompleteInput::HOME_PAGE
); // fallback to global
311 ExpectRuleValue("rule3-*-*-value",
312 "rule3", AutocompleteInput::OTHER
); // fallback to global
316 "rule4", AutocompleteInput::BLANK
); // no global fallback
319 AutocompleteInput::HOME_PAGE
); // no global fallback
320 ExpectRuleValue("rule4-4-0-value",
321 "rule4", AutocompleteInput::OTHER
); // exact match
323 // Tests for rule 5 (a missing rule).
325 "rule5", AutocompleteInput::OTHER
); // no rule at all
329 TEST_F(OmniboxFieldTrialTest
, HUPNewScoringFieldTrial
) {
331 std::map
<std::string
, std::string
> params
;
332 params
[std::string(OmniboxFieldTrial::kHUPNewScoringEnabledParam
)] = "1";
334 OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam
)] = "56";
336 OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam
)] = "77";
338 OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam
)] =
339 "0.2:25,0.1:1001,2.3:777";
341 OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam
)] = "11";
343 OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam
)] = "31";
345 OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam
)] =
347 ASSERT_TRUE(chrome_variations::AssociateVariationParams(
348 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
350 base::FieldTrialList::CreateFieldTrial(
351 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
353 HUPScoringParams scoring_params
;
354 OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params
);
355 EXPECT_TRUE(scoring_params
.experimental_scoring_enabled
);
356 EXPECT_EQ(56, scoring_params
.typed_count_buckets
.relevance_cap());
357 EXPECT_EQ(77, scoring_params
.typed_count_buckets
.half_life_days());
358 ASSERT_EQ(3u, scoring_params
.typed_count_buckets
.buckets().size());
359 EXPECT_EQ(std::make_pair(2.3, 777),
360 scoring_params
.typed_count_buckets
.buckets()[0]);
361 EXPECT_EQ(std::make_pair(0.2, 25),
362 scoring_params
.typed_count_buckets
.buckets()[1]);
363 EXPECT_EQ(std::make_pair(0.1, 1001),
364 scoring_params
.typed_count_buckets
.buckets()[2]);
365 EXPECT_EQ(11, scoring_params
.visited_count_buckets
.relevance_cap());
366 EXPECT_EQ(31, scoring_params
.visited_count_buckets
.half_life_days());
367 ASSERT_EQ(2u, scoring_params
.visited_count_buckets
.buckets().size());
368 EXPECT_EQ(std::make_pair(5.0, 300),
369 scoring_params
.visited_count_buckets
.buckets()[0]);
370 EXPECT_EQ(std::make_pair(0.0, 200),
371 scoring_params
.visited_count_buckets
.buckets()[1]);
374 TEST_F(OmniboxFieldTrialTest
, HalfLifeTimeDecay
) {
375 HUPScoringParams::ScoreBuckets buckets
;
377 // No decay by default.
378 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
380 buckets
.set_half_life_days(7);
381 EXPECT_EQ(0.5, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
382 EXPECT_EQ(0.25, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(14)));
383 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(0)));
384 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(-1)));