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 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::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 191TEST_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 219TEST_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