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.
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/common/pref_names.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "content/public/test/test_browser_thread.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 using autofill::PasswordForm;
21 using content::BrowserThread;
25 // What follows is a very simple implementation of the subset of the GNOME
26 // Keyring API that we actually use. It gets substituted for the real one by
27 // MockGnomeKeyringLoader, which hooks into the facility normally used to load
28 // the GNOME Keyring library at runtime to avoid a static dependency on it.
30 struct MockKeyringItem {
32 MockKeyringItem(const char* keyring,
33 const std::string& display_name,
34 const std::string& password)
35 : keyring(keyring ? keyring : "login"),
36 display_name(display_name),
39 struct ItemAttribute {
40 ItemAttribute() : type(UINT32), value_uint32(0) {}
41 explicit ItemAttribute(uint32_t value)
42 : type(UINT32), value_uint32(value) {}
43 explicit ItemAttribute(const std::string& value)
44 : type(STRING), value_string(value) {}
46 bool Equals(const ItemAttribute& x) const {
47 if (type != x.type) return false;
48 return (type == STRING) ? value_string == x.value_string
49 : value_uint32 == x.value_uint32;
52 enum Type { UINT32, STRING } type;
53 uint32_t value_uint32;
54 std::string value_string;
57 typedef std::map<std::string, ItemAttribute> attribute_map;
58 typedef std::vector<std::pair<std::string, ItemAttribute> > attribute_query;
60 bool Matches(const attribute_query& query) const {
61 // The real GNOME Keyring doesn't match empty queries.
62 if (query.empty()) return false;
63 for (size_t i = 0; i < query.size(); ++i) {
64 attribute_map::const_iterator match = attributes.find(query[i].first);
65 if (match == attributes.end()) return false;
66 if (!match->second.Equals(query[i].second)) return false;
72 std::string display_name;
75 attribute_map attributes;
78 // The list of all keyring items we have stored.
79 std::vector<MockKeyringItem> mock_keyring_items;
80 bool mock_keyring_reject_local_ids = false;
82 bool IsStringAttribute(const GnomeKeyringPasswordSchema* schema,
83 const std::string& name) {
84 for (size_t i = 0; schema->attributes[i].name; ++i)
85 if (name == schema->attributes[i].name)
86 return schema->attributes[i].type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING;
87 NOTREACHED() << "Requested type of nonexistent attribute";
91 gboolean mock_gnome_keyring_is_available() {
95 gpointer mock_gnome_keyring_store_password(
96 const GnomeKeyringPasswordSchema* schema,
98 const gchar* display_name,
99 const gchar* password,
100 GnomeKeyringOperationDoneCallback callback,
102 GDestroyNotify destroy_data,
104 mock_keyring_items.push_back(
105 MockKeyringItem(keyring, display_name, password));
106 MockKeyringItem* item = &mock_keyring_items.back();
107 const std::string keyring_desc =
108 keyring ? base::StringPrintf("keyring %s", keyring)
109 : std::string("default keyring");
110 VLOG(1) << "Adding item with origin " << display_name
111 << " to " << keyring_desc;
113 va_start(ap, destroy_data);
115 while ((name = va_arg(ap, gchar*))) {
116 if (IsStringAttribute(schema, name)) {
117 item->attributes[name] =
118 MockKeyringItem::ItemAttribute(va_arg(ap, gchar*));
119 VLOG(1) << "Adding item attribute " << name
120 << ", value '" << item->attributes[name].value_string << "'";
122 item->attributes[name] =
123 MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t));
124 VLOG(1) << "Adding item attribute " << name
125 << ", value " << item->attributes[name].value_uint32;
129 // As a hack to ease testing migration, make it possible to reject the new
130 // format for the app string. This way we can add them easily to migrate.
131 if (mock_keyring_reject_local_ids) {
132 MockKeyringItem::attribute_map::iterator it =
133 item->attributes.find("application");
134 if (it != item->attributes.end() &&
135 it->second.type == MockKeyringItem::ItemAttribute::STRING &&
136 base::StringPiece(it->second.value_string).starts_with("chrome-")) {
137 mock_keyring_items.pop_back();
138 // GnomeKeyringResult, data
139 callback(GNOME_KEYRING_RESULT_IO_ERROR, data);
143 // GnomeKeyringResult, data
144 callback(GNOME_KEYRING_RESULT_OK, data);
148 gpointer mock_gnome_keyring_delete_password(
149 const GnomeKeyringPasswordSchema* schema,
150 GnomeKeyringOperationDoneCallback callback,
152 GDestroyNotify destroy_data,
154 MockKeyringItem::attribute_query query;
156 va_start(ap, destroy_data);
158 while ((name = va_arg(ap, gchar*))) {
159 if (IsStringAttribute(schema, name)) {
160 query.push_back(make_pair(std::string(name),
161 MockKeyringItem::ItemAttribute(va_arg(ap, gchar*))));
162 VLOG(1) << "Querying with item attribute " << name
163 << ", value '" << query.back().second.value_string << "'";
165 query.push_back(make_pair(std::string(name),
166 MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t))));
167 VLOG(1) << "Querying with item attribute " << name
168 << ", value " << query.back().second.value_uint32;
172 bool deleted = false;
173 for (size_t i = mock_keyring_items.size(); i > 0; --i) {
174 const MockKeyringItem* item = &mock_keyring_items[i - 1];
175 if (item->Matches(query)) {
176 VLOG(1) << "Deleting item with origin " << item->display_name;
177 mock_keyring_items.erase(mock_keyring_items.begin() + (i - 1));
181 // GnomeKeyringResult, data
182 callback(deleted ? GNOME_KEYRING_RESULT_OK
183 : GNOME_KEYRING_RESULT_NO_MATCH, data);
187 gpointer mock_gnome_keyring_find_itemsv(
188 GnomeKeyringItemType type,
189 GnomeKeyringOperationGetListCallback callback,
191 GDestroyNotify destroy_data,
193 MockKeyringItem::attribute_query query;
195 va_start(ap, destroy_data);
197 while ((name = va_arg(ap, gchar*))) {
198 // Really a GnomeKeyringAttributeType, but promoted to int through ...
199 if (va_arg(ap, int) == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) {
200 query.push_back(make_pair(std::string(name),
201 MockKeyringItem::ItemAttribute(va_arg(ap, gchar*))));
202 VLOG(1) << "Querying with item attribute " << name
203 << ", value '" << query.back().second.value_string << "'";
205 query.push_back(make_pair(std::string(name),
206 MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t))));
207 VLOG(1) << "Querying with item attribute " << name
208 << ", value " << query.back().second.value_uint32;
212 // Find matches and add them to a list of results.
213 GList* results = NULL;
214 for (size_t i = 0; i < mock_keyring_items.size(); ++i) {
215 const MockKeyringItem* item = &mock_keyring_items[i];
216 if (item->Matches(query)) {
217 GnomeKeyringFound* found = new GnomeKeyringFound;
218 found->keyring = strdup(item->keyring.c_str());
220 found->attributes = gnome_keyring_attribute_list_new();
221 for (MockKeyringItem::attribute_map::const_iterator it =
222 item->attributes.begin();
223 it != item->attributes.end();
225 if (it->second.type == MockKeyringItem::ItemAttribute::STRING) {
226 gnome_keyring_attribute_list_append_string(
227 found->attributes, it->first.c_str(),
228 it->second.value_string.c_str());
230 gnome_keyring_attribute_list_append_uint32(
231 found->attributes, it->first.c_str(),
232 it->second.value_uint32);
235 found->secret = strdup(item->password.c_str());
236 results = g_list_prepend(results, found);
239 // GnomeKeyringResult, GList*, data
240 callback(results ? GNOME_KEYRING_RESULT_OK
241 : GNOME_KEYRING_RESULT_NO_MATCH, results, data);
242 // Now free the list of results.
243 GList* element = g_list_first(results);
245 GnomeKeyringFound* found = static_cast<GnomeKeyringFound*>(element->data);
246 free(found->keyring);
247 gnome_keyring_attribute_list_free(found->attributes);
250 element = g_list_next(element);
252 g_list_free(results);
256 const gchar* mock_gnome_keyring_result_to_message(GnomeKeyringResult res) {
257 return "mock keyring simulating failure";
260 // Inherit to get access to protected fields.
261 class MockGnomeKeyringLoader : public GnomeKeyringLoader {
263 static bool LoadMockGnomeKeyring() {
264 #define GNOME_KEYRING_ASSIGN_POINTER(name) \
265 gnome_keyring_##name = &mock_gnome_keyring_##name;
266 GNOME_KEYRING_FOR_EACH_FUNC(GNOME_KEYRING_ASSIGN_POINTER)
267 #undef GNOME_KEYRING_ASSIGN_POINTER
268 keyring_loaded = true;
269 // Reset the state of the mock library.
270 mock_keyring_items.clear();
271 mock_keyring_reject_local_ids = false;
276 } // anonymous namespace
278 class NativeBackendGnomeTest : public testing::Test {
280 NativeBackendGnomeTest()
281 : ui_thread_(BrowserThread::UI, &message_loop_),
282 db_thread_(BrowserThread::DB) {
285 virtual void SetUp() {
286 ASSERT_TRUE(db_thread_.Start());
288 MockGnomeKeyringLoader::LoadMockGnomeKeyring();
290 form_google_.origin = GURL("http://www.google.com/");
291 form_google_.action = GURL("http://www.google.com/login");
292 form_google_.username_element = UTF8ToUTF16("user");
293 form_google_.username_value = UTF8ToUTF16("joeschmoe");
294 form_google_.password_element = UTF8ToUTF16("pass");
295 form_google_.password_value = UTF8ToUTF16("seekrit");
296 form_google_.submit_element = UTF8ToUTF16("submit");
297 form_google_.signon_realm = "Google";
299 form_isc_.origin = GURL("http://www.isc.org/");
300 form_isc_.action = GURL("http://www.isc.org/auth");
301 form_isc_.username_element = UTF8ToUTF16("id");
302 form_isc_.username_value = UTF8ToUTF16("janedoe");
303 form_isc_.password_element = UTF8ToUTF16("passwd");
304 form_isc_.password_value = UTF8ToUTF16("ihazabukkit");
305 form_isc_.submit_element = UTF8ToUTF16("login");
306 form_isc_.signon_realm = "ISC";
309 virtual void TearDown() {
310 base::MessageLoop::current()->PostTask(FROM_HERE,
311 base::MessageLoop::QuitClosure());
312 base::MessageLoop::current()->Run();
316 void RunBothThreads() {
317 // First we post a message to the DB thread that will run after all other
318 // messages that have been posted to the DB thread (we don't expect more
319 // to be posted), which posts a message to the UI thread to quit the loop.
320 // That way we can run both loops and be sure that the UI thread loop will
321 // quit so we can get on with the rest of the test.
322 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
323 base::Bind(&PostQuitTask, &message_loop_));
324 base::MessageLoop::current()->Run();
327 static void PostQuitTask(base::MessageLoop* loop) {
328 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
331 void CheckUint32Attribute(const MockKeyringItem* item,
332 const std::string& attribute,
334 MockKeyringItem::attribute_map::const_iterator it =
335 item->attributes.find(attribute);
336 EXPECT_NE(item->attributes.end(), it);
337 if (it != item->attributes.end()) {
338 EXPECT_EQ(MockKeyringItem::ItemAttribute::UINT32, it->second.type);
339 EXPECT_EQ(value, it->second.value_uint32);
343 void CheckStringAttribute(const MockKeyringItem* item,
344 const std::string& attribute,
345 const std::string& value) {
346 MockKeyringItem::attribute_map::const_iterator it =
347 item->attributes.find(attribute);
348 EXPECT_NE(item->attributes.end(), it);
349 if (it != item->attributes.end()) {
350 EXPECT_EQ(MockKeyringItem::ItemAttribute::STRING, it->second.type);
351 EXPECT_EQ(value, it->second.value_string);
355 void CheckMockKeyringItem(const MockKeyringItem* item,
356 const PasswordForm& form,
357 const std::string& app_string) {
358 // We always add items to the login keyring.
359 EXPECT_EQ("login", item->keyring);
360 EXPECT_EQ(form.origin.spec(), item->display_name);
361 EXPECT_EQ(UTF16ToUTF8(form.password_value), item->password);
362 EXPECT_EQ(13u, item->attributes.size());
363 CheckStringAttribute(item, "origin_url", form.origin.spec());
364 CheckStringAttribute(item, "action_url", form.action.spec());
365 CheckStringAttribute(item, "username_element",
366 UTF16ToUTF8(form.username_element));
367 CheckStringAttribute(item, "username_value",
368 UTF16ToUTF8(form.username_value));
369 CheckStringAttribute(item, "password_element",
370 UTF16ToUTF8(form.password_element));
371 CheckStringAttribute(item, "submit_element",
372 UTF16ToUTF8(form.submit_element));
373 CheckStringAttribute(item, "signon_realm", form.signon_realm);
374 CheckUint32Attribute(item, "ssl_valid", form.ssl_valid);
375 CheckUint32Attribute(item, "preferred", form.preferred);
376 // We don't check the date created. It varies.
377 CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user);
378 CheckUint32Attribute(item, "scheme", form.scheme);
379 CheckStringAttribute(item, "application", app_string);
382 base::MessageLoopForUI message_loop_;
383 content::TestBrowserThread ui_thread_;
384 content::TestBrowserThread db_thread_;
386 TestingProfile profile_;
388 // Provide some test forms to avoid having to set them up in each test.
389 PasswordForm form_google_;
390 PasswordForm form_isc_;
393 TEST_F(NativeBackendGnomeTest, BasicAddLogin) {
394 // Pretend that the migration has already taken place.
395 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
397 NativeBackendGnome backend(42, profile_.GetPrefs());
400 BrowserThread::PostTask(
401 BrowserThread::DB, FROM_HERE,
402 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
403 base::Unretained(&backend), form_google_));
407 EXPECT_EQ(1u, mock_keyring_items.size());
408 if (mock_keyring_items.size() > 0)
409 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
412 TEST_F(NativeBackendGnomeTest, BasicListLogins) {
413 // Pretend that the migration has already taken place.
414 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
416 NativeBackendGnome backend(42, profile_.GetPrefs());
419 BrowserThread::PostTask(
420 BrowserThread::DB, FROM_HERE,
421 base::Bind(base::IgnoreResult( &NativeBackendGnome::AddLogin),
422 base::Unretained(&backend), form_google_));
424 std::vector<PasswordForm*> form_list;
425 BrowserThread::PostTask(
426 BrowserThread::DB, FROM_HERE,
428 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
429 base::Unretained(&backend), &form_list));
433 // Quick check that we got something back.
434 EXPECT_EQ(1u, form_list.size());
435 STLDeleteElements(&form_list);
437 EXPECT_EQ(1u, mock_keyring_items.size());
438 if (mock_keyring_items.size() > 0)
439 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
442 TEST_F(NativeBackendGnomeTest, BasicRemoveLogin) {
443 // Pretend that the migration has already taken place.
444 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
446 NativeBackendGnome backend(42, profile_.GetPrefs());
449 BrowserThread::PostTask(
450 BrowserThread::DB, FROM_HERE,
451 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
452 base::Unretained(&backend), form_google_));
456 EXPECT_EQ(1u, mock_keyring_items.size());
457 if (mock_keyring_items.size() > 0)
458 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
460 BrowserThread::PostTask(
461 BrowserThread::DB, FROM_HERE,
462 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
463 base::Unretained(&backend), form_google_));
467 EXPECT_EQ(0u, mock_keyring_items.size());
470 TEST_F(NativeBackendGnomeTest, RemoveNonexistentLogin) {
471 // Pretend that the migration has already taken place.
472 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
474 NativeBackendGnome backend(42, profile_.GetPrefs());
477 // First add an unrelated login.
478 BrowserThread::PostTask(
479 BrowserThread::DB, FROM_HERE,
480 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
481 base::Unretained(&backend), form_google_));
485 EXPECT_EQ(1u, mock_keyring_items.size());
486 if (mock_keyring_items.size() > 0)
487 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
489 // Attempt to remove a login that doesn't exist.
490 BrowserThread::PostTask(
491 BrowserThread::DB, FROM_HERE,
492 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
493 base::Unretained(&backend), form_isc_));
495 // Make sure we can still get the first form back.
496 std::vector<PasswordForm*> form_list;
497 BrowserThread::PostTask(
498 BrowserThread::DB, FROM_HERE,
500 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
501 base::Unretained(&backend), &form_list));
505 // Quick check that we got something back.
506 EXPECT_EQ(1u, form_list.size());
507 STLDeleteElements(&form_list);
509 EXPECT_EQ(1u, mock_keyring_items.size());
510 if (mock_keyring_items.size() > 0)
511 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
514 TEST_F(NativeBackendGnomeTest, AddDuplicateLogin) {
515 // Pretend that the migration has already taken place.
516 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
518 NativeBackendGnome backend(42, profile_.GetPrefs());
521 BrowserThread::PostTask(
522 BrowserThread::DB, FROM_HERE,
523 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
524 base::Unretained(&backend), form_google_));
525 BrowserThread::PostTask(
526 BrowserThread::DB, FROM_HERE,
527 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
528 base::Unretained(&backend), form_google_));
532 EXPECT_EQ(1u, mock_keyring_items.size());
533 if (mock_keyring_items.size() > 0)
534 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
537 TEST_F(NativeBackendGnomeTest, ListLoginsAppends) {
538 // Pretend that the migration has already taken place.
539 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
541 NativeBackendGnome backend(42, profile_.GetPrefs());
544 BrowserThread::PostTask(
545 BrowserThread::DB, FROM_HERE,
546 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
547 base::Unretained(&backend), form_google_));
549 // Send the same request twice with the same list both times.
550 std::vector<PasswordForm*> form_list;
551 BrowserThread::PostTask(
552 BrowserThread::DB, FROM_HERE,
554 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
555 base::Unretained(&backend), &form_list));
556 BrowserThread::PostTask(
557 BrowserThread::DB, FROM_HERE,
559 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
560 base::Unretained(&backend), &form_list));
564 // Quick check that we got two results back.
565 EXPECT_EQ(2u, form_list.size());
566 STLDeleteElements(&form_list);
568 EXPECT_EQ(1u, mock_keyring_items.size());
569 if (mock_keyring_items.size() > 0)
570 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
573 // TODO(mdm): add more basic (i.e. non-migration) tests here at some point.
575 TEST_F(NativeBackendGnomeTest, DISABLED_MigrateOneLogin) {
576 // Reject attempts to migrate so we can populate the store.
577 mock_keyring_reject_local_ids = true;
580 NativeBackendGnome backend(42, profile_.GetPrefs());
583 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
584 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
585 base::Unretained(&backend), form_google_));
587 // Make sure we can get the form back even when migration is failing.
588 std::vector<PasswordForm*> form_list;
589 BrowserThread::PostTask(
590 BrowserThread::DB, FROM_HERE,
592 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
593 base::Unretained(&backend), &form_list));
597 // Quick check that we got something back.
598 EXPECT_EQ(1u, form_list.size());
599 STLDeleteElements(&form_list);
602 EXPECT_EQ(1u, mock_keyring_items.size());
603 if (mock_keyring_items.size() > 0)
604 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
606 // Now allow the migration.
607 mock_keyring_reject_local_ids = false;
610 NativeBackendGnome backend(42, profile_.GetPrefs());
613 // This should not trigger migration because there will be no results.
614 std::vector<PasswordForm*> form_list;
615 BrowserThread::PostTask(
616 BrowserThread::DB, FROM_HERE,
617 base::Bind(base::IgnoreResult(&NativeBackendGnome::GetBlacklistLogins),
618 base::Unretained(&backend), &form_list));
622 // Check that we got nothing back.
623 EXPECT_EQ(0u, form_list.size());
624 STLDeleteElements(&form_list);
627 // Check that the keyring is unmodified.
628 EXPECT_EQ(1u, mock_keyring_items.size());
629 if (mock_keyring_items.size() > 0)
630 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
632 // Check that we haven't set the persistent preference.
634 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
637 NativeBackendGnome backend(42, profile_.GetPrefs());
640 // Trigger the migration by looking something up.
641 std::vector<PasswordForm*> form_list;
642 BrowserThread::PostTask(
643 BrowserThread::DB, FROM_HERE,
645 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
646 base::Unretained(&backend), &form_list));
650 // Quick check that we got something back.
651 EXPECT_EQ(1u, form_list.size());
652 STLDeleteElements(&form_list);
655 EXPECT_EQ(2u, mock_keyring_items.size());
656 if (mock_keyring_items.size() > 0)
657 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
658 if (mock_keyring_items.size() > 1)
659 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
661 // Check that we have set the persistent preference.
663 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
666 TEST_F(NativeBackendGnomeTest, DISABLED_MigrateToMultipleProfiles) {
667 // Reject attempts to migrate so we can populate the store.
668 mock_keyring_reject_local_ids = true;
671 NativeBackendGnome backend(42, profile_.GetPrefs());
674 BrowserThread::PostTask(
675 BrowserThread::DB, FROM_HERE,
676 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
677 base::Unretained(&backend), form_google_));
682 EXPECT_EQ(1u, mock_keyring_items.size());
683 if (mock_keyring_items.size() > 0)
684 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
686 // Now allow the migration.
687 mock_keyring_reject_local_ids = false;
690 NativeBackendGnome backend(42, profile_.GetPrefs());
693 // Trigger the migration by looking something up.
694 std::vector<PasswordForm*> form_list;
695 BrowserThread::PostTask(
696 BrowserThread::DB, FROM_HERE,
698 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
699 base::Unretained(&backend), &form_list));
703 // Quick check that we got something back.
704 EXPECT_EQ(1u, form_list.size());
705 STLDeleteElements(&form_list);
708 EXPECT_EQ(2u, mock_keyring_items.size());
709 if (mock_keyring_items.size() > 0)
710 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
711 if (mock_keyring_items.size() > 1)
712 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
714 // Check that we have set the persistent preference.
716 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
718 // Normally we'd actually have a different profile. But in the test just reset
719 // the profile's persistent pref; we pass in the local profile id anyway.
720 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false);
723 NativeBackendGnome backend(24, profile_.GetPrefs());
726 // Trigger the migration by looking something up.
727 std::vector<PasswordForm*> form_list;
728 BrowserThread::PostTask(
729 BrowserThread::DB, FROM_HERE,
731 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
732 base::Unretained(&backend), &form_list));
736 // Quick check that we got something back.
737 EXPECT_EQ(1u, form_list.size());
738 STLDeleteElements(&form_list);
741 EXPECT_EQ(3u, mock_keyring_items.size());
742 if (mock_keyring_items.size() > 0)
743 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
744 if (mock_keyring_items.size() > 1)
745 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
746 if (mock_keyring_items.size() > 2)
747 CheckMockKeyringItem(&mock_keyring_items[2], form_google_, "chrome-24");
750 TEST_F(NativeBackendGnomeTest, DISABLED_NoMigrationWithPrefSet) {
751 // Reject attempts to migrate so we can populate the store.
752 mock_keyring_reject_local_ids = true;
755 NativeBackendGnome backend(42, profile_.GetPrefs());
758 BrowserThread::PostTask(
759 BrowserThread::DB, FROM_HERE,
760 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
761 base::Unretained(&backend), form_google_));
766 EXPECT_EQ(1u, mock_keyring_items.size());
767 if (mock_keyring_items.size() > 0)
768 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
770 // Now allow migration, but also pretend that the it has already taken place.
771 mock_keyring_reject_local_ids = false;
772 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
775 NativeBackendGnome backend(42, profile_.GetPrefs());
778 // Trigger the migration by adding a new login.
779 BrowserThread::PostTask(
780 BrowserThread::DB, FROM_HERE,
781 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
782 base::Unretained(&backend), form_isc_));
784 // Look up all logins; we expect only the one we added.
785 std::vector<PasswordForm*> form_list;
786 BrowserThread::PostTask(
787 BrowserThread::DB, FROM_HERE,
789 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
790 base::Unretained(&backend), &form_list));
794 // Quick check that we got the right thing back.
795 EXPECT_EQ(1u, form_list.size());
796 if (form_list.size() > 0)
797 EXPECT_EQ(form_isc_.signon_realm, form_list[0]->signon_realm);
798 STLDeleteElements(&form_list);
801 EXPECT_EQ(2u, mock_keyring_items.size());
802 if (mock_keyring_items.size() > 0)
803 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
804 if (mock_keyring_items.size() > 1)
805 CheckMockKeyringItem(&mock_keyring_items[1], form_isc_, "chrome-42");
808 TEST_F(NativeBackendGnomeTest, DISABLED_DeleteMigratedPasswordIsIsolated) {
809 // Reject attempts to migrate so we can populate the store.
810 mock_keyring_reject_local_ids = true;
813 NativeBackendGnome backend(42, profile_.GetPrefs());
816 BrowserThread::PostTask(
817 BrowserThread::DB, FROM_HERE,
818 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
819 base::Unretained(&backend), form_google_));
824 EXPECT_EQ(1u, mock_keyring_items.size());
825 if (mock_keyring_items.size() > 0)
826 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
828 // Now allow the migration.
829 mock_keyring_reject_local_ids = false;
832 NativeBackendGnome backend(42, profile_.GetPrefs());
835 // Trigger the migration by looking something up.
836 std::vector<PasswordForm*> form_list;
837 BrowserThread::PostTask(
838 BrowserThread::DB, FROM_HERE,
840 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
841 base::Unretained(&backend), &form_list));
845 // Quick check that we got something back.
846 EXPECT_EQ(1u, form_list.size());
847 STLDeleteElements(&form_list);
850 EXPECT_EQ(2u, mock_keyring_items.size());
851 if (mock_keyring_items.size() > 0)
852 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
853 if (mock_keyring_items.size() > 1)
854 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");
856 // Check that we have set the persistent preference.
858 profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
860 // Normally we'd actually have a different profile. But in the test just reset
861 // the profile's persistent pref; we pass in the local profile id anyway.
862 profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, false);
865 NativeBackendGnome backend(24, profile_.GetPrefs());
868 // Trigger the migration by looking something up.
869 std::vector<PasswordForm*> form_list;
870 BrowserThread::PostTask(
871 BrowserThread::DB, FROM_HERE,
873 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
874 base::Unretained(&backend), &form_list));
878 // Quick check that we got something back.
879 EXPECT_EQ(1u, form_list.size());
880 STLDeleteElements(&form_list);
882 // There should be three passwords now.
883 EXPECT_EQ(3u, 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_google_, "chrome-42");
888 if (mock_keyring_items.size() > 2)
889 CheckMockKeyringItem(&mock_keyring_items[2], form_google_, "chrome-24");
891 // Now delete the password from this second profile.
892 BrowserThread::PostTask(
893 BrowserThread::DB, FROM_HERE,
894 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
895 base::Unretained(&backend), form_google_));
899 // The other two copies of the password in different profiles should remain.
900 EXPECT_EQ(2u, mock_keyring_items.size());
901 if (mock_keyring_items.size() > 0)
902 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
903 if (mock_keyring_items.size() > 1)
904 CheckMockKeyringItem(&mock_keyring_items[1], form_google_, "chrome-42");