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"
35 #if defined(OS_CHROMEOS)
36 #include "chromeos/chromeos_switches.h"
41 // An observer that returns back to test code after a new profile is
43 void OnUnblockOnProfileCreation(const base::Closure
& callback
,
45 Profile::CreateStatus status
) {
47 case Profile::CREATE_STATUS_CREATED
:
48 // Wait for CREATE_STATUS_INITIALIZED.
50 case Profile::CREATE_STATUS_INITIALIZED
:
54 ADD_FAILURE() << "Unexpected Profile::CreateStatus: " << status
;
60 // Finds a profile path corresponding to a profile that has not been loaded yet.
61 base::FilePath
GetUnloadedProfilePath() {
62 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
63 const ProfileInfoCache
& cache
= profile_manager
->GetProfileInfoCache();
64 const std::vector
<Profile
*> loaded_profiles
=
65 profile_manager
->GetLoadedProfiles();
66 std::set
<base::FilePath
> profile_paths
;
67 for (size_t i
= 0; i
< cache
.GetNumberOfProfiles(); ++i
)
68 profile_paths
.insert(cache
.GetPathOfProfileAtIndex(i
));
69 for (size_t i
= 0; i
< loaded_profiles
.size(); ++i
)
70 EXPECT_EQ(1U, profile_paths
.erase(loaded_profiles
[i
]->GetPath()));
71 if (profile_paths
.size())
72 return *profile_paths
.begin();
73 return base::FilePath();
76 // Returns the number of times |histogram_name| was reported so far; adding the
77 // results of the first 100 buckets (there are only ~14 reporting IDs as of this
78 // writting; varies depending on the platform). If |expect_zero| is true, this
79 // method will explicitly report IDs that are non-zero for ease of diagnosis.
80 int GetTrackedPrefHistogramCount(const char* histogram_name
, bool expect_zero
) {
81 const base::HistogramBase
* histogram
=
82 base::StatisticsRecorder::FindHistogram(histogram_name
);
86 scoped_ptr
<base::HistogramSamples
> samples(histogram
->SnapshotSamples());
88 for (int i
= 0; i
< 100; ++i
) {
89 int count_for_id
= samples
->GetCount(i
);
93 EXPECT_EQ(0, count_for_id
) << "Faulty reporting_id: " << i
;
100 class PrefHashBrowserTest
: public InProcessBrowserTest
,
101 public testing::WithParamInterface
<std::string
> {
103 PrefHashBrowserTest()
104 : is_unloaded_profile_seeding_allowed_(
105 IsUnloadedProfileSeedingAllowed()) {}
107 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
108 InProcessBrowserTest::SetUpCommandLine(command_line
);
109 command_line
->AppendSwitchASCII(
110 switches::kForceFieldTrials
,
111 std::string(chrome_prefs::internals::kSettingsEnforcementTrialName
) +
112 "/" + GetParam() + "/");
113 #if defined(OS_CHROMEOS)
114 command_line
->AppendSwitch(
115 chromeos::switches::kIgnoreUserProfileMappingForTests
);
119 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE
{
120 // Force the delayed PrefHashStore update task to happen immediately with
121 // no domain check (bots are on a domain).
122 chrome_prefs::DisableDelaysAndDomainCheckForTesting();
125 virtual void SetUpOnMainThread() OVERRIDE
{
126 // content::RunAllPendingInMessageLoop() is already called before
127 // SetUpOnMainThread() in in_process_browser_test.cc which guarantees that
128 // UpdateAllPrefHashStoresIfRequired() has already been called.
130 // Now flush the blocking pool to force any pending JsonPrefStore async read
132 content::BrowserThread::GetBlockingPool()->FlushForTesting();
134 // And finally run tasks on this message loop again to process the OnRead()
135 // callbacks resulting from the file reads above.
136 content::RunAllPendingInMessageLoop();
140 const bool is_unloaded_profile_seeding_allowed_
;
143 bool IsUnloadedProfileSeedingAllowed() const {
144 #if defined(OFFICIAL_BUILD)
145 // SettingsEnforcement can't be forced via --force-fieldtrials in official
146 // builds. Explicitly return whether the default in
147 // chrome_pref_service_factory.cc allows unloaded profile seeding on this
150 #endif // defined(OFFICIAL_BUILD)
151 return GetParam() == chrome_prefs::internals::
152 kSettingsEnforcementGroupNoEnforcement
||
153 GetParam() == chrome_prefs::internals::
154 kSettingsEnforcementGroupEnforceOnload
;
158 #if defined(OS_CHROMEOS)
159 // PrefHash service has been disabled on ChromeOS: crbug.com/343261
160 #define MAYBE_PRE_PRE_InitializeUnloadedProfiles DISABLED_PRE_PRE_InitializeUnloadedProfiles
161 #define MAYBE_PRE_InitializeUnloadedProfiles DISABLED_PRE_InitializeUnloadedProfiles
162 #define MAYBE_InitializeUnloadedProfiles DISABLED_InitializeUnloadedProfiles
164 #define MAYBE_PRE_PRE_InitializeUnloadedProfiles PRE_PRE_InitializeUnloadedProfiles
165 #define MAYBE_PRE_InitializeUnloadedProfiles PRE_InitializeUnloadedProfiles
166 #define MAYBE_InitializeUnloadedProfiles InitializeUnloadedProfiles
169 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest
,
170 MAYBE_PRE_PRE_InitializeUnloadedProfiles
) {
171 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
173 // Create an additional profile.
174 const base::FilePath new_path
=
175 profile_manager
->GenerateNextProfileDirectoryPath();
176 const scoped_refptr
<content::MessageLoopRunner
> runner(
177 new content::MessageLoopRunner
);
178 profile_manager
->CreateProfileAsync(
180 base::Bind(&OnUnblockOnProfileCreation
, runner
->QuitClosure()),
185 // Spin to allow profile creation to take place, loop is terminated
186 // by OnUnblockOnProfileCreation when the profile is created.
189 // No profile should have gone through the unloaded profile initialization in
190 // this phase as both profiles should have been loaded normally.
192 0, GetTrackedPrefHistogramCount(
193 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
197 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest
,
198 MAYBE_PRE_InitializeUnloadedProfiles
) {
199 // Creating the profile would have initialized its hash store. Also, we don't
200 // know whether the newly created or original profile will be launched (does
201 // creating a profile cause it to be the most recently used?).
203 // So we will find the profile that isn't loaded, reset its hash store, and
204 // then verify in the _next_ launch that it is, indeed, restored despite not
205 // having been loaded.
207 const base::DictionaryValue
* hashes
=
208 g_browser_process
->local_state()->GetDictionary(
209 prefs::kProfilePreferenceHashes
);
211 // 4 is for hash_of_hashes, versions_dict, default profile, and new profile.
212 EXPECT_EQ(4U, hashes
->size());
214 // One of the two profiles should not have been loaded. Reset its hash store.
215 const base::FilePath unloaded_profile_path
= GetUnloadedProfilePath();
216 chrome_prefs::ResetPrefHashStore(unloaded_profile_path
);
218 // One of the profile hash collections should be gone.
219 EXPECT_EQ(3U, hashes
->size());
221 // No profile should have gone through the unloaded profile initialization in
222 // this phase as both profiles were already initialized at the beginning of
223 // this phase (resetting the unloaded profile's PrefHashStore should only
224 // force initialization in the next phase's startup).
226 0, GetTrackedPrefHistogramCount(
227 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
231 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest
,
232 MAYBE_InitializeUnloadedProfiles
) {
233 const base::DictionaryValue
* hashes
=
234 g_browser_process
->local_state()->GetDictionary(
235 prefs::kProfilePreferenceHashes
);
237 // The deleted hash collection should be restored only if the current
238 // SettingsEnforcement group allows it.
239 if (is_unloaded_profile_seeding_allowed_
) {
240 EXPECT_EQ(4U, hashes
->size());
242 // Verify that the initialization truly did occur in this phase's startup;
243 // rather than in the previous phase's shutdown.
245 1, GetTrackedPrefHistogramCount(
246 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
249 EXPECT_EQ(3U, hashes
->size());
252 0, GetTrackedPrefHistogramCount(
253 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
257 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
259 // Verify that only one profile was loaded. We assume that the unloaded
260 // profile is the same one that wasn't loaded in the last launch (i.e., it's
261 // the one whose hash store we reset, and the fact that it is now restored is
262 // evidence that we restored the hashes of an unloaded profile.).
263 ASSERT_EQ(1U, profile_manager
->GetLoadedProfiles().size());
265 // Loading the first profile should only have produced unchanged reports.
267 0, GetTrackedPrefHistogramCount(
268 "Settings.TrackedPreferenceChanged", true));
270 0, GetTrackedPrefHistogramCount(
271 "Settings.TrackedPreferenceCleared", true));
273 0, GetTrackedPrefHistogramCount(
274 "Settings.TrackedPreferenceInitialized", true));
276 0, GetTrackedPrefHistogramCount(
277 "Settings.TrackedPreferenceTrustedInitialized", true));
279 0, GetTrackedPrefHistogramCount(
280 "Settings.TrackedPreferenceMigrated", true));
281 int initial_unchanged_count
=
282 GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged",
284 EXPECT_GT(initial_unchanged_count
, 0);
286 if (is_unloaded_profile_seeding_allowed_
) {
287 // Explicitly load the unloaded profile.
288 profile_manager
->GetProfile(GetUnloadedProfilePath());
289 ASSERT_EQ(2U, profile_manager
->GetLoadedProfiles().size());
291 // Loading the unloaded profile should only generate unchanged pings; and
292 // should have produced as many of them as loading the first profile.
294 0, GetTrackedPrefHistogramCount(
295 "Settings.TrackedPreferenceChanged", true));
297 0, GetTrackedPrefHistogramCount(
298 "Settings.TrackedPreferenceCleared", true));
300 0, GetTrackedPrefHistogramCount(
301 "Settings.TrackedPreferenceInitialized", true));
303 0, GetTrackedPrefHistogramCount(
304 "Settings.TrackedPreferenceTrustedInitialized", true));
306 0, GetTrackedPrefHistogramCount(
307 "Settings.TrackedPreferenceMigrated", true));
309 initial_unchanged_count
* 2,
310 GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged",
315 INSTANTIATE_TEST_CASE_P(
316 PrefHashBrowserTestInstance
,
319 chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement
,
320 chrome_prefs::internals::kSettingsEnforcementGroupEnforceOnload
,
321 chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways
,
322 chrome_prefs::internals::
323 kSettingsEnforcementGroupEnforceAlwaysWithExtensions
,
324 chrome_prefs::internals::
325 kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE
));