OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 "components/password_manager/core/browser/password_syncable_service.h" | 5 #include "components/password_manager/core/browser/password_syncable_service.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <memory> | 8 #include <memory> |
9 #include <string> | 9 #include <string> |
10 #include <utility> | 10 #include <utility> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
16 #include "base/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
17 #include "base/message_loop/message_loop.h" | |
18 #include "base/strings/utf_string_conversions.h" | 17 #include "base/strings/utf_string_conversions.h" |
| 18 #include "base/test/scoped_task_environment.h" |
| 19 #include "base/test/simple_test_clock.h" |
19 #include "components/password_manager/core/browser/mock_password_store.h" | 20 #include "components/password_manager/core/browser/mock_password_store.h" |
| 21 #include "components/password_manager/core/browser/password_manager_test_utils.h
" |
20 #include "components/sync/model/sync_change_processor.h" | 22 #include "components/sync/model/sync_change_processor.h" |
21 #include "components/sync/model/sync_error.h" | 23 #include "components/sync/model/sync_error.h" |
22 #include "components/sync/model/sync_error_factory_mock.h" | 24 #include "components/sync/model/sync_error_factory_mock.h" |
23 #include "testing/gmock/include/gmock/gmock.h" | 25 #include "testing/gmock/include/gmock/gmock.h" |
24 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
25 | 27 |
26 using syncer::SyncChange; | 28 using syncer::SyncChange; |
27 using syncer::SyncData; | 29 using syncer::SyncData; |
28 using syncer::SyncDataList; | 30 using syncer::SyncDataList; |
29 using syncer::SyncError; | 31 using syncer::SyncError; |
(...skipping 14 matching lines...) Expand all Loading... |
44 // Defined in the implementation file corresponding to this test. | 46 // Defined in the implementation file corresponding to this test. |
45 syncer::SyncData SyncDataFromPassword(const autofill::PasswordForm& password); | 47 syncer::SyncData SyncDataFromPassword(const autofill::PasswordForm& password); |
46 autofill::PasswordForm PasswordFromSpecifics( | 48 autofill::PasswordForm PasswordFromSpecifics( |
47 const sync_pb::PasswordSpecificsData& password); | 49 const sync_pb::PasswordSpecificsData& password); |
48 std::string MakePasswordSyncTag(const sync_pb::PasswordSpecificsData& password); | 50 std::string MakePasswordSyncTag(const sync_pb::PasswordSpecificsData& password); |
49 std::string MakePasswordSyncTag(const autofill::PasswordForm& password); | 51 std::string MakePasswordSyncTag(const autofill::PasswordForm& password); |
50 | 52 |
51 namespace { | 53 namespace { |
52 | 54 |
53 // PasswordForm values for tests. | 55 // PasswordForm values for tests. |
54 const autofill::PasswordForm::Type kArbitraryType = | 56 constexpr autofill::PasswordForm::Type kArbitraryType = |
55 autofill::PasswordForm::TYPE_GENERATED; | 57 autofill::PasswordForm::TYPE_GENERATED; |
56 const char kIconUrl[] = "https://fb.com/Icon"; | 58 constexpr char kAndroidAutofillRealm[] = "android://hash@com.magisto"; |
57 const char kDisplayName[] = "Agent Smith"; | 59 constexpr char kAndroidCorrectRealm[] = "android://hash@com.magisto/"; |
58 const char kFederationUrl[] = "https://fb.com/"; | 60 constexpr char kIconUrl[] = "https://fb.com/Icon"; |
59 const char kPassword[] = "abcdef"; | 61 constexpr char kDisplayName[] = "Agent Smith"; |
60 const char kSignonRealm[] = "abc"; | 62 constexpr char kFederationUrl[] = "https://fb.com/"; |
61 const char kSignonRealm2[] = "def"; | 63 constexpr char kPassword[] = "abcdef"; |
62 const char kSignonRealm3[] = "xyz"; | 64 constexpr char kSignonRealm[] = "abc"; |
63 const int kTimesUsed = 5; | 65 constexpr char kSignonRealm2[] = "def"; |
64 const char kUsername[] = "godzilla"; | 66 constexpr char kSignonRealm3[] = "xyz"; |
| 67 constexpr int kTimesUsed = 5; |
| 68 constexpr char kUsername[] = "godzilla"; |
65 | 69 |
66 typedef std::vector<SyncChange> SyncChangeList; | 70 typedef std::vector<SyncChange> SyncChangeList; |
67 | 71 |
68 const sync_pb::PasswordSpecificsData& GetPasswordSpecifics( | 72 const sync_pb::PasswordSpecificsData& GetPasswordSpecifics( |
69 const syncer::SyncData& sync_data) { | 73 const syncer::SyncData& sync_data) { |
70 return sync_data.GetSpecifics().password().client_only_encrypted_data(); | 74 return sync_data.GetSpecifics().password().client_only_encrypted_data(); |
71 } | 75 } |
72 | 76 |
73 MATCHER(HasDateSynced, "") { | 77 MATCHER_P(HasDateSynced, time, "") { |
74 return !arg.date_synced.is_null() && !arg.date_synced.is_max(); | 78 return arg.date_synced == time; |
75 } | 79 } |
76 | 80 |
77 MATCHER_P(PasswordIs, form, "") { | 81 MATCHER_P(PasswordIs, form, "") { |
78 sync_pb::PasswordSpecificsData actual_password = | 82 sync_pb::PasswordSpecificsData actual_password = |
79 GetPasswordSpecifics(SyncDataFromPassword(arg)); | 83 GetPasswordSpecifics(SyncDataFromPassword(arg)); |
80 sync_pb::PasswordSpecificsData expected_password = | 84 sync_pb::PasswordSpecificsData expected_password = |
81 GetPasswordSpecifics(SyncDataFromPassword(form)); | 85 GetPasswordSpecifics(SyncDataFromPassword(form)); |
82 if (expected_password.scheme() == actual_password.scheme() && | 86 if (expected_password.scheme() == actual_password.scheme() && |
83 expected_password.signon_realm() == actual_password.signon_realm() && | 87 expected_password.signon_realm() == actual_password.signon_realm() && |
84 expected_password.origin() == actual_password.origin() && | 88 expected_password.origin() == actual_password.origin() && |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 Matches(PasswordIs(password))(form))); | 121 Matches(PasswordIs(password))(form))); |
118 } | 122 } |
119 | 123 |
120 // The argument is std::vector<autofill::PasswordForm*>*. The caller is | 124 // The argument is std::vector<autofill::PasswordForm*>*. The caller is |
121 // responsible for the lifetime of all the password forms. | 125 // responsible for the lifetime of all the password forms. |
122 ACTION_P(AppendForm, form) { | 126 ACTION_P(AppendForm, form) { |
123 arg0->push_back(base::MakeUnique<autofill::PasswordForm>(form)); | 127 arg0->push_back(base::MakeUnique<autofill::PasswordForm>(form)); |
124 return true; | 128 return true; |
125 } | 129 } |
126 | 130 |
| 131 // The argument is std::vector<autofill::PasswordForm*>*. The caller is |
| 132 // responsible for the lifetime of all the password forms. |
| 133 ACTION_P(AppendForms, forms) { |
| 134 for (const autofill::PasswordForm& form : forms) |
| 135 arg0->push_back(base::MakeUnique<autofill::PasswordForm>(form)); |
| 136 return true; |
| 137 } |
| 138 |
127 // Creates a sync data consisting of password specifics. The sign on realm is | 139 // Creates a sync data consisting of password specifics. The sign on realm is |
128 // set to |signon_realm|. | 140 // set to |signon_realm|. |
129 SyncData CreateSyncData(const std::string& signon_realm) { | 141 SyncData CreateSyncData(const std::string& signon_realm) { |
130 sync_pb::EntitySpecifics password_data; | 142 sync_pb::EntitySpecifics password_data; |
131 sync_pb::PasswordSpecificsData* password_specifics = | 143 sync_pb::PasswordSpecificsData* password_specifics = |
132 password_data.mutable_password()->mutable_client_only_encrypted_data(); | 144 password_data.mutable_password()->mutable_client_only_encrypted_data(); |
133 password_specifics->set_signon_realm(signon_realm); | 145 password_specifics->set_signon_realm(signon_realm); |
134 password_specifics->set_type(autofill::PasswordForm::TYPE_GENERATED); | 146 password_specifics->set_type(autofill::PasswordForm::TYPE_GENERATED); |
135 password_specifics->set_times_used(3); | 147 password_specifics->set_times_used(3); |
136 password_specifics->set_display_name("Mr. X"); | 148 password_specifics->set_display_name("Mr. X"); |
137 password_specifics->set_avatar_url("https://accounts.google.com/Icon"); | 149 password_specifics->set_avatar_url("https://accounts.google.com/Icon"); |
138 password_specifics->set_federation_url("https://google.com"); | 150 password_specifics->set_federation_url("https://google.com"); |
139 password_specifics->set_username_value("kingkong"); | 151 password_specifics->set_username_value("kingkong"); |
140 password_specifics->set_password_value("sicrit"); | 152 password_specifics->set_password_value("sicrit"); |
141 | 153 |
142 std::string tag = MakePasswordSyncTag(*password_specifics); | 154 std::string tag = MakePasswordSyncTag(*password_specifics); |
143 return syncer::SyncData::CreateLocalData(tag, tag, password_data); | 155 return syncer::SyncData::CreateLocalData(tag, tag, password_data); |
144 } | 156 } |
145 | 157 |
146 SyncChange CreateSyncChange(const autofill::PasswordForm& password, | 158 SyncChange CreateSyncChange(const autofill::PasswordForm& password, |
147 SyncChange::SyncChangeType type) { | 159 SyncChange::SyncChangeType type) { |
148 SyncData data = SyncDataFromPassword(password); | 160 SyncData data = SyncDataFromPassword(password); |
149 return SyncChange(FROM_HERE, type, data); | 161 return SyncChange(FROM_HERE, type, data); |
150 } | 162 } |
151 | 163 |
152 // A testable implementation of the |PasswordSyncableService| that mocks | |
153 // out all interaction with the password database. | |
154 class MockPasswordSyncableService : public PasswordSyncableService { | |
155 public: | |
156 explicit MockPasswordSyncableService(PasswordStoreSync* password_store) | |
157 : PasswordSyncableService(password_store) {} | |
158 | |
159 MOCK_METHOD1(StartSyncFlare, void(syncer::ModelType)); | |
160 | |
161 private: | |
162 DISALLOW_COPY_AND_ASSIGN(MockPasswordSyncableService); | |
163 }; | |
164 | |
165 // Mock implementation of SyncChangeProcessor. | 164 // Mock implementation of SyncChangeProcessor. |
166 class MockSyncChangeProcessor : public syncer::SyncChangeProcessor { | 165 class MockSyncChangeProcessor : public syncer::SyncChangeProcessor { |
167 public: | 166 public: |
168 MockSyncChangeProcessor() {} | 167 MockSyncChangeProcessor() {} |
169 | 168 |
170 MOCK_METHOD2(ProcessSyncChanges, | 169 MOCK_METHOD2(ProcessSyncChanges, |
171 SyncError(const tracked_objects::Location&, | 170 SyncError(const tracked_objects::Location&, |
172 const SyncChangeList& list)); | 171 const SyncChangeList& list)); |
173 SyncDataList GetAllSyncData(syncer::ModelType type) const override { | 172 SyncDataList GetAllSyncData(syncer::ModelType type) const override { |
174 NOTREACHED(); | 173 NOTREACHED(); |
175 return SyncDataList(); | 174 return SyncDataList(); |
176 } | 175 } |
177 | 176 |
178 private: | 177 private: |
179 DISALLOW_COPY_AND_ASSIGN(MockSyncChangeProcessor); | 178 DISALLOW_COPY_AND_ASSIGN(MockSyncChangeProcessor); |
180 }; | 179 }; |
181 | 180 |
182 // Convenience wrapper around a PasswordSyncableService and PasswordStore | 181 // Convenience wrapper around a PasswordSyncableService and PasswordStore |
183 // pair. | 182 // pair. |
184 class PasswordSyncableServiceWrapper { | 183 class PasswordSyncableServiceWrapper { |
185 public: | 184 public: |
186 PasswordSyncableServiceWrapper() { | 185 PasswordSyncableServiceWrapper() { |
187 password_store_ = new testing::StrictMock<MockPasswordStore>; | 186 password_store_ = new testing::StrictMock<MockPasswordStore>; |
188 service_.reset( | 187 service_.reset( |
189 new MockPasswordSyncableService(password_store_->GetSyncInterface())); | 188 new PasswordSyncableService(password_store_->GetSyncInterface())); |
190 ON_CALL(*password_store_, AddLoginImpl(HasDateSynced())) | 189 auto clock = base::MakeUnique<base::SimpleTestClock>(); |
| 190 clock->SetNow(time()); |
| 191 service_->set_clock(std::move(clock)); |
| 192 ON_CALL(*password_store_, AddLoginImpl(HasDateSynced(time()))) |
191 .WillByDefault(Return(PasswordStoreChangeList())); | 193 .WillByDefault(Return(PasswordStoreChangeList())); |
192 ON_CALL(*password_store_, RemoveLoginImpl(_)) | 194 ON_CALL(*password_store_, RemoveLoginImpl(_)) |
193 .WillByDefault(Return(PasswordStoreChangeList())); | 195 .WillByDefault(Return(PasswordStoreChangeList())); |
194 ON_CALL(*password_store_, UpdateLoginImpl(HasDateSynced())) | 196 ON_CALL(*password_store_, UpdateLoginImpl(HasDateSynced(time()))) |
195 .WillByDefault(Return(PasswordStoreChangeList())); | 197 .WillByDefault(Return(PasswordStoreChangeList())); |
196 EXPECT_CALL(*password_store(), NotifyLoginsChanged(_)).Times(AnyNumber()); | 198 EXPECT_CALL(*password_store(), NotifyLoginsChanged(_)).Times(AnyNumber()); |
197 } | 199 } |
198 | 200 |
199 ~PasswordSyncableServiceWrapper() { password_store_->ShutdownOnUIThread(); } | 201 ~PasswordSyncableServiceWrapper() { password_store_->ShutdownOnUIThread(); } |
200 | 202 |
201 MockPasswordStore* password_store() { return password_store_.get(); } | 203 MockPasswordStore* password_store() { return password_store_.get(); } |
202 | 204 |
203 MockPasswordSyncableService* service() { return service_.get(); } | 205 PasswordSyncableService* service() { return service_.get(); } |
| 206 |
| 207 static base::Time time() { return base::Time::FromInternalValue(100000); } |
204 | 208 |
205 // Returnes the scoped_ptr to |service_| thus NULLing out it. | 209 // Returnes the scoped_ptr to |service_| thus NULLing out it. |
206 std::unique_ptr<syncer::SyncChangeProcessor> ReleaseSyncableService() { | 210 std::unique_ptr<syncer::SyncChangeProcessor> ReleaseSyncableService() { |
207 return std::move(service_); | 211 return std::move(service_); |
208 } | 212 } |
209 | 213 |
210 private: | 214 private: |
211 scoped_refptr<MockPasswordStore> password_store_; | 215 scoped_refptr<MockPasswordStore> password_store_; |
212 std::unique_ptr<MockPasswordSyncableService> service_; | 216 std::unique_ptr<PasswordSyncableService> service_; |
213 | 217 |
214 DISALLOW_COPY_AND_ASSIGN(PasswordSyncableServiceWrapper); | 218 DISALLOW_COPY_AND_ASSIGN(PasswordSyncableServiceWrapper); |
215 }; | 219 }; |
216 | 220 |
217 class PasswordSyncableServiceTest : public testing::Test { | 221 class PasswordSyncableServiceTest : public testing::Test { |
218 public: | 222 public: |
219 PasswordSyncableServiceTest() | 223 PasswordSyncableServiceTest() |
220 : processor_(new testing::StrictMock<MockSyncChangeProcessor>) { | 224 : processor_(new testing::StrictMock<MockSyncChangeProcessor>) { |
221 ON_CALL(*processor_, ProcessSyncChanges(_, _)) | 225 ON_CALL(*processor_, ProcessSyncChanges(_, _)) |
222 .WillByDefault(Return(SyncError())); | 226 .WillByDefault(Return(SyncError())); |
223 } | 227 } |
224 MockPasswordStore* password_store() { return wrapper_.password_store(); } | 228 MockPasswordStore* password_store() { return wrapper_.password_store(); } |
225 MockPasswordSyncableService* service() { return wrapper_.service(); } | 229 PasswordSyncableService* service() { return wrapper_.service(); } |
| 230 |
| 231 MOCK_METHOD1(StartSyncFlare, void(syncer::ModelType)); |
226 | 232 |
227 protected: | 233 protected: |
228 base::MessageLoop message_loop_; | |
229 std::unique_ptr<MockSyncChangeProcessor> processor_; | 234 std::unique_ptr<MockSyncChangeProcessor> processor_; |
230 | 235 |
231 private: | 236 private: |
| 237 base::test::ScopedTaskEnvironment scoped_task_environment_; |
232 PasswordSyncableServiceWrapper wrapper_; | 238 PasswordSyncableServiceWrapper wrapper_; |
233 }; | 239 }; |
234 | 240 |
235 // Both sync and password db have data that are not present in the other. | 241 // Both sync and password db have data that are not present in the other. |
236 TEST_F(PasswordSyncableServiceTest, AdditionsInBoth) { | 242 TEST_F(PasswordSyncableServiceTest, AdditionsInBoth) { |
237 autofill::PasswordForm form; | 243 autofill::PasswordForm form; |
238 form.signon_realm = kSignonRealm; | 244 form.signon_realm = kSignonRealm; |
239 form.username_value = base::ASCIIToUTF16(kUsername); | 245 form.username_value = base::ASCIIToUTF16(kUsername); |
240 form.password_value = base::ASCIIToUTF16(kPassword); | 246 form.password_value = base::ASCIIToUTF16(kPassword); |
241 | 247 |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 form.signon_realm = kSignonRealm; | 487 form.signon_realm = kSignonRealm; |
482 form.username_value = base::ASCIIToUTF16(kUsername); | 488 form.username_value = base::ASCIIToUTF16(kUsername); |
483 form.password_value = base::ASCIIToUTF16(kPassword); | 489 form.password_value = base::ASCIIToUTF16(kPassword); |
484 PasswordStoreChangeList list; | 490 PasswordStoreChangeList list; |
485 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); | 491 list.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); |
486 | 492 |
487 // No flare and no SyncChangeProcessor, the call shouldn't crash. | 493 // No flare and no SyncChangeProcessor, the call shouldn't crash. |
488 service()->ActOnPasswordStoreChanges(list); | 494 service()->ActOnPasswordStoreChanges(list); |
489 | 495 |
490 // Set the flare. It should be called as there is no SyncChangeProcessor. | 496 // Set the flare. It should be called as there is no SyncChangeProcessor. |
491 service()->InjectStartSyncFlare( | 497 service()->InjectStartSyncFlare(base::Bind( |
492 base::Bind(&MockPasswordSyncableService::StartSyncFlare, | 498 &PasswordSyncableServiceTest::StartSyncFlare, base::Unretained(this))); |
493 base::Unretained(service()))); | 499 EXPECT_CALL(*this, StartSyncFlare(syncer::PASSWORDS)); |
494 EXPECT_CALL(*service(), StartSyncFlare(syncer::PASSWORDS)); | |
495 service()->ActOnPasswordStoreChanges(list); | 500 service()->ActOnPasswordStoreChanges(list); |
496 } | 501 } |
497 | 502 |
498 // Start syncing with an error. Subsequent password store updates shouldn't be | 503 // Start syncing with an error. Subsequent password store updates shouldn't be |
499 // propagated to Sync. | 504 // propagated to Sync. |
500 TEST_F(PasswordSyncableServiceTest, FailedReadFromPasswordStore) { | 505 TEST_F(PasswordSyncableServiceTest, FailedReadFromPasswordStore) { |
501 std::unique_ptr<syncer::SyncErrorFactoryMock> error_factory( | 506 std::unique_ptr<syncer::SyncErrorFactoryMock> error_factory( |
502 new syncer::SyncErrorFactoryMock); | 507 new syncer::SyncErrorFactoryMock); |
503 syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, | 508 syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_ERROR, |
504 "Failed to get passwords from store.", | 509 "Failed to get passwords from store.", |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
666 EXPECT_TRUE(specifics.has_times_used()); | 671 EXPECT_TRUE(specifics.has_times_used()); |
667 EXPECT_EQ(11, specifics.times_used()); | 672 EXPECT_EQ(11, specifics.times_used()); |
668 EXPECT_TRUE(specifics.has_display_name()); | 673 EXPECT_TRUE(specifics.has_display_name()); |
669 EXPECT_EQ("Great Peter", specifics.display_name()); | 674 EXPECT_EQ("Great Peter", specifics.display_name()); |
670 EXPECT_TRUE(specifics.has_avatar_url()); | 675 EXPECT_TRUE(specifics.has_avatar_url()); |
671 EXPECT_EQ("https://google.com/icon", specifics.avatar_url()); | 676 EXPECT_EQ("https://google.com/icon", specifics.avatar_url()); |
672 EXPECT_TRUE(specifics.has_federation_url()); | 677 EXPECT_TRUE(specifics.has_federation_url()); |
673 EXPECT_EQ("https://google.com", specifics.federation_url()); | 678 EXPECT_EQ("https://google.com", specifics.federation_url()); |
674 } | 679 } |
675 | 680 |
| 681 // Tests for Android Autofill credentials. Those are saved in the wrong format |
| 682 // without trailing '/'. Nevertheless, password store should always contain the |
| 683 // correct values. |
| 684 class PasswordSyncableServiceAndroidAutofillTest : public testing::Test { |
| 685 public: |
| 686 PasswordSyncableServiceAndroidAutofillTest() = default; |
| 687 |
| 688 static PasswordFormData android_incorrect(double creation_time) { |
| 689 PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML, |
| 690 kAndroidAutofillRealm, |
| 691 kAndroidAutofillRealm, |
| 692 "", |
| 693 L"", |
| 694 L"", |
| 695 L"", |
| 696 L"username_value_1", |
| 697 L"11111", |
| 698 true, |
| 699 creation_time}; |
| 700 return data; |
| 701 } |
| 702 |
| 703 static PasswordFormData android_correct(double creation_time) { |
| 704 PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML, |
| 705 kAndroidCorrectRealm, |
| 706 kAndroidCorrectRealm, |
| 707 "", |
| 708 L"", |
| 709 L"", |
| 710 L"", |
| 711 L"username_value_1", |
| 712 L"22222", |
| 713 true, |
| 714 creation_time}; |
| 715 return data; |
| 716 } |
| 717 |
| 718 static PasswordFormData android_incorrect2(double creation_time) { |
| 719 PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML, |
| 720 kAndroidAutofillRealm, |
| 721 kAndroidAutofillRealm, |
| 722 "", |
| 723 L"", |
| 724 L"", |
| 725 L"", |
| 726 L"username_value_1", |
| 727 L"33333", |
| 728 false, |
| 729 creation_time}; |
| 730 return data; |
| 731 } |
| 732 |
| 733 static PasswordFormData android_correct2(double creation_time) { |
| 734 PasswordFormData data = {autofill::PasswordForm::SCHEME_HTML, |
| 735 kAndroidCorrectRealm, |
| 736 kAndroidCorrectRealm, |
| 737 "", |
| 738 L"", |
| 739 L"", |
| 740 L"", |
| 741 L"username_value_1", |
| 742 L"444444", |
| 743 false, |
| 744 creation_time}; |
| 745 return data; |
| 746 } |
| 747 |
| 748 static autofill::PasswordForm FormWithCorrectTag(PasswordFormData data) { |
| 749 autofill::PasswordForm form = *CreatePasswordFormFromDataForTesting(data); |
| 750 form.signon_realm = kAndroidCorrectRealm; |
| 751 form.origin = GURL(kAndroidCorrectRealm); |
| 752 form.date_synced = PasswordSyncableServiceWrapper::time(); |
| 753 return form; |
| 754 } |
| 755 |
| 756 static autofill::PasswordForm FormWithAndroidAutofillTag( |
| 757 PasswordFormData data) { |
| 758 autofill::PasswordForm form = *CreatePasswordFormFromDataForTesting(data); |
| 759 form.signon_realm = kAndroidAutofillRealm; |
| 760 form.origin = GURL(kAndroidAutofillRealm); |
| 761 form.date_synced = PasswordSyncableServiceWrapper::time(); |
| 762 return form; |
| 763 } |
| 764 |
| 765 // Transforms |val| into |count| numbers from 1 to |count| inclusive. |
| 766 static std::vector<unsigned> ExtractTimestamps(unsigned val, unsigned count) { |
| 767 std::vector<unsigned> result; |
| 768 for (unsigned i = 0; i < count; ++i) { |
| 769 result.push_back(val % count + 1); |
| 770 val /= count; |
| 771 } |
| 772 return result; |
| 773 } |
| 774 |
| 775 static testing::Message FormDataMessage(const std::string& prefix, |
| 776 const PasswordFormData* data) { |
| 777 testing::Message message; |
| 778 message << prefix; |
| 779 if (data) |
| 780 message << *CreatePasswordFormFromDataForTesting(*data); |
| 781 else |
| 782 message << "NULL"; |
| 783 return message; |
| 784 } |
| 785 |
| 786 protected: |
| 787 base::test::ScopedTaskEnvironment scoped_task_environment_; |
| 788 }; |
| 789 |
| 790 TEST_F(PasswordSyncableServiceAndroidAutofillTest, FourWayMerge) { |
| 791 for (unsigned val = 0; val < 4 * 4 * 4 * 4; ++val) { |
| 792 // Generate 4 creation timestamps for all the entries. |
| 793 std::vector<unsigned> dates = ExtractTimestamps(val, 4); |
| 794 ASSERT_EQ(4u, dates.size()); |
| 795 const unsigned latest = *std::max_element(dates.begin(), dates.end()); |
| 796 // Sync correct, Sync Android autofill, local correct, local incorrect. |
| 797 const PasswordFormData data[4] = { |
| 798 android_correct(dates[0]), android_incorrect(dates[1]), |
| 799 android_correct2(dates[2]), android_incorrect2(dates[3])}; |
| 800 const PasswordFormData* latest_data = |
| 801 std::find_if(data, data + 4, [latest](const PasswordFormData& data) { |
| 802 return data.creation_time == latest; |
| 803 }); |
| 804 ASSERT_TRUE(latest_data); |
| 805 std::vector<autofill::PasswordForm> expected_sync_updates; |
| 806 if (latest_data != &data[0]) |
| 807 expected_sync_updates.push_back(FormWithCorrectTag(*latest_data)); |
| 808 if (latest_data != &data[1]) |
| 809 expected_sync_updates.push_back(FormWithAndroidAutofillTag(*latest_data)); |
| 810 autofill::PasswordForm local_correct = |
| 811 *CreatePasswordFormFromDataForTesting(data[2]); |
| 812 autofill::PasswordForm local_incorrect = |
| 813 *CreatePasswordFormFromDataForTesting(data[3]); |
| 814 syncer::SyncData sync_correct = |
| 815 SyncDataFromPassword(*CreatePasswordFormFromDataForTesting(data[0])); |
| 816 syncer::SyncData sync_incorrect = |
| 817 SyncDataFromPassword(*CreatePasswordFormFromDataForTesting(data[1])); |
| 818 |
| 819 SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[0])); |
| 820 SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[1])); |
| 821 SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[2])); |
| 822 SCOPED_TRACE(*CreatePasswordFormFromDataForTesting(data[3])); |
| 823 |
| 824 for (bool correct_sync_first : {true, false}) { |
| 825 auto wrapper = base::MakeUnique<PasswordSyncableServiceWrapper>(); |
| 826 auto processor = |
| 827 base::MakeUnique<testing::StrictMock<MockSyncChangeProcessor>>(); |
| 828 |
| 829 std::vector<autofill::PasswordForm> stored_forms = {local_correct, |
| 830 local_incorrect}; |
| 831 EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_)) |
| 832 .WillOnce(AppendForms(stored_forms)); |
| 833 EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_)) |
| 834 .WillOnce(Return(true)); |
| 835 if (latest_data != &data[2]) { |
| 836 EXPECT_CALL(*wrapper->password_store(), |
| 837 UpdateLoginImpl(FormWithCorrectTag(*latest_data))); |
| 838 } |
| 839 if (latest_data != &data[3]) { |
| 840 EXPECT_CALL(*wrapper->password_store(), |
| 841 UpdateLoginImpl(FormWithAndroidAutofillTag(*latest_data))); |
| 842 } |
| 843 |
| 844 if (expected_sync_updates.size() == 1) { |
| 845 EXPECT_CALL(*processor, |
| 846 ProcessSyncChanges(_, ElementsAre(SyncChangeIs( |
| 847 SyncChange::ACTION_UPDATE, |
| 848 expected_sync_updates[0])))); |
| 849 } else { |
| 850 EXPECT_CALL( |
| 851 *processor, |
| 852 ProcessSyncChanges(_, UnorderedElementsAre( |
| 853 SyncChangeIs(SyncChange::ACTION_UPDATE, |
| 854 expected_sync_updates[0]), |
| 855 SyncChangeIs(SyncChange::ACTION_UPDATE, |
| 856 expected_sync_updates[1])))); |
| 857 } |
| 858 |
| 859 SyncDataList sync_list = {sync_correct, sync_incorrect}; |
| 860 if (!correct_sync_first) |
| 861 std::swap(sync_list[0], sync_list[1]); |
| 862 wrapper->service()->MergeDataAndStartSyncing( |
| 863 syncer::PASSWORDS, sync_list, std::move(processor), |
| 864 std::unique_ptr<syncer::SyncErrorFactory>()); |
| 865 wrapper.reset(); |
| 866 // Wait til PasswordStore is destroy end therefore all the expectations on |
| 867 // it are checked. |
| 868 scoped_task_environment_.RunUntilIdle(); |
| 869 } |
| 870 } |
| 871 } |
| 872 |
| 873 TEST_F(PasswordSyncableServiceAndroidAutofillTest, ThreeWayMerge) { |
| 874 for (int j = 0; j < 4; ++j) { |
| 875 // Whether the entry exists: Sync correct, Sync Android autofill, |
| 876 // local correct, local incorrect. |
| 877 bool entry_present[4] = {true, true, true, true}; |
| 878 entry_present[j] = false; |
| 879 for (unsigned val = 0; val < 3 * 3 * 3; ++val) { |
| 880 // Generate 3 creation timestamps for all the entries. |
| 881 std::vector<unsigned> dates = ExtractTimestamps(val, 3); |
| 882 ASSERT_EQ(3u, dates.size()); |
| 883 const unsigned latest = *std::max_element(dates.begin(), dates.end()); |
| 884 |
| 885 // Sync correct, Sync Android autofill, local correct, local incorrect. |
| 886 std::vector<std::unique_ptr<PasswordFormData>> data; |
| 887 int date_index = 0; |
| 888 data.push_back(entry_present[0] |
| 889 ? base::MakeUnique<PasswordFormData>( |
| 890 android_correct(dates[date_index++])) |
| 891 : nullptr); |
| 892 data.push_back(entry_present[1] |
| 893 ? base::MakeUnique<PasswordFormData>( |
| 894 android_incorrect(dates[date_index++])) |
| 895 : nullptr); |
| 896 data.push_back(entry_present[2] |
| 897 ? base::MakeUnique<PasswordFormData>( |
| 898 android_correct2(dates[date_index++])) |
| 899 : nullptr); |
| 900 data.push_back(entry_present[3] |
| 901 ? base::MakeUnique<PasswordFormData>( |
| 902 android_incorrect2(dates[date_index++])) |
| 903 : nullptr); |
| 904 |
| 905 SCOPED_TRACE(val); |
| 906 SCOPED_TRACE(j); |
| 907 SCOPED_TRACE(FormDataMessage("data[0]=", data[0].get())); |
| 908 SCOPED_TRACE(FormDataMessage("data[1]=", data[1].get())); |
| 909 SCOPED_TRACE(FormDataMessage("data[2]=", data[2].get())); |
| 910 SCOPED_TRACE(FormDataMessage("data[3]=", data[3].get())); |
| 911 |
| 912 const PasswordFormData* latest_data = |
| 913 std::find_if(data.begin(), data.end(), |
| 914 [latest](const std::unique_ptr<PasswordFormData>& data) { |
| 915 return data && data->creation_time == latest; |
| 916 }) |
| 917 ->get(); |
| 918 ASSERT_TRUE(latest_data); |
| 919 std::vector<std::pair<SyncChange::SyncChangeType, autofill::PasswordForm>> |
| 920 expected_sync_updates; |
| 921 for (int i = 0; i < 2; ++i) { |
| 922 if (latest_data != data[i].get()) { |
| 923 expected_sync_updates.push_back(std::make_pair( |
| 924 data[i] ? SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD, |
| 925 i == 0 ? FormWithCorrectTag(*latest_data) |
| 926 : FormWithAndroidAutofillTag(*latest_data))); |
| 927 } |
| 928 } |
| 929 |
| 930 std::vector<autofill::PasswordForm> stored_forms; |
| 931 for (int i = 2; i < 4; ++i) { |
| 932 if (data[i]) |
| 933 stored_forms.push_back( |
| 934 *CreatePasswordFormFromDataForTesting(*data[i])); |
| 935 } |
| 936 |
| 937 SyncDataList sync_list; |
| 938 for (int i = 0; i < 2; ++i) { |
| 939 if (data[i]) { |
| 940 sync_list.push_back(SyncDataFromPassword( |
| 941 *CreatePasswordFormFromDataForTesting(*data[i]))); |
| 942 } |
| 943 } |
| 944 |
| 945 for (bool swap_sync_list : {false, true}) { |
| 946 auto wrapper = base::MakeUnique<PasswordSyncableServiceWrapper>(); |
| 947 auto processor = |
| 948 base::MakeUnique<testing::StrictMock<MockSyncChangeProcessor>>(); |
| 949 |
| 950 EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_)) |
| 951 .WillOnce(AppendForms(stored_forms)); |
| 952 EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_)) |
| 953 .WillOnce(Return(true)); |
| 954 for (int i = 2; i < 4; ++i) { |
| 955 if (latest_data != data[i].get()) { |
| 956 autofill::PasswordForm latest_form = |
| 957 i == 2 ? FormWithCorrectTag(*latest_data) |
| 958 : FormWithAndroidAutofillTag(*latest_data); |
| 959 if (data[i]) { |
| 960 EXPECT_CALL(*wrapper->password_store(), |
| 961 UpdateLoginImpl(latest_form)); |
| 962 } else { |
| 963 EXPECT_CALL(*wrapper->password_store(), |
| 964 AddLoginImpl(latest_form)); |
| 965 } |
| 966 } |
| 967 } |
| 968 |
| 969 if (expected_sync_updates.size() == 0) { |
| 970 EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty())); |
| 971 } else if (expected_sync_updates.size() == 1) { |
| 972 EXPECT_CALL( |
| 973 *processor, |
| 974 ProcessSyncChanges(_, ElementsAre(SyncChangeIs( |
| 975 expected_sync_updates[0].first, |
| 976 expected_sync_updates[0].second)))); |
| 977 } else if (expected_sync_updates.size() == 2) { |
| 978 EXPECT_CALL( |
| 979 *processor, |
| 980 ProcessSyncChanges( |
| 981 _, UnorderedElementsAre( |
| 982 SyncChangeIs(expected_sync_updates[0].first, |
| 983 expected_sync_updates[0].second), |
| 984 SyncChangeIs(expected_sync_updates[1].first, |
| 985 expected_sync_updates[1].second)))); |
| 986 } |
| 987 |
| 988 if (swap_sync_list && sync_list.size() == 2) |
| 989 std::swap(sync_list[0], sync_list[1]); |
| 990 wrapper->service()->MergeDataAndStartSyncing( |
| 991 syncer::PASSWORDS, sync_list, std::move(processor), |
| 992 std::unique_ptr<syncer::SyncErrorFactory>()); |
| 993 wrapper.reset(); |
| 994 // Wait til PasswordStore is destroy end therefore all the expectations |
| 995 // on it are checked. |
| 996 scoped_task_environment_.RunUntilIdle(); |
| 997 } |
| 998 } |
| 999 } |
| 1000 } |
| 1001 |
| 1002 TEST_F(PasswordSyncableServiceAndroidAutofillTest, TwoWayServerAndLocalMerge) { |
| 1003 for (unsigned i = 0; i < 2 * 2; ++i) { |
| 1004 // Generate 4 different combinations for local/server entries. |
| 1005 std::vector<unsigned> combination = ExtractTimestamps(i, 2); |
| 1006 ASSERT_EQ(2u, combination.size()); |
| 1007 const bool sync_data_correct = !!combination[0]; |
| 1008 const bool local_data_correct = !!combination[1]; |
| 1009 |
| 1010 for (unsigned val = 0; val < 2 * 2; ++val) { |
| 1011 std::vector<unsigned> dates = ExtractTimestamps(i, 2); |
| 1012 ASSERT_EQ(2u, dates.size()); |
| 1013 |
| 1014 const PasswordFormData sync_data = sync_data_correct |
| 1015 ? android_correct(dates[0]) |
| 1016 : android_incorrect(dates[0]); |
| 1017 const PasswordFormData local_data = local_data_correct |
| 1018 ? android_correct2(dates[1]) |
| 1019 : android_incorrect2(dates[1]); |
| 1020 |
| 1021 const PasswordFormData* latest_data = |
| 1022 dates[1] > dates[0] ? &local_data : &sync_data; |
| 1023 |
| 1024 auto wrapper = base::MakeUnique<PasswordSyncableServiceWrapper>(); |
| 1025 auto processor = |
| 1026 base::MakeUnique<testing::StrictMock<MockSyncChangeProcessor>>(); |
| 1027 |
| 1028 EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_)) |
| 1029 .WillOnce( |
| 1030 AppendForm(*CreatePasswordFormFromDataForTesting(local_data))); |
| 1031 EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_)) |
| 1032 .WillOnce(Return(true)); |
| 1033 if (!local_data_correct || latest_data == &sync_data) { |
| 1034 if (local_data_correct) { |
| 1035 EXPECT_CALL(*wrapper->password_store(), |
| 1036 UpdateLoginImpl(FormWithCorrectTag(*latest_data))); |
| 1037 } else { |
| 1038 EXPECT_CALL(*wrapper->password_store(), |
| 1039 AddLoginImpl(FormWithCorrectTag(*latest_data))); |
| 1040 } |
| 1041 } |
| 1042 if (!local_data_correct && latest_data == &sync_data) { |
| 1043 EXPECT_CALL(*wrapper->password_store(), |
| 1044 UpdateLoginImpl(FormWithAndroidAutofillTag(*latest_data))); |
| 1045 } else if (local_data_correct && !sync_data_correct) { |
| 1046 EXPECT_CALL(*wrapper->password_store(), |
| 1047 AddLoginImpl(FormWithAndroidAutofillTag(*latest_data))); |
| 1048 } |
| 1049 |
| 1050 std::vector<std::pair<SyncChange::SyncChangeType, autofill::PasswordForm>> |
| 1051 expected_sync_updates; |
| 1052 // Deal with the correct sync entry and incorrect one. |
| 1053 if (sync_data_correct) { |
| 1054 if (latest_data != &sync_data) { |
| 1055 expected_sync_updates.push_back(std::make_pair( |
| 1056 SyncChange::ACTION_UPDATE, FormWithCorrectTag(*latest_data))); |
| 1057 } |
| 1058 if (!local_data_correct) { |
| 1059 expected_sync_updates.push_back( |
| 1060 std::make_pair(SyncChange::ACTION_ADD, |
| 1061 FormWithAndroidAutofillTag(*latest_data))); |
| 1062 } |
| 1063 } else { |
| 1064 expected_sync_updates.push_back(std::make_pair( |
| 1065 SyncChange::ACTION_ADD, FormWithCorrectTag(*latest_data))); |
| 1066 if (latest_data != &sync_data) { |
| 1067 expected_sync_updates.push_back( |
| 1068 std::make_pair(SyncChange::ACTION_UPDATE, |
| 1069 FormWithAndroidAutofillTag(*latest_data))); |
| 1070 } |
| 1071 } |
| 1072 |
| 1073 // Set expectation on |processor|. |
| 1074 if (expected_sync_updates.size() == 0) { |
| 1075 EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty())); |
| 1076 } else if (expected_sync_updates.size() == 1) { |
| 1077 EXPECT_CALL( |
| 1078 *processor, |
| 1079 ProcessSyncChanges( |
| 1080 _, ElementsAre(SyncChangeIs(expected_sync_updates[0].first, |
| 1081 expected_sync_updates[0].second)))); |
| 1082 } else if (expected_sync_updates.size() == 2) { |
| 1083 EXPECT_CALL(*processor, |
| 1084 ProcessSyncChanges( |
| 1085 _, UnorderedElementsAre( |
| 1086 SyncChangeIs(expected_sync_updates[0].first, |
| 1087 expected_sync_updates[0].second), |
| 1088 SyncChangeIs(expected_sync_updates[1].first, |
| 1089 expected_sync_updates[1].second)))); |
| 1090 } |
| 1091 |
| 1092 SyncDataList sync_list = {SyncDataFromPassword( |
| 1093 *CreatePasswordFormFromDataForTesting(sync_data))}; |
| 1094 wrapper->service()->MergeDataAndStartSyncing( |
| 1095 syncer::PASSWORDS, sync_list, std::move(processor), |
| 1096 std::unique_ptr<syncer::SyncErrorFactory>()); |
| 1097 wrapper.reset(); |
| 1098 // Wait til PasswordStore is destroy end therefore all the expectations on |
| 1099 // it are checked. |
| 1100 scoped_task_environment_.RunUntilIdle(); |
| 1101 } |
| 1102 } |
| 1103 } |
| 1104 |
| 1105 TEST_F(PasswordSyncableServiceAndroidAutofillTest, OneEntryOnly) { |
| 1106 for (int i = 0; i < 3; ++i) { |
| 1107 // The case when only local incorrect entry exists is excluded. It's very |
| 1108 // exotic because a local incorrect entry can come only from the server. |
| 1109 // In such a case a copy will be uploaded to the server and next |
| 1110 // MergeDataAndStartSyncing will do a proper migration. |
| 1111 SCOPED_TRACE(i); |
| 1112 // Whether the entry exists: Sync correct, Sync Android autofill, |
| 1113 // local correct, local incorrect. |
| 1114 const bool entry_is_correct = i == 0 || i == 2; |
| 1115 const bool entry_is_local = i >= 2; |
| 1116 PasswordFormData data = |
| 1117 entry_is_correct ? android_correct(100) : android_incorrect(100); |
| 1118 |
| 1119 auto wrapper = base::MakeUnique<PasswordSyncableServiceWrapper>(); |
| 1120 auto processor = |
| 1121 base::MakeUnique<testing::StrictMock<MockSyncChangeProcessor>>(); |
| 1122 |
| 1123 if (entry_is_local) { |
| 1124 EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_)) |
| 1125 .WillOnce(AppendForm(*CreatePasswordFormFromDataForTesting(data))); |
| 1126 } else { |
| 1127 EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_)) |
| 1128 .WillOnce(Return(true)); |
| 1129 } |
| 1130 EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_)) |
| 1131 .WillOnce(Return(true)); |
| 1132 if (!entry_is_local && !entry_is_correct) { |
| 1133 EXPECT_CALL(*wrapper->password_store(), |
| 1134 AddLoginImpl(FormWithAndroidAutofillTag(data))); |
| 1135 } |
| 1136 if (!entry_is_local) { |
| 1137 EXPECT_CALL(*wrapper->password_store(), |
| 1138 AddLoginImpl(FormWithCorrectTag(data))); |
| 1139 } |
| 1140 |
| 1141 if (entry_is_correct && !entry_is_local) { |
| 1142 EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty())); |
| 1143 } else { |
| 1144 EXPECT_CALL(*processor, |
| 1145 ProcessSyncChanges( |
| 1146 _, ElementsAre(SyncChangeIs(SyncChange::ACTION_ADD, |
| 1147 FormWithCorrectTag(data))))); |
| 1148 } |
| 1149 |
| 1150 SyncDataList sync_list; |
| 1151 if (!entry_is_local) { |
| 1152 sync_list.push_back( |
| 1153 SyncDataFromPassword(*CreatePasswordFormFromDataForTesting(data))); |
| 1154 } |
| 1155 wrapper->service()->MergeDataAndStartSyncing( |
| 1156 syncer::PASSWORDS, sync_list, std::move(processor), |
| 1157 std::unique_ptr<syncer::SyncErrorFactory>()); |
| 1158 wrapper.reset(); |
| 1159 // Wait til PasswordStore is destroy end therefore all the expectations on |
| 1160 // it are checked. |
| 1161 scoped_task_environment_.RunUntilIdle(); |
| 1162 } |
| 1163 } |
| 1164 |
| 1165 TEST_F(PasswordSyncableServiceAndroidAutofillTest, FourEqualEntries) { |
| 1166 // Sync correct, Sync Android autofill, local correct, local incorrect with |
| 1167 // the same content. Nothing should happen. |
| 1168 const PasswordFormData data = android_correct(100); |
| 1169 autofill::PasswordForm local_correct = FormWithCorrectTag(data); |
| 1170 autofill::PasswordForm local_incorrect = FormWithAndroidAutofillTag(data); |
| 1171 syncer::SyncData sync_correct = SyncDataFromPassword(local_correct); |
| 1172 syncer::SyncData sync_incorrect = SyncDataFromPassword(local_incorrect); |
| 1173 |
| 1174 for (bool correct_sync_first : {true, false}) { |
| 1175 auto wrapper = base::MakeUnique<PasswordSyncableServiceWrapper>(); |
| 1176 auto processor = |
| 1177 base::MakeUnique<testing::StrictMock<MockSyncChangeProcessor>>(); |
| 1178 |
| 1179 std::vector<autofill::PasswordForm> stored_forms = {local_correct, |
| 1180 local_incorrect}; |
| 1181 EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_)) |
| 1182 .WillOnce(AppendForms(stored_forms)); |
| 1183 EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_)) |
| 1184 .WillOnce(Return(true)); |
| 1185 EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty())); |
| 1186 |
| 1187 SyncDataList sync_list = {sync_correct, sync_incorrect}; |
| 1188 if (!correct_sync_first) |
| 1189 std::swap(sync_list[0], sync_list[1]); |
| 1190 wrapper->service()->MergeDataAndStartSyncing( |
| 1191 syncer::PASSWORDS, sync_list, std::move(processor), |
| 1192 std::unique_ptr<syncer::SyncErrorFactory>()); |
| 1193 wrapper.reset(); |
| 1194 // Wait til PasswordStore is destroy end therefore all the expectations on |
| 1195 // it are checked. |
| 1196 scoped_task_environment_.RunUntilIdle(); |
| 1197 } |
| 1198 } |
| 1199 |
| 1200 TEST_F(PasswordSyncableServiceAndroidAutofillTest, AndroidCorrectEqualEntries) { |
| 1201 // Sync correct, local correct with the same content. Nothing should happen. |
| 1202 const PasswordFormData data = android_correct(100); |
| 1203 autofill::PasswordForm local_correct = FormWithCorrectTag(data); |
| 1204 syncer::SyncData sync_correct = SyncDataFromPassword(local_correct); |
| 1205 |
| 1206 auto wrapper = base::MakeUnique<PasswordSyncableServiceWrapper>(); |
| 1207 auto processor = |
| 1208 base::MakeUnique<testing::StrictMock<MockSyncChangeProcessor>>(); |
| 1209 |
| 1210 EXPECT_CALL(*wrapper->password_store(), FillAutofillableLogins(_)) |
| 1211 .WillOnce(AppendForm(local_correct)); |
| 1212 EXPECT_CALL(*wrapper->password_store(), FillBlacklistLogins(_)) |
| 1213 .WillOnce(Return(true)); |
| 1214 EXPECT_CALL(*processor, ProcessSyncChanges(_, IsEmpty())); |
| 1215 |
| 1216 wrapper->service()->MergeDataAndStartSyncing( |
| 1217 syncer::PASSWORDS, {sync_correct}, std::move(processor), |
| 1218 std::unique_ptr<syncer::SyncErrorFactory>()); |
| 1219 wrapper.reset(); |
| 1220 // Wait til PasswordStore is destroy end therefore all the expectations on |
| 1221 // it are checked. |
| 1222 scoped_task_environment_.RunUntilIdle(); |
| 1223 } |
| 1224 |
676 } // namespace | 1225 } // namespace |
677 | 1226 |
678 } // namespace password_manager | 1227 } // namespace password_manager |
OLD | NEW |