BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / passwords_helper.cc
blobade29b66c0a562b4e31b0c7d914b27b26533ab91
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 <sstream>
9 #include "base/compiler_specific.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/password_manager/password_store_factory.h"
15 #include "chrome/browser/sync/profile_sync_service.h"
16 #include "chrome/browser/sync/profile_sync_service_factory.h"
17 #include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h"
18 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
19 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
20 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
21 #include "components/password_manager/core/browser/password_manager_test_utils.h"
22 #include "components/password_manager/core/browser/password_store.h"
23 #include "components/password_manager/core/browser/password_store_consumer.h"
24 #include "content/public/test/test_utils.h"
26 using autofill::PasswordForm;
27 using password_manager::PasswordStore;
28 using sync_datatype_helper::test;
30 namespace {
32 const char kFakeSignonRealm[] = "http://fake-signon-realm.google.com/";
33 const char kIndexedFakeOrigin[] = "http://fake-signon-realm.google.com/%d";
35 // We use a WaitableEvent to wait when logins are added, removed, or updated
36 // instead of running the UI message loop because of a restriction that
37 // prevents a DB thread from initiating a quit of the UI message loop.
38 void PasswordStoreCallback(base::WaitableEvent* wait_event) {
39 // Wake up passwords_helper::AddLogin.
40 wait_event->Signal();
43 class PasswordStoreConsumerHelper
44 : public password_manager::PasswordStoreConsumer {
45 public:
46 PasswordStoreConsumerHelper() {}
48 void OnGetPasswordStoreResults(ScopedVector<PasswordForm> results) override {
49 result_.swap(results);
50 // Quit the message loop to wake up passwords_helper::GetLogins.
51 base::MessageLoopForUI::current()->Quit();
54 ScopedVector<PasswordForm> result() { return result_.Pass(); }
56 private:
57 ScopedVector<PasswordForm> result_;
59 DISALLOW_COPY_AND_ASSIGN(PasswordStoreConsumerHelper);
62 // PasswordForm::date_synced is a local field. Therefore it may be different
63 // across clients.
64 void ClearSyncDateField(std::vector<PasswordForm*>* forms) {
65 for (PasswordForm* form : *forms) {
66 form->date_synced = base::Time();
70 } // namespace
72 namespace passwords_helper {
74 void AddLogin(PasswordStore* store, const PasswordForm& form) {
75 ASSERT_TRUE(store);
76 base::WaitableEvent wait_event(true, false);
77 store->AddLogin(form);
78 store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
79 wait_event.Wait();
82 void UpdateLogin(PasswordStore* store, const PasswordForm& form) {
83 ASSERT_TRUE(store);
84 base::WaitableEvent wait_event(true, false);
85 store->UpdateLogin(form);
86 store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
87 wait_event.Wait();
90 ScopedVector<PasswordForm> GetLogins(PasswordStore* store) {
91 EXPECT_TRUE(store);
92 PasswordForm matcher_form;
93 matcher_form.signon_realm = kFakeSignonRealm;
94 PasswordStoreConsumerHelper consumer;
95 store->GetLogins(matcher_form, PasswordStore::DISALLOW_PROMPT, &consumer);
96 content::RunMessageLoop();
97 return consumer.result();
100 void RemoveLogin(PasswordStore* store, const PasswordForm& form) {
101 ASSERT_TRUE(store);
102 base::WaitableEvent wait_event(true, false);
103 store->RemoveLogin(form);
104 store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
105 wait_event.Wait();
108 void RemoveLogins(PasswordStore* store) {
109 ScopedVector<PasswordForm> forms = GetLogins(store);
110 for (const PasswordForm* form : forms) {
111 RemoveLogin(store, *form);
115 void SetEncryptionPassphrase(int index,
116 const std::string& passphrase,
117 ProfileSyncService::PassphraseType type) {
118 ProfileSyncServiceFactory::GetForProfile(
119 test()->GetProfile(index))->SetEncryptionPassphrase(passphrase, type);
122 bool SetDecryptionPassphrase(int index, const std::string& passphrase) {
123 return ProfileSyncServiceFactory::GetForProfile(
124 test()->GetProfile(index))->SetDecryptionPassphrase(passphrase);
127 PasswordStore* GetPasswordStore(int index) {
128 return PasswordStoreFactory::GetForProfile(test()->GetProfile(index),
129 ServiceAccessType::IMPLICIT_ACCESS)
130 .get();
133 PasswordStore* GetVerifierPasswordStore() {
134 return PasswordStoreFactory::GetForProfile(
135 test()->verifier(), ServiceAccessType::IMPLICIT_ACCESS).get();
138 bool ProfileContainsSamePasswordFormsAsVerifier(int index) {
139 ScopedVector<PasswordForm> verifier_forms =
140 GetLogins(GetVerifierPasswordStore());
141 ScopedVector<PasswordForm> forms = GetLogins(GetPasswordStore(index));
142 ClearSyncDateField(&forms.get());
144 std::ostringstream mismatch_details_stream;
145 bool is_matching = password_manager::ContainsEqualPasswordFormsUnordered(
146 verifier_forms.get(), forms.get(), &mismatch_details_stream);
147 if (!is_matching) {
148 VLOG(1) << "Profile " << index
149 << " does not contain the same Password forms as Verifier Profile.";
150 VLOG(1) << mismatch_details_stream.str();
152 return is_matching;
155 bool ProfilesContainSamePasswordForms(int index_a, int index_b) {
156 ScopedVector<PasswordForm> forms_a = GetLogins(GetPasswordStore(index_a));
157 ScopedVector<PasswordForm> forms_b = GetLogins(GetPasswordStore(index_b));
158 ClearSyncDateField(&forms_a.get());
159 ClearSyncDateField(&forms_b.get());
161 std::ostringstream mismatch_details_stream;
162 bool is_matching = password_manager::ContainsEqualPasswordFormsUnordered(
163 forms_a.get(), forms_b.get(), &mismatch_details_stream);
164 if (!is_matching) {
165 VLOG(1) << "Password forms in Profile " << index_a
166 << " (listed as 'expected forms' below)"
167 << " do not match those in Profile " << index_b
168 << " (listed as 'actual forms' below)";
169 VLOG(1) << mismatch_details_stream.str();
171 return is_matching;
174 bool AllProfilesContainSamePasswordFormsAsVerifier() {
175 for (int i = 0; i < test()->num_clients(); ++i) {
176 if (!ProfileContainsSamePasswordFormsAsVerifier(i)) {
177 DVLOG(1) << "Profile " << i << " does not contain the same password"
178 " forms as the verifier.";
179 return false;
182 return true;
185 bool AllProfilesContainSamePasswordForms() {
186 for (int i = 1; i < test()->num_clients(); ++i) {
187 if (!ProfilesContainSamePasswordForms(0, i)) {
188 DVLOG(1) << "Profile " << i << " does not contain the same password"
189 " forms as Profile 0.";
190 return false;
193 return true;
196 namespace {
198 // Helper class used in the implementation of
199 // AwaitAllProfilesContainSamePasswordForms.
200 class SamePasswordFormsChecker : public MultiClientStatusChangeChecker {
201 public:
202 SamePasswordFormsChecker();
203 ~SamePasswordFormsChecker() override;
205 bool IsExitConditionSatisfied() override;
206 std::string GetDebugMessage() const override;
208 private:
209 bool in_progress_;
210 bool needs_recheck_;
213 SamePasswordFormsChecker::SamePasswordFormsChecker()
214 : MultiClientStatusChangeChecker(
215 sync_datatype_helper::test()->GetSyncServices()),
216 in_progress_(false),
217 needs_recheck_(false) {}
219 SamePasswordFormsChecker::~SamePasswordFormsChecker() {}
221 // This method needs protection against re-entrancy.
223 // This function indirectly calls GetLogins(), which starts a RunLoop on the UI
224 // thread. This can be a problem, since the next task to execute could very
225 // well contain a ProfileSyncService::OnStateChanged() event, which would
226 // trigger another call to this here function, and start another layer of
227 // nested RunLoops. That makes the StatusChangeChecker's Quit() method
228 // ineffective.
230 // The work-around is to not allow re-entrancy. But we can't just drop
231 // IsExitConditionSatisifed() calls if one is already in progress. Instead, we
232 // set a flag to ask the current execution of IsExitConditionSatisfied() to be
233 // re-run. This ensures that the return value is always based on the most
234 // up-to-date state.
235 bool SamePasswordFormsChecker::IsExitConditionSatisfied() {
236 if (in_progress_) {
237 LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
238 needs_recheck_ = true;
239 return false;
242 // Keep retrying until we get a good reading.
243 bool result = false;
244 in_progress_ = true;
245 do {
246 needs_recheck_ = false;
247 result = AllProfilesContainSamePasswordForms();
248 } while (needs_recheck_);
249 in_progress_ = false;
250 return result;
253 std::string SamePasswordFormsChecker::GetDebugMessage() const {
254 return "Waiting for matching passwords";
257 } // namespace
259 bool AwaitAllProfilesContainSamePasswordForms() {
260 SamePasswordFormsChecker checker;
261 checker.Wait();
262 return !checker.TimedOut();
265 namespace {
267 // Helper class used in the implementation of
268 // AwaitProfileContainSamePasswordFormsAsVerifier.
269 class SamePasswordFormsAsVerifierChecker
270 : public SingleClientStatusChangeChecker {
271 public:
272 explicit SamePasswordFormsAsVerifierChecker(int index);
273 ~SamePasswordFormsAsVerifierChecker() override;
275 bool IsExitConditionSatisfied() override;
276 std::string GetDebugMessage() const override;
278 private:
279 int index_;
281 bool in_progress_;
282 bool needs_recheck_;
285 SamePasswordFormsAsVerifierChecker::SamePasswordFormsAsVerifierChecker(int i)
286 : SingleClientStatusChangeChecker(
287 sync_datatype_helper::test()->GetSyncService(i)),
288 index_(i),
289 in_progress_(false),
290 needs_recheck_(false) {
293 SamePasswordFormsAsVerifierChecker::~SamePasswordFormsAsVerifierChecker() {
296 // This method uses the same re-entrancy prevention trick as
297 // the SamePasswordFormsChecker.
298 bool SamePasswordFormsAsVerifierChecker::IsExitConditionSatisfied() {
299 if (in_progress_) {
300 LOG(WARNING) << "Setting flag and returning early to prevent nesting.";
301 needs_recheck_ = true;
302 return false;
305 // Keep retrying until we get a good reading.
306 bool result = false;
307 in_progress_ = true;
308 do {
309 needs_recheck_ = false;
310 result = ProfileContainsSamePasswordFormsAsVerifier(index_);
311 } while (needs_recheck_);
312 in_progress_ = false;
313 return result;
316 std::string SamePasswordFormsAsVerifierChecker::GetDebugMessage() const {
317 return "Waiting for passwords to match verifier";
320 } // namespace
322 bool AwaitProfileContainsSamePasswordFormsAsVerifier(int index) {
323 SamePasswordFormsAsVerifierChecker checker(index);
324 checker.Wait();
325 return !checker.TimedOut();
328 int GetPasswordCount(int index) {
329 ScopedVector<PasswordForm> forms = GetLogins(GetPasswordStore(index));
330 return forms.size();
333 int GetVerifierPasswordCount() {
334 ScopedVector<PasswordForm> verifier_forms =
335 GetLogins(GetVerifierPasswordStore());
336 return verifier_forms.size();
339 PasswordForm CreateTestPasswordForm(int index) {
340 PasswordForm form;
341 form.signon_realm = kFakeSignonRealm;
342 form.origin = GURL(base::StringPrintf(kIndexedFakeOrigin, index));
343 form.username_value =
344 base::ASCIIToUTF16(base::StringPrintf("username%d", index));
345 form.password_value =
346 base::ASCIIToUTF16(base::StringPrintf("password%d", index));
347 form.date_created = base::Time::Now();
348 return form;
351 } // namespace passwords_helper