Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / password_manager / native_backend_gnome_x_unittest.cc
blob13905592a384c9e30992b1ea3206658cee8d84d5
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/test/base/testing_profile.h"
16 #include "components/autofill/core/common/password_form.h"
17 #include "components/password_manager/core/browser/psl_matching_helper.h"
18 #include "components/password_manager/core/common/password_manager_pref_names.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 enum UpdateType { // Used in CheckPSLUpdate().
286 UPDATE_BY_UPDATELOGIN,
287 UPDATE_BY_ADDLOGIN,
290 NativeBackendGnomeTest()
291 : ui_thread_(BrowserThread::UI, &message_loop_),
292 db_thread_(BrowserThread::DB) {
295 virtual void SetUp() {
296 ASSERT_TRUE(db_thread_.Start());
298 ASSERT_TRUE(MockGnomeKeyringLoader::LoadMockGnomeKeyring());
300 form_google_.origin = GURL("http://www.google.com/");
301 form_google_.action = GURL("http://www.google.com/login");
302 form_google_.username_element = UTF8ToUTF16("user");
303 form_google_.username_value = UTF8ToUTF16("joeschmoe");
304 form_google_.password_element = UTF8ToUTF16("pass");
305 form_google_.password_value = UTF8ToUTF16("seekrit");
306 form_google_.submit_element = UTF8ToUTF16("submit");
307 form_google_.signon_realm = "http://www.google.com/";
308 form_google_.type = PasswordForm::TYPE_GENERATED;
310 form_facebook_.origin = GURL("http://www.facebook.com/");
311 form_facebook_.action = GURL("http://www.facebook.com/login");
312 form_facebook_.username_element = UTF8ToUTF16("user");
313 form_facebook_.username_value = UTF8ToUTF16("a");
314 form_facebook_.password_element = UTF8ToUTF16("password");
315 form_facebook_.password_value = UTF8ToUTF16("b");
316 form_facebook_.submit_element = UTF8ToUTF16("submit");
317 form_facebook_.signon_realm = "http://www.facebook.com/";
319 form_isc_.origin = GURL("http://www.isc.org/");
320 form_isc_.action = GURL("http://www.isc.org/auth");
321 form_isc_.username_element = UTF8ToUTF16("id");
322 form_isc_.username_value = UTF8ToUTF16("janedoe");
323 form_isc_.password_element = UTF8ToUTF16("passwd");
324 form_isc_.password_value = UTF8ToUTF16("ihazabukkit");
325 form_isc_.submit_element = UTF8ToUTF16("login");
326 form_isc_.signon_realm = "http://www.isc.org/";
329 virtual void TearDown() {
330 base::MessageLoop::current()->PostTask(FROM_HERE,
331 base::MessageLoop::QuitClosure());
332 base::MessageLoop::current()->Run();
333 db_thread_.Stop();
336 void RunBothThreads() {
337 // First we post a message to the DB thread that will run after all other
338 // messages that have been posted to the DB thread (we don't expect more
339 // to be posted), which posts a message to the UI thread to quit the loop.
340 // That way we can run both loops and be sure that the UI thread loop will
341 // quit so we can get on with the rest of the test.
342 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
343 base::Bind(&PostQuitTask, &message_loop_));
344 base::MessageLoop::current()->Run();
347 static void PostQuitTask(base::MessageLoop* loop) {
348 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
351 void CheckUint32Attribute(const MockKeyringItem* item,
352 const std::string& attribute,
353 uint32_t value) {
354 MockKeyringItem::attribute_map::const_iterator it =
355 item->attributes.find(attribute);
356 EXPECT_NE(item->attributes.end(), it);
357 if (it != item->attributes.end()) {
358 EXPECT_EQ(MockKeyringItem::ItemAttribute::UINT32, it->second.type);
359 EXPECT_EQ(value, it->second.value_uint32);
363 void CheckStringAttribute(const MockKeyringItem* item,
364 const std::string& attribute,
365 const std::string& value) {
366 MockKeyringItem::attribute_map::const_iterator it =
367 item->attributes.find(attribute);
368 EXPECT_NE(item->attributes.end(), it);
369 if (it != item->attributes.end()) {
370 EXPECT_EQ(MockKeyringItem::ItemAttribute::STRING, it->second.type);
371 EXPECT_EQ(value, it->second.value_string);
375 void CheckMockKeyringItem(const MockKeyringItem* item,
376 const PasswordForm& form,
377 const std::string& app_string) {
378 // We always add items to the login keyring.
379 EXPECT_EQ("login", item->keyring);
380 EXPECT_EQ(form.origin.spec(), item->display_name);
381 EXPECT_EQ(UTF16ToUTF8(form.password_value), item->password);
382 EXPECT_EQ(15u, item->attributes.size());
383 CheckStringAttribute(item, "origin_url", form.origin.spec());
384 CheckStringAttribute(item, "action_url", form.action.spec());
385 CheckStringAttribute(item, "username_element",
386 UTF16ToUTF8(form.username_element));
387 CheckStringAttribute(item, "username_value",
388 UTF16ToUTF8(form.username_value));
389 CheckStringAttribute(item, "password_element",
390 UTF16ToUTF8(form.password_element));
391 CheckStringAttribute(item, "submit_element",
392 UTF16ToUTF8(form.submit_element));
393 CheckStringAttribute(item, "signon_realm", form.signon_realm);
394 CheckUint32Attribute(item, "ssl_valid", form.ssl_valid);
395 CheckUint32Attribute(item, "preferred", form.preferred);
396 // We don't check the date created. It varies.
397 CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user);
398 CheckUint32Attribute(item, "type", form.type);
399 CheckUint32Attribute(item, "times_used", form.times_used);
400 CheckUint32Attribute(item, "scheme", form.scheme);
401 CheckStringAttribute(item, "application", app_string);
404 // Saves |credentials| and then gets login for origin and realm |url|. Returns
405 // true when something is found, and in such case copies the result to
406 // |result| when |result| is not NULL. (Note that there can be max. 1 result,
407 // derived from |credentials|.)
408 bool CheckCredentialAvailability(const PasswordForm& credentials,
409 const GURL& url,
410 PasswordForm* result) {
411 NativeBackendGnome backend(321);
412 backend.Init();
414 BrowserThread::PostTask(
415 BrowserThread::DB,
416 FROM_HERE,
417 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
418 base::Unretained(&backend),
419 credentials));
421 PasswordForm target_form;
422 target_form.origin = url;
423 target_form.signon_realm = url.spec();
424 std::vector<PasswordForm*> form_list;
425 BrowserThread::PostTask(
426 BrowserThread::DB,
427 FROM_HERE,
428 base::Bind(base::IgnoreResult(&NativeBackendGnome::GetLogins),
429 base::Unretained(&backend),
430 target_form,
431 &form_list));
433 RunBothThreads();
435 EXPECT_EQ(1u, mock_keyring_items.size());
436 if (mock_keyring_items.size() > 0)
437 CheckMockKeyringItem(&mock_keyring_items[0], credentials, "chrome-321");
439 if (form_list.empty())
440 return false;
441 EXPECT_EQ(1u, form_list.size());
442 if (result)
443 *result = *form_list[0];
444 STLDeleteElements(&form_list);
445 return true;
448 // Test that updating does not use PSL matching: Add a www.facebook.com
449 // password, then use PSL matching to get a copy of it for m.facebook.com, and
450 // add that copy as well. Now update the www.facebook.com password -- the
451 // m.facebook.com password should not get updated. Depending on the argument,
452 // the credential update is done via UpdateLogin or AddLogin.
453 void CheckPSLUpdate(UpdateType update_type) {
454 password_manager::PSLMatchingHelper helper;
455 ASSERT_TRUE(helper.IsMatchingEnabled());
457 NativeBackendGnome backend(321);
458 backend.Init();
460 // Add |form_facebook_| to saved logins.
461 BrowserThread::PostTask(
462 BrowserThread::DB,
463 FROM_HERE,
464 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
465 base::Unretained(&backend),
466 form_facebook_));
468 // Get the PSL-matched copy of the saved login for m.facebook.
469 const GURL kMobileURL("http://m.facebook.com/");
470 PasswordForm m_facebook_lookup;
471 m_facebook_lookup.origin = kMobileURL;
472 m_facebook_lookup.signon_realm = kMobileURL.spec();
473 std::vector<PasswordForm*> form_list;
474 BrowserThread::PostTask(
475 BrowserThread::DB,
476 FROM_HERE,
477 base::Bind(base::IgnoreResult(&NativeBackendGnome::GetLogins),
478 base::Unretained(&backend),
479 m_facebook_lookup,
480 &form_list));
481 RunBothThreads();
482 EXPECT_EQ(1u, mock_keyring_items.size());
483 EXPECT_EQ(1u, form_list.size());
484 PasswordForm m_facebook = *form_list[0];
485 STLDeleteElements(&form_list);
486 EXPECT_EQ(kMobileURL, m_facebook.origin);
487 EXPECT_EQ(kMobileURL.spec(), m_facebook.signon_realm);
489 // Add the PSL-matched copy to saved logins.
490 BrowserThread::PostTask(
491 BrowserThread::DB,
492 FROM_HERE,
493 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
494 base::Unretained(&backend),
495 m_facebook));
496 RunBothThreads();
497 EXPECT_EQ(2u, mock_keyring_items.size());
499 // Update www.facebook.com login.
500 PasswordForm new_facebook(form_facebook_);
501 const base::string16 kOldPassword(form_facebook_.password_value);
502 const base::string16 kNewPassword(UTF8ToUTF16("new_b"));
503 EXPECT_NE(kOldPassword, kNewPassword);
504 new_facebook.password_value = kNewPassword;
505 switch (update_type) {
506 case UPDATE_BY_UPDATELOGIN:
507 BrowserThread::PostTask(
508 BrowserThread::DB,
509 FROM_HERE,
510 base::Bind(base::IgnoreResult(&NativeBackendGnome::UpdateLogin),
511 base::Unretained(&backend),
512 new_facebook));
513 break;
514 case UPDATE_BY_ADDLOGIN:
515 BrowserThread::PostTask(
516 BrowserThread::DB,
517 FROM_HERE,
518 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
519 base::Unretained(&backend),
520 new_facebook));
521 break;
524 RunBothThreads();
525 EXPECT_EQ(2u, mock_keyring_items.size());
527 // Check that m.facebook.com login was not modified by the update.
528 BrowserThread::PostTask(
529 BrowserThread::DB,
530 FROM_HERE,
531 base::Bind(base::IgnoreResult(&NativeBackendGnome::GetLogins),
532 base::Unretained(&backend),
533 m_facebook_lookup,
534 &form_list));
535 RunBothThreads();
536 // There should be two results -- the exact one, and the PSL-matched one.
537 EXPECT_EQ(2u, form_list.size());
538 size_t index_non_psl = 0;
539 if (!form_list[index_non_psl]->original_signon_realm.empty())
540 index_non_psl = 1;
541 EXPECT_EQ(kMobileURL, form_list[index_non_psl]->origin);
542 EXPECT_EQ(kMobileURL.spec(), form_list[index_non_psl]->signon_realm);
543 EXPECT_EQ(kOldPassword, form_list[index_non_psl]->password_value);
544 STLDeleteElements(&form_list);
546 // Check that www.facebook.com login was modified by the update.
547 BrowserThread::PostTask(
548 BrowserThread::DB,
549 FROM_HERE,
550 base::Bind(base::IgnoreResult(&NativeBackendGnome::GetLogins),
551 base::Unretained(&backend),
552 form_facebook_,
553 &form_list));
554 RunBothThreads();
555 // There should be two results -- the exact one, and the PSL-matched one.
556 EXPECT_EQ(2u, form_list.size());
557 index_non_psl = 0;
558 if (!form_list[index_non_psl]->original_signon_realm.empty())
559 index_non_psl = 1;
560 EXPECT_EQ(form_facebook_.origin, form_list[index_non_psl]->origin);
561 EXPECT_EQ(form_facebook_.signon_realm,
562 form_list[index_non_psl]->signon_realm);
563 EXPECT_EQ(kNewPassword, form_list[index_non_psl]->password_value);
564 STLDeleteElements(&form_list);
567 base::MessageLoopForUI message_loop_;
568 content::TestBrowserThread ui_thread_;
569 content::TestBrowserThread db_thread_;
571 // Provide some test forms to avoid having to set them up in each test.
572 PasswordForm form_google_;
573 PasswordForm form_facebook_;
574 PasswordForm form_isc_;
577 TEST_F(NativeBackendGnomeTest, BasicAddLogin) {
578 NativeBackendGnome backend(42);
579 backend.Init();
581 BrowserThread::PostTask(
582 BrowserThread::DB, FROM_HERE,
583 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
584 base::Unretained(&backend), form_google_));
586 RunBothThreads();
588 EXPECT_EQ(1u, mock_keyring_items.size());
589 if (mock_keyring_items.size() > 0)
590 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
593 TEST_F(NativeBackendGnomeTest, BasicListLogins) {
594 NativeBackendGnome backend(42);
595 backend.Init();
597 BrowserThread::PostTask(
598 BrowserThread::DB, FROM_HERE,
599 base::Bind(base::IgnoreResult( &NativeBackendGnome::AddLogin),
600 base::Unretained(&backend), form_google_));
602 std::vector<PasswordForm*> form_list;
603 BrowserThread::PostTask(
604 BrowserThread::DB, FROM_HERE,
605 base::Bind(
606 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
607 base::Unretained(&backend), &form_list));
609 RunBothThreads();
611 // Quick check that we got something back.
612 EXPECT_EQ(1u, form_list.size());
613 STLDeleteElements(&form_list);
615 EXPECT_EQ(1u, mock_keyring_items.size());
616 if (mock_keyring_items.size() > 0)
617 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
620 // Save a password for www.facebook.com and see it suggested for m.facebook.com.
621 TEST_F(NativeBackendGnomeTest, PSLMatchingPositive) {
622 PasswordForm result;
623 const GURL kMobileURL("http://m.facebook.com/");
624 password_manager::PSLMatchingHelper helper;
625 ASSERT_TRUE(helper.IsMatchingEnabled());
626 EXPECT_TRUE(CheckCredentialAvailability(form_facebook_, kMobileURL, &result));
627 EXPECT_EQ(kMobileURL, result.origin);
628 EXPECT_EQ(kMobileURL.spec(), result.signon_realm);
631 // Save a password for www.facebook.com and see it not suggested for
632 // m-facebook.com.
633 TEST_F(NativeBackendGnomeTest, PSLMatchingNegativeDomainMismatch) {
634 password_manager::PSLMatchingHelper helper;
635 ASSERT_TRUE(helper.IsMatchingEnabled());
636 EXPECT_FALSE(CheckCredentialAvailability(
637 form_facebook_, GURL("http://m-facebook.com/"), NULL));
640 // Test PSL matching is off for domains excluded from it.
641 TEST_F(NativeBackendGnomeTest, PSLMatchingDisabledDomains) {
642 password_manager::PSLMatchingHelper helper;
643 ASSERT_TRUE(helper.IsMatchingEnabled());
644 EXPECT_FALSE(CheckCredentialAvailability(
645 form_google_, GURL("http://one.google.com/"), NULL));
648 TEST_F(NativeBackendGnomeTest, PSLUpdatingStrictUpdateLogin) {
649 CheckPSLUpdate(UPDATE_BY_UPDATELOGIN);
652 TEST_F(NativeBackendGnomeTest, PSLUpdatingStrictAddLogin) {
653 // TODO(vabr): if AddLogin becomes no longer valid for existing logins, then
654 // just delete this test.
655 CheckPSLUpdate(UPDATE_BY_ADDLOGIN);
658 TEST_F(NativeBackendGnomeTest, BasicUpdateLogin) {
659 NativeBackendGnome backend(42);
660 backend.Init();
662 // First add google login.
663 BrowserThread::PostTask(
664 BrowserThread::DB, FROM_HERE,
665 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
666 base::Unretained(&backend), form_google_));
668 RunBothThreads();
670 PasswordForm new_form_google(form_google_);
671 new_form_google.times_used = 1;
672 new_form_google.action = GURL("http://www.google.com/different/login");
674 EXPECT_EQ(1u, mock_keyring_items.size());
675 if (mock_keyring_items.size() > 0)
676 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
678 // Update login
679 BrowserThread::PostTask(
680 BrowserThread::DB, FROM_HERE,
681 base::Bind(base::IgnoreResult(&NativeBackendGnome::UpdateLogin),
682 base::Unretained(&backend), new_form_google));
684 RunBothThreads();
686 EXPECT_EQ(1u, mock_keyring_items.size());
687 if (mock_keyring_items.size() > 0)
688 CheckMockKeyringItem(&mock_keyring_items[0], new_form_google, "chrome-42");
691 TEST_F(NativeBackendGnomeTest, BasicRemoveLogin) {
692 NativeBackendGnome backend(42);
693 backend.Init();
695 BrowserThread::PostTask(
696 BrowserThread::DB, FROM_HERE,
697 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
698 base::Unretained(&backend), form_google_));
700 RunBothThreads();
702 EXPECT_EQ(1u, mock_keyring_items.size());
703 if (mock_keyring_items.size() > 0)
704 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
706 BrowserThread::PostTask(
707 BrowserThread::DB, FROM_HERE,
708 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
709 base::Unretained(&backend), form_google_));
711 RunBothThreads();
713 EXPECT_EQ(0u, mock_keyring_items.size());
716 TEST_F(NativeBackendGnomeTest, RemoveNonexistentLogin) {
717 NativeBackendGnome backend(42);
718 backend.Init();
720 // First add an unrelated login.
721 BrowserThread::PostTask(
722 BrowserThread::DB, FROM_HERE,
723 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
724 base::Unretained(&backend), form_google_));
726 RunBothThreads();
728 EXPECT_EQ(1u, mock_keyring_items.size());
729 if (mock_keyring_items.size() > 0)
730 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
732 // Attempt to remove a login that doesn't exist.
733 BrowserThread::PostTask(
734 BrowserThread::DB, FROM_HERE,
735 base::Bind(base::IgnoreResult(&NativeBackendGnome::RemoveLogin),
736 base::Unretained(&backend), form_isc_));
738 // Make sure we can still get the first form back.
739 std::vector<PasswordForm*> form_list;
740 BrowserThread::PostTask(
741 BrowserThread::DB, FROM_HERE,
742 base::Bind(
743 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
744 base::Unretained(&backend), &form_list));
746 RunBothThreads();
748 // Quick check that we got something back.
749 EXPECT_EQ(1u, form_list.size());
750 STLDeleteElements(&form_list);
752 EXPECT_EQ(1u, mock_keyring_items.size());
753 if (mock_keyring_items.size() > 0)
754 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
757 TEST_F(NativeBackendGnomeTest, AddDuplicateLogin) {
758 NativeBackendGnome backend(42);
759 backend.Init();
761 BrowserThread::PostTask(
762 BrowserThread::DB, FROM_HERE,
763 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
764 base::Unretained(&backend), form_google_));
765 BrowserThread::PostTask(
766 BrowserThread::DB, FROM_HERE,
767 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
768 base::Unretained(&backend), form_google_));
770 RunBothThreads();
772 EXPECT_EQ(1u, mock_keyring_items.size());
773 if (mock_keyring_items.size() > 0)
774 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
777 TEST_F(NativeBackendGnomeTest, ListLoginsAppends) {
778 NativeBackendGnome backend(42);
779 backend.Init();
781 BrowserThread::PostTask(
782 BrowserThread::DB, FROM_HERE,
783 base::Bind(base::IgnoreResult(&NativeBackendGnome::AddLogin),
784 base::Unretained(&backend), form_google_));
786 // Send the same request twice with the same list both times.
787 std::vector<PasswordForm*> form_list;
788 BrowserThread::PostTask(
789 BrowserThread::DB, FROM_HERE,
790 base::Bind(
791 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
792 base::Unretained(&backend), &form_list));
793 BrowserThread::PostTask(
794 BrowserThread::DB, FROM_HERE,
795 base::Bind(
796 base::IgnoreResult(&NativeBackendGnome::GetAutofillableLogins),
797 base::Unretained(&backend), &form_list));
799 RunBothThreads();
801 // Quick check that we got two results back.
802 EXPECT_EQ(2u, form_list.size());
803 STLDeleteElements(&form_list);
805 EXPECT_EQ(1u, mock_keyring_items.size());
806 if (mock_keyring_items.size() > 0)
807 CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42");
810 // TODO(mdm): add more basic tests here at some point.