Commit 72868bf8 authored by engedy@chromium.org's avatar engedy@chromium.org

Added the ability to specify AutomaticProfileResetter's evaluation program through field trials.

BUG=298036

Review URL: https://codereview.chromium.org/50883003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232995 0039d316-1c4b-4281-b951-d872f2087c98
parent f4a8554c
......@@ -12,6 +12,7 @@
#include "base/metrics/histogram.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_worker_pool.h"
......@@ -23,6 +24,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/browser_thread.h"
#include "grit/browser_resources.h"
#include "ui/base/resource/resource_bundle.h"
......@@ -55,6 +57,8 @@ namespace {
const char kAutomaticProfileResetStudyName[] = "AutomaticProfileReset";
const char kAutomaticProfileResetStudyDryRunGroupName[] = "DryRun";
const char kAutomaticProfileResetStudyEnabledGroupName[] = "Enabled";
const char kAutomaticProfileResetStudyProgramParameterName[] = "program";
const char kAutomaticProfileResetStudyHashSeedParameterName[] = "hash_seed";
// How long to wait after start-up before unleashing the evaluation flow.
const int64 kEvaluationFlowDelayInSeconds = 55;
......@@ -117,14 +121,30 @@ enum PromptResult {
// Returns whether or not a dry-run shall be performed.
bool ShouldPerformDryRun() {
return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
kAutomaticProfileResetStudyDryRunGroupName;
return StartsWithASCII(
base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName),
kAutomaticProfileResetStudyDryRunGroupName, true);
}
// Returns whether or not a live-run shall be performed.
bool ShouldPerformLiveRun() {
return base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName) ==
kAutomaticProfileResetStudyEnabledGroupName;
return StartsWithASCII(
base::FieldTrialList::FindFullName(kAutomaticProfileResetStudyName),
kAutomaticProfileResetStudyEnabledGroupName, true);
}
// Returns whether or not the currently active experiment group prescribes the
// program and hash seed to use instead of the baked-in ones.
bool DoesExperimentOverrideProgramAndHashSeed() {
#if defined(GOOGLE_CHROME_BUILD)
std::map<std::string, std::string> params;
chrome_variations::GetVariationParams(kAutomaticProfileResetStudyName,
&params);
return params.count(kAutomaticProfileResetStudyProgramParameterName) &&
params.count(kAutomaticProfileResetStudyHashSeedParameterName);
#else
return false;
#endif
}
// Deep-copies all preferences in |source| to a sub-tree named |value_tree_key|
......@@ -176,11 +196,48 @@ AutomaticProfileResetter::AutomaticProfileResetter(Profile* profile)
memento_in_file_(profile_),
weak_ptr_factory_(this) {
DCHECK(profile_);
Initialize();
}
AutomaticProfileResetter::~AutomaticProfileResetter() {}
void AutomaticProfileResetter::Initialize() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK_EQ(state_, STATE_UNINITIALIZED);
if (!ShouldPerformDryRun() && !ShouldPerformLiveRun()) {
state_ = STATE_DISABLED;
return;
}
ui::ResourceBundle& resources(ui::ResourceBundle::GetSharedInstance());
if (DoesExperimentOverrideProgramAndHashSeed()) {
program_ = chrome_variations::GetVariationParamValue(
kAutomaticProfileResetStudyName,
kAutomaticProfileResetStudyProgramParameterName);
hash_seed_ = chrome_variations::GetVariationParamValue(
kAutomaticProfileResetStudyName,
kAutomaticProfileResetStudyHashSeedParameterName);
} else if (ShouldPerformLiveRun()) {
program_ = resources.GetRawDataResource(
IDR_AUTOMATIC_PROFILE_RESET_RULES).as_string();
hash_seed_ = resources.GetRawDataResource(
IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED).as_string();
} else { // ShouldPerformDryRun()
program_ = resources.GetRawDataResource(
IDR_AUTOMATIC_PROFILE_RESET_RULES_DRY).as_string();
hash_seed_ = resources.GetRawDataResource(
IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED_DRY).as_string();
}
delegate_.reset(new AutomaticProfileResetterDelegateImpl(
TemplateURLServiceFactory::GetForProfile(profile_)));
task_runner_for_waiting_ =
content::BrowserThread::GetMessageLoopProxyForThread(
content::BrowserThread::UI);
state_ = STATE_INITIALIZED;
}
void AutomaticProfileResetter::Activate() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(state_ == STATE_INITIALIZED || state_ == STATE_DISABLED);
......@@ -201,16 +258,16 @@ void AutomaticProfileResetter::Activate() {
}
}
void AutomaticProfileResetter::SetHashSeedForTesting(
const base::StringPiece& hash_key) {
hash_seed_ = hash_key;
}
void AutomaticProfileResetter::SetProgramForTesting(
const base::StringPiece& program) {
const std::string& program) {
program_ = program;
}
void AutomaticProfileResetter::SetHashSeedForTesting(
const std::string& hash_key) {
hash_seed_ = hash_key;
}
void AutomaticProfileResetter::SetDelegateForTesting(
scoped_ptr<AutomaticProfileResetterDelegate> delegate) {
delegate_ = delegate.Pass();
......@@ -221,34 +278,6 @@ void AutomaticProfileResetter::SetTaskRunnerForWaitingForTesting(
task_runner_for_waiting_ = task_runner;
}
void AutomaticProfileResetter::Initialize() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK_EQ(state_, STATE_UNINITIALIZED);
if (ShouldPerformDryRun() || ShouldPerformLiveRun()) {
ui::ResourceBundle& resources(ui::ResourceBundle::GetSharedInstance());
if (ShouldPerformLiveRun()) {
program_ =
resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES);
hash_seed_ =
resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED);
} else { // ShouldPerformDryRun()
program_ =
resources.GetRawDataResource(IDR_AUTOMATIC_PROFILE_RESET_RULES_DRY);
hash_seed_ = resources.GetRawDataResource(
IDR_AUTOMATIC_PROFILE_RESET_HASH_SEED_DRY);
}
delegate_.reset(new AutomaticProfileResetterDelegateImpl(
TemplateURLServiceFactory::GetForProfile(profile_)));
task_runner_for_waiting_ =
content::BrowserThread::GetMessageLoopProxyForThread(
content::BrowserThread::UI);
state_ = STATE_INITIALIZED;
} else {
state_ = STATE_DISABLED;
}
}
void AutomaticProfileResetter::PrepareEvaluationFlow() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK_EQ(state_, STATE_INITIALIZED);
......@@ -380,11 +409,10 @@ void AutomaticProfileResetter::ContinueWithEvaluationFlow(
// static
scoped_ptr<AutomaticProfileResetter::EvaluationResults>
AutomaticProfileResetter::EvaluateConditionsOnWorkerPoolThread(
const base::StringPiece& hash_seed,
const base::StringPiece& program,
const std::string& hash_seed,
const std::string& program,
scoped_ptr<base::DictionaryValue> program_input) {
JtlInterpreter interpreter(
hash_seed.as_string(), program.as_string(), program_input.get());
JtlInterpreter interpreter(hash_seed, program, program_input.get());
interpreter.Execute();
UMA_HISTOGRAM_ENUMERATION("AutomaticProfileReset.InterpreterResult",
interpreter.result(),
......
......@@ -39,6 +39,11 @@ class AutomaticProfileResetter : public BrowserContextKeyedService {
explicit AutomaticProfileResetter(Profile* profile);
virtual ~AutomaticProfileResetter();
// Initializes the service if it is enabled in the field trial. Otherwise,
// skips the initialization steps, and also permanently disables the service.
// Called by AutomaticProfileResetterFactory.
void Initialize();
// Fires up the service by unleashing the asynchronous evaluation flow, unless
// the service has been already disabled in Initialize() or there is no
// |program_| to run (in which case the service also gets disabled).
......@@ -46,10 +51,10 @@ class AutomaticProfileResetter : public BrowserContextKeyedService {
void Activate();
// Should be called before Activate().
void SetHashSeedForTesting(const base::StringPiece& hash_seed);
void SetProgramForTesting(const std::string& program);
// Should be called before Activate().
void SetProgramForTesting(const base::StringPiece& program);
void SetHashSeedForTesting(const std::string& hash_seed);
// Should be called before Activate().
void SetDelegateForTesting(
......@@ -73,10 +78,6 @@ class AutomaticProfileResetter : public BrowserContextKeyedService {
STATE_DONE
};
// Initializes the service if it is enabled in the field trial, otherwise,
// skips the initialization steps and also permanently disables the service.
void Initialize();
// Prepares the asynchronous evaluation flow by requesting services that it
// depends on to make themselves ready.
void PrepareEvaluationFlow();
......@@ -114,8 +115,8 @@ class AutomaticProfileResetter : public BrowserContextKeyedService {
// program will only see hashed keys and values that are produced using
// |hash_seed| as a key.
static scoped_ptr<EvaluationResults> EvaluateConditionsOnWorkerPoolThread(
const base::StringPiece& hash_seed,
const base::StringPiece& program,
const std::string& hash_seed,
const std::string& program,
scoped_ptr<base::DictionaryValue> program_input);
// Called back when EvaluateConditionsOnWorkerPoolThread completes executing
......@@ -137,8 +138,8 @@ class AutomaticProfileResetter : public BrowserContextKeyedService {
bool enumeration_of_loaded_modules_ready_;
bool template_url_service_ready_;
base::StringPiece hash_seed_;
base::StringPiece program_;
std::string hash_seed_;
std::string program_;
PreferenceHostedPromptMemento memento_in_prefs_;
LocalStateHostedPromptMemento memento_in_local_state_;
......
......@@ -51,6 +51,7 @@ AutomaticProfileResetterFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
Profile* profile = Profile::FromBrowserContext(context);
AutomaticProfileResetter* service = new AutomaticProfileResetter(profile);
service->Initialize();
service->Activate();
return service;
}
......
......@@ -25,6 +25,7 @@
#include "chrome/test/base/testing_pref_service_syncable.h"
#include "chrome/test/base/testing_profile.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -407,6 +408,7 @@ class AutomaticProfileResetterTestBase : public testing::Test {
local_state_(TestingBrowserProcess::GetGlobal()),
profile_(new TestingProfile()),
experiment_group_name_(experiment_group_name),
inject_data_through_variation_params_(false),
mock_delegate_(NULL) {
// Make sure the factory is not optimized away, so whatever preferences it
// wants to register will actually get registered.
......@@ -429,18 +431,14 @@ class AutomaticProfileResetterTestBase : public testing::Test {
virtual void SetUp() OVERRIDE {
field_trials_.reset(new base::FieldTrialList(NULL));
chrome_variations::testing::ClearAllVariationParams();
base::FieldTrialList::CreateFieldTrial(kAutomaticProfileResetStudyName,
experiment_group_name_);
resetter_.reset(new testing::StrictMock<AutomaticProfileResetterUnderTest>(
profile_.get()));
scoped_ptr<MockProfileResetterDelegate> mock_delegate(
resetter_.reset(
new testing::StrictMock<AutomaticProfileResetterUnderTest>(profile()));
mock_delegate_owned_.reset(
new testing::StrictMock<MockProfileResetterDelegate>());
mock_delegate_ = mock_delegate.get();
resetter_->SetDelegateForTesting(
mock_delegate.PassAs<AutomaticProfileResetterDelegate>());
resetter_->SetTaskRunnerForWaitingForTesting(waiting_task_runner_);
mock_delegate_ = mock_delegate_owned_.get();
}
void SetTestingHashSeed(const std::string& hash_seed) {
......@@ -451,14 +449,32 @@ class AutomaticProfileResetterTestBase : public testing::Test {
testing_program_ = source_code;
}
void UnleashResetterAndWait() {
resetter_->SetHashSeedForTesting(testing_hash_seed_);
resetter_->SetProgramForTesting(testing_program_);
void AllowInjectingTestDataThroughVariationParams(bool value) {
inject_data_through_variation_params_ = value;
}
void UnleashResetterAndWait() {
if (inject_data_through_variation_params_) {
std::map<std::string, std::string> variation_params;
variation_params["program"] = testing_program_;
variation_params["hash_seed"] = testing_hash_seed_;
ASSERT_TRUE(chrome_variations::AssociateVariationParams(
kAutomaticProfileResetStudyName,
experiment_group_name_,
variation_params));
}
resetter_->Initialize();
resetter_->SetDelegateForTesting(
mock_delegate_owned_.PassAs<AutomaticProfileResetterDelegate>());
resetter_->SetTaskRunnerForWaitingForTesting(waiting_task_runner_);
if (!inject_data_through_variation_params_) {
resetter_->SetProgramForTesting(testing_program_);
resetter_->SetHashSeedForTesting(testing_hash_seed_);
}
resetter_->Activate();
if (waiting_task_runner_->HasPendingTask()) {
EXPECT_EQ(base::TimeDelta::FromSeconds(55),
ASSERT_EQ(base::TimeDelta::FromSeconds(55),
waiting_task_runner_->NextPendingTaskDelay());
waiting_task_runner_->RunPendingTasks();
}
......@@ -482,8 +498,10 @@ class AutomaticProfileResetterTestBase : public testing::Test {
std::string experiment_group_name_;
std::string testing_program_;
std::string testing_hash_seed_;
bool inject_data_through_variation_params_;
scoped_ptr<AutomaticProfileResetterUnderTest> resetter_;
scoped_ptr<MockProfileResetterDelegate> mock_delegate_owned_;
MockProfileResetterDelegate* mock_delegate_;
DISALLOW_COPY_AND_ASSIGN(AutomaticProfileResetterTestBase);
......@@ -601,6 +619,32 @@ TEST_F(AutomaticProfileResetterTestDryRun, OtherConditionSatisfied) {
EXPECT_EQ(kTestMementoValue, memento_in_file.ReadValue());
}
#if defined(GOOGLE_CHROME_BUILD)
TEST_F(AutomaticProfileResetterTestDryRun, ProgramSetThroughVariationParams) {
PreferenceHostedPromptMemento memento_in_prefs(profile());
LocalStateHostedPromptMemento memento_in_local_state(profile());
FileHostedPromptMementoSynchronous memento_in_file(profile());
EXPECT_EQ("", memento_in_prefs.ReadValue());
EXPECT_EQ("", memento_in_local_state.ReadValue());
EXPECT_EQ("", memento_in_file.ReadValue());
SetTestingProgram(ConstructProgram(true, true));
SetTestingHashSeed(kTestHashSeed);
AllowInjectingTestDataThroughVariationParams(true);
mock_delegate().ExpectCallsToDependenciesSetUpMethods();
mock_delegate().ExpectCallsToGetterMethods();
EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x01u));
UnleashResetterAndWait();
EXPECT_EQ(kTestMementoValue, memento_in_prefs.ReadValue());
EXPECT_EQ(kTestMementoValue, memento_in_local_state.ReadValue());
EXPECT_EQ(kTestMementoValue, memento_in_file.ReadValue());
}
#endif
TEST_F(AutomaticProfileResetterTestDryRun,
ConditionsSatisfiedAndInvalidMementos) {
PreferenceHostedPromptMemento memento_in_prefs(profile());
......@@ -776,6 +820,33 @@ TEST_F(AutomaticProfileResetterTest, OtherConditionSatisfied) {
EXPECT_EQ(kTestMementoValue, memento_in_file.ReadValue());
}
#if defined(GOOGLE_CHROME_BUILD)
TEST_F(AutomaticProfileResetterTest, ProgramSetThroughVariationParams) {
PreferenceHostedPromptMemento memento_in_prefs(profile());
LocalStateHostedPromptMemento memento_in_local_state(profile());
FileHostedPromptMementoSynchronous memento_in_file(profile());
EXPECT_EQ("", memento_in_prefs.ReadValue());
EXPECT_EQ("", memento_in_local_state.ReadValue());
EXPECT_EQ("", memento_in_file.ReadValue());
SetTestingProgram(ConstructProgram(true, true));
SetTestingHashSeed(kTestHashSeed);
AllowInjectingTestDataThroughVariationParams(true);
mock_delegate().ExpectCallsToDependenciesSetUpMethods();
mock_delegate().ExpectCallsToGetterMethods();
EXPECT_CALL(mock_delegate(), ShowPrompt());
EXPECT_CALL(resetter(), ReportStatistics(0x03u, 0x01u));
UnleashResetterAndWait();
EXPECT_EQ(kTestMementoValue, memento_in_prefs.ReadValue());
EXPECT_EQ(kTestMementoValue, memento_in_local_state.ReadValue());
EXPECT_EQ(kTestMementoValue, memento_in_file.ReadValue());
}
#endif
TEST_F(AutomaticProfileResetterTest, ConditionsSatisfiedAndInvalidMementos) {
PreferenceHostedPromptMemento memento_in_prefs(profile());
LocalStateHostedPromptMemento memento_in_local_state(profile());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment