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 "chrome/browser/omnibox/omnibox_field_trial.h"
6
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/entropy_provider.h"
16#include "chrome/common/metrics/variations/variations_util.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19class OmniboxFieldTrialTest : public testing::Test {
20 public:
21  OmniboxFieldTrialTest() {
22    ResetFieldTrialList();
23  }
24
25  void ResetFieldTrialList() {
26    // Destroy the existing FieldTrialList before creating a new one to avoid
27    // a DCHECK.
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();
33  }
34
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(
39        name, group_name);
40    trial->group();
41    return trial;
42  }
43
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);
49
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);
56
57 private:
58  scoped_ptr<base::FieldTrialList> field_trial_list_;
59
60  DISALLOW_COPY_AND_ASSIGN(OmniboxFieldTrialTest);
61};
62
63// static
64void 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);
72}
73
74// static
75void OmniboxFieldTrialTest::ExpectRuleValue(
76    const std::string& rule_value,
77    const std::string& rule,
78    AutocompleteInput::PageClassification page_classification) {
79  EXPECT_EQ(rule_value,
80            OmniboxFieldTrial::GetValueForRuleInContext(
81                rule, page_classification));
82}
83
84// Test if GetDisabledProviderTypes() properly parses various field trial
85// group names.
86TEST_F(OmniboxFieldTrialTest, GetDisabledProviderTypes) {
87  EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
88
89  {
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());
99  }
100
101  {
102    SCOPED_TRACE("Valid group name, unsupported trial name.");
103    ResetFieldTrialList();
104    CreateTestTrial("UnsupportedTrialName", "DisabledProviders_20");
105    EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
106  }
107
108  {
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());
116  }
117}
118
119// Test if InZeroSuggestFieldTrial() properly parses various field trial
120// group names.
121TEST_F(OmniboxFieldTrialTest, ZeroSuggestFieldTrial) {
122  EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
123
124  {
125    SCOPED_TRACE("Valid group name, unsupported trial name.");
126    ResetFieldTrialList();
127    CreateTestTrial("UnsupportedTrialName", "EnableZeroSuggest");
128    EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
129
130    ResetFieldTrialList();
131    CreateTestTrial("UnsupportedTrialName", "EnableZeroSuggest_Queries");
132    EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
133
134    ResetFieldTrialList();
135    CreateTestTrial("UnsupportedTrialName", "EnableZeroSuggest_URLS");
136    EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
137  }
138
139  {
140    SCOPED_TRACE("Valid trial name, unsupported group name.");
141    ResetFieldTrialList();
142    CreateTestTrial("AutocompleteDynamicTrial_2", "UnrelatedGroup");
143    EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
144  }
145
146  {
147    SCOPED_TRACE("Valid field and group name.");
148    ResetFieldTrialList();
149    CreateTestTrial("AutocompleteDynamicTrial_2", "EnableZeroSuggest");
150    EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
151
152    ResetFieldTrialList();
153    CreateTestTrial("AutocompleteDynamicTrial_2", "EnableZeroSuggest_Queries");
154    EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
155
156    ResetFieldTrialList();
157    CreateTestTrial("AutocompleteDynamicTrial_3", "EnableZeroSuggest_URLs");
158    EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
159  }
160}
161
162TEST_F(OmniboxFieldTrialTest, GetDemotionsByTypeWithFallback) {
163  {
164    std::map<std::string, std::string> params;
165    params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":1:*"] =
166        "1:50,2:0";
167    params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":3:*"] =
168        "5:100";
169    params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":*:*"] = "1:25";
170    ASSERT_TRUE(chrome_variations::AssociateVariationParams(
171        OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
172  }
173  base::FieldTrialList::CreateFieldTrial(
174      OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
175  OmniboxFieldTrial::DemotionMultipliers demotions_by_type;
176  OmniboxFieldTrial::GetDemotionsByType(
177      AutocompleteInput::NEW_TAB_PAGE, &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::HOMEPAGE, &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);
189}
190
191TEST_F(OmniboxFieldTrialTest, GetValueForRuleInContext) {
192  // This test starts with Instant Extended off (the default state), then
193  // enables Instant Extended and tests again on the same rules.
194
195  {
196    std::map<std::string, std::string> params;
197    // Rule 1 has some exact matches and fallbacks at every level.
198    params["rule1:1:0"] = "rule1-1-0-value";  // NEW_TAB_PAGE
199    params["rule1:3:0"] = "rule1-3-0-value";  // HOMEPAGE
200    params["rule1:4:1"] = "rule1-4-1-value";  // OTHER
201    params["rule1:4:*"] = "rule1-4-*-value";  // OTHER
202    params["rule1:*:1"] = "rule1-*-1-value";  // global
203    params["rule1:*:*"] = "rule1-*-*-value";  // global
204    // Rule 2 has no exact matches but has fallbacks.
205    params["rule2:*:0"] = "rule2-*-0-value";  // global
206    params["rule2:1:*"] = "rule2-1-*-value";  // NEW_TAB_PAGE
207    params["rule2:*:*"] = "rule2-*-*-value";  // global
208    // Rule 3 has only a global fallback.
209    params["rule3:*:*"] = "rule3-*-*-value";  // global
210    // Rule 4 has an exact match but no fallbacks.
211    params["rule4:4:0"] = "rule4-4-0-value";  // OTHER
212    // Add a malformed rule to make sure it doesn't screw things up.
213    params["unrecognized"] = "unrecognized-value";
214    ASSERT_TRUE(chrome_variations::AssociateVariationParams(
215        OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
216  }
217
218  base::FieldTrialList::CreateFieldTrial(
219      OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
220
221  // Tests with Instant Extended disabled.
222  // Tests for rule 1.
223  ExpectRuleValue("rule1-1-0-value",
224                  "rule1", AutocompleteInput::NEW_TAB_PAGE);  // exact match
225  ExpectRuleValue("rule1-1-0-value",
226                  "rule1", AutocompleteInput::NEW_TAB_PAGE);  // exact match
227  ExpectRuleValue("rule1-*-*-value",
228                  "rule1", AutocompleteInput::BLANK);     // fallback to global
229  ExpectRuleValue("rule1-3-0-value",
230                  "rule1", AutocompleteInput::HOMEPAGE);  // exact match
231  ExpectRuleValue("rule1-4-*-value",
232                  "rule1", AutocompleteInput::OTHER);     // partial fallback
233  ExpectRuleValue("rule1-*-*-value",
234                  "rule1",
235                  AutocompleteInput::                     // fallback to global
236                      SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT);
237  // Tests for rule 2.
238  ExpectRuleValue("rule2-*-0-value",
239                  "rule2", AutocompleteInput::HOMEPAGE);  // partial fallback
240  ExpectRuleValue("rule2-*-0-value",
241                  "rule2", AutocompleteInput::OTHER);     // partial fallback
242
243  // Tests for rule 3.
244  ExpectRuleValue("rule3-*-*-value",
245                  "rule3", AutocompleteInput::HOMEPAGE);  // fallback to global
246  ExpectRuleValue("rule3-*-*-value",
247                  "rule3", AutocompleteInput::OTHER);     // fallback to global
248
249  // Tests for rule 4.
250  ExpectRuleValue("",
251                  "rule4", AutocompleteInput::BLANK);     // no global fallback
252  ExpectRuleValue("",
253                  "rule4", AutocompleteInput::HOMEPAGE);  // no global fallback
254  ExpectRuleValue("rule4-4-0-value",
255                  "rule4", AutocompleteInput::OTHER);     // exact match
256
257  // Tests for rule 5 (a missing rule).
258  ExpectRuleValue("",
259                  "rule5", AutocompleteInput::OTHER);     // no rule at all
260
261  // Now change the Instant Extended state and run analogous tests.
262  // Instant Extended only works on non-mobile platforms.
263#if !defined(OS_IOS) && !defined(OS_ANDROID)
264  chrome::ResetInstantExtendedOptInStateGateForTest();
265  CommandLine::ForCurrentProcess()->AppendSwitch(
266      switches::kEnableInstantExtendedAPI);
267
268  // Tests with Instant Extended enabled.
269  // Tests for rule 1.
270  ExpectRuleValue("rule1-4-1-value",
271                  "rule1", AutocompleteInput::OTHER);     // exact match
272  ExpectRuleValue("rule1-*-1-value",
273                  "rule1", AutocompleteInput::BLANK);     // partial fallback
274  ExpectRuleValue("rule1-*-1-value",
275                  "rule1",
276                  AutocompleteInput::NEW_TAB_PAGE);       // partial fallback
277
278  // Tests for rule 2.
279  ExpectRuleValue("rule2-1-*-value",
280                  "rule2",
281                  AutocompleteInput::NEW_TAB_PAGE);       // partial fallback
282  ExpectRuleValue("rule2-*-*-value",
283                  "rule2", AutocompleteInput::OTHER);     // global fallback
284
285  // Tests for rule 3.
286  ExpectRuleValue("rule3-*-*-value",
287                  "rule3", AutocompleteInput::HOMEPAGE);  // global fallback
288  ExpectRuleValue("rule3-*-*-value",
289                  "rule3", AutocompleteInput::OTHER);     // global fallback
290
291  // Tests for rule 4.
292  ExpectRuleValue("",
293                  "rule4", AutocompleteInput::BLANK);     // no global fallback
294  ExpectRuleValue("",
295                  "rule4", AutocompleteInput::HOMEPAGE);  // no global fallback
296
297  // Tests for rule 5 (a missing rule).
298  ExpectRuleValue("",
299                  "rule5", AutocompleteInput::OTHER);     // no rule at all
300#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
301}
302