Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / passwords_helper.cc
blobd0cc03b3af5e2c389f02bc414f7e50b5400236a1
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/sync/test/integration/passwords_helper.h"
7 #include "base/compiler_specific.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/time/time.h"
12 #include "chrome/browser/password_manager/password_store_factory.h"
13 #include "chrome/browser/sync/profile_sync_service.h"
14 #include "chrome/browser/sync/profile_sync_service_factory.h"
15 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
16 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
17 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
18 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
19 #include "components/password_manager/core/browser/password_manager_test_utils.h"
20 #include "components/password_manager/core/browser/password_store.h"
21 #include "components/password_manager/core/browser/password_store_consumer.h"
22 #include "content/public/test/test_utils.h"
24 using autofill::PasswordForm;
25 using password_manager::PasswordStore;
26 using sync_datatype_helper::test;
28 namespace {
30 const char kFakeSignonRealm[] = "http://fake-signon-realm.google.com/";
31 const char kIndexedFakeOrigin[] = "http://fake-signon-realm.google.com/%d";
33 // We use a WaitableEvent to wait when logins are added, removed, or updated
34 // instead of running the UI message loop because of a restriction that
35 // prevents a DB thread from initiating a quit of the UI message loop.
36 void PasswordStoreCallback(base::WaitableEvent* wait_event) {
37 // Wake up passwords_helper::AddLogin.
38 wait_event->Signal();
41 class PasswordStoreConsumerHelper
42 : public password_manager::PasswordStoreConsumer {
43 public:
44 PasswordStoreConsumerHelper() {}
46 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
47 result_.swap(results);
48 // Quit the message loop to wake up passwords_helper::GetLogins.
49 base::MessageLoopForUI::current()->Quit();
52 ScopedVector<PasswordForm> result() { return result_.Pass(); }
54 private:
55 ScopedVector<PasswordForm> result_;
57 DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper);
60 // PasswordForm::date_synced is a local field. Therefore it may be different
61 // across clients.
62 void ClearSyncDateField(std::vector<PasswordForm*>* forms) {
63 for (PasswordForm* form : *forms) {
64 form->date_synced = base::Time();
68 } // namespace
70 namespace passwords_helper {
72 void AddLogin(PasswordStore* store, const PasswordForm& form) {
73 ASSERT_TRUE(store);
74 base::WaitableEvent wait_event(true, false);
75 store->AddLogin(form);
76 store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
77 wait_event.Wait();
80 void UpdateLogin(PasswordStore* store, const PasswordForm& form) {
81 ASSERT_TRUE(store);
82 base::WaitableEvent wait_event(true, false);
83 store->UpdateLogin(form);
84 store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
85 wait_event.Wait();
88 ScopedVector<PasswordForm> GetLogins(PasswordStore* store) {
89 EXPECT_TRUE(store);
90 PasswordForm matcher_form;
91 matcher_form.signon_realm = kFakeSignonRealm;
92 PasswordStoreConsumerHelper consumer;
93 store->GetLogins(matcher_form, PasswordStore::DISALLOW_PROMPT, &consumer);
94 content::RunMessageLoop();
95 return consumer.result();
98 void RemoveLogin(PasswordStore* store, const PasswordForm& form) {
99 ASSERT_TRUE(store);
100 base::WaitableEvent wait_event(true, false);
101 store->RemoveLogin(form);
102 store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
103 wait_event.Wait();
106 void RemoveLogins(PasswordStore* store) {
107 ScopedVector<PasswordForm> forms = GetLogins(store);
108 for (const PasswordForm* form : forms) {
109 RemoveLogin(store, *form);
113 void SetEncryptionPassphrase(int index,
114 const std::string& passphrase,
115 ProfileSyncService::PassphraseType type) {
116 ProfileSyncServiceFactory::GetForProfile(
117 test()->GetProfile(index))->SetEncryptionPassphrase(passphrase, type);
120 bool SetDecryptionPassphrase(int index, const std::string& passphrase) {
121 return ProfileSyncServiceFactory::GetForProfile(
122 test()->GetProfile(index))->SetDecryptionPassphrase(passphrase);
125 PasswordStore* GetPasswordStore(int index) {
126 return PasswordStoreFactory::GetForProfile(test()->GetProfile(index),
127 ServiceAccessType::IMPLICIT_ACCESS)
128 .get();
131 PasswordStore* GetVerifierPasswordStore() {
132 return PasswordStoreFactory::GetForProfile(
133 test()->verifier(), ServiceAccessType::IMPLICIT_ACCESS).get();
136 bool ProfileContainsSamePasswordFormsAsVerifier(int index) {
137 ScopedVector<PasswordForm> verifier_forms =
138 GetLogins(GetVerifierPasswordStore());
139 ScopedVector<PasswordForm> forms = GetLogins(GetPasswordStore(index));
140 ClearSyncDateField(&forms.get());
141 bool result = password_manager::ContainsSamePasswordFormsPtr(
142 verifier_forms.get(), forms.get());
143 if (!result) {
144 VLOG(1) << "Password forms in Verifier Profile:";
145 for (const PasswordForm* form : verifier_forms) {
146 VLOG(1) << *form;
148 VLOG(1) << "Password forms in Profile" << index << ":";
149 for (const PasswordForm* form : forms) {
150 VLOG(1) << *form;
153 return result;
156 bool ProfilesContainSamePasswordForms(int index_a, int index_b) {
157 ScopedVector<PasswordForm> forms_a = GetLogins(GetPasswordStore(index_a));
158 ScopedVector<PasswordForm> forms_b = GetLogins(GetPasswordStore(index_b));
159 ClearSyncDateField(&forms_a.get());
160 ClearSyncDateField(&forms_b.get());
161 bool result = password_manager::ContainsSamePasswordFormsPtr(forms_a.get(),
162 forms_b.get());
163 if (!result) {
164 VLOG(1) << "Password forms in Profile" << index_a << ":";
165 for (const PasswordForm* form : forms_a) {
166 VLOG(1) << *form;
168 VLOG(1) << "Password forms in Profile" << index_b << ":";
169 for (const PasswordForm* form : forms_b) {
170 VLOG(1) << *form;
173 return result;
176 bool AllProfilesContainSamePasswordFormsAsVerifier() {
177 for (int i = 0; i < test()->num_clients(); ++i) {
178 if (!ProfileContainsSamePasswordFormsAsVerifier(i)) {
179 DVLOG(1) << "Profile " << i << " does not contain the same password"
180 " forms as the verifier.";
181 return false;
184 return true;
187 bool AllProfilesContainSamePasswordForms() {
188 for (int i = 1; i < test()->num_clients(); ++i) {
189 if (!ProfilesContainSamePasswordForms(0, i)) {
190 DVLOG(1) << "Profile " << i << " does not contain the same password"
191 " forms as Profile 0.";
192 return false;
195 return true;
198 namespace {
200 // Helper class used in the implementation of
201 // AwaitAllProfilesContainSamePasswordForms.
202 class SamePasswordFormsChecker : public MultiClientStatusChangeChecker {
203 public:
204 SamePasswordFormsChecker();
205 ~SamePasswordFormsChecker() override;
207 bool IsExitConditionSatisfied() override;
208 std::string GetDebugMessage() const override;
210 private:
211 bool in_progress_;
212 bool needs_recheck_;
215 SamePasswordFormsChecker::SamePasswordFormsChecker()
216 : MultiClientStatusChangeChecker(
217 sync_datatype_helper::test()->GetSyncServices()),
218 in_progress_(false),
219 needs_recheck_(false) {}
221 SamePasswordFormsChecker::~SamePasswordFormsChecker() {}
223 // This method needs protection against re-entrancy.
225 // This function indirectly calls GetLogins(), which starts a RunLoop on the UI
226 // thread. This can be a problem, since the next task to execute could very
227 // well contain a ProfileSyncService::OnStateChanged() event, which would
228 // trigger another call to this here function, and start another layer of
229 // nested RunLoops. That makes the StatusChangeChecker's Quit() method
230 // ineffective.
232 // The work-around is to not allow re-entrancy. But we can't just drop
233 // IsExitConditionSatisifed() calls if one is already in progress. Instead, we
234 // set a flag to ask the current execution of IsExitConditionSatisfied() to be
235 // re-run. This ensures that the return value is always based on the most
236 // up-to-date state.
237 bool SamePasswordFormsChecker::IsExitConditionSatisfied() {
238 if (in_progress_) {
239 LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
240 needs_recheck_ = true;
241 return false;
244 // Keep retrying until we get a good reading.
245 bool result = false;
246 in_progress_ = true;
247 do {
248 needs_recheck_ = false;
249 result = AllProfilesContainSamePasswordForms();
250 } while (needs_recheck_);
251 in_progress_ = false;
252 return result;
255 std::string SamePasswordFormsChecker::GetDebugMessage() const {
256 return "Waiting for matching passwords";
259 } // namespace
261 bool AwaitAllProfilesContainSamePasswordForms() {
262 SamePasswordFormsChecker checker;
263 checker.Wait();
264 return !checker.TimedOut();
267 namespace {
269 // Helper class used in the implementation of
270 // AwaitProfileContainSamePasswordFormsAsVerifier.
271 class SamePasswordFormsAsVerifierChecker
272 : public SingleClientStatusChangeChecker {
273 public:
274 explicit SamePasswordFormsAsVerifierChecker(int index);
275 ~SamePasswordFormsAsVerifierChecker() override;
277 bool IsExitConditionSatisfied() override;
278 std::string GetDebugMessage() const override;
280 private:
281 int index_;
283 bool in_progress_;
284 bool needs_recheck_;
287 SamePasswordFormsAsVerifierChecker::SamePasswordFormsAsVerifierChecker(int i)
288 : SingleClientStatusChangeChecker(
289 sync_datatype_helper::test()->GetSyncService(i)),
290 index_(i),
291 in_progress_(false),
292 needs_recheck_(false) {
295 SamePasswordFormsAsVerifierChecker::~SamePasswordFormsAsVerifierChecker() {
298 // This method uses the same re-entrancy prevention trick as
299 // the SamePasswordFormsChecker.
300 bool SamePasswordFormsAsVerifierChecker::IsExitConditionSatisfied() {
301 if (in_progress_) {
302 LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
303 needs_recheck_ = true;
304 return false;
307 // Keep retrying until we get a good reading.
308 bool result = false;
309 in_progress_ = true;
310 do {
311 needs_recheck_ = false;
312 result = ProfileContainsSamePasswordFormsAsVerifier(index_);
313 } while (needs_recheck_);
314 in_progress_ = false;
315 return result;
318 std::string SamePasswordFormsAsVerifierChecker::GetDebugMessage() const {
319 return "Waiting for passwords to match verifier";
322 } // namespace
324 bool AwaitProfileContainsSamePasswordFormsAsVerifier(int index) {
325 SamePasswordFormsAsVerifierChecker checker(index);
326 checker.Wait();
327 return !checker.TimedOut();
330 int GetPasswordCount(int index) {
331 ScopedVector<PasswordForm> forms = GetLogins(GetPasswordStore(index));
332 return forms.size();
335 int GetVerifierPasswordCount() {
336 ScopedVector<PasswordForm> verifier_forms =
337 GetLogins(GetVerifierPasswordStore());
338 return verifier_forms.size();
341 PasswordForm CreateTestPasswordForm(int index) {
342 PasswordForm form;
343 form.signon_realm = kFakeSignonRealm;
344 form.origin = GURL(base::StringPrintf(kIndexedFakeOrigin, index));
345 form.username_value =
346 base::ASCIIToUTF16(base::StringPrintf("username%d", index));
347 form.password_value =
348 base::ASCIIToUTF16(base::StringPrintf("password%d", index));
349 form.date_created = base::Time::Now();
350 return form;
353 } // namespace passwords_helper