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/browser/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.
199 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
201 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
205 SCOPED_TRACE("Disable ZeroSuggest.");
206 ResetFieldTrialList();
207 CreateDisableZeroSuggestTrial();
208 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
212 SCOPED_TRACE("Bundled field trial parameters.");
213 ResetFieldTrialList();
214 std::map
<std::string
, std::string
> params
;
215 params
[std::string(OmniboxFieldTrial::kZeroSuggestRule
)] = "true";
216 ASSERT_TRUE(variations::AssociateVariationParams(
217 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
218 base::FieldTrialList::CreateFieldTrial(
219 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
220 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
221 #if defined(OS_ANDROID)
222 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
224 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
226 #if defined(OS_IOS) || defined(OS_ANDROID)
227 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
229 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
232 ResetFieldTrialList();
233 params
[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule
)] =
235 ASSERT_TRUE(variations::AssociateVariationParams(
236 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
237 base::FieldTrialList::CreateFieldTrial(
238 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
239 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
240 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
241 #if defined(OS_IOS) || defined(OS_ANDROID)
242 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
244 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
247 ResetFieldTrialList();
248 params
.erase(std::string(OmniboxFieldTrial::kZeroSuggestVariantRule
));
249 params
[std::string(OmniboxFieldTrial::kSuggestVariantRule
)] =
251 base::FieldTrialList::CreateFieldTrial(
252 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
253 ASSERT_TRUE(variations::AssociateVariationParams(
254 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
255 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
256 #if defined(OS_ANDROID)
257 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
259 EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
261 EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
265 TEST_F(OmniboxFieldTrialTest
, GetDemotionsByTypeWithFallback
) {
267 std::map
<std::string
, std::string
> params
;
268 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":1:*"] =
270 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":3:*"] =
272 params
[std::string(OmniboxFieldTrial::kDemoteByTypeRule
) + ":*:*"] = "1:25";
273 ASSERT_TRUE(variations::AssociateVariationParams(
274 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
276 base::FieldTrialList::CreateFieldTrial(
277 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
278 OmniboxFieldTrial::DemotionMultipliers demotions_by_type
;
279 OmniboxFieldTrial::GetDemotionsByType(
280 OmniboxEventProto::NTP
, &demotions_by_type
);
281 ASSERT_EQ(2u, demotions_by_type
.size());
282 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_URL
, 0.5);
283 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_TITLE
, 0.0);
284 OmniboxFieldTrial::GetDemotionsByType(
285 OmniboxEventProto::HOME_PAGE
, &demotions_by_type
);
286 ASSERT_EQ(1u, demotions_by_type
.size());
287 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::NAVSUGGEST
, 1.0);
288 OmniboxFieldTrial::GetDemotionsByType(
289 OmniboxEventProto::BLANK
, &demotions_by_type
);
290 ASSERT_EQ(1u, demotions_by_type
.size());
291 VerifyDemotion(demotions_by_type
, AutocompleteMatchType::HISTORY_URL
, 0.25);
294 TEST_F(OmniboxFieldTrialTest
, GetValueForRuleInContext
) {
296 std::map
<std::string
, std::string
> params
;
297 // Rule 1 has some exact matches and fallbacks at every level.
298 params
["rule1:1:0"] = "rule1-1-0-value"; // NTP
299 params
["rule1:3:0"] = "rule1-3-0-value"; // HOME_PAGE
300 params
["rule1:4:1"] = "rule1-4-1-value"; // OTHER
301 params
["rule1:4:*"] = "rule1-4-*-value"; // OTHER
302 params
["rule1:*:1"] = "rule1-*-1-value"; // global
303 params
["rule1:*:*"] = "rule1-*-*-value"; // global
304 // Rule 2 has no exact matches but has fallbacks.
305 params
["rule2:*:0"] = "rule2-*-0-value"; // global
306 params
["rule2:1:*"] = "rule2-1-*-value"; // NTP
307 params
["rule2:*:*"] = "rule2-*-*-value"; // global
308 // Rule 3 has only a global fallback.
309 params
["rule3:*:*"] = "rule3-*-*-value"; // global
310 // Rule 4 has an exact match but no fallbacks.
311 params
["rule4:4:0"] = "rule4-4-0-value"; // OTHER
312 // Add a malformed rule to make sure it doesn't screw things up.
313 params
["unrecognized"] = "unrecognized-value";
314 ASSERT_TRUE(variations::AssociateVariationParams(
315 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
318 base::FieldTrialList::CreateFieldTrial(
319 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
321 if (search::IsInstantExtendedAPIEnabled()) {
322 // Tests with Instant Extended enabled.
324 ExpectRuleValue("rule1-4-1-value",
325 "rule1", OmniboxEventProto::OTHER
); // exact match
326 ExpectRuleValue("rule1-*-1-value",
327 "rule1", OmniboxEventProto::BLANK
); // partial fallback
328 ExpectRuleValue("rule1-*-1-value",
330 OmniboxEventProto::NTP
); // partial fallback
333 ExpectRuleValue("rule2-1-*-value",
335 OmniboxEventProto::NTP
); // partial fallback
336 ExpectRuleValue("rule2-*-*-value",
337 "rule2", OmniboxEventProto::OTHER
); // global fallback
340 ExpectRuleValue("rule3-*-*-value",
342 OmniboxEventProto::HOME_PAGE
); // global fallback
343 ExpectRuleValue("rule3-*-*-value",
345 OmniboxEventProto::OTHER
); // global fallback
350 OmniboxEventProto::BLANK
); // no global fallback
353 OmniboxEventProto::HOME_PAGE
); // no global fallback
355 // Tests for rule 5 (a missing rule).
357 "rule5", OmniboxEventProto::OTHER
); // no rule at all
360 ExpectRuleValue("rule1-1-0-value",
361 "rule1", OmniboxEventProto::NTP
); // exact match
362 ExpectRuleValue("rule1-1-0-value",
363 "rule1", OmniboxEventProto::NTP
); // exact match
364 ExpectRuleValue("rule1-*-*-value",
365 "rule1", OmniboxEventProto::BLANK
); // fallback to global
366 ExpectRuleValue("rule1-3-0-value",
368 OmniboxEventProto::HOME_PAGE
); // exact match
369 ExpectRuleValue("rule1-4-*-value",
370 "rule1", OmniboxEventProto::OTHER
); // partial fallback
371 ExpectRuleValue("rule1-*-*-value",
373 OmniboxEventProto:: // fallback to global
374 SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT
);
376 ExpectRuleValue("rule2-*-0-value",
378 OmniboxEventProto::HOME_PAGE
); // partial fallback
379 ExpectRuleValue("rule2-*-0-value",
380 "rule2", OmniboxEventProto::OTHER
); // partial fallback
383 ExpectRuleValue("rule3-*-*-value",
385 OmniboxEventProto::HOME_PAGE
); // fallback to global
386 ExpectRuleValue("rule3-*-*-value",
387 "rule3", OmniboxEventProto::OTHER
); // fallback to global
391 "rule4", OmniboxEventProto::BLANK
); // no global fallback
394 OmniboxEventProto::HOME_PAGE
); // no global fallback
395 ExpectRuleValue("rule4-4-0-value",
396 "rule4", OmniboxEventProto::OTHER
); // exact match
398 // Tests for rule 5 (a missing rule).
400 "rule5", OmniboxEventProto::OTHER
); // no rule at all
404 TEST_F(OmniboxFieldTrialTest
, HUPNewScoringFieldTrial
) {
406 std::map
<std::string
, std::string
> params
;
407 params
[std::string(OmniboxFieldTrial::kHUPNewScoringEnabledParam
)] = "1";
409 OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam
)] = "56";
411 OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam
)] = "77";
413 OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam
)] =
414 "0.2:25,0.1:1001,2.3:777";
416 OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam
)] = "11";
418 OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam
)] = "31";
420 OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam
)] =
422 ASSERT_TRUE(variations::AssociateVariationParams(
423 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
425 base::FieldTrialList::CreateFieldTrial(
426 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
428 HUPScoringParams scoring_params
;
429 OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params
);
430 EXPECT_TRUE(scoring_params
.experimental_scoring_enabled
);
431 EXPECT_EQ(56, scoring_params
.typed_count_buckets
.relevance_cap());
432 EXPECT_EQ(77, scoring_params
.typed_count_buckets
.half_life_days());
433 ASSERT_EQ(3u, scoring_params
.typed_count_buckets
.buckets().size());
434 EXPECT_EQ(std::make_pair(2.3, 777),
435 scoring_params
.typed_count_buckets
.buckets()[0]);
436 EXPECT_EQ(std::make_pair(0.2, 25),
437 scoring_params
.typed_count_buckets
.buckets()[1]);
438 EXPECT_EQ(std::make_pair(0.1, 1001),
439 scoring_params
.typed_count_buckets
.buckets()[2]);
440 EXPECT_EQ(11, scoring_params
.visited_count_buckets
.relevance_cap());
441 EXPECT_EQ(31, scoring_params
.visited_count_buckets
.half_life_days());
442 ASSERT_EQ(2u, scoring_params
.visited_count_buckets
.buckets().size());
443 EXPECT_EQ(std::make_pair(5.0, 300),
444 scoring_params
.visited_count_buckets
.buckets()[0]);
445 EXPECT_EQ(std::make_pair(0.0, 200),
446 scoring_params
.visited_count_buckets
.buckets()[1]);
449 TEST_F(OmniboxFieldTrialTest
, HalfLifeTimeDecay
) {
450 HUPScoringParams::ScoreBuckets buckets
;
452 // No decay by default.
453 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
455 buckets
.set_half_life_days(7);
456 EXPECT_EQ(0.5, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
457 EXPECT_EQ(0.25, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(14)));
458 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(0)));
459 EXPECT_EQ(1.0, buckets
.HalfLifeTimeDecay(base::TimeDelta::FromDays(-1)));
462 TEST_F(OmniboxFieldTrialTest
, DisableResultsCaching
) {
463 EXPECT_FALSE(OmniboxFieldTrial::DisableResultsCaching());
466 std::map
<std::string
, std::string
> params
;
467 params
[std::string(OmniboxFieldTrial::kDisableResultsCachingRule
)] = "true";
468 ASSERT_TRUE(variations::AssociateVariationParams(
469 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A", params
));
470 base::FieldTrialList::CreateFieldTrial(
471 OmniboxFieldTrial::kBundledExperimentFieldTrialName
, "A");
473 EXPECT_TRUE(OmniboxFieldTrial::DisableResultsCaching());
477 TEST_F(OmniboxFieldTrialTest
, GetSuggestPollingStrategy
) {
479 VerifySuggestPollingStrategy(
481 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
482 VerifySuggestPollingStrategy(
484 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
485 VerifySuggestPollingStrategy(
486 "TRUE", "xyz", false,
487 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
490 VerifySuggestPollingStrategy(
492 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);
495 VerifySuggestPollingStrategy("true", "50", true, 50);
496 VerifySuggestPollingStrategy(NULL
, "35", false, 35);
497 VerifySuggestPollingStrategy(
499 OmniboxFieldTrial::kDefaultMinimumTimeBetweenSuggestQueriesMs
);