Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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. | |
| 4 | |
| 5 #include <set> | |
| 6 #include <vector> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 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" | |
| 34 | |
| 35 #if defined(OS_CHROMEOS) | |
| 36 #include "chromeos/chromeos_switches.h" | |
| 37 #endif | |
| 38 | |
| 39 namespace { | |
| 40 | |
| 41 // An observer that returns back to test code after a new profile is | |
| 42 // initialized. | |
| 43 void OnUnblockOnProfileCreation(const base::Closure& callback, | |
| 44 Profile* profile, | |
| 45 Profile::CreateStatus status) { | |
| 46 switch (status) { | |
| 47 case Profile::CREATE_STATUS_CREATED: | |
| 48 // Wait for CREATE_STATUS_INITIALIZED. | |
| 49 break; | |
| 50 case Profile::CREATE_STATUS_INITIALIZED: | |
| 51 callback.Run(); | |
| 52 break; | |
| 53 default: | |
| 54 ADD_FAILURE() << "Unexpected Profile::CreateStatus: " << status; | |
| 55 callback.Run(); | |
| 56 break; | |
| 57 } | |
| 58 } | |
| 59 | |
| 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(); | |
| 74 } | |
| 75 | |
| 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); | |
| 83 if (!histogram) | |
| 84 return 0; | |
| 85 | |
| 86 scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples()); | |
| 87 int sum = 0; | |
| 88 for (int i = 0; i < 100; ++i) { | |
| 89 int count_for_id = samples->GetCount(i); | |
| 90 sum += count_for_id; | |
| 91 | |
| 92 if (expect_zero) | |
| 93 EXPECT_EQ(0, count_for_id) << "Faulty reporting_id: " << i; | |
| 94 } | |
| 95 return sum; | |
| 96 } | |
| 97 | |
| 98 } // namespace | |
| 99 | |
| 100 class PrefHashBrowserTest : public InProcessBrowserTest, | |
| 101 public testing::WithParamInterface<std::string> { | |
| 102 public: | |
| 103 PrefHashBrowserTest() | |
| 104 : is_unloaded_profile_seeding_allowed_( | |
| 105 IsUnloadedProfileSeedingAllowed()) {} | |
| 106 | |
| 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); | |
| 116 #endif | |
| 117 } | |
| 118 | |
| 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(); | |
| 123 } | |
| 124 | |
| 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. | |
| 129 | |
| 130 // Now flush the blocking pool to force any pending JsonPrefStore async read | |
| 131 // requests. | |
| 132 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 133 | |
| 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(); | |
| 137 } | |
| 138 | |
| 139 protected: | |
| 140 const bool is_unloaded_profile_seeding_allowed_; | |
| 141 | |
| 142 private: | |
| 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 | |
| 148 // platform. | |
| 149 return true; | |
| 150 #endif // defined(OFFICIAL_BUILD) | |
| 151 return GetParam() == chrome_prefs::internals:: | |
| 152 kSettingsEnforcementGroupNoEnforcement || | |
| 153 GetParam() == chrome_prefs::internals:: | |
| 154 kSettingsEnforcementGroupEnforceOnload; | |
| 155 } | |
| 156 }; | |
| 157 | |
| 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_InitializeUnlo adedProfiles | |
| 161 #define MAYBE_PRE_InitializeUnloadedProfiles DISABLED_PRE_InitializeUnloadedProf iles | |
| 162 #define MAYBE_InitializeUnloadedProfiles DISABLED_InitializeUnloadedProfiles | |
| 163 #else | |
| 164 #define MAYBE_PRE_PRE_InitializeUnloadedProfiles PRE_PRE_InitializeUnloadedProfi les | |
| 165 #define MAYBE_PRE_InitializeUnloadedProfiles PRE_InitializeUnloadedProfiles | |
| 166 #define MAYBE_InitializeUnloadedProfiles InitializeUnloadedProfiles | |
| 167 #endif | |
| 168 | |
| 169 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest, | |
| 170 MAYBE_PRE_PRE_InitializeUnloadedProfiles) { | |
| 171 ProfileManager* profile_manager = g_browser_process->profile_manager(); | |
| 172 | |
| 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( | |
| 179 new_path, | |
| 180 base::Bind(&OnUnblockOnProfileCreation, runner->QuitClosure()), | |
| 181 base::string16(), | |
| 182 base::string16(), | |
| 183 std::string()); | |
| 184 | |
| 185 // Spin to allow profile creation to take place, loop is terminated | |
| 186 // by OnUnblockOnProfileCreation when the profile is created. | |
| 187 runner->Run(); | |
| 188 | |
| 189 // No profile should have gone through the unloaded profile initialization in | |
| 190 // this phase as both profiles should have been loaded normally. | |
| 191 EXPECT_EQ( | |
| 192 0, GetTrackedPrefHistogramCount( | |
| 193 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom", | |
| 194 true)); | |
| 195 } | |
| 196 | |
| 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?). | |
| 202 | |
| 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. | |
| 206 | |
| 207 const base::DictionaryValue* hashes = | |
| 208 g_browser_process->local_state()->GetDictionary( | |
| 209 prefs::kProfilePreferenceHashes); | |
| 210 | |
| 211 // 4 is for hash_of_hashes, versions_dict, default profile, and new profile. | |
| 212 EXPECT_EQ(4U, hashes->size()); | |
| 213 | |
| 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); | |
| 217 | |
| 218 // One of the profile hash collections should be gone. | |
| 219 EXPECT_EQ(3U, hashes->size()); | |
| 220 | |
| 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). | |
| 225 EXPECT_EQ( | |
| 226 0, GetTrackedPrefHistogramCount( | |
| 227 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom", | |
| 228 true)); | |
| 229 } | |
| 230 | |
| 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); | |
| 236 | |
| 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()); | |
| 241 | |
| 242 // Verify that the initialization truly did occur in this phase's startup; | |
| 243 // rather than in the previous phase's shutdown. | |
| 244 EXPECT_EQ( | |
| 245 1, GetTrackedPrefHistogramCount( | |
| 246 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom", | |
| 247 false)); | |
| 248 } else { | |
| 249 EXPECT_EQ(3U, hashes->size()); | |
| 250 | |
| 251 EXPECT_EQ( | |
| 252 0, GetTrackedPrefHistogramCount( | |
| 253 "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom", | |
| 254 true)); | |
| 255 } | |
| 256 | |
| 257 ProfileManager* profile_manager = g_browser_process->profile_manager(); | |
| 258 | |
| 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()); | |
| 264 | |
| 265 // Loading the first profile should only have produced unchanged reports. | |
| 266 EXPECT_EQ( | |
| 267 0, GetTrackedPrefHistogramCount( | |
| 268 "Settings.TrackedPreferenceChanged", true)); | |
| 269 EXPECT_EQ( | |
| 270 0, GetTrackedPrefHistogramCount( | |
| 271 "Settings.TrackedPreferenceCleared", true)); | |
| 272 EXPECT_EQ( | |
| 273 0, GetTrackedPrefHistogramCount( | |
| 274 "Settings.TrackedPreferenceInitialized", true)); | |
| 275 EXPECT_EQ( | |
| 276 0, GetTrackedPrefHistogramCount( | |
| 277 "Settings.TrackedPreferenceTrustedInitialized", true)); | |
| 278 EXPECT_EQ( | |
| 279 0, GetTrackedPrefHistogramCount( | |
| 280 "Settings.TrackedPreferenceMigrated", true)); | |
| 281 int initial_unchanged_count = | |
| 282 GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged", | |
| 283 false); | |
| 284 EXPECT_GT(initial_unchanged_count, 0); | |
| 285 | |
| 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()); | |
| 290 | |
| 291 // Loading the unloaded profile should only generate unchanged pings; and | |
| 292 // should have produced as many of them as loading the first profile. | |
| 293 EXPECT_EQ( | |
| 294 0, GetTrackedPrefHistogramCount( | |
| 295 "Settings.TrackedPreferenceChanged", true)); | |
| 296 EXPECT_EQ( | |
| 297 0, GetTrackedPrefHistogramCount( | |
| 298 "Settings.TrackedPreferenceCleared", true)); | |
| 299 EXPECT_EQ( | |
| 300 0, GetTrackedPrefHistogramCount( | |
| 301 "Settings.TrackedPreferenceInitialized", true)); | |
| 302 EXPECT_EQ( | |
| 303 0, GetTrackedPrefHistogramCount( | |
| 304 "Settings.TrackedPreferenceTrustedInitialized", true)); | |
| 305 EXPECT_EQ( | |
| 306 0, GetTrackedPrefHistogramCount( | |
| 307 "Settings.TrackedPreferenceMigrated", true)); | |
| 308 EXPECT_EQ( | |
| 309 initial_unchanged_count * 2, | |
| 310 GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged", | |
| 311 false)); | |
| 312 } | |
|
gab
2014/06/11 19:25:41
This test also had the benefit of being the only i
erikwright (departed)
2014/06/11 21:08:35
Do you want that done in this CL or separately?
gab
2014/06/11 21:39:29
Separately, as a follow-up to the main CL (please
| |
| 313 } | |
| 314 | |
| 315 INSTANTIATE_TEST_CASE_P( | |
| 316 PrefHashBrowserTestInstance, | |
| 317 PrefHashBrowserTest, | |
| 318 testing::Values( | |
| 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)); | |
| OLD | NEW |