diff options
author | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 10:37:23 +0000 |
---|---|---|
committer | hashimoto@chromium.org <hashimoto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 10:39:32 +0000 |
commit | 4c583b681190c262b5a95d0a3f9e6a44641925f9 (patch) | |
tree | f90d564759639886b2f373fac42bbd1b1572f2ec /components | |
parent | e93710a4dc1ac82407acabe799a37a24f7820df0 (diff) | |
download | chromium_src-4c583b681190c262b5a95d0a3f9e6a44641925f9.zip chromium_src-4c583b681190c262b5a95d0a3f9e6a44641925f9.tar.gz chromium_src-4c583b681190c262b5a95d0a3f9e6a44641925f9.tar.bz2 |
Move OmniboxFieldTrial to components/omnibox
Move omnibox_field_trial{.cc,.h,_unittest.cc} to components/omnibox.
Add components/omnibox/omnibox_switches.{cc,h}
BUG=371538
TBR=sky@chromium.org for include fix under chrome/browser.
Review URL: https://codereview.chromium.org/447183003
Cr-Commit-Position: refs/heads/master@{#288315}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288315 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r-- | components/components_tests.gyp | 1 | ||||
-rw-r--r-- | components/omnibox.gypi | 6 | ||||
-rw-r--r-- | components/omnibox/DEPS | 2 | ||||
-rw-r--r-- | components/omnibox/omnibox_field_trial.cc | 442 | ||||
-rw-r--r-- | components/omnibox/omnibox_field_trial.h | 347 | ||||
-rw-r--r-- | components/omnibox/omnibox_field_trial_unittest.cc | 380 | ||||
-rw-r--r-- | components/omnibox/omnibox_switches.cc | 15 | ||||
-rw-r--r-- | components/omnibox/omnibox_switches.h | 15 |
8 files changed, 1208 insertions, 0 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index e8d7f9d..8c8d01f 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -138,6 +138,7 @@ 'omaha_query_params/omaha_query_params_unittest.cc', 'omnibox/autocomplete_input_unittest.cc', 'omnibox/autocomplete_match_unittest.cc', + 'omnibox/omnibox_field_trial_unittest.cc', 'os_crypt/ie7_password_win_unittest.cc', 'os_crypt/keychain_password_mac_unittest.mm', 'os_crypt/os_crypt_unittest.cc', diff --git a/components/omnibox.gypi b/components/omnibox.gypi index 6721110..63b399f 100644 --- a/components/omnibox.gypi +++ b/components/omnibox.gypi @@ -12,7 +12,9 @@ '../base/base.gyp:base', '../net/net.gyp:net', '../url/url.gyp:url_lib', + 'search', 'search_engines', + 'variations', 'component_metrics_proto', 'components_resources.gyp:components_resources', 'url_fixer', @@ -32,6 +34,10 @@ 'omnibox/autocomplete_provider.h', 'omnibox/autocomplete_provider_listener.h', 'omnibox/autocomplete_scheme_classifier.h', + 'omnibox/omnibox_field_trial.cc', + 'omnibox/omnibox_field_trial.h', + 'omnibox/omnibox_switches.cc', + 'omnibox/omnibox_switches.h', 'omnibox/search_suggestion_parser.cc', 'omnibox/search_suggestion_parser.h', 'omnibox/url_prefix.cc', diff --git a/components/omnibox/DEPS b/components/omnibox/DEPS index a919c94..86542c8 100644 --- a/components/omnibox/DEPS +++ b/components/omnibox/DEPS @@ -1,7 +1,9 @@ include_rules = [ "+components/metrics/proto", + "+components/search", "+components/search_engines", "+components/url_fixer", + "+components/variations", "+grit", "+net", "+url", diff --git a/components/omnibox/omnibox_field_trial.cc b/components/omnibox/omnibox_field_trial.cc new file mode 100644 index 0000000..943b5dc --- /dev/null +++ b/components/omnibox/omnibox_field_trial.cc @@ -0,0 +1,442 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/omnibox/omnibox_field_trial.h" + +#include <cmath> +#include <string> + +#include "base/command_line.h" +#include "base/metrics/field_trial.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "components/metrics/proto/omnibox_event.pb.h" +#include "components/omnibox/omnibox_switches.h" +#include "components/search/search.h" +#include "components/variations/active_field_trials.h" +#include "components/variations/metrics_util.h" +#include "components/variations/variations_associated_data.h" + +using metrics::OmniboxEventProto; + +namespace { + +typedef std::map<std::string, std::string> VariationParams; +typedef HUPScoringParams::ScoreBuckets ScoreBuckets; + +// Field trial names. +const char kStopTimerFieldTrialName[] = "OmniboxStopTimer"; + +// The autocomplete dynamic field trial name prefix. Each field trial is +// configured dynamically and is retrieved automatically by Chrome during +// the startup. +const char kAutocompleteDynamicFieldTrialPrefix[] = "AutocompleteDynamicTrial_"; +// The maximum number of the autocomplete dynamic field trials (aka layers). +const int kMaxAutocompleteDynamicFieldTrials = 5; + + +// Concatenates the autocomplete dynamic field trial prefix with a field trial +// ID to form a complete autocomplete field trial name. +std::string DynamicFieldTrialName(int id) { + return base::StringPrintf("%s%d", kAutocompleteDynamicFieldTrialPrefix, id); +} + +void InitializeScoreBuckets(const VariationParams& params, + const char* relevance_cap_param, + const char* half_life_param, + const char* score_buckets_param, + ScoreBuckets* score_buckets) { + VariationParams::const_iterator it = params.find(relevance_cap_param); + if (it != params.end()) { + int relevance_cap; + if (base::StringToInt(it->second, &relevance_cap)) + score_buckets->set_relevance_cap(relevance_cap); + } + + it = params.find(half_life_param); + if (it != params.end()) { + int half_life_days; + if (base::StringToInt(it->second, &half_life_days)) + score_buckets->set_half_life_days(half_life_days); + } + + it = params.find(score_buckets_param); + if (it != params.end()) { + // The value of the score bucket is a comma-separated list of + // {DecayedCount + ":" + MaxRelevance}. + base::StringPairs kv_pairs; + if (base::SplitStringIntoKeyValuePairs(it->second, ':', ',', &kv_pairs)) { + for (base::StringPairs::const_iterator it = kv_pairs.begin(); + it != kv_pairs.end(); ++it) { + ScoreBuckets::CountMaxRelevance bucket; + base::StringToDouble(it->first, &bucket.first); + base::StringToInt(it->second, &bucket.second); + score_buckets->buckets().push_back(bucket); + } + std::sort(score_buckets->buckets().begin(), + score_buckets->buckets().end(), + std::greater<ScoreBuckets::CountMaxRelevance>()); + } + } +} + +} // namespace + +HUPScoringParams::ScoreBuckets::ScoreBuckets() + : relevance_cap_(-1), + half_life_days_(-1) { +} + +HUPScoringParams::ScoreBuckets::~ScoreBuckets() { +} + +double HUPScoringParams::ScoreBuckets::HalfLifeTimeDecay( + const base::TimeDelta& elapsed_time) const { + double time_ms; + if ((half_life_days_ <= 0) || + ((time_ms = elapsed_time.InMillisecondsF()) <= 0)) + return 1.0; + + const double half_life_intervals = + time_ms / base::TimeDelta::FromDays(half_life_days_).InMillisecondsF(); + return pow(2.0, -half_life_intervals); +} + +void OmniboxFieldTrial::ActivateDynamicTrials() { + // Initialize all autocomplete dynamic field trials. This method may be + // called multiple times. + for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) + base::FieldTrialList::FindValue(DynamicFieldTrialName(i)); +} + +int OmniboxFieldTrial::GetDisabledProviderTypes() { + // Make sure that Autocomplete dynamic field trials are activated. It's OK to + // call this method multiple times. + ActivateDynamicTrials(); + + // Look for group names in form of "DisabledProviders_<mask>" where "mask" + // is a bitmap of disabled provider types (AutocompleteProvider::Type). + int provider_types = 0; + for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) { + std::string group_name = base::FieldTrialList::FindFullName( + DynamicFieldTrialName(i)); + const char kDisabledProviders[] = "DisabledProviders_"; + if (!StartsWithASCII(group_name, kDisabledProviders, true)) + continue; + int types = 0; + if (!base::StringToInt(base::StringPiece( + group_name.substr(strlen(kDisabledProviders))), &types)) + continue; + provider_types |= types; + } + return provider_types; +} + +void OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes( + std::vector<uint32>* field_trial_hashes) { + field_trial_hashes->clear(); + for (int i = 0; i < kMaxAutocompleteDynamicFieldTrials; ++i) { + const std::string& trial_name = DynamicFieldTrialName(i); + if (base::FieldTrialList::TrialExists(trial_name)) + field_trial_hashes->push_back(metrics::HashName(trial_name)); + } + if (base::FieldTrialList::TrialExists(kBundledExperimentFieldTrialName)) { + field_trial_hashes->push_back( + metrics::HashName(kBundledExperimentFieldTrialName)); + } +} + +base::TimeDelta OmniboxFieldTrial::StopTimerFieldTrialDuration() { + int stop_timer_ms; + if (base::StringToInt( + base::FieldTrialList::FindFullName(kStopTimerFieldTrialName), + &stop_timer_ms)) + return base::TimeDelta::FromMilliseconds(stop_timer_ms); + return base::TimeDelta::FromMilliseconds(1500); +} + +bool OmniboxFieldTrial::InZeroSuggestFieldTrial() { + if (variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, kZeroSuggestRule) == "true") + return true; + if (variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, kZeroSuggestRule) == "false") + return false; +#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) + return true; +#else + return false; +#endif +} + +bool OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kZeroSuggestVariantRule) == "MostVisited"; +} + +bool OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kZeroSuggestVariantRule) == "AfterTyping"; +} + +bool OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kZeroSuggestVariantRule) == "Personalized"; +} + +bool OmniboxFieldTrial::ShortcutsScoringMaxRelevance( + OmniboxEventProto::PageClassification current_page_classification, + int* max_relevance) { + // The value of the rule is a string that encodes an integer containing + // the max relevance. + const std::string& max_relevance_str = + OmniboxFieldTrial::GetValueForRuleInContext( + kShortcutsScoringMaxRelevanceRule, current_page_classification); + if (max_relevance_str.empty()) + return false; + if (!base::StringToInt(max_relevance_str, max_relevance)) + return false; + return true; +} + +bool OmniboxFieldTrial::SearchHistoryPreventInlining( + OmniboxEventProto::PageClassification current_page_classification) { + return OmniboxFieldTrial::GetValueForRuleInContext( + kSearchHistoryRule, current_page_classification) == "PreventInlining"; +} + +bool OmniboxFieldTrial::SearchHistoryDisable( + OmniboxEventProto::PageClassification current_page_classification) { + return OmniboxFieldTrial::GetValueForRuleInContext( + kSearchHistoryRule, current_page_classification) == "Disable"; +} + +void OmniboxFieldTrial::GetDemotionsByType( + OmniboxEventProto::PageClassification current_page_classification, + DemotionMultipliers* demotions_by_type) { + demotions_by_type->clear(); + std::string demotion_rule = OmniboxFieldTrial::GetValueForRuleInContext( + kDemoteByTypeRule, current_page_classification); + // If there is no demotion rule for this context, then use the default + // value for that context. At the moment the default value is non-empty + // only for the fakebox-focus context. + if (demotion_rule.empty() && + (current_page_classification == + OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS)) + demotion_rule = "1:61,2:61,3:61,4:61,16:61"; + + // The value of the DemoteByType rule is a comma-separated list of + // {ResultType + ":" + Number} where ResultType is an AutocompleteMatchType:: + // Type enum represented as an integer and Number is an integer number + // between 0 and 100 inclusive. Relevance scores of matches of that result + // type are multiplied by Number / 100. 100 means no change. + base::StringPairs kv_pairs; + if (base::SplitStringIntoKeyValuePairs(demotion_rule, ':', ',', &kv_pairs)) { + for (base::StringPairs::const_iterator it = kv_pairs.begin(); + it != kv_pairs.end(); ++it) { + // This is a best-effort conversion; we trust the hand-crafted parameters + // downloaded from the server to be perfect. There's no need to handle + // errors smartly. + int k, v; + base::StringToInt(it->first, &k); + base::StringToInt(it->second, &v); + (*demotions_by_type)[static_cast<AutocompleteMatchType::Type>(k)] = + static_cast<float>(v) / 100.0f; + } + } +} + +void OmniboxFieldTrial::GetExperimentalHUPScoringParams( + HUPScoringParams* scoring_params) { + scoring_params->experimental_scoring_enabled = false; + + VariationParams params; + if (!variations::GetVariationParams(kBundledExperimentFieldTrialName, + ¶ms)) + return; + + VariationParams::const_iterator it = params.find(kHUPNewScoringEnabledParam); + if (it != params.end()) { + int enabled = 0; + if (base::StringToInt(it->second, &enabled)) + scoring_params->experimental_scoring_enabled = (enabled != 0); + } + + InitializeScoreBuckets(params, kHUPNewScoringTypedCountRelevanceCapParam, + kHUPNewScoringTypedCountHalfLifeTimeParam, + kHUPNewScoringTypedCountScoreBucketsParam, + &scoring_params->typed_count_buckets); + InitializeScoreBuckets(params, kHUPNewScoringVisitedCountRelevanceCapParam, + kHUPNewScoringVisitedCountHalfLifeTimeParam, + kHUPNewScoringVisitedCountScoreBucketsParam, + &scoring_params->visited_count_buckets); +} + +int OmniboxFieldTrial::HQPBookmarkValue() { + std::string bookmark_value_str = + variations::GetVariationParamValue(kBundledExperimentFieldTrialName, + kHQPBookmarkValueRule); + if (bookmark_value_str.empty()) + return 10; + // This is a best-effort conversion; we trust the hand-crafted parameters + // downloaded from the server to be perfect. There's no need for handle + // errors smartly. + int bookmark_value; + base::StringToInt(bookmark_value_str, &bookmark_value); + return bookmark_value; +} + +bool OmniboxFieldTrial::HQPAllowMatchInTLDValue() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kHQPAllowMatchInTLDRule) == "true"; +} + +bool OmniboxFieldTrial::HQPAllowMatchInSchemeValue() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kHQPAllowMatchInSchemeRule) == "true"; +} + +bool OmniboxFieldTrial::BookmarksIndexURLsValue() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kBookmarksIndexURLsRule) == "true"; +} + +bool OmniboxFieldTrial::DisableInlining() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kDisableInliningRule) == "true"; +} + +bool OmniboxFieldTrial::EnableAnswersInSuggest() { + const CommandLine* cl = CommandLine::ForCurrentProcess(); + if (cl->HasSwitch(switches::kDisableAnswersInSuggest)) + return false; + if (cl->HasSwitch(switches::kEnableAnswersInSuggest)) + return true; + + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kAnswersInSuggestRule) == "true"; +} + +bool OmniboxFieldTrial::AddUWYTMatchEvenIfPromotedURLs() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kAddUWYTMatchEvenIfPromotedURLsRule) == "true"; +} + +bool OmniboxFieldTrial::DisplayHintTextWhenPossible() { + return variations::GetVariationParamValue( + kBundledExperimentFieldTrialName, + kDisplayHintTextWhenPossibleRule) == "true"; +} + +const char OmniboxFieldTrial::kBundledExperimentFieldTrialName[] = + "OmniboxBundledExperimentV1"; +const char OmniboxFieldTrial::kShortcutsScoringMaxRelevanceRule[] = + "ShortcutsScoringMaxRelevance"; +const char OmniboxFieldTrial::kSearchHistoryRule[] = "SearchHistory"; +const char OmniboxFieldTrial::kDemoteByTypeRule[] = "DemoteByType"; +const char OmniboxFieldTrial::kHQPBookmarkValueRule[] = + "HQPBookmarkValue"; +const char OmniboxFieldTrial::kHQPAllowMatchInTLDRule[] = "HQPAllowMatchInTLD"; +const char OmniboxFieldTrial::kHQPAllowMatchInSchemeRule[] = + "HQPAllowMatchInScheme"; +const char OmniboxFieldTrial::kZeroSuggestRule[] = "ZeroSuggest"; +const char OmniboxFieldTrial::kZeroSuggestVariantRule[] = "ZeroSuggestVariant"; +const char OmniboxFieldTrial::kBookmarksIndexURLsRule[] = "BookmarksIndexURLs"; +const char OmniboxFieldTrial::kDisableInliningRule[] = "DisableInlining"; +const char OmniboxFieldTrial::kAnswersInSuggestRule[] = "AnswersInSuggest"; +const char OmniboxFieldTrial::kAddUWYTMatchEvenIfPromotedURLsRule[] = + "AddUWYTMatchEvenIfPromotedURLs"; +const char OmniboxFieldTrial::kDisplayHintTextWhenPossibleRule[] = + "DisplayHintTextWhenPossible"; + +const char OmniboxFieldTrial::kHUPNewScoringEnabledParam[] = + "HUPExperimentalScoringEnabled"; +const char OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam[] = + "TypedCountRelevanceCap"; +const char OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam[] = + "TypedCountHalfLifeTime"; +const char OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam[] = + "TypedCountScoreBuckets"; +const char OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam[] = + "VisitedCountRelevanceCap"; +const char OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam[] = + "VisitedCountHalfLifeTime"; +const char OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam[] = + "VisitedCountScoreBuckets"; + +// Background and implementation details: +// +// Each experiment group in any field trial can come with an optional set of +// parameters (key-value pairs). In the bundled omnibox experiment +// (kBundledExperimentFieldTrialName), each experiment group comes with a +// list of parameters in the form: +// key=<Rule>: +// <OmniboxEventProto::PageClassification (as an int)>: +// <whether Instant Extended is enabled (as a 1 or 0)> +// (note that there are no linebreaks in keys; this format is for +// presentation only> +// value=<arbitrary string> +// Both the OmniboxEventProto::PageClassification and the Instant Extended +// entries can be "*", which means this rule applies for all values of the +// matching portion of the context. +// One example parameter is +// key=SearchHistory:6:1 +// value=PreventInlining +// This means in page classification context 6 (a search result page doing +// search term replacement) with Instant Extended enabled, the SearchHistory +// experiment should PreventInlining. +// +// When an exact match to the rule in the current context is missing, we +// give preference to a wildcard rule that matches the instant extended +// context over a wildcard rule that matches the page classification +// context. Hopefully, though, users will write their field trial configs +// so as not to rely on this fall back order. +// +// In short, this function tries to find the value associated with key +// |rule|:|page_classification|:|instant_extended|, failing that it looks up +// |rule|:*:|instant_extended|, failing that it looks up +// |rule|:|page_classification|:*, failing that it looks up |rule|:*:*, +// and failing that it returns the empty string. +std::string OmniboxFieldTrial::GetValueForRuleInContext( + const std::string& rule, + OmniboxEventProto::PageClassification page_classification) { + VariationParams params; + if (!variations::GetVariationParams(kBundledExperimentFieldTrialName, + ¶ms)) { + return std::string(); + } + const std::string page_classification_str = + base::IntToString(static_cast<int>(page_classification)); + const std::string instant_extended = + chrome::IsInstantExtendedAPIEnabled() ? "1" : "0"; + // Look up rule in this exact context. + VariationParams::const_iterator it = params.find( + rule + ":" + page_classification_str + ":" + instant_extended); + if (it != params.end()) + return it->second; + // Fall back to the global page classification context. + it = params.find(rule + ":*:" + instant_extended); + if (it != params.end()) + return it->second; + // Fall back to the global instant extended context. + it = params.find(rule + ":" + page_classification_str + ":*"); + if (it != params.end()) + return it->second; + // Look up rule in the global context. + it = params.find(rule + ":*:*"); + return (it != params.end()) ? it->second : std::string(); +} diff --git a/components/omnibox/omnibox_field_trial.h b/components/omnibox/omnibox_field_trial.h new file mode 100644 index 0000000..cc4440d --- /dev/null +++ b/components/omnibox/omnibox_field_trial.h @@ -0,0 +1,347 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OMNIBOX_OMNIBOX_FIELD_TRIAL_H_ +#define COMPONENTS_OMNIBOX_OMNIBOX_FIELD_TRIAL_H_ + +#include <map> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/gtest_prod_util.h" +#include "components/metrics/proto/omnibox_event.pb.h" +#include "components/omnibox/autocomplete_match_type.h" + +namespace base { +class TimeDelta; +} + +// The set of parameters customizing the HUP scoring. +struct HUPScoringParams { + // A set of parameters describing how to cap a given count score. First, + // we apply a half-life based decay of the given count and then find the + // maximum relevance score in the corresponding bucket list. + class ScoreBuckets { + public: + // (decayed_count, max_relevance) pair. + typedef std::pair<double, int> CountMaxRelevance; + + ScoreBuckets(); + ~ScoreBuckets(); + + // Computes a half-life time decay given the |elapsed_time|. + double HalfLifeTimeDecay(const base::TimeDelta& elapsed_time) const; + + int relevance_cap() const { return relevance_cap_; } + void set_relevance_cap(int relevance_cap) { + relevance_cap_ = relevance_cap; + } + + int half_life_days() const { return half_life_days_; } + void set_half_life_days(int half_life_days) { + half_life_days_ = half_life_days; + } + + std::vector<CountMaxRelevance>& buckets() { return buckets_; } + const std::vector<CountMaxRelevance>& buckets() const { return buckets_; } + + private: + // History matches with relevance score greater or equal to |relevance_cap_| + // are not affected by this experiment. + // Set to -1, if there is no relevance cap in place and all matches are + // subject to demotion. + int relevance_cap_; + + // Half life time for a decayed count as measured since the last visit. + // Set to -1 if not used. + int half_life_days_; + + // The relevance score caps for given decayed count values. + // Each pair (decayed_count, max_score) indicates what the maximum relevance + // score is of a decayed count equal or greater than decayed_count. + // + // Consider this example: + // [(1, 1000), (0.5, 500), (0, 100)] + // If decayed count is 2 (which is >= 1), the corresponding match's maximum + // relevance will be capped at 1000. In case of 0.5, the score is capped + // at 500. Anything below 0.5 is capped at 100. + // + // This list is sorted by the pair's first element in descending order. + std::vector<CountMaxRelevance> buckets_; + }; + + HUPScoringParams() : experimental_scoring_enabled(false) {} + + bool experimental_scoring_enabled; + + ScoreBuckets typed_count_buckets; + + // Used only when the typed count is 0. + ScoreBuckets visited_count_buckets; +}; + +// This class manages the Omnibox field trials. +class OmniboxFieldTrial { + public: + // A mapping that contains multipliers indicating that matches of the + // specified type should have their relevance score multiplied by the + // given number. Omitted types are assumed to have multipliers of 1.0. + typedef std::map<AutocompleteMatchType::Type, float> DemotionMultipliers; + + // Activates all dynamic field trials. The main difference between + // the autocomplete dynamic and static field trials is that the former + // don't require any code changes on the Chrome side as they are controlled + // on the server side. Chrome binary simply propagates all necessary + // information through the X-Client-Data header. + // This method may be called multiple times. + static void ActivateDynamicTrials(); + + // Returns a bitmap containing AutocompleteProvider::Type values + // that should be disabled in AutocompleteController. + // This method simply goes over all autocomplete dynamic field trial groups + // and looks for group names like "ProvidersDisabled_NNN" where NNN is + // an integer corresponding to a bitmap mask. All extracted bitmaps + // are OR-ed together and returned as the final result. + static int GetDisabledProviderTypes(); + + // Returns whether the user is in any dynamic field trial where the + // group has a the prefix |group_prefix|. + static bool HasDynamicFieldTrialGroupPrefix(const char *group_prefix); + + // --------------------------------------------------------- + // For the suggest field trial. + + // Populates |field_trial_hash| with hashes of the active suggest field trial + // names, if any. + static void GetActiveSuggestFieldTrialHashes( + std::vector<uint32>* field_trial_hash); + + // --------------------------------------------------------- + // For the AutocompleteController "stop timer" field trial. + + // Returns the duration to be used for the AutocompleteController's stop + // timer. Returns the default value of 1.5 seconds if the stop timer + // override experiment isn't active or if parsing the experiment-provided + // duration fails. + static base::TimeDelta StopTimerFieldTrialDuration(); + + // --------------------------------------------------------- + // For the ZeroSuggestProvider field trial. + + // Returns whether the user is in any field trial where the + // ZeroSuggestProvider should be used to get suggestions when the + // user clicks on the omnibox but has not typed anything yet. + static bool InZeroSuggestFieldTrial(); + + // Returns whether the user is in a ZeroSuggest field trial, but should + // show most visited URL instead. This is used to compare metrics of + // ZeroSuggest and most visited suggestions. + static bool InZeroSuggestMostVisitedFieldTrial(); + + // Returns whether the user is in a ZeroSuggest field trial and URL-based + // suggestions can continue to appear after the user has started typing. + static bool InZeroSuggestAfterTypingFieldTrial(); + + // Returns whether the user is in a ZeroSuggest field trial, but should + // show recently searched-for queries instead. + static bool InZeroSuggestPersonalizedFieldTrial(); + + // --------------------------------------------------------- + // For the ShortcutsScoringMaxRelevance experiment that's part of the + // bundled omnibox field trial. + + // If the user is in an experiment group that, given the provided + // |current_page_classification| context, changes the maximum relevance + // ShortcutsProvider::CalculateScore() is supposed to assign, extract + // that maximum relevance score and put in in |max_relevance|. Returns + // true on a successful extraction. CalculateScore()'s return value is + // a product of this maximum relevance score and some attenuating factors + // that are all between 0 and 1. (Note that Shortcuts results may have + // their scores reduced later if the assigned score is higher than allowed + // for non-inlineable results. Shortcuts results are not allowed to be + // inlined.) + static bool ShortcutsScoringMaxRelevance( + metrics::OmniboxEventProto::PageClassification + current_page_classification, + int* max_relevance); + + // --------------------------------------------------------- + // For the SearchHistory experiment that's part of the bundled omnibox + // field trial. + + // Returns true if the user is in the experiment group that, given the + // provided |current_page_classification| context, scores search history + // query suggestions less aggressively so that they don't inline. + static bool SearchHistoryPreventInlining( + metrics::OmniboxEventProto::PageClassification + current_page_classification); + + // Returns true if the user is in the experiment group that, given the + // provided |current_page_classification| context, disables all query + // suggestions from search history. + static bool SearchHistoryDisable( + metrics::OmniboxEventProto::PageClassification + current_page_classification); + + // --------------------------------------------------------- + // For the DemoteByType experiment that's part of the bundled omnibox field + // trial. + + // If the user is in an experiment group that, in the provided + // |current_page_classification| context, demotes the relevance scores + // of certain types of matches, populates the |demotions_by_type| map + // appropriately. Otherwise, sets |demotions_by_type| to its default + // value based on the context. + static void GetDemotionsByType( + metrics::OmniboxEventProto::PageClassification + current_page_classification, + DemotionMultipliers* demotions_by_type); + + // --------------------------------------------------------- + // For the HistoryURL provider new scoring experiment that is part of the + // bundled omnibox field trial. + + // Initializes the HUP |scoring_params| based on the active HUP scoring + // experiment. If there is no such experiment, this function simply sets + // |scoring_params|->experimental_scoring_enabled to false. + static void GetExperimentalHUPScoringParams(HUPScoringParams* scoring_params); + + // For the HQPBookmarkValue experiment that's part of the + // bundled omnibox field trial. + + // Returns the value an untyped visit to a bookmark should receive. + // Compare this value with the default of 1 for non-bookmarked untyped + // visits to pages and the default of 20 for typed visits. Returns + // 10 if the bookmark value experiment isn't active. + static int HQPBookmarkValue(); + + // --------------------------------------------------------- + // For the HQPAllowMatchInTLD experiment that's part of the + // bundled omnibox field trial. + + // Returns true if HQP should allow an input term to match in the + // top level domain (e.g., .com) of a URL. Returns false if the + // allow match in TLD experiment isn't active. + static bool HQPAllowMatchInTLDValue(); + + // --------------------------------------------------------- + // For the HQPAllowMatchInScheme experiment that's part of the + // bundled omnibox field trial. + + // Returns true if HQP should allow an input term to match in the + // scheme (e.g., http://) of a URL. Returns false if the allow + // match in scheme experiment isn't active. + static bool HQPAllowMatchInSchemeValue(); + + // --------------------------------------------------------- + // For the BookmarksIndexURLs experiment that's part of the + // bundled omnibox field trial. + + // Returns true if BookmarkIndex should index the URL of bookmarks + // (not only the titles) and search for / mark matches in the URLs, + // and BookmarkProvider should score bookmarks based on both the + // matches in bookmark title and URL. Returns false if the bookmarks + // index URLs experiment isn't active. + static bool BookmarksIndexURLsValue(); + + // --------------------------------------------------------- + // For the DisableInlining experiment that's part of the bundled omnibox + // field trial. + + // Returns true if AutocompleteResult should prevent any suggestion with + // a non-empty |inline_autocomplete| from being the default match. In + // other words, prevent an inline autocompletion from appearing as the + // top suggestion / within the omnibox itself, reordering matches as + // necessary to make this true. Returns false if the experiment isn't + // active. + static bool DisableInlining(); + + // --------------------------------------------------------- + // For the AnswersInSuggest experiment that's part of the bundled omnibox + // field trial. + + // Returns true if the AnswersInSuggest feature should be enabled causing + // query responses such as current weather conditions or stock quotes + // to be provided in the Omnibox suggestion list. Considers both the + // field trial state as well as the overriding command-line flags. + static bool EnableAnswersInSuggest(); + + // --------------------------------------------------------- + // For the AddUWYTMatchEvenIfPromotedURLs experiment that's part of the + // bundled omnibox field trial. + + // Returns true if HistoryURL Provider should add the URL-what-you-typed match + // (if valid and reasonable) even if the provider has good inline + // autocompletions to offer. Normally HistoryURL does not add the UWYT match + // if there are good inline autocompletions, as the user could simply hit + // backspace to delete the completion and get the what-you-typed match. + // However, for the disabling inlining experiment we want to have the UWYT + // always explicitly displayed at an option if possible. Returns false if + // the experiment isn't active. + static bool AddUWYTMatchEvenIfPromotedURLs(); + + // --------------------------------------------------------- + // For the DisplayHintTextWhenPossible experiment that's part of the + // bundled omnibox field trial. + + // Returns true if the omnibox should display hint text (Search + // <search engine> or type URL) when possible (i.e., the omnibox + // is otherwise non-empty). + static bool DisplayHintTextWhenPossible(); + + // --------------------------------------------------------- + // Exposed publicly for the sake of unittests. + static const char kBundledExperimentFieldTrialName[]; + // Rule names used by the bundled experiment. + static const char kShortcutsScoringMaxRelevanceRule[]; + static const char kSearchHistoryRule[]; + static const char kDemoteByTypeRule[]; + static const char kHQPBookmarkValueRule[]; + static const char kHQPDiscountFrecencyWhenFewVisitsRule[]; + static const char kHQPAllowMatchInTLDRule[]; + static const char kHQPAllowMatchInSchemeRule[]; + static const char kZeroSuggestRule[]; + static const char kZeroSuggestVariantRule[]; + static const char kBookmarksIndexURLsRule[]; + static const char kDisableInliningRule[]; + static const char kAnswersInSuggestRule[]; + static const char kAddUWYTMatchEvenIfPromotedURLsRule[]; + static const char kDisplayHintTextWhenPossibleRule[]; + + // Parameter names used by the HUP new scoring experiments. + static const char kHUPNewScoringEnabledParam[]; + static const char kHUPNewScoringTypedCountRelevanceCapParam[]; + static const char kHUPNewScoringTypedCountHalfLifeTimeParam[]; + static const char kHUPNewScoringTypedCountScoreBucketsParam[]; + static const char kHUPNewScoringVisitedCountRelevanceCapParam[]; + static const char kHUPNewScoringVisitedCountHalfLifeTimeParam[]; + static const char kHUPNewScoringVisitedCountScoreBucketsParam[]; + + private: + friend class OmniboxFieldTrialTest; + + // The bundled omnibox experiment comes with a set of parameters + // (key-value pairs). Each key indicates a certain rule that applies in + // a certain context. The value indicates what the consequences of + // applying the rule are. For example, the value of a SearchHistory rule + // in the context of a search results page might indicate that we should + // prevent search history matches from inlining. + // + // This function returns the value associated with the |rule| that applies + // in the current context (which currently consists of |page_classification| + // and whether Instant Extended is enabled). If no such rule exists in the + // current context, fall back to the rule in various wildcard contexts and + // return its value if found. If the rule remains unfound in the global + // context, returns the empty string. For more details, including how we + // prioritize different wildcard contexts, see the implementation. How to + // interpret the value is left to the caller; this is rule-dependent. + static std::string GetValueForRuleInContext( + const std::string& rule, + metrics::OmniboxEventProto::PageClassification page_classification); + + DISALLOW_IMPLICIT_CONSTRUCTORS(OmniboxFieldTrial); +}; + +#endif // COMPONENTS_OMNIBOX_OMNIBOX_FIELD_TRIAL_H_ diff --git a/components/omnibox/omnibox_field_trial_unittest.cc b/components/omnibox/omnibox_field_trial_unittest.cc new file mode 100644 index 0000000..9a78a67 --- /dev/null +++ b/components/omnibox/omnibox_field_trial_unittest.cc @@ -0,0 +1,380 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/omnibox/omnibox_field_trial.h" + +#include "base/basictypes.h" +#include "base/command_line.h" +#include "base/memory/scoped_ptr.h" +#include "base/metrics/field_trial.h" +#include "base/strings/string16.h" +#include "components/metrics/proto/omnibox_event.pb.h" +#include "components/search/search.h" +#include "components/variations/entropy_provider.h" +#include "components/variations/variations_associated_data.h" +#include "testing/gtest/include/gtest/gtest.h" + +using metrics::OmniboxEventProto; + +class OmniboxFieldTrialTest : public testing::Test { + public: + OmniboxFieldTrialTest() { + ResetFieldTrialList(); + } + + void ResetFieldTrialList() { + // Destroy the existing FieldTrialList before creating a new one to avoid + // a DCHECK. + field_trial_list_.reset(); + field_trial_list_.reset(new base::FieldTrialList( + new metrics::SHA1EntropyProvider("foo"))); + variations::testing::ClearAllVariationParams(); + OmniboxFieldTrial::ActivateDynamicTrials(); + } + + // Creates and activates a field trial. + static base::FieldTrial* CreateTestTrial(const std::string& name, + const std::string& group_name) { + base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial( + name, group_name); + trial->group(); + return trial; + } + + // Add a field trial disabling ZeroSuggest. + static void CreateDisableZeroSuggestTrial() { + std::map<std::string, std::string> params; + params[std::string(OmniboxFieldTrial::kZeroSuggestRule)] = "false"; + variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params); + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + } + + // EXPECTS that demotions[match_type] exists with value expected_value. + static void VerifyDemotion( + const OmniboxFieldTrial::DemotionMultipliers& demotions, + AutocompleteMatchType::Type match_type, + float expected_value); + + // EXPECT()s that OmniboxFieldTrial::GetValueForRuleInContext(|rule|, + // |page_classification|) returns |rule_value|. + static void ExpectRuleValue( + const std::string& rule_value, + const std::string& rule, + OmniboxEventProto::PageClassification page_classification); + + private: + scoped_ptr<base::FieldTrialList> field_trial_list_; + + DISALLOW_COPY_AND_ASSIGN(OmniboxFieldTrialTest); +}; + +// static +void OmniboxFieldTrialTest::VerifyDemotion( + const OmniboxFieldTrial::DemotionMultipliers& demotions, + AutocompleteMatchType::Type match_type, + float expected_value) { + OmniboxFieldTrial::DemotionMultipliers::const_iterator demotion_it = + demotions.find(match_type); + ASSERT_TRUE(demotion_it != demotions.end()); + EXPECT_FLOAT_EQ(expected_value, demotion_it->second); +} + +// static +void OmniboxFieldTrialTest::ExpectRuleValue( + const std::string& rule_value, + const std::string& rule, + OmniboxEventProto::PageClassification page_classification) { + EXPECT_EQ(rule_value, + OmniboxFieldTrial::GetValueForRuleInContext( + rule, page_classification)); +} + +// Test if GetDisabledProviderTypes() properly parses various field trial +// group names. +TEST_F(OmniboxFieldTrialTest, GetDisabledProviderTypes) { + EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); + + { + SCOPED_TRACE("Invalid groups"); + CreateTestTrial("AutocompleteDynamicTrial_0", "DisabledProviders_"); + EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); + ResetFieldTrialList(); + CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_XXX"); + EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); + ResetFieldTrialList(); + CreateTestTrial("AutocompleteDynamicTrial_1", "DisabledProviders_12abc"); + EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); + } + + { + SCOPED_TRACE("Valid group name, unsupported trial name."); + ResetFieldTrialList(); + CreateTestTrial("UnsupportedTrialName", "DisabledProviders_20"); + EXPECT_EQ(0, OmniboxFieldTrial::GetDisabledProviderTypes()); + } + + { + SCOPED_TRACE("Valid field and group name."); + ResetFieldTrialList(); + CreateTestTrial("AutocompleteDynamicTrial_2", "DisabledProviders_3"); + EXPECT_EQ(3, OmniboxFieldTrial::GetDisabledProviderTypes()); + // Two groups should be OR-ed together. + CreateTestTrial("AutocompleteDynamicTrial_3", "DisabledProviders_6"); + EXPECT_EQ(7, OmniboxFieldTrial::GetDisabledProviderTypes()); + } +} + +// Test if InZeroSuggestFieldTrial() properly parses various field trial +// group names. +TEST_F(OmniboxFieldTrialTest, ZeroSuggestFieldTrial) { + // Default ZeroSuggest setting depends on OS. +#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_LINUX) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) + EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial()); +#else + EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial()); +#endif + + { + SCOPED_TRACE("Disable ZeroSuggest."); + ResetFieldTrialList(); + CreateDisableZeroSuggestTrial(); + EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestFieldTrial()); + } + + { + SCOPED_TRACE("Bundled field trial parameters."); + ResetFieldTrialList(); + std::map<std::string, std::string> params; + params[std::string(OmniboxFieldTrial::kZeroSuggestRule)] = "true"; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial()); + EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()); + EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial()); + + ResetFieldTrialList(); + params[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule)] = + "MostVisited"; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial()); + EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()); + EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial()); + + ResetFieldTrialList(); + params[std::string(OmniboxFieldTrial::kZeroSuggestVariantRule)] = + "AfterTyping"; + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestFieldTrial()); + EXPECT_FALSE(OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()); + EXPECT_TRUE(OmniboxFieldTrial::InZeroSuggestAfterTypingFieldTrial()); + } +} + +TEST_F(OmniboxFieldTrialTest, GetDemotionsByTypeWithFallback) { + { + std::map<std::string, std::string> params; + params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":1:*"] = + "1:50,2:0"; + params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":3:*"] = + "5:100"; + params[std::string(OmniboxFieldTrial::kDemoteByTypeRule) + ":*:*"] = "1:25"; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + } + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + OmniboxFieldTrial::DemotionMultipliers demotions_by_type; + OmniboxFieldTrial::GetDemotionsByType( + OmniboxEventProto::NTP, &demotions_by_type); + ASSERT_EQ(2u, demotions_by_type.size()); + VerifyDemotion(demotions_by_type, AutocompleteMatchType::HISTORY_URL, 0.5); + VerifyDemotion(demotions_by_type, AutocompleteMatchType::HISTORY_TITLE, 0.0); + OmniboxFieldTrial::GetDemotionsByType( + OmniboxEventProto::HOME_PAGE, &demotions_by_type); + ASSERT_EQ(1u, demotions_by_type.size()); + VerifyDemotion(demotions_by_type, AutocompleteMatchType::NAVSUGGEST, 1.0); + OmniboxFieldTrial::GetDemotionsByType( + OmniboxEventProto::BLANK, &demotions_by_type); + ASSERT_EQ(1u, demotions_by_type.size()); + VerifyDemotion(demotions_by_type, AutocompleteMatchType::HISTORY_URL, 0.25); +} + +TEST_F(OmniboxFieldTrialTest, GetValueForRuleInContext) { + { + std::map<std::string, std::string> params; + // Rule 1 has some exact matches and fallbacks at every level. + params["rule1:1:0"] = "rule1-1-0-value"; // NTP + params["rule1:3:0"] = "rule1-3-0-value"; // HOME_PAGE + params["rule1:4:1"] = "rule1-4-1-value"; // OTHER + params["rule1:4:*"] = "rule1-4-*-value"; // OTHER + params["rule1:*:1"] = "rule1-*-1-value"; // global + params["rule1:*:*"] = "rule1-*-*-value"; // global + // Rule 2 has no exact matches but has fallbacks. + params["rule2:*:0"] = "rule2-*-0-value"; // global + params["rule2:1:*"] = "rule2-1-*-value"; // NTP + params["rule2:*:*"] = "rule2-*-*-value"; // global + // Rule 3 has only a global fallback. + params["rule3:*:*"] = "rule3-*-*-value"; // global + // Rule 4 has an exact match but no fallbacks. + params["rule4:4:0"] = "rule4-4-0-value"; // OTHER + // Add a malformed rule to make sure it doesn't screw things up. + params["unrecognized"] = "unrecognized-value"; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + } + + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + + if (chrome::IsInstantExtendedAPIEnabled()) { + // Tests with Instant Extended enabled. + // Tests for rule 1. + ExpectRuleValue("rule1-4-1-value", + "rule1", OmniboxEventProto::OTHER); // exact match + ExpectRuleValue("rule1-*-1-value", + "rule1", OmniboxEventProto::BLANK); // partial fallback + ExpectRuleValue("rule1-*-1-value", + "rule1", + OmniboxEventProto::NTP); // partial fallback + + // Tests for rule 2. + ExpectRuleValue("rule2-1-*-value", + "rule2", + OmniboxEventProto::NTP); // partial fallback + ExpectRuleValue("rule2-*-*-value", + "rule2", OmniboxEventProto::OTHER); // global fallback + + // Tests for rule 3. + ExpectRuleValue("rule3-*-*-value", + "rule3", + OmniboxEventProto::HOME_PAGE); // global fallback + ExpectRuleValue("rule3-*-*-value", + "rule3", + OmniboxEventProto::OTHER); // global fallback + + // Tests for rule 4. + ExpectRuleValue("", + "rule4", + OmniboxEventProto::BLANK); // no global fallback + ExpectRuleValue("", + "rule4", + OmniboxEventProto::HOME_PAGE); // no global fallback + + // Tests for rule 5 (a missing rule). + ExpectRuleValue("", + "rule5", OmniboxEventProto::OTHER); // no rule at all + } else { + // Tests for rule 1. + ExpectRuleValue("rule1-1-0-value", + "rule1", OmniboxEventProto::NTP); // exact match + ExpectRuleValue("rule1-1-0-value", + "rule1", OmniboxEventProto::NTP); // exact match + ExpectRuleValue("rule1-*-*-value", + "rule1", OmniboxEventProto::BLANK); // fallback to global + ExpectRuleValue("rule1-3-0-value", + "rule1", + OmniboxEventProto::HOME_PAGE); // exact match + ExpectRuleValue("rule1-4-*-value", + "rule1", OmniboxEventProto::OTHER); // partial fallback + ExpectRuleValue("rule1-*-*-value", + "rule1", + OmniboxEventProto:: // fallback to global + SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT); + // Tests for rule 2. + ExpectRuleValue("rule2-*-0-value", + "rule2", + OmniboxEventProto::HOME_PAGE); // partial fallback + ExpectRuleValue("rule2-*-0-value", + "rule2", OmniboxEventProto::OTHER); // partial fallback + + // Tests for rule 3. + ExpectRuleValue("rule3-*-*-value", + "rule3", + OmniboxEventProto::HOME_PAGE); // fallback to global + ExpectRuleValue("rule3-*-*-value", + "rule3", OmniboxEventProto::OTHER); // fallback to global + + // Tests for rule 4. + ExpectRuleValue("", + "rule4", OmniboxEventProto::BLANK); // no global fallback + ExpectRuleValue("", + "rule4", + OmniboxEventProto::HOME_PAGE); // no global fallback + ExpectRuleValue("rule4-4-0-value", + "rule4", OmniboxEventProto::OTHER); // exact match + + // Tests for rule 5 (a missing rule). + ExpectRuleValue("", + "rule5", OmniboxEventProto::OTHER); // no rule at all + } +} + +TEST_F(OmniboxFieldTrialTest, HUPNewScoringFieldTrial) { + { + std::map<std::string, std::string> params; + params[std::string(OmniboxFieldTrial::kHUPNewScoringEnabledParam)] = "1"; + params[std::string( + OmniboxFieldTrial::kHUPNewScoringTypedCountRelevanceCapParam)] = "56"; + params[std::string( + OmniboxFieldTrial::kHUPNewScoringTypedCountHalfLifeTimeParam)] = "77"; + params[std::string( + OmniboxFieldTrial::kHUPNewScoringTypedCountScoreBucketsParam)] = + "0.2:25,0.1:1001,2.3:777"; + params[std::string( + OmniboxFieldTrial::kHUPNewScoringVisitedCountRelevanceCapParam)] = "11"; + params[std::string( + OmniboxFieldTrial::kHUPNewScoringVisitedCountHalfLifeTimeParam)] = "31"; + params[std::string( + OmniboxFieldTrial::kHUPNewScoringVisitedCountScoreBucketsParam)] = + "5:300,0:200"; + ASSERT_TRUE(variations::AssociateVariationParams( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params)); + } + base::FieldTrialList::CreateFieldTrial( + OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A"); + + HUPScoringParams scoring_params; + OmniboxFieldTrial::GetExperimentalHUPScoringParams(&scoring_params); + EXPECT_TRUE(scoring_params.experimental_scoring_enabled); + EXPECT_EQ(56, scoring_params.typed_count_buckets.relevance_cap()); + EXPECT_EQ(77, scoring_params.typed_count_buckets.half_life_days()); + ASSERT_EQ(3u, scoring_params.typed_count_buckets.buckets().size()); + EXPECT_EQ(std::make_pair(2.3, 777), + scoring_params.typed_count_buckets.buckets()[0]); + EXPECT_EQ(std::make_pair(0.2, 25), + scoring_params.typed_count_buckets.buckets()[1]); + EXPECT_EQ(std::make_pair(0.1, 1001), + scoring_params.typed_count_buckets.buckets()[2]); + EXPECT_EQ(11, scoring_params.visited_count_buckets.relevance_cap()); + EXPECT_EQ(31, scoring_params.visited_count_buckets.half_life_days()); + ASSERT_EQ(2u, scoring_params.visited_count_buckets.buckets().size()); + EXPECT_EQ(std::make_pair(5.0, 300), + scoring_params.visited_count_buckets.buckets()[0]); + EXPECT_EQ(std::make_pair(0.0, 200), + scoring_params.visited_count_buckets.buckets()[1]); +} + +TEST_F(OmniboxFieldTrialTest, HalfLifeTimeDecay) { + HUPScoringParams::ScoreBuckets buckets; + + // No decay by default. + EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(7))); + + buckets.set_half_life_days(7); + EXPECT_EQ(0.5, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(7))); + EXPECT_EQ(0.25, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(14))); + EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(0))); + EXPECT_EQ(1.0, buckets.HalfLifeTimeDecay(base::TimeDelta::FromDays(-1))); +} diff --git a/components/omnibox/omnibox_switches.cc b/components/omnibox/omnibox_switches.cc new file mode 100644 index 0000000..ce498be --- /dev/null +++ b/components/omnibox/omnibox_switches.cc @@ -0,0 +1,15 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/omnibox/omnibox_switches.h" + +namespace switches { + +// Disables the experimental Answers in Suggest feature. +const char kDisableAnswersInSuggest[] = "disable-answers-in-suggest"; + +// Enables the experimental Answers in Suggest feature. +const char kEnableAnswersInSuggest[] = "enable-answers-in-suggest"; + +} // namespace switches diff --git a/components/omnibox/omnibox_switches.h b/components/omnibox/omnibox_switches.h new file mode 100644 index 0000000..7cd73e2 --- /dev/null +++ b/components/omnibox/omnibox_switches.h @@ -0,0 +1,15 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OMNIBOX_OMNIBOX_SWITCHES_H_ +#define COMPONENTS_OMNIBOX_OMNIBOX_SWITCHES_H_ + +namespace switches { + +extern const char kDisableAnswersInSuggest[]; +extern const char kEnableAnswersInSuggest[]; + +} // namespace switches + +#endif // COMPONENTS_OMNIBOX_OMNIBOX_SWITCHES_H_ |