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

Side by Side Diff: chrome/browser/password_manager/password_store_mac_unittest.cc

Issue 838453003: Open the LoginDatabase on the DB thread, not the UI thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix nits from vabr@. Created 5 years, 11 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/password_manager/password_store_mac.h" 5 #include "chrome/browser/password_manager/password_store_mac.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/files/scoped_temp_dir.h" 8 #include "base/files/scoped_temp_dir.h"
9 #include "base/memory/scoped_vector.h" 9 #include "base/memory/scoped_vector.h"
10 #include "base/scoped_observer.h" 10 #include "base/scoped_observer.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/synchronization/waitable_event.h"
14 #include "chrome/browser/password_manager/password_store_mac_internal.h" 15 #include "chrome/browser/password_manager/password_store_mac_internal.h"
15 #include "chrome/common/chrome_paths.h" 16 #include "chrome/common/chrome_paths.h"
17 #include "components/password_manager/core/browser/login_database.h"
16 #include "components/password_manager/core/browser/password_store_consumer.h" 18 #include "components/password_manager/core/browser/password_store_consumer.h"
17 #include "content/public/test/test_browser_thread.h" 19 #include "content/public/test/test_browser_thread.h"
18 #include "crypto/mock_apple_keychain.h" 20 #include "crypto/mock_apple_keychain.h"
19 #include "testing/gmock/include/gmock/gmock.h" 21 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/gtest/include/gtest/gtest.h"
21 23
22 using autofill::PasswordForm; 24 using autofill::PasswordForm;
23 using base::ASCIIToUTF16; 25 using base::ASCIIToUTF16;
24 using base::WideToUTF16; 26 using base::WideToUTF16;
25 using content::BrowserThread; 27 using content::BrowserThread;
26 using crypto::MockAppleKeychain; 28 using crypto::MockAppleKeychain;
27 using internal_keychain_helpers::FormsMatchForMerge; 29 using internal_keychain_helpers::FormsMatchForMerge;
28 using internal_keychain_helpers::STRICT_FORM_MATCH; 30 using internal_keychain_helpers::STRICT_FORM_MATCH;
29 using password_manager::LoginDatabase; 31 using password_manager::LoginDatabase;
30 using password_manager::PasswordStore; 32 using password_manager::PasswordStore;
31 using password_manager::PasswordStoreConsumer; 33 using password_manager::PasswordStoreConsumer;
32 using testing::_; 34 using testing::_;
33 using testing::DoAll; 35 using testing::DoAll;
34 using testing::Invoke; 36 using testing::Invoke;
35 using testing::WithArg; 37 using testing::WithArg;
36 38
37 namespace { 39 namespace {
38 40
41 ACTION(STLDeleteElements0) {
42 STLDeleteContainerPointers(arg0.begin(), arg0.end());
43 }
44
45 ACTION(QuitUIMessageLoop) {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
47 base::MessageLoop::current()->Quit();
48 }
49
39 class MockPasswordStoreConsumer : public PasswordStoreConsumer { 50 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
40 public: 51 public:
41 MOCK_METHOD1(OnGetPasswordStoreResults, 52 MOCK_METHOD1(OnGetPasswordStoreResults,
42 void(const std::vector<autofill::PasswordForm*>&)); 53 void(const std::vector<autofill::PasswordForm*>&));
43 54
44 void CopyElements(const std::vector<autofill::PasswordForm*>& forms) { 55 void CopyElements(const std::vector<autofill::PasswordForm*>& forms) {
45 last_result.clear(); 56 last_result.clear();
46 for (size_t i = 0; i < forms.size(); ++i) { 57 for (size_t i = 0; i < forms.size(); ++i) {
47 last_result.push_back(*forms[i]); 58 last_result.push_back(*forms[i]);
48 } 59 }
49 } 60 }
50 61
62 // Runs the current thread's message loop until OnGetPasswordStoreResults()
63 // is posted to it. This method should be called immediately after GetLogins,
64 // without pumping the message loop in-between.
65 void WaitOnGetPasswordStoreResults() {
66 EXPECT_CALL(*this, OnGetPasswordStoreResults(_)).WillOnce(DoAll(
67 WithArg<0>(Invoke(this, &MockPasswordStoreConsumer::CopyElements)),
68 WithArg<0>(STLDeleteElements0()),
69 QuitUIMessageLoop()));
70 base::MessageLoop::current()->Run();
71 }
72
51 std::vector<PasswordForm> last_result; 73 std::vector<PasswordForm> last_result;
52 }; 74 };
53 75
54 ACTION(STLDeleteElements0) { 76 class MockPasswordStoreObserver : public PasswordStore::Observer {
55 STLDeleteContainerPointers(arg0.begin(), arg0.end()); 77 public:
56 } 78 MOCK_METHOD1(OnLoginsChanged,
79 void(const password_manager::PasswordStoreChangeList& changes));
80 };
57 81
58 ACTION(QuitUIMessageLoop) { 82 // A mock LoginDatabase that simulates a failing Init() method.
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 83 class BadLoginDatabase : public password_manager::LoginDatabase {
60 base::MessageLoop::current()->Quit(); 84 public:
61 } 85 BadLoginDatabase() : password_manager::LoginDatabase(base::FilePath()) {}
86 ~BadLoginDatabase() override {}
87
88 // LoginDatabase:
89 bool Init() override { return false; }
90
91 private:
92 DISALLOW_COPY_AND_ASSIGN(BadLoginDatabase);
93 };
94
95 // A LoginDatabase that simulates an Init() method that takes a long time.
96 class SlowToInitLoginDatabase : public password_manager::LoginDatabase {
97 public:
98 // Creates an instance whose Init() method will block until |event| is
99 // signaled. |event| must outlive |this|.
100 SlowToInitLoginDatabase(const base::FilePath& db_path,
101 base::WaitableEvent* event)
102 : password_manager::LoginDatabase(db_path), event_(event) {}
103 ~SlowToInitLoginDatabase() override {}
104
105 // LoginDatabase:
106 bool Init() override {
107 event_->Wait();
108 return password_manager::LoginDatabase::Init();
109 }
110
111 private:
112 base::WaitableEvent* event_;
113
114 DISALLOW_COPY_AND_ASSIGN(SlowToInitLoginDatabase);
115 };
62 116
63 class TestPasswordStoreMac : public PasswordStoreMac { 117 class TestPasswordStoreMac : public PasswordStoreMac {
64 public: 118 public:
65 TestPasswordStoreMac( 119 TestPasswordStoreMac(
66 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, 120 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
67 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner, 121 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
68 crypto::AppleKeychain* keychain, 122 scoped_ptr<crypto::AppleKeychain> keychain,
69 LoginDatabase* login_db) 123 scoped_ptr<password_manager::LoginDatabase> login_db)
70 : PasswordStoreMac(main_thread_runner, 124 : PasswordStoreMac(main_thread_runner,
71 db_thread_runner, 125 db_thread_runner,
72 keychain, 126 keychain.Pass(),
73 login_db) { 127 login_db.Pass()) {}
74 }
75 128
76 using PasswordStoreMac::GetBackgroundTaskRunner; 129 using PasswordStoreMac::GetBackgroundTaskRunner;
77 130
78 private: 131 private:
79 ~TestPasswordStoreMac() override {} 132 ~TestPasswordStoreMac() override {}
80 133
81 DISALLOW_COPY_AND_ASSIGN(TestPasswordStoreMac); 134 DISALLOW_COPY_AND_ASSIGN(TestPasswordStoreMac);
82 }; 135 };
83 136
84 } // namespace 137 } // namespace
(...skipping 960 matching lines...) Expand 10 before | Expand all | Expand 10 after
1045 STLDeleteElements(&owned_passwords); 1098 STLDeleteElements(&owned_passwords);
1046 } 1099 }
1047 1100
1048 #pragma mark - 1101 #pragma mark -
1049 1102
1050 class PasswordStoreMacTest : public testing::Test { 1103 class PasswordStoreMacTest : public testing::Test {
1051 public: 1104 public:
1052 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} 1105 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {}
1053 1106
1054 void SetUp() override { 1107 void SetUp() override {
1055 login_db_ = new LoginDatabase();
1056 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); 1108 ASSERT_TRUE(db_dir_.CreateUniqueTempDir());
1057 base::FilePath db_file = db_dir_.path().AppendASCII("login.db");
1058 ASSERT_TRUE(login_db_->Init(db_file));
1059 1109
1060 keychain_ = new MockAppleKeychain(); 1110 scoped_ptr<password_manager::LoginDatabase> login_db(
1111 new password_manager::LoginDatabase(test_login_db_file_path()));
1112 CreateAndInitPasswordStore(login_db.Pass());
1113 // Make sure deferred initialization is performed before some tests start
1114 // accessing the |login_db| directly.
1115 FinishAsyncProcessing();
1116 }
1061 1117
1118 void TearDown() override { ClosePasswordStore(); }
1119
1120 void CreateAndInitPasswordStore(
1121 scoped_ptr<password_manager::LoginDatabase> login_db) {
1062 store_ = new TestPasswordStoreMac( 1122 store_ = new TestPasswordStoreMac(
1063 base::MessageLoopProxy::current(), 1123 base::MessageLoopProxy::current(), base::MessageLoopProxy::current(),
1064 base::MessageLoopProxy::current(), 1124 make_scoped_ptr<AppleKeychain>(new MockAppleKeychain), login_db.Pass());
1065 keychain_,
1066 login_db_);
1067 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare())); 1125 ASSERT_TRUE(store_->Init(syncer::SyncableService::StartSyncFlare()));
1068 } 1126 }
1069 1127
1070 void TearDown() override { 1128 void ClosePasswordStore() {
1129 if (!store_)
1130 return;
1131
1071 store_->Shutdown(); 1132 store_->Shutdown();
1072 EXPECT_FALSE(store_->GetBackgroundTaskRunner().get()); 1133 EXPECT_FALSE(store_->GetBackgroundTaskRunner());
1134 base::MessageLoop::current()->RunUntilIdle();
1135 store_ = nullptr;
1073 } 1136 }
1074 1137
1075 void WaitForStoreUpdate() { 1138 base::FilePath test_login_db_file_path() const {
1076 // Do a store-level query to wait for all the operations above to be done. 1139 return db_dir_.path().Append(FILE_PATH_LITERAL("login.db"));
1140 }
1141
1142 password_manager::LoginDatabase* login_db() const {
1143 return store_->login_metadata_db();
1144 }
1145
1146 MockAppleKeychain* keychain() {
1147 return static_cast<MockAppleKeychain*>(store_->keychain());
1148 }
1149
1150 void FinishAsyncProcessing() {
1151 // Do a store-level query to wait for all the previously enqueued operations
1152 // to finish.
1077 MockPasswordStoreConsumer consumer; 1153 MockPasswordStoreConsumer consumer;
1078 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_))
1079 .WillOnce(DoAll(WithArg<0>(STLDeleteElements0()), QuitUIMessageLoop()));
1080 store_->GetLogins(PasswordForm(), PasswordStore::ALLOW_PROMPT, &consumer); 1154 store_->GetLogins(PasswordForm(), PasswordStore::ALLOW_PROMPT, &consumer);
1081 base::MessageLoop::current()->Run(); 1155 consumer.WaitOnGetPasswordStoreResults();
1082 } 1156 }
1083 1157
1084 TestPasswordStoreMac* store() { return store_.get(); } 1158 TestPasswordStoreMac* store() { return store_.get(); }
1085 1159
1086 MockAppleKeychain* keychain() { return keychain_; }
1087
1088 protected: 1160 protected:
1089 base::MessageLoopForUI message_loop_; 1161 base::MessageLoopForUI message_loop_;
1090 content::TestBrowserThread ui_thread_; 1162 content::TestBrowserThread ui_thread_;
1091 1163
1092 MockAppleKeychain* keychain_; // Owned by store_. 1164 base::ScopedTempDir db_dir_;
1093 LoginDatabase* login_db_; // Owned by store_.
1094 scoped_refptr<TestPasswordStoreMac> store_; 1165 scoped_refptr<TestPasswordStoreMac> store_;
1095 base::ScopedTempDir db_dir_;
1096 }; 1166 };
1097 1167
1098 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { 1168 TEST_F(PasswordStoreMacTest, TestStoreUpdate) {
1099 // Insert a password into both the database and the keychain. 1169 // Insert a password into both the database and the keychain.
1100 // This is done manually, rather than through store_->AddLogin, because the 1170 // This is done manually, rather than through store_->AddLogin, because the
1101 // Mock Keychain isn't smart enough to be able to support update generically, 1171 // Mock Keychain isn't smart enough to be able to support update generically,
1102 // so some.domain.com triggers special handling to test it that make inserting 1172 // so some.domain.com triggers special handling to test it that make inserting
1103 // fail. 1173 // fail.
1104 PasswordFormData joint_data = { 1174 PasswordFormData joint_data = {
1105 PasswordForm::SCHEME_HTML, "http://some.domain.com/", 1175 PasswordForm::SCHEME_HTML, "http://some.domain.com/",
1106 "http://some.domain.com/insecure.html", "login.cgi", 1176 "http://some.domain.com/insecure.html", "login.cgi",
1107 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 1177 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1
1108 }; 1178 };
1109 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); 1179 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data));
1110 login_db_->AddLogin(*joint_form); 1180 login_db()->AddLogin(*joint_form);
1111 MockAppleKeychain::KeychainTestData joint_keychain_data = { 1181 MockAppleKeychain::KeychainTestData joint_keychain_data = {
1112 kSecAuthenticationTypeHTMLForm, "some.domain.com", 1182 kSecAuthenticationTypeHTMLForm, "some.domain.com",
1113 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", 1183 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z",
1114 "joe_user", "sekrit", false }; 1184 "joe_user", "sekrit", false };
1115 keychain_->AddTestItem(joint_keychain_data); 1185 keychain()->AddTestItem(joint_keychain_data);
1116 1186
1117 // Insert a password into the keychain only. 1187 // Insert a password into the keychain only.
1118 MockAppleKeychain::KeychainTestData keychain_only_data = { 1188 MockAppleKeychain::KeychainTestData keychain_only_data = {
1119 kSecAuthenticationTypeHTMLForm, "keychain.only.com", 1189 kSecAuthenticationTypeHTMLForm, "keychain.only.com",
1120 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", 1190 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z",
1121 "keychain", "only", false 1191 "keychain", "only", false
1122 }; 1192 };
1123 keychain_->AddTestItem(keychain_only_data); 1193 keychain()->AddTestItem(keychain_only_data);
1124 1194
1125 struct UpdateData { 1195 struct UpdateData {
1126 PasswordFormData form_data; 1196 PasswordFormData form_data;
1127 const char* password; // NULL indicates no entry should be present. 1197 const char* password; // NULL indicates no entry should be present.
1128 }; 1198 };
1129 1199
1130 // Make a series of update calls. 1200 // Make a series of update calls.
1131 UpdateData updates[] = { 1201 UpdateData updates[] = {
1132 // Update the keychain+db passwords (the normal password update case). 1202 // Update the keychain+db passwords (the normal password update case).
1133 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/", 1203 { { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
(...skipping 19 matching lines...) Expand all
1153 true, false, 2 }, 1223 true, false, 2 },
1154 NULL, 1224 NULL,
1155 }, 1225 },
1156 }; 1226 };
1157 for (unsigned int i = 0; i < arraysize(updates); ++i) { 1227 for (unsigned int i = 0; i < arraysize(updates); ++i) {
1158 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData( 1228 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(
1159 updates[i].form_data)); 1229 updates[i].form_data));
1160 store_->UpdateLogin(*form); 1230 store_->UpdateLogin(*form);
1161 } 1231 }
1162 1232
1163 WaitForStoreUpdate(); 1233 FinishAsyncProcessing();
1164 1234
1165 MacKeychainPasswordFormAdapter keychain_adapter(keychain_); 1235 MacKeychainPasswordFormAdapter keychain_adapter(keychain());
1166 for (unsigned int i = 0; i < arraysize(updates); ++i) { 1236 for (unsigned int i = 0; i < arraysize(updates); ++i) {
1167 scoped_ptr<PasswordForm> query_form( 1237 scoped_ptr<PasswordForm> query_form(
1168 CreatePasswordFormFromData(updates[i].form_data)); 1238 CreatePasswordFormFromData(updates[i].form_data));
1169 1239
1170 std::vector<PasswordForm*> matching_items = 1240 std::vector<PasswordForm*> matching_items =
1171 keychain_adapter.PasswordsFillingForm(query_form->signon_realm, 1241 keychain_adapter.PasswordsFillingForm(query_form->signon_realm,
1172 query_form->scheme); 1242 query_form->scheme);
1173 if (updates[i].password) { 1243 if (updates[i].password) {
1174 EXPECT_GT(matching_items.size(), 0U) << "iteration " << i; 1244 EXPECT_GT(matching_items.size(), 0U) << "iteration " << i;
1175 if (matching_items.size() >= 1) 1245 if (matching_items.size() >= 1)
1176 EXPECT_EQ(ASCIIToUTF16(updates[i].password), 1246 EXPECT_EQ(ASCIIToUTF16(updates[i].password),
1177 matching_items[0]->password_value) << "iteration " << i; 1247 matching_items[0]->password_value) << "iteration " << i;
1178 } else { 1248 } else {
1179 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; 1249 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i;
1180 } 1250 }
1181 STLDeleteElements(&matching_items); 1251 STLDeleteElements(&matching_items);
1182 1252
1183 login_db_->GetLogins(*query_form, &matching_items); 1253 login_db()->GetLogins(*query_form, &matching_items);
1184 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) 1254 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size())
1185 << "iteration " << i; 1255 << "iteration " << i;
1186 STLDeleteElements(&matching_items); 1256 STLDeleteElements(&matching_items);
1187 } 1257 }
1188 } 1258 }
1189 1259
1190 TEST_F(PasswordStoreMacTest, TestDBKeychainAssociation) { 1260 TEST_F(PasswordStoreMacTest, TestDBKeychainAssociation) {
1191 // Tests that association between the keychain and login database parts of a 1261 // Tests that association between the keychain and login database parts of a
1192 // password added by fuzzy (PSL) matching works. 1262 // password added by fuzzy (PSL) matching works.
1193 // 1. Add a password for www.facebook.com 1263 // 1. Add a password for www.facebook.com
1194 // 2. Get a password for m.facebook.com. This fuzzy matches and returns the 1264 // 2. Get a password for m.facebook.com. This fuzzy matches and returns the
1195 // www.facebook.com password. 1265 // www.facebook.com password.
1196 // 3. Add the returned password for m.facebook.com. 1266 // 3. Add the returned password for m.facebook.com.
1197 // 4. Remove both passwords. 1267 // 4. Remove both passwords.
1198 // -> check: that both are gone from the login DB and the keychain 1268 // -> check: that both are gone from the login DB and the keychain
1199 // This test should in particular ensure that we don't keep passwords in the 1269 // This test should in particular ensure that we don't keep passwords in the
1200 // keychain just before we think we still have other (fuzzy-)matching entries 1270 // keychain just before we think we still have other (fuzzy-)matching entries
1201 // for them in the login database. (For example, here if we deleted the 1271 // for them in the login database. (For example, here if we deleted the
1202 // www.facebook.com password from the login database, we should not be blocked 1272 // www.facebook.com password from the login database, we should not be blocked
1203 // from deleting it from the keystore just becaus the m.facebook.com password 1273 // from deleting it from the keystore just becaus the m.facebook.com password
1204 // fuzzy-matches the www.facebook.com one.) 1274 // fuzzy-matches the www.facebook.com one.)
1205 1275
1206 // 1. Add a password for www.facebook.com 1276 // 1. Add a password for www.facebook.com
1207 PasswordFormData www_form_data = { 1277 PasswordFormData www_form_data = {
1208 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", 1278 PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
1209 "http://www.facebook.com/index.html", "login", 1279 "http://www.facebook.com/index.html", "login",
1210 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 1280 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1
1211 }; 1281 };
1212 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data)); 1282 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data));
1213 login_db_->AddLogin(*www_form); 1283 login_db()->AddLogin(*www_form);
1214 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); 1284 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain());
1215 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); 1285 owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
1216 owned_keychain_adapter.AddPassword(*www_form); 1286 owned_keychain_adapter.AddPassword(*www_form);
1217 1287
1218 // 2. Get a password for m.facebook.com. 1288 // 2. Get a password for m.facebook.com.
1219 PasswordForm m_form(*www_form); 1289 PasswordForm m_form(*www_form);
1220 m_form.signon_realm = "http://m.facebook.com"; 1290 m_form.signon_realm = "http://m.facebook.com";
1221 m_form.origin = GURL("http://m.facebook.com/index.html"); 1291 m_form.origin = GURL("http://m.facebook.com/index.html");
1292
1222 MockPasswordStoreConsumer consumer; 1293 MockPasswordStoreConsumer consumer;
1223 EXPECT_CALL(consumer, OnGetPasswordStoreResults(_)).WillOnce(DoAll(
1224 WithArg<0>(Invoke(&consumer, &MockPasswordStoreConsumer::CopyElements)),
1225 WithArg<0>(STLDeleteElements0()),
1226 QuitUIMessageLoop()));
1227 store_->GetLogins(m_form, PasswordStore::ALLOW_PROMPT, &consumer); 1294 store_->GetLogins(m_form, PasswordStore::ALLOW_PROMPT, &consumer);
1228 base::MessageLoop::current()->Run(); 1295 consumer.WaitOnGetPasswordStoreResults();
1229 EXPECT_EQ(1u, consumer.last_result.size()); 1296 EXPECT_EQ(1u, consumer.last_result.size());
1230 1297
1231 // 3. Add the returned password for m.facebook.com. 1298 // 3. Add the returned password for m.facebook.com.
1232 login_db_->AddLogin(consumer.last_result[0]); 1299 login_db()->AddLogin(consumer.last_result[0]);
1233 owned_keychain_adapter.AddPassword(m_form); 1300 owned_keychain_adapter.AddPassword(m_form);
1234 1301
1235 // 4. Remove both passwords. 1302 // 4. Remove both passwords.
1236 store_->RemoveLogin(*www_form); 1303 store_->RemoveLogin(*www_form);
1237 store_->RemoveLogin(m_form); 1304 store_->RemoveLogin(m_form);
1238 WaitForStoreUpdate(); 1305 FinishAsyncProcessing();
1239 1306
1240 std::vector<PasswordForm*> matching_items; 1307 std::vector<PasswordForm*> matching_items;
1241 // No trace of www.facebook.com. 1308 // No trace of www.facebook.com.
1242 matching_items = owned_keychain_adapter.PasswordsFillingForm( 1309 matching_items = owned_keychain_adapter.PasswordsFillingForm(
1243 www_form->signon_realm, www_form->scheme); 1310 www_form->signon_realm, www_form->scheme);
1244 EXPECT_EQ(0u, matching_items.size()); 1311 EXPECT_EQ(0u, matching_items.size());
1245 login_db_->GetLogins(*www_form, &matching_items); 1312 login_db()->GetLogins(*www_form, &matching_items);
1246 EXPECT_EQ(0u, matching_items.size()); 1313 EXPECT_EQ(0u, matching_items.size());
1247 // No trace of m.facebook.com. 1314 // No trace of m.facebook.com.
1248 matching_items = owned_keychain_adapter.PasswordsFillingForm( 1315 matching_items = owned_keychain_adapter.PasswordsFillingForm(
1249 m_form.signon_realm, m_form.scheme); 1316 m_form.signon_realm, m_form.scheme);
1250 EXPECT_EQ(0u, matching_items.size()); 1317 EXPECT_EQ(0u, matching_items.size());
1251 login_db_->GetLogins(m_form, &matching_items); 1318 login_db()->GetLogins(m_form, &matching_items);
1252 EXPECT_EQ(0u, matching_items.size()); 1319 EXPECT_EQ(0u, matching_items.size());
1253 } 1320 }
1254 1321
1255 namespace { 1322 namespace {
1256 1323
1257 class PasswordsChangeObserver : 1324 class PasswordsChangeObserver :
1258 public password_manager::PasswordStore::Observer { 1325 public password_manager::PasswordStore::Observer {
1259 public: 1326 public:
1260 PasswordsChangeObserver(TestPasswordStoreMac* store) : observer_(this) { 1327 PasswordsChangeObserver(TestPasswordStoreMac* store) : observer_(this) {
1261 observer_.Add(store); 1328 observer_.Add(store);
1262 } 1329 }
1263 1330
1264 void WaitAndVerify(PasswordStoreMacTest* test) { 1331 void WaitAndVerify(PasswordStoreMacTest* test) {
1265 test->WaitForStoreUpdate(); 1332 test->FinishAsyncProcessing();
1266 ::testing::Mock::VerifyAndClearExpectations(this); 1333 ::testing::Mock::VerifyAndClearExpectations(this);
1267 } 1334 }
1268 1335
1269 // password_manager::PasswordStore::Observer: 1336 // password_manager::PasswordStore::Observer:
1270 MOCK_METHOD1(OnLoginsChanged, 1337 MOCK_METHOD1(OnLoginsChanged,
1271 void(const password_manager::PasswordStoreChangeList& changes)); 1338 void(const password_manager::PasswordStoreChangeList& changes));
1272 1339
1273 private: 1340 private:
1274 ScopedObserver<password_manager::PasswordStore, 1341 ScopedObserver<password_manager::PasswordStore,
1275 PasswordsChangeObserver> observer_; 1342 PasswordsChangeObserver> observer_;
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
1388 1455
1389 TEST_F(PasswordStoreMacTest, TestRemoveLoginsMultiProfile) { 1456 TEST_F(PasswordStoreMacTest, TestRemoveLoginsMultiProfile) {
1390 // Make sure that RemoveLoginsCreatedBetween does affect only the correct 1457 // Make sure that RemoveLoginsCreatedBetween does affect only the correct
1391 // profile. 1458 // profile.
1392 1459
1393 // Add a third-party password. 1460 // Add a third-party password.
1394 MockAppleKeychain::KeychainTestData keychain_data = { 1461 MockAppleKeychain::KeychainTestData keychain_data = {
1395 kSecAuthenticationTypeHTMLForm, "some.domain.com", 1462 kSecAuthenticationTypeHTMLForm, "some.domain.com",
1396 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", 1463 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z",
1397 "joe_user", "sekrit", false }; 1464 "joe_user", "sekrit", false };
1398 keychain_->AddTestItem(keychain_data); 1465 keychain()->AddTestItem(keychain_data);
1399 1466
1400 // Add a password through the adapter. It has the "Chrome" creator tag. 1467 // Add a password through the adapter. It has the "Chrome" creator tag.
1401 // However, it's not referenced by the password database. 1468 // However, it's not referenced by the password database.
1402 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); 1469 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain());
1403 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); 1470 owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
1404 PasswordFormData www_form_data1 = { 1471 PasswordFormData www_form_data1 = {
1405 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", 1472 PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
1406 "http://www.facebook.com/index.html", "login", L"username", L"password", 1473 "http://www.facebook.com/index.html", "login", L"username", L"password",
1407 L"submit", L"joe_user", L"sekrit", true, false, 1 }; 1474 L"submit", L"joe_user", L"sekrit", true, false, 1 };
1408 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data1)); 1475 scoped_ptr<PasswordForm> www_form(CreatePasswordFormFromData(www_form_data1));
1409 EXPECT_TRUE(owned_keychain_adapter.AddPassword(*www_form)); 1476 EXPECT_TRUE(owned_keychain_adapter.AddPassword(*www_form));
1410 1477
1411 // Add a password from the current profile. 1478 // Add a password from the current profile.
1412 PasswordFormData www_form_data2 = { 1479 PasswordFormData www_form_data2 = {
1413 PasswordForm::SCHEME_HTML, "http://www.facebook.com/", 1480 PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
1414 "http://www.facebook.com/index.html", "login", L"username", L"password", 1481 "http://www.facebook.com/index.html", "login", L"username", L"password",
1415 L"submit", L"not_joe_user", L"12345", true, false, 1 }; 1482 L"submit", L"not_joe_user", L"12345", true, false, 1 };
1416 www_form.reset(CreatePasswordFormFromData(www_form_data2)); 1483 www_form.reset(CreatePasswordFormFromData(www_form_data2));
1417 store_->AddLogin(*www_form); 1484 store_->AddLogin(*www_form);
1418 WaitForStoreUpdate(); 1485 FinishAsyncProcessing();
1419 1486
1420 ScopedVector<PasswordForm> matching_items; 1487 ScopedVector<PasswordForm> matching_items;
1421 login_db_->GetLogins(*www_form, &matching_items.get()); 1488 login_db()->GetLogins(*www_form, &matching_items.get());
1422 EXPECT_EQ(1u, matching_items.size()); 1489 EXPECT_EQ(1u, matching_items.size());
1423 matching_items.clear(); 1490 matching_items.clear();
1424 1491
1425 store_->RemoveLoginsCreatedBetween(base::Time(), base::Time()); 1492 store_->RemoveLoginsCreatedBetween(base::Time(), base::Time());
1426 WaitForStoreUpdate(); 1493 FinishAsyncProcessing();
1427 1494
1428 // Check the second facebook form is gone. 1495 // Check the second facebook form is gone.
1429 login_db_->GetLogins(*www_form, &matching_items.get()); 1496 login_db()->GetLogins(*www_form, &matching_items.get());
1430 EXPECT_EQ(0u, matching_items.size()); 1497 EXPECT_EQ(0u, matching_items.size());
1431 1498
1432 // Check the first facebook form is still there. 1499 // Check the first facebook form is still there.
1433 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( 1500 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm(
1434 www_form->signon_realm, www_form->scheme); 1501 www_form->signon_realm, www_form->scheme);
1435 ASSERT_EQ(1u, matching_items.size()); 1502 ASSERT_EQ(1u, matching_items.size());
1436 EXPECT_EQ(ASCIIToUTF16("joe_user"), matching_items[0]->username_value); 1503 EXPECT_EQ(ASCIIToUTF16("joe_user"), matching_items[0]->username_value);
1437 matching_items.clear(); 1504 matching_items.clear();
1438 1505
1439 // Check the third-party password is still there. 1506 // Check the third-party password is still there.
1440 owned_keychain_adapter.SetFindsOnlyOwnedItems(false); 1507 owned_keychain_adapter.SetFindsOnlyOwnedItems(false);
1441 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm( 1508 matching_items.get() = owned_keychain_adapter.PasswordsFillingForm(
1442 "http://some.domain.com/insecure.html", PasswordForm::SCHEME_HTML); 1509 "http://some.domain.com/insecure.html", PasswordForm::SCHEME_HTML);
1443 ASSERT_EQ(1u, matching_items.size()); 1510 ASSERT_EQ(1u, matching_items.size());
1444 } 1511 }
1512
1513 // Open the store and immediately write to it and try to read it back, without
1514 // first waiting for the initialization to finish. If tasks are processed in
1515 // order, read/write operations will correctly be performed only after the
1516 // initialization has finished.
1517 TEST_F(PasswordStoreMacTest, StoreIsUsableImmediatelyAfterConstruction) {
1518 ClosePasswordStore();
1519
1520 base::WaitableEvent event(false, false);
1521 CreateAndInitPasswordStore(make_scoped_ptr<password_manager::LoginDatabase>(
1522 new SlowToInitLoginDatabase(test_login_db_file_path(), &event)));
1523
1524 PasswordFormData www_form_data = {
1525 PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
1526 "http://www.facebook.com/index.html", "login", L"username", L"password",
1527 L"submit", L"not_joe_user", L"12345", true, false, 1};
1528 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(www_form_data));
1529 store()->AddLogin(*form);
1530
1531 MockPasswordStoreConsumer mock_consumer;
1532 store()->GetLogins(*form, PasswordStore::ALLOW_PROMPT, &mock_consumer);
1533
1534 // Now the read/write tasks are scheduled, let the DB initialization proceed.
1535 event.Signal();
1536
1537 mock_consumer.WaitOnGetPasswordStoreResults();
1538 EXPECT_EQ(1u, mock_consumer.last_result.size());
1539 EXPECT_TRUE(login_db());
1540 }
1541
1542 // Verify that operations on a PasswordStore with a bad database cause no
1543 // explosions, but fail without side effect, return no data and trigger no
1544 // notifications.
1545 TEST_F(PasswordStoreMacTest, OperationsOnABadDatabaseSilentlyFail) {
1546 ClosePasswordStore();
1547 CreateAndInitPasswordStore(
1548 make_scoped_ptr<password_manager::LoginDatabase>(new BadLoginDatabase));
1549 FinishAsyncProcessing();
1550 EXPECT_FALSE(login_db());
1551
1552 testing::StrictMock<MockPasswordStoreObserver> mock_observer;
1553 store()->AddObserver(&mock_observer);
1554
1555 // Add a new autofillable login + a blacklisted login.
1556 PasswordFormData www_form_data = {
1557 PasswordForm::SCHEME_HTML, "http://www.facebook.com/",
1558 "http://www.facebook.com/index.html", "login", L"username", L"password",
1559 L"submit", L"not_joe_user", L"12345", true, false, 1};
1560 scoped_ptr<PasswordForm> form(CreatePasswordFormFromData(www_form_data));
1561 scoped_ptr<PasswordForm> blacklisted_form(new PasswordForm(*form));
1562 blacklisted_form->signon_realm = "http://foo.example.com";
1563 blacklisted_form->origin = GURL("http://foo.example.com/origin");
1564 blacklisted_form->action = GURL("http://foo.example.com/action");
1565 blacklisted_form->blacklisted_by_user = true;
1566 store()->AddLogin(*form);
1567 store()->AddLogin(*blacklisted_form);
1568 FinishAsyncProcessing();
1569
1570 // Get all logins; autofillable logins; blacklisted logins.
1571 MockPasswordStoreConsumer mock_consumer;
1572 store()->GetLogins(*form, PasswordStore::DISALLOW_PROMPT, &mock_consumer);
1573 mock_consumer.WaitOnGetPasswordStoreResults();
1574 EXPECT_TRUE(mock_consumer.last_result.empty());
1575 store()->GetAutofillableLogins(&mock_consumer);
1576 mock_consumer.WaitOnGetPasswordStoreResults();
1577 EXPECT_TRUE(mock_consumer.last_result.empty());
1578 store()->GetBlacklistLogins(&mock_consumer);
1579 mock_consumer.WaitOnGetPasswordStoreResults();
1580 EXPECT_TRUE(mock_consumer.last_result.empty());
1581
1582 // Report metrics.
1583 store()->ReportMetrics("Test Username", true);
1584 FinishAsyncProcessing();
1585
1586 // Change the login.
1587 form->password_value = base::ASCIIToUTF16("a different password");
1588 store()->UpdateLogin(*form);
1589 FinishAsyncProcessing();
1590
1591 // Delete one login; a range of logins.
1592 store()->RemoveLogin(*form);
1593 store()->RemoveLoginsCreatedBetween(base::Time(), base::Time::Max());
1594 store()->RemoveLoginsSyncedBetween(base::Time(), base::Time::Max());
1595 FinishAsyncProcessing();
1596
1597 // Verify no notifications are fired during shutdown either.
1598 ClosePasswordStore();
1599 }
OLDNEW
« no previous file with comments | « chrome/browser/password_manager/password_store_mac.cc ('k') | chrome/browser/password_manager/password_store_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698