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.
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram_base.h"
14 #include "base/metrics/histogram_samples.h"
15 #include "base/metrics/statistics_recorder.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/strings/string16.h"
18 #include "base/threading/sequenced_worker_pool.h"
19 #include "base/values.h"
20 #include "build/build_config.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
23 #include "chrome/browser/prefs/pref_hash_store.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/profiles/profile_info_cache.h"
26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/profiles/profiles_state.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/test/base/in_process_browser_test.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/common/content_switches.h"
32 #include "content/public/test/test_utils.h"
33 #include "testing/gtest/include/gtest/gtest.h"
37 // An observer that returns back to test code after a new profile is
39 void OnUnblockOnProfileCreation(const base::Closure& callback,
41 Profile::CreateStatus status) {
43 case Profile::CREATE_STATUS_CREATED:
44 // Wait for CREATE_STATUS_INITIALIZED.
46 case Profile::CREATE_STATUS_INITIALIZED:
50 ADD_FAILURE() << "Unexpected Profile::CreateStatus: " << status;
56 // Finds a profile path corresponding to a profile that has not been loaded yet.
57 base::FilePath GetUnloadedProfilePath() {
58 ProfileManager* profile_manager = g_browser_process->profile_manager();
59 const ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
60 const std::vector<Profile*> loaded_profiles =
61 profile_manager->GetLoadedProfiles();
62 std::set<base::FilePath> profile_paths;
63 for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i)
64 profile_paths.insert(cache.GetPathOfProfileAtIndex(i));
65 for (size_t i = 0; i < loaded_profiles.size(); ++i)
66 EXPECT_EQ(1U, profile_paths.erase(loaded_profiles[i]->GetPath()));
67 if (profile_paths.size())
68 return *profile_paths.begin();
69 return base::FilePath();
72 // Returns the number of times |histogram_name| was reported so far; adding the
73 // results of the first 100 buckets (there are only ~14 reporting IDs as of this
74 // writting; varies depending on the platform). If |expect_zero| is true, this
75 // method will explicitly report IDs that are non-zero for ease of diagnosis.
76 int GetTrackedPrefHistogramCount(const char* histogram_name, bool expect_zero) {
77 const base::HistogramBase* histogram =
78 base::StatisticsRecorder::FindHistogram(histogram_name);
82 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
84 for (int i = 0; i < 100; ++i) {
85 int count_for_id = samples->GetCount(i);
89 EXPECT_EQ(0, count_for_id) << "Faulty reporting_id: " << i;
96 class PrefHashBrowserTest : public InProcessBrowserTest,
97 public testing::WithParamInterface<std::string> {
100 : is_unloaded_profile_seeding_allowed_(
101 IsUnloadedProfileSeedingAllowed()) {}
103 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
104 InProcessBrowserTest::SetUpCommandLine(command_line);
105 command_line->AppendSwitchASCII(
106 switches::kForceFieldTrials,
107 std::string(chrome_prefs::internals::kSettingsEnforcementTrialName) +
108 "/" + GetParam() + "/");
111 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
112 // Force the delayed PrefHashStore update task to happen immediately with
113 // no domain check (bots are on a domain).
114 chrome_prefs::DisableDelaysAndDomainCheckForTesting();
117 virtual void SetUpOnMainThread() OVERRIDE {
118 // content::RunAllPendingInMessageLoop() is already called before
119 // SetUpOnMainThread() in in_process_browser_test.cc which guarantees that
120 // UpdateAllPrefHashStoresIfRequired() has already been called.
122 // Now flush the blocking pool to force any pending JsonPrefStore async read
124 content::BrowserThread::GetBlockingPool()->FlushForTesting();
126 // And finally run tasks on this message loop again to process the OnRead()
127 // callbacks resulting from the file reads above.
128 content::RunAllPendingInMessageLoop();
132 const bool is_unloaded_profile_seeding_allowed_;
135 bool IsUnloadedProfileSeedingAllowed() const {
136 const bool allowed_from_param =
138 chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways;
139 const bool allowed_from_configuration =
140 #if defined(OFFICIAL_BUILD)
141 // SettingsEnforcement can't be forced via --force-fieldtrials in
147 return allowed_from_param || allowed_from_configuration;
151 #if defined(OS_CHROMEOS)
152 // PrefHash service has been disabled on ChromeOS: crbug.com/343261
153 #define MAYBE_PRE_PRE_InitializeUnloadedProfiles DISABLED_PRE_PRE_InitializeUnloadedProfiles
154 #define MAYBE_PRE_InitializeUnloadedProfiles DISABLED_PRE_InitializeUnloadedProfiles
155 #define MAYBE_InitializeUnloadedProfiles DISABLED_InitializeUnloadedProfiles
157 #define MAYBE_PRE_PRE_InitializeUnloadedProfiles PRE_PRE_InitializeUnloadedProfiles
158 #define MAYBE_PRE_InitializeUnloadedProfiles PRE_InitializeUnloadedProfiles
159 #define MAYBE_InitializeUnloadedProfiles InitializeUnloadedProfiles
162 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest,
163 MAYBE_PRE_PRE_InitializeUnloadedProfiles) {
164 if (!profiles::IsMultipleProfilesEnabled())
166 ProfileManager* profile_manager = g_browser_process->profile_manager();
168 // Create an additional profile.
169 const base::FilePath new_path =
170 profile_manager->GenerateNextProfileDirectoryPath();
171 const scoped_refptr<content::MessageLoopRunner> runner(
172 new content::MessageLoopRunner);
173 profile_manager->CreateProfileAsync(
175 base::Bind(&OnUnblockOnProfileCreation, runner->QuitClosure()),
180 // Spin to allow profile creation to take place, loop is terminated
181 // by OnUnblockOnProfileCreation when the profile is created.
184 // No profile should have gone through the unloaded profile initialization in
185 // this phase as both profiles should have been loaded normally.
187 0, GetTrackedPrefHistogramCount(
188 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
192 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest,
193 MAYBE_PRE_InitializeUnloadedProfiles) {
194 if (!profiles::IsMultipleProfilesEnabled())
197 // Creating the profile would have initialized its hash store. Also, we don't
198 // know whether the newly created or original profile will be launched (does
199 // creating a profile cause it to be the most recently used?).
201 // So we will find the profile that isn't loaded, reset its hash store, and
202 // then verify in the _next_ launch that it is, indeed, restored despite not
203 // having been loaded.
205 const base::DictionaryValue* hashes =
206 g_browser_process->local_state()->GetDictionary(
207 prefs::kProfilePreferenceHashes);
209 // 4 is for hash_of_hashes, versions_dict, default profile, and new profile.
210 EXPECT_EQ(4U, hashes->size());
212 // One of the two profiles should not have been loaded. Reset its hash store.
213 const base::FilePath unloaded_profile_path = GetUnloadedProfilePath();
214 chrome_prefs::ResetPrefHashStore(unloaded_profile_path);
216 // One of the profile hash collections should be gone.
217 EXPECT_EQ(3U, hashes->size());
219 // No profile should have gone through the unloaded profile initialization in
220 // this phase as both profiles were already initialized at the beginning of
221 // this phase (resetting the unloaded profile's PrefHashStore should only
222 // force initialization in the next phase's startup).
224 0, GetTrackedPrefHistogramCount(
225 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
229 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest,
230 MAYBE_InitializeUnloadedProfiles) {
231 if (!profiles::IsMultipleProfilesEnabled())
234 const base::DictionaryValue* hashes =
235 g_browser_process->local_state()->GetDictionary(
236 prefs::kProfilePreferenceHashes);
238 // The deleted hash collection should be restored only if the current
239 // SettingsEnforcement group allows it.
240 if (is_unloaded_profile_seeding_allowed_) {
241 EXPECT_EQ(4U, hashes->size());
243 // Verify that the initialization truly did occur in this phase's startup;
244 // rather than in the previous phase's shutdown.
246 1, GetTrackedPrefHistogramCount(
247 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
250 EXPECT_EQ(3U, hashes->size());
253 0, GetTrackedPrefHistogramCount(
254 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
258 ProfileManager* profile_manager = g_browser_process->profile_manager();
260 // Verify that only one profile was loaded. We assume that the unloaded
261 // profile is the same one that wasn't loaded in the last launch (i.e., it's
262 // the one whose hash store we reset, and the fact that it is now restored is
263 // evidence that we restored the hashes of an unloaded profile.).
264 ASSERT_EQ(1U, profile_manager->GetLoadedProfiles().size());
266 // Loading the first profile should only have produced unchanged reports.
268 0, GetTrackedPrefHistogramCount(
269 "Settings.TrackedPreferenceChanged", true));
271 0, GetTrackedPrefHistogramCount(
272 "Settings.TrackedPreferenceCleared", true));
274 0, GetTrackedPrefHistogramCount(
275 "Settings.TrackedPreferenceInitialized", true));
277 0, GetTrackedPrefHistogramCount(
278 "Settings.TrackedPreferenceTrustedInitialized", true));
280 0, GetTrackedPrefHistogramCount(
281 "Settings.TrackedPreferenceMigrated", true));
282 int initial_unchanged_count =
283 GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged",
285 EXPECT_GT(initial_unchanged_count, 0);
287 if (is_unloaded_profile_seeding_allowed_) {
288 // Explicitly load the unloaded profile.
289 profile_manager->GetProfile(GetUnloadedProfilePath());
290 ASSERT_EQ(2U, profile_manager->GetLoadedProfiles().size());
292 // Loading the unloaded profile should only generate unchanged pings; and
293 // should have produced as many of them as loading the first profile.
295 0, GetTrackedPrefHistogramCount(
296 "Settings.TrackedPreferenceChanged", true));
298 0, GetTrackedPrefHistogramCount(
299 "Settings.TrackedPreferenceCleared", true));
301 0, GetTrackedPrefHistogramCount(
302 "Settings.TrackedPreferenceInitialized", true));
304 0, GetTrackedPrefHistogramCount(
305 "Settings.TrackedPreferenceTrustedInitialized", true));
307 0, GetTrackedPrefHistogramCount(
308 "Settings.TrackedPreferenceMigrated", true));
310 initial_unchanged_count * 2,
311 GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged",
316 INSTANTIATE_TEST_CASE_P(
317 PrefHashBrowserTestInstance,
320 chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,
321 chrome_prefs::internals::kSettingsEnforcementGroupEnforceOnload,
322 chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways));