Home | History | Annotate | Download | only in omnibox
      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.
      4 
      5 #include "components/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 "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"
     17 
     18 using metrics::OmniboxEventProto;
     19 
     20 class OmniboxFieldTrialTest : public testing::Test {
     21  public:
     22   OmniboxFieldTrialTest() {
     23     ResetFieldTrialList();
     24   }
     25 
     26   void ResetFieldTrialList() {
     27     // Destroy the existing FieldTrialList before creating a new one to avoid
     28     // a DCHECK.
     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();
     34   }
     35 
     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(
     40         name, group_name);
     41     trial->group();
     42     return trial;
     43   }
     44 
     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");
     53   }
     54 
     55   // EXPECTS 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);
     60 
     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);
     67 
     68  private:
     69   scoped_ptr<base::FieldTrialList> field_trial_list_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(OmniboxFieldTrialTest);
     72 };
     73 
     74 // static
     75 void OmniboxFieldTrialTest::VerifyDemotion(
     76     const OmniboxFieldTrial::DemotionMultipliers& demotions,
     77     AutocompleteMatchType::Type match_type,
     78     float expected_value) {
     79   OmniboxFieldTrial::DemotionMultipliers::const_iterator demotion_it =
     80       demotions.find(match_type);
     81   ASSERT_TRUE(demotion_it != demotions.end());
     82   EXPECT_FLOAT_EQ(expected_value, demotion_it->second);
     83 }
     84 
     85 // static
     86 void OmniboxFieldTrialTest::ExpectRuleValue(
     87     const std::string& rule_value,
     88     const std::string& rule,
     89     OmniboxEventProto::PageClassification page_classification) {
     90   EXPECT_EQ(rule_value,
     91             OmniboxFieldTrial::GetValueForRuleInContext(
     92                 rule, page_classification));
     93 }
     94 
     95 // Test if GetDisabledProviderTypes() properly parses various field trial
     96 // group names.
     97 TEST_F(OmniboxFieldTrialTest, GetDisabledProviderTypes) {
     98   EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
     99 
    100   {
    101     SCOPED_TRACE("Invalid groups");
    102     CreateTestTrial("AutocompleteDynamicTrial_0", "DisabledProviders_");
    103     EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
    104     ResetFieldTrialList();
    105     CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_XXX");
    106     EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
    107     ResetFieldTrialList();
    108     CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_12abc");
    109     EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
    110   }
    111 
    112   {
    113     SCOPED_TRACE("Valid group name, unsupported trial name.");
    114     ResetFieldTrialList();
    115     CreateTestTrial("UnsupportedTrialName", "DisabledProviders_20");
    116     EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes());
    117   }
    118 
    119   {
    120     SCOPED_TRACE("Valid field and group name.");
    121     ResetFieldTrialList();
    122     CreateTestTrial("AutocompleteDynamicTrial_2", "DisabledProviders_3");
    123     EXPECT_EQ(3, OmniboxFieldTrial::GetDisabledProviderTypes());
    124     // Two groups should be OR-ed together.
    125     CreateTestTrial("AutocompleteDynamicTrial_3", "DisabledProviders_6");
    126     EXPECT_EQ(7, OmniboxFieldTrial::GetDisabledProviderTypes());
    127   }
    128 }
    129 
    130 // Test if InZeroSuggestFieldTrial() properly parses various field trial
    131 // group names.
    132 TEST_F(OmniboxFieldTrialTest, ZeroSuggestFieldTrial) {
    133   // Default ZeroSuggest setting depends on OS.
    134 #if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \
    135     (defined(OS_MACOSX) && !defined(OS_IOS))
    136   EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
    137 #else
    138   EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
    139 #endif
    140 
    141   {
    142     SCOPED_TRACE("Disable ZeroSuggest.");
    143     ResetFieldTrialList();
    144     CreateDisableZeroSuggestTrial();
    145     EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
    146   }
    147 
    148   {
    149     SCOPED_TRACE("Bundled field trial parameters.");
    150     ResetFieldTrialList();
    151     std::map<std::string, std::string> params;
    152     params[std::string(OmniboxFieldTrial::kZeroSuggestRule)] = "true";
    153     ASSERT_TRUE(variations::AssociateVariationParams(
    154         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
    155     base::FieldTrialList::CreateFieldTrial(
    156         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
    157     EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
    158     EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
    159     EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
    160 
    161     ResetFieldTrialList();
    162     params[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule)] =
    163         "MostVisited";
    164     ASSERT_TRUE(variations::AssociateVariationParams(
    165         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
    166     base::FieldTrialList::CreateFieldTrial(
    167         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
    168     EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
    169     EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
    170     EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
    171 
    172     ResetFieldTrialList();
    173     params[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule)] =
    174         "AfterTyping";
    175     base::FieldTrialList::CreateFieldTrial(
    176         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
    177     ASSERT_TRUE(variations::AssociateVariationParams(
    178         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
    179     EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial());
    180     EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial());
    181     EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial());
    182   }
    183 }
    184 
    185 TEST_F(OmniboxFieldTrialTest, GetDemotionsByTypeWithFallback) {
    186   {
    187     std::map<std::string, std::string> params;
    188     params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":1:*"] =
    189         "1:50,2:0";
    190     params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":3:*"] =
    191         "5:100";
    192     params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":*:*"] = "1:25";
    193     ASSERT_TRUE(variations::AssociateVariationParams(
    194         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
    195   }
    196   base::FieldTrialList::CreateFieldTrial(
    197       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
    198   OmniboxFieldTrial::DemotionMultipliers demotions_by_type;
    199   OmniboxFieldTrial::GetDemotionsByType(
    200       OmniboxEventProto::NTP, &demotions_by_type);
    201   ASSERT_EQ(2u, demotions_by_type.size());
    202   VerifyDemotion(demotions_by_type, AutocompleteMatchType::HISTORY_URL, 0.5);
    203   VerifyDemotion(demotions_by_type, AutocompleteMatchType::HISTORY_TITLE, 0.0);
    204   OmniboxFieldTrial::GetDemotionsByType(
    205       OmniboxEventProto::HOME_PAGE, &demotions_by_type);
    206   ASSERT_EQ(1u, demotions_by_type.size());
    207   VerifyDemotion(demotions_by_type, AutocompleteMatchType::NAVSUGGEST, 1.0);
    208   OmniboxFieldTrial::GetDemotionsByType(
    209       OmniboxEventProto::BLANK, &demotions_by_type);
    210   ASSERT_EQ(1u, demotions_by_type.size());
    211   VerifyDemotion(demotions_by_type, AutocompleteMatchType::HISTORY_URL, 0.25);
    212 }
    213 
    214 TEST_F(OmniboxFieldTrialTest, GetValueForRuleInContext) {
    215   {
    216     std::map<std::string, std::string> params;
    217     // Rule 1 has some exact matches and fallbacks at every level.
    218     params["rule1:1:0"] = "rule1-1-0-value";  // NTP
    219     params["rule1:3:0"] = "rule1-3-0-value";  // HOME_PAGE
    220     params["rule1:4:1"] = "rule1-4-1-value";  // OTHER
    221     params["rule1:4:*"] = "rule1-4-*-value";  // OTHER
    222     params["rule1:*:1"] = "rule1-*-1-value";  // global
    223     params["rule1:*:*"] = "rule1-*-*-value";  // global
    224     // Rule 2 has no exact matches but has fallbacks.
    225     params["rule2:*:0"] = "rule2-*-0-value";  // global
    226     params["rule2:1:*"] = "rule2-1-*-value";  // NTP
    227     params["rule2:*:*"] = "rule2-*-*-value";  // global
    228     // Rule 3 has only a global fallback.
    229     params["rule3:*:*"] = "rule3-*-*-value";  // global
    230     // Rule 4 has an exact match but no fallbacks.
    231     params["rule4:4:0"] = "rule4-4-0-value";  // OTHER
    232     // Add a malformed rule to make sure it doesn't screw things up.
    233     params["unrecognized"] = "unrecognized-value";
    234     ASSERT_TRUE(variations::AssociateVariationParams(
    235         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
    236   }
    237 
    238   base::FieldTrialList::CreateFieldTrial(
    239       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
    240 
    241   if (chrome::IsInstantExtendedAPIEnabled()) {
    242     // Tests with Instant Extended enabled.
    243     // Tests for rule 1.
    244     ExpectRuleValue("rule1-4-1-value",
    245                     "rule1", OmniboxEventProto::OTHER);    // exact match
    246     ExpectRuleValue("rule1-*-1-value",
    247                     "rule1", OmniboxEventProto::BLANK);    // partial fallback
    248     ExpectRuleValue("rule1-*-1-value",
    249                     "rule1",
    250                     OmniboxEventProto::NTP);               // partial fallback
    251 
    252     // Tests for rule 2.
    253     ExpectRuleValue("rule2-1-*-value",
    254                     "rule2",
    255                     OmniboxEventProto::NTP);               // partial fallback
    256     ExpectRuleValue("rule2-*-*-value",
    257                     "rule2", OmniboxEventProto::OTHER);    // global fallback
    258 
    259     // Tests for rule 3.
    260     ExpectRuleValue("rule3-*-*-value",
    261                     "rule3",
    262                     OmniboxEventProto::HOME_PAGE);         // global fallback
    263     ExpectRuleValue("rule3-*-*-value",
    264                     "rule3",
    265                     OmniboxEventProto::OTHER);             // global fallback
    266 
    267     // Tests for rule 4.
    268     ExpectRuleValue("",
    269                     "rule4",
    270                     OmniboxEventProto::BLANK);             // no global fallback
    271     ExpectRuleValue("",
    272                     "rule4",
    273                     OmniboxEventProto::HOME_PAGE);         // no global fallback
    274 
    275     // Tests for rule 5 (a missing rule).
    276     ExpectRuleValue("",
    277                     "rule5", OmniboxEventProto::OTHER);    // no rule at all
    278   } else {
    279     // Tests for rule 1.
    280     ExpectRuleValue("rule1-1-0-value",
    281                     "rule1", OmniboxEventProto::NTP);      // exact match
    282     ExpectRuleValue("rule1-1-0-value",
    283                     "rule1", OmniboxEventProto::NTP);      // exact match
    284     ExpectRuleValue("rule1-*-*-value",
    285                     "rule1", OmniboxEventProto::BLANK);    // fallback to global
    286     ExpectRuleValue("rule1-3-0-value",
    287                     "rule1",
    288                     OmniboxEventProto::HOME_PAGE);         // exact match
    289     ExpectRuleValue("rule1-4-*-value",
    290                     "rule1", OmniboxEventProto::OTHER);    // partial fallback
    291     ExpectRuleValue("rule1-*-*-value",
    292                     "rule1",
    293                     OmniboxEventProto::                    // fallback to global
    294                     SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT);
    295     // Tests for rule 2.
    296     ExpectRuleValue("rule2-*-0-value",
    297                     "rule2",
    298                     OmniboxEventProto::HOME_PAGE);         // partial fallback
    299     ExpectRuleValue("rule2-*-0-value",
    300                     "rule2", OmniboxEventProto::OTHER);    // partial fallback
    301 
    302     // Tests for rule 3.
    303     ExpectRuleValue("rule3-*-*-value",
    304                     "rule3",
    305                     OmniboxEventProto::HOME_PAGE);         // fallback to global
    306     ExpectRuleValue("rule3-*-*-value",
    307                     "rule3", OmniboxEventProto::OTHER);    // fallback to global
    308 
    309     // Tests for rule 4.
    310     ExpectRuleValue("",
    311                     "rule4", OmniboxEventProto::BLANK);    // no global fallback
    312     ExpectRuleValue("",
    313                     "rule4",
    314                     OmniboxEventProto::HOME_PAGE);         // no global fallback
    315     ExpectRuleValue("rule4-4-0-value",
    316                     "rule4", OmniboxEventProto::OTHER);    // exact match
    317 
    318     // Tests for rule 5 (a missing rule).
    319     ExpectRuleValue("",
    320                     "rule5", OmniboxEventProto::OTHER);    // no rule at all
    321   }
    322 }
    323 
    324 TEST_F(OmniboxFieldTrialTest, HUPNewScoringFieldTrial) {
    325   {
    326     std::map<std::string, std::string> params;
    327     params[std::string(OmniboxFieldTrial::kHUPNewScoringEnabledParam)] = "1";
    328     params[std::string(
    329         OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam)] = "56";
    330     params[std::string(
    331         OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam)] = "77";
    332     params[std::string(
    333         OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam)] =
    334         "0.2:25,0.1:1001,2.3:777";
    335     params[std::string(
    336         OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam)] = "11";
    337     params[std::string(
    338         OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam)] = "31";
    339     params[std::string(
    340         OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam)] =
    341         "5:300,0:200";
    342     ASSERT_TRUE(variations::AssociateVariationParams(
    343         OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
    344   }
    345   base::FieldTrialList::CreateFieldTrial(
    346       OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
    347 
    348   HUPScoringParams scoring_params;
    349   OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params);
    350   EXPECT_TRUE(scoring_params.experimental_scoring_enabled);
    351   EXPECT_EQ(56, scoring_params.typed_count_buckets.relevance_cap());
    352   EXPECT_EQ(77, scoring_params.typed_count_buckets.half_life_days());
    353   ASSERT_EQ(3u, scoring_params.typed_count_buckets.buckets().size());
    354   EXPECT_EQ(std::make_pair(2.3, 777),
    355             scoring_params.typed_count_buckets.buckets()[0]);
    356   EXPECT_EQ(std::make_pair(0.2, 25),
    357             scoring_params.typed_count_buckets.buckets()[1]);
    358   EXPECT_EQ(std::make_pair(0.1, 1001),
    359             scoring_params.typed_count_buckets.buckets()[2]);
    360   EXPECT_EQ(11, scoring_params.visited_count_buckets.relevance_cap());
    361   EXPECT_EQ(31, scoring_params.visited_count_buckets.half_life_days());
    362   ASSERT_EQ(2u, scoring_params.visited_count_buckets.buckets().size());
    363   EXPECT_EQ(std::make_pair(5.0, 300),
    364             scoring_params.visited_count_buckets.buckets()[0]);
    365   EXPECT_EQ(std::make_pair(0.0, 200),
    366             scoring_params.visited_count_buckets.buckets()[1]);
    367 }
    368 
    369 TEST_F(OmniboxFieldTrialTest, HalfLifeTimeDecay) {
    370   HUPScoringParams::ScoreBuckets buckets;
    371 
    372   // No decay by default.
    373   EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
    374 
    375   buckets.set_half_life_days(7);
    376   EXPECT_EQ(0.5, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(7)));
    377   EXPECT_EQ(0.25, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(14)));
    378   EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(0)));
    379   EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(-1)));
    380 }
    381