Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(476)

Side by Side Diff: chrome/browser/sync/test/integration/autofill_helper.cc

Issue 2791793002: [Sync] Fix flaky TwoClientAutofillSyncTest.ConflictingFields. (Closed)
Patch Set: Updated for Pavel's comment. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/test/integration/autofill_helper.h" 5 #include "chrome/browser/sync/test/integration/autofill_helper.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <map> 9 #include <map>
10 #include <utility>
10 11
11 #include "base/guid.h" 12 #include "base/guid.h"
12 #include "base/run_loop.h" 13 #include "base/run_loop.h"
13 #include "chrome/browser/autofill/personal_data_manager_factory.h" 14 #include "chrome/browser/autofill/personal_data_manager_factory.h"
14 #include "chrome/browser/chrome_notification_types.h" 15 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sync/profile_sync_test_util.h" 17 #include "chrome/browser/sync/profile_sync_test_util.h"
17 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h" 18 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
18 #include "chrome/browser/sync/test/integration/sync_test.h" 19 #include "chrome/browser/sync/test/integration/sync_test.h"
19 #include "chrome/browser/web_data_service_factory.h" 20 #include "chrome/browser/web_data_service_factory.h"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 event->Signal(); 52 event->Signal();
52 } 53 }
53 54
54 class MockWebDataServiceObserver 55 class MockWebDataServiceObserver
55 : public AutofillWebDataServiceObserverOnDBThread { 56 : public AutofillWebDataServiceObserverOnDBThread {
56 public: 57 public:
57 MOCK_METHOD1(AutofillEntriesChanged, 58 MOCK_METHOD1(AutofillEntriesChanged,
58 void(const AutofillChangeList& changes)); 59 void(const AutofillChangeList& changes));
59 }; 60 };
60 61
61 class MockPersonalDataManagerObserver : public PersonalDataManagerObserver {
62 public:
63 MOCK_METHOD0(OnPersonalDataChanged, void());
64 };
65
66 void RunOnDBThreadAndSignal(base::Closure task, 62 void RunOnDBThreadAndSignal(base::Closure task,
67 base::WaitableEvent* done_event) { 63 base::WaitableEvent* done_event) {
68 if (!task.is_null()) { 64 if (!task.is_null()) {
69 task.Run(); 65 task.Run();
70 } 66 }
71 done_event->Signal(); 67 done_event->Signal();
72 } 68 }
73 69
74 void RunOnDBThreadAndBlock(base::Closure task) { 70 void RunOnDBThreadAndBlock(base::Closure task) {
75 WaitableEvent done_event(base::WaitableEvent::ResetPolicy::AUTOMATIC, 71 WaitableEvent done_event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 // the sync. This function blocks until after this scheduled sync is complete by 121 // the sync. This function blocks until after this scheduled sync is complete by
126 // scheduling additional empty task on DB Thread. Call after AddKeys/RemoveKey. 122 // scheduling additional empty task on DB Thread. Call after AddKeys/RemoveKey.
127 void BlockForPendingDBThreadTasks() { 123 void BlockForPendingDBThreadTasks() {
128 // The order of the notifications is undefined, so sync change sometimes is 124 // The order of the notifications is undefined, so sync change sometimes is
129 // posted after the notification for observer_helper. Post new task to db 125 // posted after the notification for observer_helper. Post new task to db
130 // thread that guaranteed to be after sync and would be blocking until 126 // thread that guaranteed to be after sync and would be blocking until
131 // completion. 127 // completion.
132 RunOnDBThreadAndBlock(base::Closure()); 128 RunOnDBThreadAndBlock(base::Closure());
133 } 129 }
134 130
131 bool ProfilesMatchImpl(
132 int profile_a,
133 const std::vector<AutofillProfile*>& autofill_profiles_a,
134 int profile_b,
135 const std::vector<AutofillProfile*>& autofill_profiles_b) {
136 std::map<std::string, AutofillProfile> autofill_profiles_a_map;
137 for (AutofillProfile* p : autofill_profiles_a) {
138 autofill_profiles_a_map[p->guid()] = *p;
139 }
140
141 // This seems to be a transient state that will eventually be rectified by
142 // model type logic. We don't need to check b for duplicates directly because
143 // after the first is erased from |autofill_profiles_a_map| the second will
144 // not be found.
145 if (autofill_profiles_a.size() != autofill_profiles_a_map.size()) {
146 DVLOG(1) << "Profile " << profile_a << " contains duplicate GUID(s).";
147 return false;
148 }
149
150 for (AutofillProfile* p : autofill_profiles_b) {
151 if (!autofill_profiles_a_map.count(p->guid())) {
152 DVLOG(1) << "GUID " << p->guid() << " not found in profile " << profile_b
153 << ".";
154 return false;
155 }
156 AutofillProfile* expected_profile = &autofill_profiles_a_map[p->guid()];
157 expected_profile->set_guid(p->guid());
158 if (*expected_profile != *p) {
159 DVLOG(1) << "Mismatch in profile with GUID " << p->guid() << ".";
160 return false;
161 }
162 autofill_profiles_a_map.erase(p->guid());
163 }
164
165 if (autofill_profiles_a_map.size()) {
166 DVLOG(1) << "Entries present in Profile " << profile_a << " but not in "
167 << profile_b << ".";
168 return false;
169 }
170 return true;
171 }
172
135 } // namespace 173 } // namespace
136 174
137 namespace autofill_helper { 175 namespace autofill_helper {
138 176
139 AutofillProfile CreateAutofillProfile(ProfileType type) { 177 AutofillProfile CreateAutofillProfile(ProfileType type) {
140 AutofillProfile profile; 178 AutofillProfile profile;
141 switch (type) { 179 switch (type) {
142 case PROFILE_MARION: 180 case PROFILE_MARION:
143 autofill::test::SetProfileInfoWithGuid(&profile, 181 autofill::test::SetProfileInfoWithGuid(&profile,
144 "C837507A-6C3B-4872-AC14-5113F157D668", 182 "C837507A-6C3B-4872-AC14-5113F157D668",
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 test()->GetProfile(index), ServiceAccessType::EXPLICIT_ACCESS); 225 test()->GetProfile(index), ServiceAccessType::EXPLICIT_ACCESS);
188 } 226 }
189 227
190 PersonalDataManager* GetPersonalDataManager(int index) { 228 PersonalDataManager* GetPersonalDataManager(int index) {
191 return autofill::PersonalDataManagerFactory::GetForProfile( 229 return autofill::PersonalDataManagerFactory::GetForProfile(
192 test()->GetProfile(index)); 230 test()->GetProfile(index));
193 } 231 }
194 232
195 void AddKeys(int profile, const std::set<AutofillKey>& keys) { 233 void AddKeys(int profile, const std::set<AutofillKey>& keys) {
196 std::vector<FormFieldData> form_fields; 234 std::vector<FormFieldData> form_fields;
197 for (std::set<AutofillKey>::const_iterator i = keys.begin(); 235 for (const AutofillKey& key : keys) {
198 i != keys.end();
199 ++i) {
200 FormFieldData field; 236 FormFieldData field;
201 field.name = i->name(); 237 field.name = key.name();
202 field.value = i->value(); 238 field.value = key.value();
203 form_fields.push_back(field); 239 form_fields.push_back(field);
204 } 240 }
205 241
206 WaitableEvent done_event(base::WaitableEvent::ResetPolicy::AUTOMATIC, 242 WaitableEvent done_event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
207 base::WaitableEvent::InitialState::NOT_SIGNALED); 243 base::WaitableEvent::InitialState::NOT_SIGNALED);
208 MockWebDataServiceObserver mock_observer; 244 MockWebDataServiceObserver mock_observer;
209 EXPECT_CALL(mock_observer, AutofillEntriesChanged(_)) 245 EXPECT_CALL(mock_observer, AutofillEntriesChanged(_))
210 .WillOnce(SignalEvent(&done_event)); 246 .WillOnce(SignalEvent(&done_event));
211 247
212 scoped_refptr<AutofillWebDataService> wds = GetWebDataService(profile); 248 scoped_refptr<AutofillWebDataService> wds = GetWebDataService(profile);
(...skipping 13 matching lines...) Expand all
226 RunOnDBThreadAndBlock(Bind(remove_observer_func, wds, &mock_observer)); 262 RunOnDBThreadAndBlock(Bind(remove_observer_func, wds, &mock_observer));
227 } 263 }
228 264
229 void RemoveKey(int profile, const AutofillKey& key) { 265 void RemoveKey(int profile, const AutofillKey& key) {
230 RemoveKeyDontBlockForSync(profile, key); 266 RemoveKeyDontBlockForSync(profile, key);
231 BlockForPendingDBThreadTasks(); 267 BlockForPendingDBThreadTasks();
232 } 268 }
233 269
234 void RemoveKeys(int profile) { 270 void RemoveKeys(int profile) {
235 std::set<AutofillEntry> keys = GetAllKeys(profile); 271 std::set<AutofillEntry> keys = GetAllKeys(profile);
236 for (std::set<AutofillEntry>::const_iterator it = keys.begin(); 272 for (const AutofillEntry& entry : keys) {
237 it != keys.end(); ++it) { 273 RemoveKeyDontBlockForSync(profile, entry.key());
238 RemoveKeyDontBlockForSync(profile, it->key());
239 } 274 }
240 BlockForPendingDBThreadTasks(); 275 BlockForPendingDBThreadTasks();
241 } 276 }
242 277
243 std::set<AutofillEntry> GetAllKeys(int profile) { 278 std::set<AutofillEntry> GetAllKeys(int profile) {
244 scoped_refptr<AutofillWebDataService> wds = GetWebDataService(profile); 279 scoped_refptr<AutofillWebDataService> wds = GetWebDataService(profile);
245 std::vector<AutofillEntry> all_entries = GetAllAutofillEntries(wds.get()); 280 std::vector<AutofillEntry> all_entries = GetAllAutofillEntries(wds.get());
246 std::set<AutofillEntry> all_keys; 281 return std::set<AutofillEntry>(all_entries.begin(), all_entries.end());
247 for (std::vector<AutofillEntry>::const_iterator it = all_entries.begin();
248 it != all_entries.end(); ++it) {
249 all_keys.insert(*it);
250 }
251 return all_keys;
252 } 282 }
253 283
254 bool KeysMatch(int profile_a, int profile_b) { 284 bool KeysMatch(int profile_a, int profile_b) {
255 return GetAllKeys(profile_a) == GetAllKeys(profile_b); 285 return GetAllKeys(profile_a) == GetAllKeys(profile_b);
256 } 286 }
257 287
258 void SetProfiles(int profile, std::vector<AutofillProfile>* autofill_profiles) { 288 void SetProfiles(int profile, std::vector<AutofillProfile>* autofill_profiles) {
259 MockPersonalDataManagerObserver observer; 289 GetPersonalDataManager(profile)->SetProfiles(autofill_profiles);
260 EXPECT_CALL(observer, OnPersonalDataChanged()).
261 WillOnce(QuitUIMessageLoop());
262 PersonalDataManager* pdm = GetPersonalDataManager(profile);
263 pdm->AddObserver(&observer);
264 pdm->SetProfiles(autofill_profiles);
265 base::RunLoop().Run();
266 pdm->RemoveObserver(&observer);
267 } 290 }
268 291
269 void SetCreditCards(int profile, std::vector<CreditCard>* credit_cards) { 292 void SetCreditCards(int profile, std::vector<CreditCard>* credit_cards) {
270 MockPersonalDataManagerObserver observer; 293 GetPersonalDataManager(profile)->SetCreditCards(credit_cards);
271 EXPECT_CALL(observer, OnPersonalDataChanged()).
272 WillOnce(QuitUIMessageLoop());
273 PersonalDataManager* pdm = GetPersonalDataManager(profile);
274 pdm->AddObserver(&observer);
275 pdm->SetCreditCards(credit_cards);
276 base::RunLoop().Run();
277 pdm->RemoveObserver(&observer);
278 } 294 }
279 295
280 void AddProfile(int profile, const AutofillProfile& autofill_profile) { 296 void AddProfile(int profile, const AutofillProfile& autofill_profile) {
281 const std::vector<AutofillProfile*>& all_profiles =
282 GetAllAutoFillProfiles(profile);
283 std::vector<AutofillProfile> autofill_profiles; 297 std::vector<AutofillProfile> autofill_profiles;
284 for (size_t i = 0; i < all_profiles.size(); ++i) 298 for (AutofillProfile* profile : GetAllAutoFillProfiles(profile)) {
285 autofill_profiles.push_back(*all_profiles[i]); 299 autofill_profiles.push_back(*profile);
300 }
286 autofill_profiles.push_back(autofill_profile); 301 autofill_profiles.push_back(autofill_profile);
287 autofill_helper::SetProfiles(profile, &autofill_profiles); 302 autofill_helper::SetProfiles(profile, &autofill_profiles);
288 } 303 }
289 304
290 void RemoveProfile(int profile, const std::string& guid) { 305 void RemoveProfile(int profile, const std::string& guid) {
291 const std::vector<AutofillProfile*>& all_profiles =
292 GetAllAutoFillProfiles(profile);
293 std::vector<AutofillProfile> autofill_profiles; 306 std::vector<AutofillProfile> autofill_profiles;
294 for (size_t i = 0; i < all_profiles.size(); ++i) { 307 for (AutofillProfile* profile : GetAllAutoFillProfiles(profile)) {
295 if (all_profiles[i]->guid() != guid) 308 if (profile->guid() != guid) {
296 autofill_profiles.push_back(*all_profiles[i]); 309 autofill_profiles.push_back(*profile);
310 }
297 } 311 }
298 autofill_helper::SetProfiles(profile, &autofill_profiles); 312 autofill_helper::SetProfiles(profile, &autofill_profiles);
299 } 313 }
300 314
301 void UpdateProfile(int profile, 315 void UpdateProfile(int profile,
302 const std::string& guid, 316 const std::string& guid,
303 const AutofillType& type, 317 const AutofillType& type,
304 const base::string16& value) { 318 const base::string16& value) {
305 const std::vector<AutofillProfile*>& all_profiles =
306 GetAllAutoFillProfiles(profile);
307 std::vector<AutofillProfile> profiles; 319 std::vector<AutofillProfile> profiles;
308 for (size_t i = 0; i < all_profiles.size(); ++i) { 320 for (AutofillProfile* profile : GetAllAutoFillProfiles(profile)) {
309 profiles.push_back(*all_profiles[i]); 321 profiles.push_back(*profile);
310 if (all_profiles[i]->guid() == guid) 322 if (profile->guid() == guid) {
311 profiles.back().SetRawInfo(type.GetStorableType(), value); 323 profiles.back().SetRawInfo(type.GetStorableType(), value);
324 }
312 } 325 }
313 autofill_helper::SetProfiles(profile, &profiles); 326 autofill_helper::SetProfiles(profile, &profiles);
314 } 327 }
315 328
316 std::vector<AutofillProfile*> GetAllAutoFillProfiles(int profile) { 329 std::vector<AutofillProfile*> GetAllAutoFillProfiles(int profile) {
317 MockPersonalDataManagerObserver observer;
318 EXPECT_CALL(observer, OnPersonalDataChanged()).
319 WillOnce(QuitUIMessageLoop());
320 PersonalDataManager* pdm = GetPersonalDataManager(profile); 330 PersonalDataManager* pdm = GetPersonalDataManager(profile);
321 pdm->AddObserver(&observer);
322 pdm->Refresh(); 331 pdm->Refresh();
323 base::RunLoop().Run(); 332
324 pdm->RemoveObserver(&observer); 333 // PersonalDataManager::web_profiles() simply returns the current values that
334 // have been last reported to the UI thread. PersonalDataManager::Refresh()
335 // will post a task to the DB thread to read back the latest values, and we
336 // very much want the latest values. Unfortunately, the Refresh() call is
337 // asynchronous and there's no way to pass a callback that's run when our
338 // Refresh() call finishes. A PersonalDataManagerObserver won't completely fix
339 // the problem either since there could be multiple outstanding modifications
340 // scheduled, and we cannot ensure that we have the latest view. Instead post
341 // a task to the DB thread and wait for it run. This will ensure that our
342 // Refresh() was executed first, as long as the DB thread is sequenced. It is
343 // possible for another write to sneak in between our Refresh() and the task
344 // that is blocked for, causing the web_profiles() read to return even more
345 // current data, but this shouldn't cause problems. While PersonalDataManager
346 // will cancel outstanding queries, this is only instigated on the UI thread,
347 // which we are about to block, which means we are safe.
348 BlockForPendingDBThreadTasks();
349
325 return pdm->web_profiles(); 350 return pdm->web_profiles();
326 } 351 }
327 352
328 int GetProfileCount(int profile) { 353 int GetProfileCount(int profile) {
329 return GetAllAutoFillProfiles(profile).size(); 354 return GetAllAutoFillProfiles(profile).size();
330 } 355 }
331 356
332 int GetKeyCount(int profile) { 357 int GetKeyCount(int profile) {
333 return GetAllKeys(profile).size(); 358 return GetAllKeys(profile).size();
334 } 359 }
335 360
336 namespace {
337
338 bool ProfilesMatchImpl(
339 int profile_a,
340 const std::vector<AutofillProfile*>& autofill_profiles_a,
341 int profile_b,
342 const std::vector<AutofillProfile*>& autofill_profiles_b) {
343 std::map<std::string, AutofillProfile> autofill_profiles_a_map;
344 for (size_t i = 0; i < autofill_profiles_a.size(); ++i) {
345 const AutofillProfile* p = autofill_profiles_a[i];
346 autofill_profiles_a_map[p->guid()] = *p;
347 }
348
349 for (size_t i = 0; i < autofill_profiles_b.size(); ++i) {
350 const AutofillProfile* p = autofill_profiles_b[i];
351 if (!autofill_profiles_a_map.count(p->guid())) {
352 DVLOG(1) << "GUID " << p->guid() << " not found in profile " << profile_b
353 << ".";
354 return false;
355 }
356 AutofillProfile* expected_profile = &autofill_profiles_a_map[p->guid()];
357 expected_profile->set_guid(p->guid());
358 if (*expected_profile != *p) {
359 DVLOG(1) << "Mismatch in profile with GUID " << p->guid() << ".";
360 return false;
361 }
362 autofill_profiles_a_map.erase(p->guid());
363 }
364
365 if (autofill_profiles_a_map.size()) {
366 DVLOG(1) << "Entries present in Profile " << profile_a << " but not in "
367 << profile_b << ".";
368 return false;
369 }
370 return true;
371 }
372
373 } // namespace
374
375 bool ProfilesMatch(int profile_a, int profile_b) { 361 bool ProfilesMatch(int profile_a, int profile_b) {
376 const std::vector<AutofillProfile*>& autofill_profiles_a = 362 const std::vector<AutofillProfile*>& autofill_profiles_a =
377 GetAllAutoFillProfiles(profile_a); 363 GetAllAutoFillProfiles(profile_a);
378 const std::vector<AutofillProfile*>& autofill_profiles_b = 364 const std::vector<AutofillProfile*>& autofill_profiles_b =
379 GetAllAutoFillProfiles(profile_b); 365 GetAllAutoFillProfiles(profile_b);
380 return ProfilesMatchImpl( 366 return ProfilesMatchImpl(
381 profile_a, autofill_profiles_a, profile_b, autofill_profiles_b); 367 profile_a, autofill_profiles_a, profile_b, autofill_profiles_b);
382 } 368 }
383 369
384 bool AllProfilesMatch() {
385 for (int i = 1; i < test()->num_clients(); ++i) {
386 if (!ProfilesMatch(0, i)) {
387 DVLOG(1) << "Profile " << i << "does not contain the same autofill "
388 "profiles as profile 0.";
389 return false;
390 }
391 }
392 return true;
393 }
394
395 } // namespace autofill_helper 370 } // namespace autofill_helper
396 371
397 AutofillKeysChecker::AutofillKeysChecker(int profile_a, int profile_b) 372 AutofillKeysChecker::AutofillKeysChecker(int profile_a, int profile_b)
398 : MultiClientStatusChangeChecker( 373 : MultiClientStatusChangeChecker(
399 sync_datatype_helper::test()->GetSyncServices()), 374 sync_datatype_helper::test()->GetSyncServices()),
400 profile_a_(profile_a), 375 profile_a_(profile_a),
401 profile_b_(profile_b) {} 376 profile_b_(profile_b) {}
402 377
403 bool AutofillKeysChecker::IsExitConditionSatisfied() { 378 bool AutofillKeysChecker::IsExitConditionSatisfied() {
404 return autofill_helper::KeysMatch(profile_a_, profile_b_); 379 return autofill_helper::KeysMatch(profile_a_, profile_b_);
(...skipping 10 matching lines...) Expand all
415 } 390 }
416 391
417 AutofillProfileChecker::~AutofillProfileChecker() { 392 AutofillProfileChecker::~AutofillProfileChecker() {
418 autofill_helper::GetPersonalDataManager(profile_a_)->RemoveObserver(this); 393 autofill_helper::GetPersonalDataManager(profile_a_)->RemoveObserver(this);
419 autofill_helper::GetPersonalDataManager(profile_b_)->RemoveObserver(this); 394 autofill_helper::GetPersonalDataManager(profile_b_)->RemoveObserver(this);
420 } 395 }
421 396
422 bool AutofillProfileChecker::Wait() { 397 bool AutofillProfileChecker::Wait() {
423 autofill_helper::GetPersonalDataManager(profile_a_)->Refresh(); 398 autofill_helper::GetPersonalDataManager(profile_a_)->Refresh();
424 autofill_helper::GetPersonalDataManager(profile_b_)->Refresh(); 399 autofill_helper::GetPersonalDataManager(profile_b_)->Refresh();
400 // Similar to GetAllAutoFillProfiles() we need to make sure we are not reading
401 // before any locally instigated async writes. This is run exactly one time
402 // before the first IsExitConditionSatisfied() is called.
403 BlockForPendingDBThreadTasks();
425 return StatusChangeChecker::Wait(); 404 return StatusChangeChecker::Wait();
426 } 405 }
427 406
428 bool AutofillProfileChecker::IsExitConditionSatisfied() { 407 bool AutofillProfileChecker::IsExitConditionSatisfied() {
429 const std::vector<AutofillProfile*>& autofill_profiles_a = 408 const std::vector<AutofillProfile*>& autofill_profiles_a =
430 autofill_helper::GetPersonalDataManager(profile_a_)->web_profiles(); 409 autofill_helper::GetPersonalDataManager(profile_a_)->web_profiles();
431 const std::vector<AutofillProfile*>& autofill_profiles_b = 410 const std::vector<AutofillProfile*>& autofill_profiles_b =
432 autofill_helper::GetPersonalDataManager(profile_b_)->web_profiles(); 411 autofill_helper::GetPersonalDataManager(profile_b_)->web_profiles();
433 return autofill_helper::ProfilesMatchImpl(profile_a_, autofill_profiles_a, 412 return ProfilesMatchImpl(profile_a_, autofill_profiles_a, profile_b_,
434 profile_b_, autofill_profiles_b); 413 autofill_profiles_b);
435 } 414 }
436 415
437 std::string AutofillProfileChecker::GetDebugMessage() const { 416 std::string AutofillProfileChecker::GetDebugMessage() const {
438 return "Waiting for matching autofill profiles"; 417 return "Waiting for matching autofill profiles";
439 } 418 }
440 419
441 void AutofillProfileChecker::OnPersonalDataChanged() { 420 void AutofillProfileChecker::OnPersonalDataChanged() {
442 CheckExitCondition(); 421 CheckExitCondition();
443 } 422 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698