1 // Copyright (c) 2011 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 "chrome/browser/sync/test/integration/preferences_helper.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/threading/thread_restrictions.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
13 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
14 #include "chrome/browser/sync/test/integration/sync_test.h"
15 #include "chrome/common/chrome_constants.h"
16 #include "components/pref_registry/pref_registry_syncable.h"
17 #include "components/prefs/persistent_pref_store.h"
18 #include "components/prefs/pref_change_registrar.h"
19 #include "components/prefs/pref_service.h"
20 #include "components/prefs/scoped_user_pref_update.h"
21 
22 using sync_datatype_helper::test;
23 
24 namespace preferences_helper {
25 
GetPrefs(int index)26 PrefService* GetPrefs(int index) {
27   return test()->GetProfile(index)->GetPrefs();
28 }
29 
GetRegistry(Profile * profile)30 user_prefs::PrefRegistrySyncable* GetRegistry(Profile* profile) {
31   // TODO(tschumann): Not sure what's the cleanest way to avoid this deprecated
32   // call is. Ideally we could use a servicification integration test.
33   // Another option would be to have a ForTest-only variant of
34   // KeyedServiceBaseFactory::GetAssociatedPrefRegistry().
35   return static_cast<user_prefs::PrefRegistrySyncable*>(
36       profile->GetPrefs()->DeprecatedGetPrefRegistry());
37 }
38 
ChangeBooleanPref(int index,const char * pref_name)39 void ChangeBooleanPref(int index, const char* pref_name) {
40   bool new_value = !GetPrefs(index)->GetBoolean(pref_name);
41   GetPrefs(index)->SetBoolean(pref_name, new_value);
42 }
43 
ChangeIntegerPref(int index,const char * pref_name,int new_value)44 void ChangeIntegerPref(int index, const char* pref_name, int new_value) {
45   GetPrefs(index)->SetInteger(pref_name, new_value);
46 }
47 
ChangeStringPref(int index,const char * pref_name,const std::string & new_value)48 void ChangeStringPref(int index,
49                       const char* pref_name,
50                       const std::string& new_value) {
51   GetPrefs(index)->SetString(pref_name, new_value);
52 }
53 
ClearPref(int index,const char * pref_name)54 void ClearPref(int index, const char* pref_name) {
55   GetPrefs(index)->ClearPref(pref_name);
56 }
57 
ChangeListPref(int index,const char * pref_name,const base::ListValue & new_value)58 void ChangeListPref(int index,
59                     const char* pref_name,
60                     const base::ListValue& new_value) {
61   ListPrefUpdate update(GetPrefs(index), pref_name);
62   base::ListValue* list = update.Get();
63   for (const auto& it : new_value) {
64     list->Append(it.CreateDeepCopy());
65   }
66 }
67 
BuildPrefStoreFromPrefsFile(Profile * profile)68 scoped_refptr<PrefStore> BuildPrefStoreFromPrefsFile(Profile* profile) {
69   base::RunLoop run_loop;
70   profile->GetPrefs()->CommitPendingWrite(run_loop.QuitClosure());
71   run_loop.Run();
72 
73   auto pref_store = base::MakeRefCounted<JsonPrefStore>(
74       profile->GetPath().Append(chrome::kPreferencesFilename));
75   base::ScopedAllowBlockingForTesting allow_blocking;
76   if (pref_store->ReadPrefs() != PersistentPrefStore::PREF_READ_ERROR_NONE) {
77     ADD_FAILURE() << " Failed reading the prefs file into the store.";
78   }
79 
80   return pref_store;
81 }
82 
BooleanPrefMatches(const char * pref_name)83 bool BooleanPrefMatches(const char* pref_name) {
84   bool reference_value = GetPrefs(0)->GetBoolean(pref_name);
85   for (int i = 1; i < test()->num_clients(); ++i) {
86     if (reference_value != GetPrefs(i)->GetBoolean(pref_name)) {
87       DVLOG(1) << "Boolean preference " << pref_name << " mismatched in"
88                << " profile " << i << ".";
89       return false;
90     }
91   }
92   return true;
93 }
94 
IntegerPrefMatches(const char * pref_name)95 bool IntegerPrefMatches(const char* pref_name) {
96   int reference_value = GetPrefs(0)->GetInteger(pref_name);
97   for (int i = 1; i < test()->num_clients(); ++i) {
98     if (reference_value != GetPrefs(i)->GetInteger(pref_name)) {
99       DVLOG(1) << "Integer preference " << pref_name << " mismatched in"
100                << " profile " << i << ".";
101       return false;
102     }
103   }
104   return true;
105 }
106 
StringPrefMatches(const char * pref_name)107 bool StringPrefMatches(const char* pref_name) {
108   std::string reference_value = GetPrefs(0)->GetString(pref_name);
109   for (int i = 1; i < test()->num_clients(); ++i) {
110     if (reference_value != GetPrefs(i)->GetString(pref_name)) {
111       DVLOG(1) << "String preference " << pref_name << " mismatched in"
112                << " profile " << i << ".";
113       return false;
114     }
115   }
116   return true;
117 }
118 
ClearedPrefMatches(const char * pref_name)119 bool ClearedPrefMatches(const char* pref_name) {
120   for (int i = 0; i < test()->num_clients(); ++i) {
121     if (GetPrefs(i)->GetUserPrefValue(pref_name)) {
122       DVLOG(1) << "Preference " << pref_name << " isn't cleared in"
123                << " profile " << i << ".";
124       return false;
125     }
126   }
127   return true;
128 }
129 
ListPrefMatches(const char * pref_name)130 bool ListPrefMatches(const char* pref_name) {
131   const base::ListValue* reference_value = GetPrefs(0)->GetList(pref_name);
132   for (int i = 1; i < test()->num_clients(); ++i) {
133     if (!reference_value->Equals(GetPrefs(i)->GetList(pref_name))) {
134       DVLOG(1) << "List preference " << pref_name << " mismatched in"
135                << " profile " << i << ".";
136       return false;
137     }
138   }
139   return true;
140 }
141 
142 }  // namespace preferences_helper
143 
PrefMatchChecker(const char * path)144 PrefMatchChecker::PrefMatchChecker(const char* path) : path_(path) {
145   for (int i = 0; i < test()->num_clients(); ++i) {
146     RegisterPrefListener(preferences_helper::GetPrefs(i));
147   }
148 }
149 
150 PrefMatchChecker::~PrefMatchChecker() = default;
151 
GetPath() const152 const char* PrefMatchChecker::GetPath() const {
153   return path_;
154 }
155 
RegisterPrefListener(PrefService * pref_service)156 void PrefMatchChecker::RegisterPrefListener(PrefService* pref_service) {
157   std::unique_ptr<PrefChangeRegistrar> registrar(new PrefChangeRegistrar());
158   registrar->Init(pref_service);
159   registrar->Add(path_,
160                  base::BindRepeating(&PrefMatchChecker::CheckExitCondition,
161                                      base::Unretained(this)));
162   pref_change_registrars_.push_back(std::move(registrar));
163 }
164 
ListPrefMatchChecker(const char * path)165 ListPrefMatchChecker::ListPrefMatchChecker(const char* path)
166     : PrefMatchChecker(path) {}
167 
IsExitConditionSatisfied(std::ostream * os)168 bool ListPrefMatchChecker::IsExitConditionSatisfied(std::ostream* os) {
169   *os << "Waiting for pref '" << GetPath() << "' to match";
170   return preferences_helper::ListPrefMatches(GetPath());
171 }
172 
BooleanPrefMatchChecker(const char * path)173 BooleanPrefMatchChecker::BooleanPrefMatchChecker(const char* path)
174     : PrefMatchChecker(path) {}
175 
IsExitConditionSatisfied(std::ostream * os)176 bool BooleanPrefMatchChecker::IsExitConditionSatisfied(std::ostream* os) {
177   *os << "Waiting for pref '" << GetPath() << "' to match";
178   return preferences_helper::BooleanPrefMatches(GetPath());
179 }
180 
IntegerPrefMatchChecker(const char * path)181 IntegerPrefMatchChecker::IntegerPrefMatchChecker(const char* path)
182     : PrefMatchChecker(path) {}
183 
IsExitConditionSatisfied(std::ostream * os)184 bool IntegerPrefMatchChecker::IsExitConditionSatisfied(std::ostream* os) {
185   *os << "Waiting for pref '" << GetPath() << "' to match";
186   return preferences_helper::IntegerPrefMatches(GetPath());
187 }
188 
StringPrefMatchChecker(const char * path)189 StringPrefMatchChecker::StringPrefMatchChecker(const char* path)
190     : PrefMatchChecker(path) {}
191 
IsExitConditionSatisfied(std::ostream * os)192 bool StringPrefMatchChecker::IsExitConditionSatisfied(std::ostream* os) {
193   *os << "Waiting for pref '" << GetPath() << "' to match";
194   return preferences_helper::StringPrefMatches(GetPath());
195 }
196 
ClearedPrefMatchChecker(const char * path)197 ClearedPrefMatchChecker::ClearedPrefMatchChecker(const char* path)
198     : PrefMatchChecker(path) {}
199 
IsExitConditionSatisfied(std::ostream * os)200 bool ClearedPrefMatchChecker::IsExitConditionSatisfied(std::ostream* os) {
201   *os << "Waiting for pref '" << GetPath() << "' to match";
202   return preferences_helper::ClearedPrefMatches(GetPath());
203 }
204