0259e6edb85a9eb4b3b7bd82a79cf9564444e1a2
[platform/framework/web/crosswalk.git] / src / chrome / browser / prefs / pref_hash_browsertest.cc
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 namespace {
36
37 // An observer that returns back to test code after a new profile is
38 // initialized.
39 void OnUnblockOnProfileCreation(const base::Closure& callback,
40                                 Profile* profile,
41                                 Profile::CreateStatus status) {
42   switch (status) {
43     case Profile::CREATE_STATUS_CREATED:
44       // Wait for CREATE_STATUS_INITIALIZED.
45       break;
46     case Profile::CREATE_STATUS_INITIALIZED:
47       callback.Run();
48       break;
49     default:
50       ADD_FAILURE() << "Unexpected Profile::CreateStatus: " << status;
51       callback.Run();
52       break;
53   }
54 }
55
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();
70 }
71
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);
79   if (!histogram)
80     return 0;
81
82   scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
83   int sum = 0;
84   for (int i = 0; i < 100; ++i) {
85     int count_for_id = samples->GetCount(i);
86     sum += count_for_id;
87
88     if (expect_zero)
89       EXPECT_EQ(0, count_for_id) << "Faulty reporting_id: " << i;
90   }
91   return sum;
92 }
93
94 }  // namespace
95
96 class PrefHashBrowserTest : public InProcessBrowserTest,
97                             public testing::WithParamInterface<std::string> {
98  public:
99   PrefHashBrowserTest()
100       : is_unloaded_profile_seeding_allowed_(
101             IsUnloadedProfileSeedingAllowed()) {}
102
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() + "/");
109   }
110
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();
115   }
116
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.
121
122     // Now flush the blocking pool to force any pending JsonPrefStore async read
123     // requests.
124     content::BrowserThread::GetBlockingPool()->FlushForTesting();
125
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();
129   }
130
131  protected:
132   const bool is_unloaded_profile_seeding_allowed_;
133
134  private:
135   bool IsUnloadedProfileSeedingAllowed() const {
136     const bool allowed_from_param =
137         GetParam() !=
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
142         // official builds.
143         true;
144 #else
145         false;
146 #endif
147     return allowed_from_param || allowed_from_configuration;
148   }
149 };
150
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
156 #else
157 #define MAYBE_PRE_PRE_InitializeUnloadedProfiles PRE_PRE_InitializeUnloadedProfiles
158 #define MAYBE_PRE_InitializeUnloadedProfiles PRE_InitializeUnloadedProfiles
159 #define MAYBE_InitializeUnloadedProfiles InitializeUnloadedProfiles
160 #endif
161
162 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest,
163                        MAYBE_PRE_PRE_InitializeUnloadedProfiles) {
164   if (!profiles::IsMultipleProfilesEnabled())
165     return;
166   ProfileManager* profile_manager = g_browser_process->profile_manager();
167
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(
174       new_path,
175       base::Bind(&OnUnblockOnProfileCreation, runner->QuitClosure()),
176       base::string16(),
177       base::string16(),
178       std::string());
179
180   // Spin to allow profile creation to take place, loop is terminated
181   // by OnUnblockOnProfileCreation when the profile is created.
182   runner->Run();
183
184   // No profile should have gone through the unloaded profile initialization in
185   // this phase as both profiles should have been loaded normally.
186   EXPECT_EQ(
187       0, GetTrackedPrefHistogramCount(
188              "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
189              true));
190 }
191
192 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest,
193                        MAYBE_PRE_InitializeUnloadedProfiles) {
194   if (!profiles::IsMultipleProfilesEnabled())
195     return;
196
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?).
200
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.
204
205   const base::DictionaryValue* hashes =
206       g_browser_process->local_state()->GetDictionary(
207           prefs::kProfilePreferenceHashes);
208
209   // 4 is for hash_of_hashes, versions_dict, default profile, and new profile.
210   EXPECT_EQ(4U, hashes->size());
211
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);
215
216   // One of the profile hash collections should be gone.
217   EXPECT_EQ(3U, hashes->size());
218
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).
223   EXPECT_EQ(
224       0, GetTrackedPrefHistogramCount(
225              "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
226              true));
227 }
228
229 IN_PROC_BROWSER_TEST_P(PrefHashBrowserTest,
230                        MAYBE_InitializeUnloadedProfiles) {
231   if (!profiles::IsMultipleProfilesEnabled())
232     return;
233
234   const base::DictionaryValue* hashes =
235       g_browser_process->local_state()->GetDictionary(
236           prefs::kProfilePreferenceHashes);
237
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());
242
243     // Verify that the initialization truly did occur in this phase's startup;
244     // rather than in the previous phase's shutdown.
245     EXPECT_EQ(
246         1, GetTrackedPrefHistogramCount(
247                "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
248                false));
249   } else {
250     EXPECT_EQ(3U, hashes->size());
251
252     EXPECT_EQ(
253         0, GetTrackedPrefHistogramCount(
254                "Settings.TrackedPreferencesAlternateStoreVersionUpdatedFrom",
255                true));
256   }
257
258   ProfileManager* profile_manager = g_browser_process->profile_manager();
259
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());
265
266   // Loading the first profile should only have produced unchanged reports.
267   EXPECT_EQ(
268       0, GetTrackedPrefHistogramCount(
269              "Settings.TrackedPreferenceChanged", true));
270   EXPECT_EQ(
271       0, GetTrackedPrefHistogramCount(
272              "Settings.TrackedPreferenceCleared", true));
273   EXPECT_EQ(
274       0, GetTrackedPrefHistogramCount(
275              "Settings.TrackedPreferenceInitialized", true));
276   EXPECT_EQ(
277       0, GetTrackedPrefHistogramCount(
278              "Settings.TrackedPreferenceTrustedInitialized", true));
279   EXPECT_EQ(
280       0, GetTrackedPrefHistogramCount(
281              "Settings.TrackedPreferenceMigrated", true));
282   int initial_unchanged_count =
283       GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged",
284                                    false);
285   EXPECT_GT(initial_unchanged_count, 0);
286
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());
291
292     // Loading the unloaded profile should only generate unchanged pings; and
293     // should have produced as many of them as loading the first profile.
294     EXPECT_EQ(
295         0, GetTrackedPrefHistogramCount(
296                "Settings.TrackedPreferenceChanged", true));
297     EXPECT_EQ(
298         0, GetTrackedPrefHistogramCount(
299                "Settings.TrackedPreferenceCleared", true));
300     EXPECT_EQ(
301         0, GetTrackedPrefHistogramCount(
302                "Settings.TrackedPreferenceInitialized", true));
303     EXPECT_EQ(
304         0, GetTrackedPrefHistogramCount(
305                "Settings.TrackedPreferenceTrustedInitialized", true));
306     EXPECT_EQ(
307         0, GetTrackedPrefHistogramCount(
308                "Settings.TrackedPreferenceMigrated", true));
309     EXPECT_EQ(
310         initial_unchanged_count * 2,
311         GetTrackedPrefHistogramCount("Settings.TrackedPreferenceUnchanged",
312                                      false));
313   }
314 }
315
316 INSTANTIATE_TEST_CASE_P(
317     PrefHashBrowserTestInstance,
318     PrefHashBrowserTest,
319     testing::Values(
320         chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement,
321         chrome_prefs::internals::kSettingsEnforcementGroupEnforceOnload,
322         chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways));