- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / native_backend_gnome_x_unittest.cc
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.
4
5 #include <stdarg.h>
6
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"
19
20 using autofill::PasswordForm;
21 using content::BrowserThread;
22
23 namespace {
24
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.
29
30 struct MockKeyringItem {
31   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),
37       password(password) {}
38
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) {}
45
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;
50     }
51
52     enum Type { UINT32, STRING } type;
53     uint32_t value_uint32;
54     std::string value_string;
55   };
56
57   typedef std::map<std::string, ItemAttribute> attribute_map;
58   typedef std::vector<std::pair<std::string, ItemAttribute> > attribute_query;
59
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;
67     }
68     return true;
69   }
70
71   std::string keyring;
72   std::string display_name;
73   std::string password;
74
75   attribute_map attributes;
76 };
77
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;
81
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";
88   return false;
89 }
90
91 gboolean mock_gnome_keyring_is_available() {
92   return true;
93 }
94
95 gpointer mock_gnome_keyring_store_password(
96     const GnomeKeyringPasswordSchema* schema,
97     const gchar* keyring,
98     const gchar* display_name,
99     const gchar* password,
100     GnomeKeyringOperationDoneCallback callback,
101     gpointer data,
102     GDestroyNotify destroy_data,
103     ...) {
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;
112   va_list ap;
113   va_start(ap, destroy_data);
114   char* name;
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 << "'";
121     } else {
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;
126     }
127   }
128   va_end(ap);
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);
140       return NULL;
141     }
142   }
143   // GnomeKeyringResult, data
144   callback(GNOME_KEYRING_RESULT_OK, data);
145   return NULL;
146 }
147
148 gpointer mock_gnome_keyring_delete_password(
149     const GnomeKeyringPasswordSchema* schema,
150     GnomeKeyringOperationDoneCallback callback,
151     gpointer data,
152     GDestroyNotify destroy_data,
153     ...) {
154   MockKeyringItem::attribute_query query;
155   va_list ap;
156   va_start(ap, destroy_data);
157   char* name;
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 << "'";
164     } else {
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;
169     }
170   }
171   va_end(ap);
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));
178       deleted = true;
179     }
180   }
181   // GnomeKeyringResult, data
182   callback(deleted ? GNOME_KEYRING_RESULT_OK
183                    : GNOME_KEYRING_RESULT_NO_MATCH, data);
184   return NULL;
185 }
186
187 gpointer mock_gnome_keyring_find_itemsv(
188     GnomeKeyringItemType type,
189     GnomeKeyringOperationGetListCallback callback,
190     gpointer data,
191     GDestroyNotify destroy_data,
192     ...) {
193   MockKeyringItem::attribute_query query;
194   va_list ap;
195   va_start(ap, destroy_data);
196   char* name;
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 << "'";
204     } else {
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;
209     }
210   }
211   va_end(ap);
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());
219       found->item_id = i;
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();
224            ++it) {
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());
229         } else {
230           gnome_keyring_attribute_list_append_uint32(
231               found->attributes, it->first.c_str(),
232               it->second.value_uint32);
233         }
234       }
235       found->secret = strdup(item->password.c_str());
236       results = g_list_prepend(results, found);
237     }
238   }
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);
244   while (element) {
245     GnomeKeyringFound* found = static_cast<GnomeKeyringFound*>(element->data);
246     free(found->keyring);
247     gnome_keyring_attribute_list_free(found->attributes);
248     free(found->secret);
249     delete found;
250     element = g_list_next(element);
251   }
252   g_list_free(results);
253   return NULL;
254 }
255
256 const gchar* mock_gnome_keyring_result_to_message(GnomeKeyringResult res) {
257   return "mock keyring simulating failure";
258 }
259
260 // Inherit to get access to protected fields.
261 class MockGnomeKeyringLoader : public GnomeKeyringLoader {
262  public:
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;
272     return true;
273   }
274 };
275
276 }  // anonymous namespace
277
278 class NativeBackendGnomeTest : public testing::Test {
279  protected:
280   NativeBackendGnomeTest()
281       : ui_thread_(BrowserThread::UI, &message_loop_),
282         db_thread_(BrowserThread::DB) {
283   }
284
285   virtual void SetUp() {
286     ASSERT_TRUE(db_thread_.Start());
287
288     MockGnomeKeyringLoader::LoadMockGnomeKeyring();
289
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";
298
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";
307   }
308
309   virtual void TearDown() {
310     base::MessageLoop::current()->PostTask(FROM_HERE,
311                                            base::MessageLoop::QuitClosure());
312     base::MessageLoop::current()->Run();
313     db_thread_.Stop();
314   }
315
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();
325   }
326
327   static void PostQuitTask(base::MessageLoop* loop) {
328     loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
329   }
330
331   void CheckUint32Attribute(const MockKeyringItem* item,
332                             const std::string& attribute,
333                             uint32_t value) {
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);
340     }
341   }
342
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);
352     }
353   }
354
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);
380   }
381
382   base::MessageLoopForUI message_loop_;
383   content::TestBrowserThread ui_thread_;
384   content::TestBrowserThread db_thread_;
385
386   TestingProfile profile_;
387
388   // Provide some test forms to avoid having to set them up in each test.
389   PasswordForm form_google_;
390   PasswordForm form_isc_;
391 };
392
393 TEST_F(NativeBackendGnomeTest, BasicAddLogin) {
394   // Pretend that the migration has already taken place.
395   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
396
397   NativeBackendGnome backend(42, profile_.GetPrefs());
398   backend.Init();
399
400   BrowserThread::PostTask(
401       BrowserThread::DB, FROM_HERE,
402       base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
403                  base::Unretained(&backend), form_google_));
404
405   RunBothThreads();
406
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");
410 }
411
412 TEST_F(NativeBackendGnomeTest, BasicListLogins) {
413   // Pretend that the migration has already taken place.
414   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
415
416   NativeBackendGnome backend(42, profile_.GetPrefs());
417   backend.Init();
418
419   BrowserThread::PostTask(
420       BrowserThread::DB, FROM_HERE,
421       base::Bind(base::IgnoreResult( &NativeBackendGnome::AddLogin),
422                  base::Unretained(&backend), form_google_));
423
424   std::vector<PasswordForm*> form_list;
425   BrowserThread::PostTask(
426       BrowserThread::DB, FROM_HERE,
427       base::Bind(
428           base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
429           base::Unretained(&backend), &form_list));
430
431   RunBothThreads();
432
433   // Quick check that we got something back.
434   EXPECT_EQ(1u, form_list.size());
435   STLDeleteElements(&form_list);
436
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");
440 }
441
442 TEST_F(NativeBackendGnomeTest, BasicRemoveLogin) {
443   // Pretend that the migration has already taken place.
444   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
445
446   NativeBackendGnome backend(42, profile_.GetPrefs());
447   backend.Init();
448
449   BrowserThread::PostTask(
450       BrowserThread::DB, FROM_HERE,
451       base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
452                  base::Unretained(&backend), form_google_));
453
454   RunBothThreads();
455
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");
459
460   BrowserThread::PostTask(
461       BrowserThread::DB, FROM_HERE,
462       base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
463                  base::Unretained(&backend), form_google_));
464
465   RunBothThreads();
466
467   EXPECT_EQ(0u, mock_keyring_items.size());
468 }
469
470 TEST_F(NativeBackendGnomeTest, RemoveNonexistentLogin) {
471   // Pretend that the migration has already taken place.
472   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
473
474   NativeBackendGnome backend(42, profile_.GetPrefs());
475   backend.Init();
476
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_));
482
483   RunBothThreads();
484
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");
488
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_));
494
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,
499       base::Bind(
500           base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
501           base::Unretained(&backend), &form_list));
502
503   RunBothThreads();
504
505   // Quick check that we got something back.
506   EXPECT_EQ(1u, form_list.size());
507   STLDeleteElements(&form_list);
508
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");
512 }
513
514 TEST_F(NativeBackendGnomeTest, AddDuplicateLogin) {
515   // Pretend that the migration has already taken place.
516   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
517
518   NativeBackendGnome backend(42, profile_.GetPrefs());
519   backend.Init();
520
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_));
529
530   RunBothThreads();
531
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");
535 }
536
537 TEST_F(NativeBackendGnomeTest, ListLoginsAppends) {
538   // Pretend that the migration has already taken place.
539   profile_.GetPrefs()->SetBoolean(prefs::kPasswordsUseLocalProfileId, true);
540
541   NativeBackendGnome backend(42, profile_.GetPrefs());
542   backend.Init();
543
544   BrowserThread::PostTask(
545       BrowserThread::DB, FROM_HERE,
546       base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
547                  base::Unretained(&backend), form_google_));
548
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,
553       base::Bind(
554           base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
555           base::Unretained(&backend), &form_list));
556   BrowserThread::PostTask(
557       BrowserThread::DB, FROM_HERE,
558       base::Bind(
559           base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
560           base::Unretained(&backend), &form_list));
561
562   RunBothThreads();
563
564   // Quick check that we got two results back.
565   EXPECT_EQ(2u, form_list.size());
566   STLDeleteElements(&form_list);
567
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");
571 }
572
573 // TODO(mdm): add more basic (i.e. non-migration) tests here at some point.
574
575 TEST_F(NativeBackendGnomeTest, DISABLED_MigrateOneLogin) {
576   // Reject attempts to migrate so we can populate the store.
577   mock_keyring_reject_local_ids = true;
578
579   {
580     NativeBackendGnome backend(42, profile_.GetPrefs());
581     backend.Init();
582
583     BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
584         base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
585                    base::Unretained(&backend), form_google_));
586
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,
591         base::Bind(
592             base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
593             base::Unretained(&backend), &form_list));
594
595     RunBothThreads();
596
597     // Quick check that we got something back.
598     EXPECT_EQ(1u, form_list.size());
599     STLDeleteElements(&form_list);
600   }
601
602   EXPECT_EQ(1u, mock_keyring_items.size());
603   if (mock_keyring_items.size() > 0)
604     CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
605
606   // Now allow the migration.
607   mock_keyring_reject_local_ids = false;
608
609   {
610     NativeBackendGnome backend(42, profile_.GetPrefs());
611     backend.Init();
612
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));
619
620     RunBothThreads();
621
622     // Check that we got nothing back.
623     EXPECT_EQ(0u, form_list.size());
624     STLDeleteElements(&form_list);
625   }
626
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");
631
632   // Check that we haven't set the persistent preference.
633   EXPECT_FALSE(
634       profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
635
636   {
637     NativeBackendGnome backend(42, profile_.GetPrefs());
638     backend.Init();
639
640     // Trigger the migration by looking something up.
641     std::vector<PasswordForm*> form_list;
642     BrowserThread::PostTask(
643         BrowserThread::DB, FROM_HERE,
644         base::Bind(
645             base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
646             base::Unretained(&backend), &form_list));
647
648     RunBothThreads();
649
650     // Quick check that we got something back.
651     EXPECT_EQ(1u, form_list.size());
652     STLDeleteElements(&form_list);
653   }
654
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");
660
661   // Check that we have set the persistent preference.
662   EXPECT_TRUE(
663       profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
664 }
665
666 TEST_F(NativeBackendGnomeTest, DISABLED_MigrateToMultipleProfiles) {
667   // Reject attempts to migrate so we can populate the store.
668   mock_keyring_reject_local_ids = true;
669
670   {
671     NativeBackendGnome backend(42, profile_.GetPrefs());
672     backend.Init();
673
674     BrowserThread::PostTask(
675         BrowserThread::DB, FROM_HERE,
676         base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
677                    base::Unretained(&backend), form_google_));
678
679     RunBothThreads();
680   }
681
682   EXPECT_EQ(1u, mock_keyring_items.size());
683   if (mock_keyring_items.size() > 0)
684     CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
685
686   // Now allow the migration.
687   mock_keyring_reject_local_ids = false;
688
689   {
690     NativeBackendGnome backend(42, profile_.GetPrefs());
691     backend.Init();
692
693     // Trigger the migration by looking something up.
694     std::vector<PasswordForm*> form_list;
695     BrowserThread::PostTask(
696         BrowserThread::DB, FROM_HERE,
697         base::Bind(
698             base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
699             base::Unretained(&backend), &form_list));
700
701     RunBothThreads();
702
703     // Quick check that we got something back.
704     EXPECT_EQ(1u, form_list.size());
705     STLDeleteElements(&form_list);
706   }
707
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");
713
714   // Check that we have set the persistent preference.
715   EXPECT_TRUE(
716       profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
717
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);
721
722   {
723     NativeBackendGnome backend(24, profile_.GetPrefs());
724     backend.Init();
725
726     // Trigger the migration by looking something up.
727     std::vector<PasswordForm*> form_list;
728     BrowserThread::PostTask(
729         BrowserThread::DB, FROM_HERE,
730         base::Bind(
731             base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
732             base::Unretained(&backend), &form_list));
733
734     RunBothThreads();
735
736     // Quick check that we got something back.
737     EXPECT_EQ(1u, form_list.size());
738     STLDeleteElements(&form_list);
739   }
740
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");
748 }
749
750 TEST_F(NativeBackendGnomeTest, DISABLED_NoMigrationWithPrefSet) {
751   // Reject attempts to migrate so we can populate the store.
752   mock_keyring_reject_local_ids = true;
753
754   {
755     NativeBackendGnome backend(42, profile_.GetPrefs());
756     backend.Init();
757
758     BrowserThread::PostTask(
759         BrowserThread::DB, FROM_HERE,
760         base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
761                    base::Unretained(&backend), form_google_));
762
763     RunBothThreads();
764   }
765
766   EXPECT_EQ(1u, mock_keyring_items.size());
767   if (mock_keyring_items.size() > 0)
768     CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
769
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);
773
774   {
775     NativeBackendGnome backend(42, profile_.GetPrefs());
776     backend.Init();
777
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_));
783
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,
788         base::Bind(
789             base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
790             base::Unretained(&backend), &form_list));
791
792     RunBothThreads();
793
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);
799   }
800
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");
806 }
807
808 TEST_F(NativeBackendGnomeTest, DISABLED_DeleteMigratedPasswordIsIsolated) {
809   // Reject attempts to migrate so we can populate the store.
810   mock_keyring_reject_local_ids = true;
811
812   {
813     NativeBackendGnome backend(42, profile_.GetPrefs());
814     backend.Init();
815
816     BrowserThread::PostTask(
817         BrowserThread::DB, FROM_HERE,
818         base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
819                    base::Unretained(&backend), form_google_));
820
821     RunBothThreads();
822   }
823
824   EXPECT_EQ(1u, mock_keyring_items.size());
825   if (mock_keyring_items.size() > 0)
826     CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome");
827
828   // Now allow the migration.
829   mock_keyring_reject_local_ids = false;
830
831   {
832     NativeBackendGnome backend(42, profile_.GetPrefs());
833     backend.Init();
834
835     // Trigger the migration by looking something up.
836     std::vector<PasswordForm*> form_list;
837     BrowserThread::PostTask(
838         BrowserThread::DB, FROM_HERE,
839         base::Bind(
840             base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
841             base::Unretained(&backend), &form_list));
842
843     RunBothThreads();
844
845     // Quick check that we got something back.
846     EXPECT_EQ(1u, form_list.size());
847     STLDeleteElements(&form_list);
848   }
849
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");
855
856   // Check that we have set the persistent preference.
857   EXPECT_TRUE(
858       profile_.GetPrefs()->GetBoolean(prefs::kPasswordsUseLocalProfileId));
859
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);
863
864   {
865     NativeBackendGnome backend(24, profile_.GetPrefs());
866     backend.Init();
867
868     // Trigger the migration by looking something up.
869     std::vector<PasswordForm*> form_list;
870     BrowserThread::PostTask(
871         BrowserThread::DB, FROM_HERE,
872         base::Bind(
873             base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
874             base::Unretained(&backend), &form_list));
875
876     RunBothThreads();
877
878     // Quick check that we got something back.
879     EXPECT_EQ(1u, form_list.size());
880     STLDeleteElements(&form_list);
881
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");
890
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_));
896
897     RunBothThreads();
898
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");
905   }
906 }