Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / password_manager / native_backend_gnome_x_unittest.cc
blob45929bbda4307d7c305ac3043f69906205b0aa60
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <stdarg.h>
7 #include "base/basictypes.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/password_manager/native_backend_gnome_x.h"
15 #include "chrome/browser/password_manager/psl_matching_helper.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "components/autofill/core/common/password_form.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using autofill::PasswordForm;
23 using base::UTF8ToUTF16;
24 using base::UTF16ToUTF8;
25 using content::BrowserThread;
27 namespace {
29 // What follows is a very simple implementation of the subset of the GNOME
30 // Keyring API that we actually use. It gets substituted for the real one by
31 // MockGnomeKeyringLoader, which hooks into the facility normally used to load
32 // the GNOME Keyring library at runtime to avoid a static dependency on it.
34 struct MockKeyringItem {
35 MockKeyringItem() {}
36 MockKeyringItem(const char* keyring,
37 const std::string& display_name,
38 const std::string& password)
39 : keyring(keyring ? keyring : "login"),
40 display_name(display_name),
41 password(password) {}
43 struct ItemAttribute {
44 ItemAttribute() : type(UINT32), value_uint32(0) {}
45 explicit ItemAttribute(uint32_t value)
46 : type(UINT32), value_uint32(value) {}
47 explicit ItemAttribute(const std::string& value)
48 : type(STRING), value_string(value) {}
50 bool Equals(const ItemAttribute& x) const {
51 if (type != x.type) return false;
52 return (type == STRING) ? value_string == x.value_string
53 : value_uint32 == x.value_uint32;
56 enum Type { UINT32, STRING } type;
57 uint32_t value_uint32;
58 std::string value_string;
61 typedef std::map<std::string, ItemAttribute> attribute_map;
62 typedef std::vector<std::pair<std::string, ItemAttribute> > attribute_query;
64 bool Matches(const attribute_query& query) const {
65 // The real GNOME Keyring doesn't match empty queries.
66 if (query.empty()) return false;
67 for (size_t i = 0; i < query.size(); ++i) {
68 attribute_map::const_iterator match = attributes.find(query[i].first);
69 if (match == attributes.end()) return false;
70 if (!match->second.Equals(query[i].second)) return false;
72 return true;
75 std::string keyring;
76 std::string display_name;
77 std::string password;
79 attribute_map attributes;
82 // The list of all keyring items we have stored.
83 std::vector<MockKeyringItem> mock_keyring_items;
84 bool mock_keyring_reject_local_ids = false;
86 bool IsStringAttribute(const GnomeKeyringPasswordSchema* schema,
87 const std::string& name) {
88 for (size_t i = 0; schema->attributes[i].name; ++i)
89 if (name == schema->attributes[i].name)
90 return schema->attributes[i].type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
91 NOTREACHED() << "Requested type of nonexistent attribute";
92 return false;
95 gboolean mock_gnome_keyring_is_available() {
96 return true;
99 gpointer mock_gnome_keyring_store_password(
100 const GnomeKeyringPasswordSchema* schema,
101 const gchar* keyring,
102 const gchar* display_name,
103 const gchar* password,
104 GnomeKeyringOperationDoneCallback callback,
105 gpointer data,
106 GDestroyNotify destroy_data,
107 ...) {
108 mock_keyring_items.push_back(
109 MockKeyringItem(keyring, display_name, password));
110 MockKeyringItem* item = &mock_keyring_items.back();
111 const std::string keyring_desc =
112 keyring ? base::StringPrintf("keyring %s", keyring)
113 : std::string("default keyring");
114 VLOG(1) << "Adding item with origin " << display_name
115 << " to " << keyring_desc;
116 va_list ap;
117 va_start(ap, destroy_data);
118 char* name;
119 while ((name = va_arg(ap, gchar*))) {
120 if (IsStringAttribute(schema, name)) {
121 item->attributes[name] =
122 MockKeyringItem::ItemAttribute(va_arg(ap, gchar*));
123 VLOG(1) << "Adding item attribute " << name
124 << ", value '" << item->attributes[name].value_string << "'";
125 } else {
126 item->attributes[name] =
127 MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t));
128 VLOG(1) << "Adding item attribute " << name
129 << ", value " << item->attributes[name].value_uint32;
132 va_end(ap);
133 // As a hack to ease testing migration, make it possible to reject the new
134 // format for the app string. This way we can add them easily to migrate.
135 if (mock_keyring_reject_local_ids) {
136 MockKeyringItem::attribute_map::iterator it =
137 item->attributes.find("application");
138 if (it != item->attributes.end() &&
139 it->second.type == MockKeyringItem::ItemAttribute::STRING &&
140 base::StringPiece(it->second.value_string).starts_with("chrome-")) {
141 mock_keyring_items.pop_back();
142 // GnomeKeyringResult, data
143 callback(GNOME_KEYRING_RESULT_IO_ERROR, data);
144 return NULL;
147 // GnomeKeyringResult, data
148 callback(GNOME_KEYRING_RESULT_OK, data);
149 return NULL;
152 gpointer mock_gnome_keyring_delete_password(
153 const GnomeKeyringPasswordSchema* schema,
154 GnomeKeyringOperationDoneCallback callback,
155 gpointer data,
156 GDestroyNotify destroy_data,
157 ...) {
158 MockKeyringItem::attribute_query query;
159 va_list ap;
160 va_start(ap, destroy_data);
161 char* name;
162 while ((name = va_arg(ap, gchar*))) {
163 if (IsStringAttribute(schema, name)) {
164 query.push_back(make_pair(std::string(name),
165 MockKeyringItem::ItemAttribute(va_arg(ap, gchar*))));
166 VLOG(1) << "Querying with item attribute " << name
167 << ", value '" << query.back().second.value_string << "'";
168 } else {
169 query.push_back(make_pair(std::string(name),
170 MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t))));
171 VLOG(1) << "Querying with item attribute " << name
172 << ", value " << query.back().second.value_uint32;
175 va_end(ap);
176 bool deleted = false;
177 for (size_t i = mock_keyring_items.size(); i > 0; --i) {
178 const MockKeyringItem* item = &mock_keyring_items[i - 1];
179 if (item->Matches(query)) {
180 VLOG(1) << "Deleting item with origin " << item->display_name;
181 mock_keyring_items.erase(mock_keyring_items.begin() + (i - 1));
182 deleted = true;
185 // GnomeKeyringResult, data
186 callback(deleted ? GNOME_KEYRING_RESULT_OK
187 : GNOME_KEYRING_RESULT_NO_MATCH, data);
188 return NULL;
191 gpointer mock_gnome_keyring_find_items(
192 GnomeKeyringItemType type,
193 GnomeKeyringAttributeList* attributes,
194 GnomeKeyringOperationGetListCallback callback,
195 gpointer data,
196 GDestroyNotify destroy_data) {
197 MockKeyringItem::attribute_query query;
198 for (size_t i = 0; i < attributes->len; ++i) {
199 GnomeKeyringAttribute attribute =
200 g_array_index(attributes, GnomeKeyringAttribute, i);
201 if (attribute.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
202 query.push_back(
203 make_pair(std::string(attribute.name),
204 MockKeyringItem::ItemAttribute(attribute.value.string)));
205 VLOG(1) << "Querying with item attribute " << attribute.name
206 << ", value '" << query.back().second.value_string << "'";
207 } else {
208 query.push_back(
209 make_pair(std::string(attribute.name),
210 MockKeyringItem::ItemAttribute(attribute.value.integer)));
211 VLOG(1) << "Querying with item attribute " << attribute.name << ", value "
212 << query.back().second.value_uint32;
215 // Find matches and add them to a list of results.
216 GList* results = NULL;
217 for (size_t i = 0; i < mock_keyring_items.size(); ++i) {
218 const MockKeyringItem* item = &mock_keyring_items[i];
219 if (item->Matches(query)) {
220 GnomeKeyringFound* found = new GnomeKeyringFound;
221 found->keyring = strdup(item->keyring.c_str());
222 found->item_id = i;
223 found->attributes = gnome_keyring_attribute_list_new();
224 for (MockKeyringItem::attribute_map::const_iterator it =
225 item->attributes.begin();
226 it != item->attributes.end();
227 ++it) {
228 if (it->second.type == MockKeyringItem::ItemAttribute::STRING) {
229 gnome_keyring_attribute_list_append_string(
230 found->attributes, it->first.c_str(),
231 it->second.value_string.c_str());
232 } else {
233 gnome_keyring_attribute_list_append_uint32(
234 found->attributes, it->first.c_str(),
235 it->second.value_uint32);
238 found->secret = strdup(item->password.c_str());
239 results = g_list_prepend(results, found);
242 // GnomeKeyringResult, GList*, data
243 callback(results ? GNOME_KEYRING_RESULT_OK
244 : GNOME_KEYRING_RESULT_NO_MATCH, results, data);
245 // Now free the list of results.
246 GList* element = g_list_first(results);
247 while (element) {
248 GnomeKeyringFound* found = static_cast<GnomeKeyringFound*>(element->data);
249 free(found->keyring);
250 gnome_keyring_attribute_list_free(found->attributes);
251 free(found->secret);
252 delete found;
253 element = g_list_next(element);
255 g_list_free(results);
256 return NULL;
259 const gchar* mock_gnome_keyring_result_to_message(GnomeKeyringResult res) {
260 return "mock keyring simulating failure";
263 // Inherit to get access to protected fields.
264 class MockGnomeKeyringLoader : public GnomeKeyringLoader {
265 public:
266 static bool LoadMockGnomeKeyring() {
267 if (!LoadGnomeKeyring())
268 return false;
269 #define GNOME_KEYRING_ASSIGN_POINTER(name) \
270 gnome_keyring_##name = &mock_gnome_keyring_##name;
271 GNOME_KEYRING_FOR_EACH_MOCKED_FUNC(GNOME_KEYRING_ASSIGN_POINTER)
272 #undef GNOME_KEYRING_ASSIGN_POINTER
273 keyring_loaded = true;
274 // Reset the state of the mock library.
275 mock_keyring_items.clear();
276 mock_keyring_reject_local_ids = false;
277 return true;
281 } // anonymous namespace
283 class NativeBackendGnomeTest : public testing::Test {
284 protected:
285 NativeBackendGnomeTest()
286 : ui_thread_(BrowserThread::UI, &message_loop_),
287 db_thread_(BrowserThread::DB) {
290 virtual void SetUp() {
291 ASSERT_TRUE(db_thread_.Start());
293 ASSERT_TRUE(MockGnomeKeyringLoader::LoadMockGnomeKeyring());
295 form_google_.origin = GURL("http://www.google.com/");
296 form_google_.action = GURL("http://www.google.com/login");
297 form_google_.username_element = UTF8ToUTF16("user");
298 form_google_.username_value = UTF8ToUTF16("joeschmoe");
299 form_google_.password_element = UTF8ToUTF16("pass");
300 form_google_.password_value = UTF8ToUTF16("seekrit");
301 form_google_.submit_element = UTF8ToUTF16("submit");
302 form_google_.signon_realm = "http://www.google.com/";
304 form_facebook_.origin = GURL("http://www.facebook.com/");
305 form_facebook_.action = GURL("http://www.facebook.com/login");
306 form_facebook_.username_element = UTF8ToUTF16("user");
307 form_facebook_.username_value = UTF8ToUTF16("a");
308 form_facebook_.password_element = UTF8ToUTF16("password");
309 form_facebook_.password_value = UTF8ToUTF16("b");
310 form_facebook_.submit_element = UTF8ToUTF16("submit");
311 form_facebook_.signon_realm = "http://www.facebook.com/";
313 form_isc_.origin = GURL("http://www.isc.org/");
314 form_isc_.action = GURL("http://www.isc.org/auth");
315 form_isc_.username_element = UTF8ToUTF16("id");
316 form_isc_.username_value = UTF8ToUTF16("janedoe");
317 form_isc_.password_element = UTF8ToUTF16("passwd");
318 form_isc_.password_value = UTF8ToUTF16("ihazabukkit");
319 form_isc_.submit_element = UTF8ToUTF16("login");
320 form_isc_.signon_realm = "http://www.isc.org/";
323 virtual void TearDown() {
324 base::MessageLoop::current()->PostTask(FROM_HERE,
325 base::MessageLoop::QuitClosure());
326 base::MessageLoop::current()->Run();
327 db_thread_.Stop();
330 void RunBothThreads() {
331 // First we post a message to the DB thread that will run after all other
332 // messages that have been posted to the DB thread (we don't expect more
333 // to be posted), which posts a message to the UI thread to quit the loop.
334 // That way we can run both loops and be sure that the UI thread loop will
335 // quit so we can get on with the rest of the test.
336 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
337 base::Bind(&PostQuitTask, &message_loop_));
338 base::MessageLoop::current()->Run();
341 static void PostQuitTask(base::MessageLoop* loop) {
342 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
345 void CheckUint32Attribute(const MockKeyringItem* item,
346 const std::string& attribute,
347 uint32_t value) {
348 MockKeyringItem::attribute_map::const_iterator it =
349 item->attributes.find(attribute);
350 EXPECT_NE(item->attributes.end(), it);
351 if (it != item->attributes.end()) {
352 EXPECT_EQ(MockKeyringItem::ItemAttribute::UINT32, it->second.type);
353 EXPECT_EQ(value, it->second.value_uint32);
357 void CheckStringAttribute(const MockKeyringItem* item,
358 const std::string& attribute,
359 const std::string& value) {
360 MockKeyringItem::attribute_map::const_iterator it =
361 item->attributes.find(attribute);
362 EXPECT_NE(item->attributes.end(), it);
363 if (it != item->attributes.end()) {
364 EXPECT_EQ(MockKeyringItem::ItemAttribute::STRING, it->second.type);
365 EXPECT_EQ(value, it->second.value_string);
369 void CheckMockKeyringItem(const MockKeyringItem* item,
370 const PasswordForm& form,
371 const std::string& app_string) {
372 // We always add items to the login keyring.
373 EXPECT_EQ("login", item->keyring);
374 EXPECT_EQ(form.origin.spec(), item->display_name);
375 EXPECT_EQ(UTF16ToUTF8(form.password_value), item->password);
376 EXPECT_EQ(13u, item->attributes.size());
377 CheckStringAttribute(item, "origin_url", form.origin.spec());
378 CheckStringAttribute(item, "action_url", form.action.spec());
379 CheckStringAttribute(item, "username_element",
380 UTF16ToUTF8(form.username_element));
381 CheckStringAttribute(item, "username_value",
382 UTF16ToUTF8(form.username_value));
383 CheckStringAttribute(item, "password_element",
384 UTF16ToUTF8(form.password_element));
385 CheckStringAttribute(item, "submit_element",
386 UTF16ToUTF8(form.submit_element));
387 CheckStringAttribute(item, "signon_realm", form.signon_realm);
388 CheckUint32Attribute(item, "ssl_valid", form.ssl_valid);
389 CheckUint32Attribute(item, "preferred", form.preferred);
390 // We don't check the date created. It varies.
391 CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user);
392 CheckUint32Attribute(item, "scheme", form.scheme);
393 CheckStringAttribute(item, "application", app_string);
396 // Checks (using EXPECT_* macros), that |credentials| are accessible for
397 // filling in for a page with |origin| iff
398 // |should_credential_be_available_to_url| is true.
399 void CheckCredentialAvailability(const PasswordForm& credentials,
400 const std::string& url,
401 bool should_credential_be_available_to_url) {
402 PSLMatchingHelper helper;
403 ASSERT_TRUE(helper.IsMatchingEnabled())
404 << "PSL matching needs to be enabled.";
406 NativeBackendGnome backend(321, profile_.GetPrefs());
407 backend.Init();
409 BrowserThread::PostTask(
410 BrowserThread::DB,
411 FROM_HERE,
412 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
413 base::Unretained(&backend),
414 credentials));
416 PasswordForm target_form;
417 target_form.origin = GURL(url);
418 target_form.signon_realm = url;
419 std::vector<PasswordForm*> form_list;
420 BrowserThread::PostTask(
421 BrowserThread::DB,
422 FROM_HERE,
423 base::Bind(base::IgnoreResult(&NativeBackendGnome::GetLogins),
424 base::Unretained(&backend),
425 target_form,
426 &form_list));
428 RunBothThreads();
430 EXPECT_EQ(1u, mock_keyring_items.size());
431 if (mock_keyring_items.size() > 0)
432 CheckMockKeyringItem(&mock_keyring_items[0], credentials, "chrome-321");
434 if (should_credential_be_available_to_url)
435 EXPECT_EQ(1u, form_list.size());
436 else
437 EXPECT_EQ(0u, form_list.size());
438 STLDeleteElements(&form_list);
441 base::MessageLoopForUI message_loop_;
442 content::TestBrowserThread ui_thread_;
443 content::TestBrowserThread db_thread_;
445 TestingProfile profile_;
447 // Provide some test forms to avoid having to set them up in each test.
448 PasswordForm form_google_;
449 PasswordForm form_facebook_;
450 PasswordForm form_isc_;
453 TEST_F(NativeBackendGnomeTest, BasicAddLogin) {
454 // Pretend that the migration has already taken place.
455 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
457 NativeBackendGnome backend(42, profile_.GetPrefs());
458 backend.Init();
460 BrowserThread::PostTask(
461 BrowserThread::DB, FROM_HERE,
462 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
463 base::Unretained(&backend), form_google_));
465 RunBothThreads();
467 EXPECT_EQ(1u, mock_keyring_items.size());
468 if (mock_keyring_items.size() > 0)
469 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
472 TEST_F(NativeBackendGnomeTest, BasicListLogins) {
473 // Pretend that the migration has already taken place.
474 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
476 NativeBackendGnome backend(42, profile_.GetPrefs());
477 backend.Init();
479 BrowserThread::PostTask(
480 BrowserThread::DB, FROM_HERE,
481 base::Bind(base::IgnoreResult( &NativeBackendGnome::AddLogin),
482 base::Unretained(&backend), form_google_));
484 std::vector<PasswordForm*> form_list;
485 BrowserThread::PostTask(
486 BrowserThread::DB, FROM_HERE,
487 base::Bind(
488 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
489 base::Unretained(&backend), &form_list));
491 RunBothThreads();
493 // Quick check that we got something back.
494 EXPECT_EQ(1u, form_list.size());
495 STLDeleteElements(&form_list);
497 EXPECT_EQ(1u, mock_keyring_items.size());
498 if (mock_keyring_items.size() > 0)
499 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
502 // Save a password for www.facebook.com and see it suggested for m.facebook.com.
503 TEST_F(NativeBackendGnomeTest, PSLMatchingPositive) {
504 CheckCredentialAvailability(form_facebook_,
505 "http://m.facebook.com/",
506 /*should_credential_be_available_to_url=*/true);
509 // Save a password for www.facebook.com and see it not suggested for
510 // m-facebook.com.
511 TEST_F(NativeBackendGnomeTest, PSLMatchingNegativeDomainMismatch) {
512 CheckCredentialAvailability(form_facebook_,
513 "http://m-facebook.com/",
514 /*should_credential_be_available_to_url=*/false);
517 // Test PSL matching is off for domains excluded from it.
518 TEST_F(NativeBackendGnomeTest, PSLMatchingDisabledDomains) {
519 CheckCredentialAvailability(form_google_,
520 "http://one.google.com/",
521 /*should_credential_be_available_to_url=*/false);
524 TEST_F(NativeBackendGnomeTest, BasicRemoveLogin) {
525 // Pretend that the migration has already taken place.
526 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
528 NativeBackendGnome backend(42, profile_.GetPrefs());
529 backend.Init();
531 BrowserThread::PostTask(
532 BrowserThread::DB, FROM_HERE,
533 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
534 base::Unretained(&backend), form_google_));
536 RunBothThreads();
538 EXPECT_EQ(1u, mock_keyring_items.size());
539 if (mock_keyring_items.size() > 0)
540 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
542 BrowserThread::PostTask(
543 BrowserThread::DB, FROM_HERE,
544 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
545 base::Unretained(&backend), form_google_));
547 RunBothThreads();
549 EXPECT_EQ(0u, mock_keyring_items.size());
552 TEST_F(NativeBackendGnomeTest, RemoveNonexistentLogin) {
553 // Pretend that the migration has already taken place.
554 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
556 NativeBackendGnome backend(42, profile_.GetPrefs());
557 backend.Init();
559 // First add an unrelated login.
560 BrowserThread::PostTask(
561 BrowserThread::DB, FROM_HERE,
562 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
563 base::Unretained(&backend), form_google_));
565 RunBothThreads();
567 EXPECT_EQ(1u, mock_keyring_items.size());
568 if (mock_keyring_items.size() > 0)
569 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
571 // Attempt to remove a login that doesn't exist.
572 BrowserThread::PostTask(
573 BrowserThread::DB, FROM_HERE,
574 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
575 base::Unretained(&backend), form_isc_));
577 // Make sure we can still get the first form back.
578 std::vector<PasswordForm*> form_list;
579 BrowserThread::PostTask(
580 BrowserThread::DB, FROM_HERE,
581 base::Bind(
582 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
583 base::Unretained(&backend), &form_list));
585 RunBothThreads();
587 // Quick check that we got something back.
588 EXPECT_EQ(1u, form_list.size());
589 STLDeleteElements(&form_list);
591 EXPECT_EQ(1u, mock_keyring_items.size());
592 if (mock_keyring_items.size() > 0)
593 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
596 TEST_F(NativeBackendGnomeTest, AddDuplicateLogin) {
597 // Pretend that the migration has already taken place.
598 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
600 NativeBackendGnome backend(42, profile_.GetPrefs());
601 backend.Init();
603 BrowserThread::PostTask(
604 BrowserThread::DB, FROM_HERE,
605 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
606 base::Unretained(&backend), form_google_));
607 BrowserThread::PostTask(
608 BrowserThread::DB, FROM_HERE,
609 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
610 base::Unretained(&backend), form_google_));
612 RunBothThreads();
614 EXPECT_EQ(1u, mock_keyring_items.size());
615 if (mock_keyring_items.size() > 0)
616 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
619 TEST_F(NativeBackendGnomeTest, ListLoginsAppends) {
620 // Pretend that the migration has already taken place.
621 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
623 NativeBackendGnome backend(42, profile_.GetPrefs());
624 backend.Init();
626 BrowserThread::PostTask(
627 BrowserThread::DB, FROM_HERE,
628 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
629 base::Unretained(&backend), form_google_));
631 // Send the same request twice with the same list both times.
632 std::vector<PasswordForm*> form_list;
633 BrowserThread::PostTask(
634 BrowserThread::DB, FROM_HERE,
635 base::Bind(
636 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
637 base::Unretained(&backend), &form_list));
638 BrowserThread::PostTask(
639 BrowserThread::DB, FROM_HERE,
640 base::Bind(
641 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
642 base::Unretained(&backend), &form_list));
644 RunBothThreads();
646 // Quick check that we got two results back.
647 EXPECT_EQ(2u, form_list.size());
648 STLDeleteElements(&form_list);
650 EXPECT_EQ(1u, mock_keyring_items.size());
651 if (mock_keyring_items.size() > 0)
652 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
655 // TODO(mdm): add more basic (i.e. non-migration) tests here at some point.
657 TEST_F(NativeBackendGnomeTest, DISABLED_MigrateOneLogin) {
658 // Reject attempts to migrate so we can populate the store.
659 mock_keyring_reject_local_ids = true;
662 NativeBackendGnome backend(42, profile_.GetPrefs());
663 backend.Init();
665 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
666 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
667 base::Unretained(&backend), form_google_));
669 // Make sure we can get the form back even when migration is failing.
670 std::vector<PasswordForm*> form_list;
671 BrowserThread::PostTask(
672 BrowserThread::DB, FROM_HERE,
673 base::Bind(
674 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
675 base::Unretained(&backend), &form_list));
677 RunBothThreads();
679 // Quick check that we got something back.
680 EXPECT_EQ(1u, form_list.size());
681 STLDeleteElements(&form_list);
684 EXPECT_EQ(1u, mock_keyring_items.size());
685 if (mock_keyring_items.size() > 0)
686 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
688 // Now allow the migration.
689 mock_keyring_reject_local_ids = false;
692 NativeBackendGnome backend(42, profile_.GetPrefs());
693 backend.Init();
695 // This should not trigger migration because there will be no results.
696 std::vector<PasswordForm*> form_list;
697 BrowserThread::PostTask(
698 BrowserThread::DB, FROM_HERE,
699 base::Bind(base::IgnoreResult(&NativeBackendGnome::GetBlacklistLogins),
700 base::Unretained(&backend), &form_list));
702 RunBothThreads();
704 // Check that we got nothing back.
705 EXPECT_EQ(0u, form_list.size());
706 STLDeleteElements(&form_list);
709 // Check that the keyring is unmodified.
710 EXPECT_EQ(1u, mock_keyring_items.size());
711 if (mock_keyring_items.size() > 0)
712 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
714 // Check that we haven't set the persistent preference.
715 EXPECT_FALSE(
716 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
719 NativeBackendGnome backend(42, profile_.GetPrefs());
720 backend.Init();
722 // Trigger the migration by looking something up.
723 std::vector<PasswordForm*> form_list;
724 BrowserThread::PostTask(
725 BrowserThread::DB, FROM_HERE,
726 base::Bind(
727 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
728 base::Unretained(&backend), &form_list));
730 RunBothThreads();
732 // Quick check that we got something back.
733 EXPECT_EQ(1u, form_list.size());
734 STLDeleteElements(&form_list);
737 EXPECT_EQ(2u, mock_keyring_items.size());
738 if (mock_keyring_items.size() > 0)
739 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
740 if (mock_keyring_items.size() > 1)
741 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
743 // Check that we have set the persistent preference.
744 EXPECT_TRUE(
745 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
748 TEST_F(NativeBackendGnomeTest, DISABLED_MigrateToMultipleProfiles) {
749 // Reject attempts to migrate so we can populate the store.
750 mock_keyring_reject_local_ids = true;
753 NativeBackendGnome backend(42, profile_.GetPrefs());
754 backend.Init();
756 BrowserThread::PostTask(
757 BrowserThread::DB, FROM_HERE,
758 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
759 base::Unretained(&backend), form_google_));
761 RunBothThreads();
764 EXPECT_EQ(1u, mock_keyring_items.size());
765 if (mock_keyring_items.size() > 0)
766 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
768 // Now allow the migration.
769 mock_keyring_reject_local_ids = false;
772 NativeBackendGnome backend(42, profile_.GetPrefs());
773 backend.Init();
775 // Trigger the migration by looking something up.
776 std::vector<PasswordForm*> form_list;
777 BrowserThread::PostTask(
778 BrowserThread::DB, FROM_HERE,
779 base::Bind(
780 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
781 base::Unretained(&backend), &form_list));
783 RunBothThreads();
785 // Quick check that we got something back.
786 EXPECT_EQ(1u, form_list.size());
787 STLDeleteElements(&form_list);
790 EXPECT_EQ(2u, mock_keyring_items.size());
791 if (mock_keyring_items.size() > 0)
792 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
793 if (mock_keyring_items.size() > 1)
794 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
796 // Check that we have set the persistent preference.
797 EXPECT_TRUE(
798 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
800 // Normally we'd actually have a different profile. But in the test just reset
801 // the profile's persistent pref; we pass in the local profile id anyway.
802 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false);
805 NativeBackendGnome backend(24, profile_.GetPrefs());
806 backend.Init();
808 // Trigger the migration by looking something up.
809 std::vector<PasswordForm*> form_list;
810 BrowserThread::PostTask(
811 BrowserThread::DB, FROM_HERE,
812 base::Bind(
813 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
814 base::Unretained(&backend), &form_list));
816 RunBothThreads();
818 // Quick check that we got something back.
819 EXPECT_EQ(1u, form_list.size());
820 STLDeleteElements(&form_list);
823 EXPECT_EQ(3u, mock_keyring_items.size());
824 if (mock_keyring_items.size() > 0)
825 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
826 if (mock_keyring_items.size() > 1)
827 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
828 if (mock_keyring_items.size() > 2)
829 CheckMockKeyringItem(&mock_keyring_items[2], form_google_, "chrome-24");
832 TEST_F(NativeBackendGnomeTest, DISABLED_NoMigrationWithPrefSet) {
833 // Reject attempts to migrate so we can populate the store.
834 mock_keyring_reject_local_ids = true;
837 NativeBackendGnome backend(42, profile_.GetPrefs());
838 backend.Init();
840 BrowserThread::PostTask(
841 BrowserThread::DB, FROM_HERE,
842 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
843 base::Unretained(&backend), form_google_));
845 RunBothThreads();
848 EXPECT_EQ(1u, mock_keyring_items.size());
849 if (mock_keyring_items.size() > 0)
850 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
852 // Now allow migration, but also pretend that the it has already taken place.
853 mock_keyring_reject_local_ids = false;
854 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
857 NativeBackendGnome backend(42, profile_.GetPrefs());
858 backend.Init();
860 // Trigger the migration by adding a new login.
861 BrowserThread::PostTask(
862 BrowserThread::DB, FROM_HERE,
863 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
864 base::Unretained(&backend), form_isc_));
866 // Look up all logins; we expect only the one we added.
867 std::vector<PasswordForm*> form_list;
868 BrowserThread::PostTask(
869 BrowserThread::DB, FROM_HERE,
870 base::Bind(
871 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
872 base::Unretained(&backend), &form_list));
874 RunBothThreads();
876 // Quick check that we got the right thing back.
877 EXPECT_EQ(1u, form_list.size());
878 if (form_list.size() > 0)
879 EXPECT_EQ(form_isc_.signon_realm, form_list[0]->signon_realm);
880 STLDeleteElements(&form_list);
883 EXPECT_EQ(2u, mock_keyring_items.size());
884 if (mock_keyring_items.size() > 0)
885 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
886 if (mock_keyring_items.size() > 1)
887 CheckMockKeyringItem(&mock_keyring_items[1], form_isc_, "chrome-42");
890 TEST_F(NativeBackendGnomeTest, DISABLED_DeleteMigratedPasswordIsIsolated) {
891 // Reject attempts to migrate so we can populate the store.
892 mock_keyring_reject_local_ids = true;
895 NativeBackendGnome backend(42, profile_.GetPrefs());
896 backend.Init();
898 BrowserThread::PostTask(
899 BrowserThread::DB, FROM_HERE,
900 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
901 base::Unretained(&backend), form_google_));
903 RunBothThreads();
906 EXPECT_EQ(1u, mock_keyring_items.size());
907 if (mock_keyring_items.size() > 0)
908 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
910 // Now allow the migration.
911 mock_keyring_reject_local_ids = false;
914 NativeBackendGnome backend(42, profile_.GetPrefs());
915 backend.Init();
917 // Trigger the migration by looking something up.
918 std::vector<PasswordForm*> form_list;
919 BrowserThread::PostTask(
920 BrowserThread::DB, FROM_HERE,
921 base::Bind(
922 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
923 base::Unretained(&backend), &form_list));
925 RunBothThreads();
927 // Quick check that we got something back.
928 EXPECT_EQ(1u, form_list.size());
929 STLDeleteElements(&form_list);
932 EXPECT_EQ(2u, mock_keyring_items.size());
933 if (mock_keyring_items.size() > 0)
934 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
935 if (mock_keyring_items.size() > 1)
936 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
938 // Check that we have set the persistent preference.
939 EXPECT_TRUE(
940 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
942 // Normally we'd actually have a different profile. But in the test just reset
943 // the profile's persistent pref; we pass in the local profile id anyway.
944 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false);
947 NativeBackendGnome backend(24, profile_.GetPrefs());
948 backend.Init();
950 // Trigger the migration by looking something up.
951 std::vector<PasswordForm*> form_list;
952 BrowserThread::PostTask(
953 BrowserThread::DB, FROM_HERE,
954 base::Bind(
955 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
956 base::Unretained(&backend), &form_list));
958 RunBothThreads();
960 // Quick check that we got something back.
961 EXPECT_EQ(1u, form_list.size());
962 STLDeleteElements(&form_list);
964 // There should be three passwords now.
965 EXPECT_EQ(3u, mock_keyring_items.size());
966 if (mock_keyring_items.size() > 0)
967 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
968 if (mock_keyring_items.size() > 1)
969 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
970 if (mock_keyring_items.size() > 2)
971 CheckMockKeyringItem(&mock_keyring_items[2], form_google_, "chrome-24");
973 // Now delete the password from this second profile.
974 BrowserThread::PostTask(
975 BrowserThread::DB, FROM_HERE,
976 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
977 base::Unretained(&backend), form_google_));
979 RunBothThreads();
981 // The other two copies of the password in different profiles should remain.
982 EXPECT_EQ(2u, mock_keyring_items.size());
983 if (mock_keyring_items.size() > 0)
984 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
985 if (mock_keyring_items.size() > 1)
986 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");