1 // Copyright 2014 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 "components/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 "components/metrics/proto/omnibox_event.pb.h"
13 #include "components/search/search.h"
14 #include "components/variations/entropy_provider.h"
15 #include "components/variations/variations_associated_data.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using metrics::OmniboxEventProto
;
20 class OmniboxFieldTrialTest
: public testing::Test
{
22 OmniboxFieldTrialTest() {
23 ResetFieldTrialList();
26 void ResetFieldTrialList() {
27 // Destroy the existing FieldTrialList before creating a new one to avoid
29 field_trial_list_
.reset();
30 field_trial_list_
.reset(new base::FieldTrialList(
31 new metrics::SHA1EntropyProvider("foo")));
32 variations::testing::ClearAllVariationParams();
33 OmniboxFieldTrial::ActivateDynamicTrials();
36 // Creates and activates a field trial.
37 static base::FieldTrial
* CreateTestTrial(const std::string
& name
,
38 const std::string
& group_name
) {
39 base::FieldTrial
* trial
= base::FieldTrialList::CreateFieldTrial(
45 // Add a field trial disabling ZeroSuggest.
46 static void CreateDisableZeroSuggestTrial() {
47 std::map
<std::string
, std::string
> params
;
48 params
[std::string(OmniboxFieldTrial::kZeroSuggestRule
)] = "false";
49 variations::AssociateVariationParams(
50 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
);
51 base::FieldTrialList::CreateFieldTrial(
52 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
55 // EXPECT()s that demotions[match_type] exists with value expected_value.
56 static void VerifyDemotion(
57 const OmniboxFieldTrial::DemotionMultipliers
& demotions
,
58 AutocompleteMatchType::Type match_type
,
59 float expected_value
);
61 // EXPECT()s that OmniboxFieldTrial::GetValueForRuleInContext(|rule|,
62 // |page_classification|) returns |rule_value|.
63 static void ExpectRuleValue(
64 const std::string
& rule_value
,
65 const std::string
& rule
,
66 OmniboxEventProto::PageClassification page_classification
);
68 // EXPECT()s that OmniboxFieldTrial::GetSuggestPollingStrategy returns
69 // |expected_from_last_keystroke| and |expected_delay_ms| for the given
70 // experiment params. If one the rule values is NULL, the corresponding
71 // variation parameter won't be set thus allowing to test the default
73 void VerifySuggestPollingStrategy(
74 const char* from_last_keystroke_rule_value
,
75 const char* polling_delay_ms_rule_value
,
76 bool expected_from_last_keystroke
,
77 int expected_delay_ms
);
80 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
82 DISALLOW_COPY_AND_ASSIGN(OmniboxFieldTrialTest
);
86 void OmniboxFieldTrialTest::VerifyDemotion(
87 const OmniboxFieldTrial::DemotionMultipliers
& demotions
,
88 AutocompleteMatchType::Type match_type
,
89 float expected_value
) {
90 OmniboxFieldTrial::DemotionMultipliers::const_iterator demotion_it
=
91 demotions
.find(match_type
);
92 ASSERT_TRUE(demotion_it
!= demotions
.end());
93 EXPECT_FLOAT_EQ(expected_value
, demotion_it
->second
);
97 void OmniboxFieldTrialTest::ExpectRuleValue(
98 const std::string
& rule_value
,
99 const std::string
& rule
,
100 OmniboxEventProto::PageClassification page_classification
) {
101 EXPECT_EQ(rule_value
,
102 OmniboxFieldTrial::GetValueForRuleInContext(
103 rule
, page_classification
));
106 void OmniboxFieldTrialTest::VerifySuggestPollingStrategy(
107 const char* from_last_keystroke_rule_value
,
108 const char* polling_delay_ms_rule_value
,
109 bool expected_from_last_keystroke
,
110 int expected_delay_ms
) {
111 ResetFieldTrialList();
112 std::map
<std::string
, std::string
> params
;
113 if (from_last_keystroke_rule_value
!= NULL
) {
115 OmniboxFieldTrial::kMeasureSuggestPollingDelayFromLastKeystrokeRule
)] =
116 from_last_keystroke_rule_value
;
118 if (polling_delay_ms_rule_value
!= NULL
) {
120 OmniboxFieldTrial::kSuggestPollingDelayMsRule
)] =
121 polling_delay_ms_rule_value
;
123 ASSERT_TRUE(variations::AssociateVariationParams(
124 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
125 base::FieldTrialList::CreateFieldTrial(
126 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
128 bool from_last_keystroke
;
130 OmniboxFieldTrial::GetSuggestPollingStrategy(&from_last_keystroke
, &delay_ms
);
131 EXPECT_EQ(expected_from_last_keystroke
, from_last_keystroke
);
132 EXPECT_EQ(expected_delay_ms
, delay_ms
);
135 // Test if GetDisabledProviderTypes() properly parses various field trial
137 TEST_F(OmniboxFieldTrialTest
, GetDisabledProviderTypes
) {
138 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
141 SCOPED_TRACE("Outside the bundled field trial.");
142 CreateTestTrial("AutocompleteDynamicTrial_0", "DisabledProviders_123");
143 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
147 SCOPED_TRACE("Valid field trial, missing param.");
148 ResetFieldTrialList();
149 std::map
<std::string
, std::string
> params
;
150 ASSERT_TRUE(variations::AssociateVariationParams(
151 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
152 base::FieldTrialList::CreateFieldTrial(
153 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
154 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
158 SCOPED_TRACE("Valid field trial, empty param value.");
159 ResetFieldTrialList();
160 std::map
<std::string
, std::string
> params
;
161 params
[std::string(OmniboxFieldTrial::kDisableProvidersRule
)] = "";
162 ASSERT_TRUE(variations::AssociateVariationParams(
163 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
164 base::FieldTrialList::CreateFieldTrial(
165 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
166 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
170 SCOPED_TRACE("Valid field trial, invalid param value.");
171 ResetFieldTrialList();
172 std::map
<std::string
, std::string
> params
;
173 params
[std::string(OmniboxFieldTrial::kDisableProvidersRule
)] = "aaa";
174 ASSERT_TRUE(variations::AssociateVariationParams(
175 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
176 base::FieldTrialList::CreateFieldTrial(
177 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
178 EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
182 SCOPED_TRACE("Valid field trial and param.");
183 ResetFieldTrialList();
184 std::map
<std::string
, std::string
> params
;
185 params
[std::string(OmniboxFieldTrial::kDisableProvidersRule
)] = "12321";
186 ASSERT_TRUE(variations::AssociateVariationParams(
187 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
188 base::FieldTrialList::CreateFieldTrial(
189 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
190 EXPECT_EQ(12321, OmniboxFieldTrial::GetDisabledProviderTypes());
194 // Test if InZeroSuggestFieldTrial() properly parses various field trial
196 TEST_F(OmniboxFieldTrialTest
, ZeroSuggestFieldTrial
) {
197 // Default ZeroSuggest setting depends on OS.
198 #if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \
199 (defined(OS_MACOSX) && !defined(OS_IOS))
200 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
202 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
206 SCOPED_TRACE("Disable ZeroSuggest.");
207 ResetFieldTrialList();
208 CreateDisableZeroSuggestTrial();
209 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
213 SCOPED_TRACE("Bundled field trial parameters.");
214 ResetFieldTrialList();
215 std::map
<std::string
, std::string
> params
;
216 params
[std::string(OmniboxFieldTrial::kZeroSuggestRule
)] = "true";
217 ASSERT_TRUE(variations::AssociateVariationParams(
218 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
219 base::FieldTrialList::CreateFieldTrial(
220 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
221 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
222 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
223 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
225 ResetFieldTrialList();
226 params
[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule
)] =
228 ASSERT_TRUE(variations::AssociateVariationParams(
229 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
230 base::FieldTrialList::CreateFieldTrial(
231 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
232 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
233 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
234 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
236 ResetFieldTrialList();
237 params
[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule
)] =
239 base::FieldTrialList::CreateFieldTrial(
240 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
241 ASSERT_TRUE(variations::AssociateVariationParams(
242 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
243 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
244 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
245 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
249 TEST_F(OmniboxFieldTrialTest
, GetDemotionsByTypeWithFallback
) {
251 std::map
<std::string
, std::string
> params
;
252 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":1:*"] =
254 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":3:*"] =
256 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":*:*"] = "1:25";
257 ASSERT_TRUE(variations::AssociateVariationParams(
258 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
260 base::FieldTrialList::CreateFieldTrial(
261 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
262 OmniboxFieldTrial::DemotionMultipliers demotions_by_type
;
263 OmniboxFieldTrial::GetDemotionsByType(
264 OmniboxEventProto::NTP
, &demotions_by_type
);
265 ASSERT_EQ(2u, demotions_by_type
.size());
266 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_URL
, 0.5);
267 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_TITLE
, 0.0);
268 OmniboxFieldTrial::GetDemotionsByType(
269 OmniboxEventProto::HOME_PAGE
, &demotions_by_type
);
270 ASSERT_EQ(1u, demotions_by_type
.size());
271 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::NAVSUGGEST
, 1.0);
272 OmniboxFieldTrial::GetDemotionsByType(
273 OmniboxEventProto::BLANK
, &demotions_by_type
);
274 ASSERT_EQ(1u, demotions_by_type
.size());
275 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_URL
, 0.25);
278 TEST_F(OmniboxFieldTrialTest
, GetValueForRuleInContext
) {
280 std::map
<std::string
, std::string
> params
;
281 // Rule 1 has some exact matches and fallbacks at every level.
282 params
["rule1:1:0"] = "rule1-1-0-value"; // NTP
283 params
["rule1:3:0"] = "rule1-3-0-value"; // HOME_PAGE
284 params
["rule1:4:1"] = "rule1-4-1-value"; // OTHER
285 params
["rule1:4:*"] = "rule1-4-*-value"; // OTHER
286 params
["rule1:*:1"] = "rule1-*-1-value"; // global
287 params
["rule1:*:*"] = "rule1-*-*-value"; // global
288 // Rule 2 has no exact matches but has fallbacks.
289 params
["rule2:*:0"] = "rule2-*-0-value"; // global
290 params
["rule2:1:*"] = "rule2-1-*-value"; // NTP
291 params
["rule2:*:*"] = "rule2-*-*-value"; // global
292 // Rule 3 has only a global fallback.
293 params
["rule3:*:*"] = "rule3-*-*-value"; // global
294 // Rule 4 has an exact match but no fallbacks.
295 params
["rule4:4:0"] = "rule4-4-0-value"; // OTHER
296 // Add a malformed rule to make sure it doesn't screw things up.
297 params
["unrecognized"] = "unrecognized-value";
298 ASSERT_TRUE(variations::AssociateVariationParams(
299 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
302 base::FieldTrialList::CreateFieldTrial(
303 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
305 if (chrome::IsInstantExtendedAPIEnabled()) {
306 // Tests with Instant Extended enabled.
308 ExpectRuleValue("rule1-4-1-value",
309 "rule1", OmniboxEventProto::OTHER
); // exact match
310 ExpectRuleValue("rule1-*-1-value",
311 "rule1", OmniboxEventProto::BLANK
); // partial fallback
312 ExpectRuleValue("rule1-*-1-value",
314 OmniboxEventProto::NTP
); // partial fallback
317 ExpectRuleValue("rule2-1-*-value",
319 OmniboxEventProto::NTP
); // partial fallback
320 ExpectRuleValue("rule2-*-*-value",
321 "rule2", OmniboxEventProto::OTHER
); // global fallback
324 ExpectRuleValue("rule3-*-*-value",
326 OmniboxEventProto::HOME_PAGE
); // global fallback
327 ExpectRuleValue("rule3-*-*-value",
329 OmniboxEventProto::OTHER
); // global fallback
334 OmniboxEventProto::BLANK
); // no global fallback
337 OmniboxEventProto::HOME_PAGE
); // no global fallback
339 // Tests for rule 5 (a missing rule).
341 "rule5", OmniboxEventProto::OTHER
); // no rule at all
344 ExpectRuleValue("rule1-1-0-value",
345 "rule1", OmniboxEventProto::NTP
); // exact match
346 ExpectRuleValue("rule1-1-0-value",
347 "rule1", OmniboxEventProto::NTP
); // exact match
348 ExpectRuleValue("rule1-*-*-value",
349 "rule1", OmniboxEventProto::BLANK
); // fallback to global
350 ExpectRuleValue("rule1-3-0-value",
352 OmniboxEventProto::HOME_PAGE
); // exact match
353 ExpectRuleValue("rule1-4-*-value",
354 "rule1", OmniboxEventProto::OTHER
); // partial fallback
355 ExpectRuleValue("rule1-*-*-value",
357 OmniboxEventProto:: // fallback to global
358 SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT
);
360 ExpectRuleValue("rule2-*-0-value",
362 OmniboxEventProto::HOME_PAGE
); // partial fallback
363 ExpectRuleValue("rule2-*-0-value",
364 "rule2", OmniboxEventProto::OTHER
); // partial fallback
367 ExpectRuleValue("rule3-*-*-value",
369 OmniboxEventProto::HOME_PAGE
); // fallback to global
370 ExpectRuleValue("rule3-*-*-value",
371 "rule3", OmniboxEventProto::OTHER
); // fallback to global
375 "rule4", OmniboxEventProto::BLANK
); // no global fallback
378 OmniboxEventProto::HOME_PAGE
); // no global fallback
379 ExpectRuleValue("rule4-4-0-value",
380 "rule4", OmniboxEventProto::OTHER
); // exact match
382 // Tests for rule 5 (a missing rule).
384 "rule5", OmniboxEventProto::OTHER
); // no rule at all
388 TEST_F(OmniboxFieldTrialTest
, HUPNewScoringFieldTrial
) {
390 std::map
<std::string
, std::string
> params
;
391 params
[std::string(OmniboxFieldTrial::kHUPNewScoringEnabledParam
)] = "1";
393 OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam
)] = "56";
395 OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam
)] = "77";
397 OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam
)] =
398 "0.2:25,0.1:1001,2.3:777";
400 OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam
)] = "11";
402 OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam
)] = "31";
404 OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam
)] =
406 ASSERT_TRUE(variations::AssociateVariationParams(
407 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
409 base::FieldTrialList::CreateFieldTrial(
410 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
412 HUPScoringParams scoring_params
;
413 OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params
);
414 EXPECT_TRUE(scoring_params
.experimental_scoring_enabled
);
415 EXPECT_EQ(56, scoring_params
.typed_count_buckets
.relevance_cap());
416 EXPECT_EQ(77, scoring_params
.typed_count_buckets
.half_life_days());
417 ASSERT_EQ(3u, scoring_params
.typed_count_buckets
.buckets().size());
418 EXPECT_EQ(std::make_pair(2.3, 777),
419 scoring_params
.typed_count_buckets
.buckets()[0]);
420 EXPECT_EQ(std::make_pair(0.2, 25),
421 scoring_params
.typed_count_buckets
.buckets()[1]);
422 EXPECT_EQ(std::make_pair(0.1, 1001),
423 scoring_params
.typed_count_buckets
.buckets()[2]);
424 EXPECT_EQ(11, scoring_params
.visited_count_buckets
.relevance_cap());
425 EXPECT_EQ(31, scoring_params
.visited_count_buckets
.half_life_days());
426 ASSERT_EQ(2u, scoring_params
.visited_count_buckets
.buckets().size());
427 EXPECT_EQ(std::make_pair(5.0, 300),
428 scoring_params
.visited_count_buckets
.buckets()[0]);
429 EXPECT_EQ(std::make_pair(0.0, 200),
430 scoring_params
.visited_count_buckets
.buckets()[1]);
433 TEST_F(OmniboxFieldTrialTest
, HalfLifeTimeDecay
) {
434 HUPScoringParams::ScoreBuckets buckets
;
436 // No decay by default.
437 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
439 buckets
.set_half_life_days(7);
440 EXPECT_EQ(0.5, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
441 EXPECT_EQ(0.25, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(14)));
442 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(0)));
443 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(-1)));
446 TEST_F(OmniboxFieldTrialTest
, DisableResultsCaching
) {
447 EXPECT_FALSE(OmniboxFieldTrial::DisableResultsCaching());
450 std::map
<std::string
, std::string
> params
;
451 params
[std::string(OmniboxFieldTrial::kDisableResultsCachingRule
)] = "true";
452 ASSERT_TRUE(variations::AssociateVariationParams(
453 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
454 base::FieldTrialList::CreateFieldTrial(
455 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
457 EXPECT_TRUE(OmniboxFieldTrial::DisableResultsCaching());
461 TEST_F(OmniboxFieldTrialTest
, GetSuggestPollingStrategy
) {
463 VerifySuggestPollingStrategy(
465 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
466 VerifySuggestPollingStrategy(
468 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
469 VerifySuggestPollingStrategy(
470 "TRUE", "xyz", false,
471 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
474 VerifySuggestPollingStrategy(
476 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
479 VerifySuggestPollingStrategy("true", "50", true, 50);
480 VerifySuggestPollingStrategy(NULL
, "35", false, 35);
481 VerifySuggestPollingStrategy(
483 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);