Home | History | Annotate | Download | only in omnibox
      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/variations/variations_util.h"
     16 #include "components/variations/entropy_provider.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 class 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
     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);
     72 }
     73 
     74 // static
     75 void 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.
     86 TEST_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.
    121 TEST_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 
    162 TEST_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::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);
    189 }
    190 
    191 TEST_F(OmniboxFieldTrialTest, GetUndemotableTopTypes) {
    192   {
    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));
    200   }
    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));
    217 }
    218 
    219 TEST_F(OmniboxFieldTrialTest, GetValueForRuleInContext) {
    220   {
    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));
    241   }
    242 
    243   base::FieldTrialList::CreateFieldTrial(
    244       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
    245 
    246   if (chrome::IsInstantExtendedAPIEnabled()) {
    247     // Tests with Instant Extended enabled.
    248     // Tests for rule 1.
    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",
    254                     "rule1",
    255                     AutocompleteInput::NTP);               // partial fallback
    256 
    257     // Tests for rule 2.
    258     ExpectRuleValue("rule2-1-*-value",
    259                     "rule2",
    260                     AutocompleteInput::NTP);               // partial fallback
    261     ExpectRuleValue("rule2-*-*-value",
    262                     "rule2", AutocompleteInput::OTHER);    // global fallback
    263 
    264     // Tests for rule 3.
    265     ExpectRuleValue("rule3-*-*-value",
    266                     "rule3",
    267                     AutocompleteInput::HOME_PAGE);         // global fallback
    268     ExpectRuleValue("rule3-*-*-value",
    269                     "rule3",
    270                     AutocompleteInput::OTHER);             // global fallback
    271 
    272     // Tests for rule 4.
    273     ExpectRuleValue("",
    274                     "rule4",
    275                     AutocompleteInput::BLANK);             // no global fallback
    276     ExpectRuleValue("",
    277                     "rule4",
    278                     AutocompleteInput::HOME_PAGE);         // no global fallback
    279 
    280     // Tests for rule 5 (a missing rule).
    281     ExpectRuleValue("",
    282                     "rule5", AutocompleteInput::OTHER);    // no rule at all
    283   } else {
    284     // Tests for rule 1.
    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",
    292                     "rule1",
    293                     AutocompleteInput::HOME_PAGE);         // exact match
    294     ExpectRuleValue("rule1-4-*-value",
    295                     "rule1", AutocompleteInput::OTHER);    // partial fallback
    296     ExpectRuleValue("rule1-*-*-value",
    297                     "rule1",
    298                     AutocompleteInput::                    // fallback to global
    299                     SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT);
    300     // Tests for rule 2.
    301     ExpectRuleValue("rule2-*-0-value",
    302                     "rule2",
    303                     AutocompleteInput::HOME_PAGE);         // partial fallback
    304     ExpectRuleValue("rule2-*-0-value",
    305                     "rule2", AutocompleteInput::OTHER);    // partial fallback
    306 
    307     // Tests for rule 3.
    308     ExpectRuleValue("rule3-*-*-value",
    309                     "rule3",
    310                     AutocompleteInput::HOME_PAGE);         // fallback to global
    311     ExpectRuleValue("rule3-*-*-value",
    312                     "rule3", AutocompleteInput::OTHER);    // fallback to global
    313 
    314     // Tests for rule 4.
    315     ExpectRuleValue("",
    316                     "rule4", AutocompleteInput::BLANK);    // no global fallback
    317     ExpectRuleValue("",
    318                     "rule4",
    319                     AutocompleteInput::HOME_PAGE);         // no global fallback
    320     ExpectRuleValue("rule4-4-0-value",
    321                     "rule4", AutocompleteInput::OTHER);    // exact match
    322 
    323     // Tests for rule 5 (a missing rule).
    324     ExpectRuleValue("",
    325                     "rule5", AutocompleteInput::OTHER);    // no rule at all
    326   }
    327 }
    328