Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / password_manager / native_backend_kwallet_x_unittest.cc
blobfffc53363f9b30c1871185278274d2f46eee03ef
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 <algorithm>
6 #include <map>
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/pickle.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/stl_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "chrome/browser/password_manager/native_backend_kwallet_x.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "components/autofill/core/common/password_form.h"
23 #include "components/password_manager/core/common/password_manager_pref_names.h"
24 #include "content/public/test/test_browser_thread.h"
25 #include "dbus/message.h"
26 #include "dbus/mock_bus.h"
27 #include "dbus/mock_object_proxy.h"
28 #include "dbus/object_path.h"
29 #include "dbus/object_proxy.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 using autofill::PasswordForm;
34 using base::UTF8ToUTF16;
35 using content::BrowserThread;
36 using password_manager::PasswordStoreChange;
37 using password_manager::PasswordStoreChangeList;
38 using testing::_;
39 using testing::Invoke;
40 using testing::Return;
42 namespace {
44 // This class implements a very simple version of KWallet in memory.
45 // We only provide the parts we actually use; the real version has more.
46 class TestKWallet {
47 public:
48 typedef std::basic_string<uint8_t> Blob; // std::string is binary-safe.
50 TestKWallet() : reject_local_folders_(false) {}
52 void set_reject_local_folders(bool value) { reject_local_folders_ = value; }
54 // NOTE: The method names here are the same as the corresponding DBus
55 // methods, and therefore have names that don't match our style guide.
57 // Check for presence of a given password folder.
58 bool hasFolder(const std::string& folder) const {
59 return data_.find(folder) != data_.end();
62 // Check for presence of a given password in a given password folder.
63 bool hasEntry(const std::string& folder, const std::string& key) const {
64 Data::const_iterator it = data_.find(folder);
65 return it != data_.end() && it->second.find(key) != it->second.end();
68 // Get a list of password keys in a given password folder.
69 bool entryList(const std::string& folder,
70 std::vector<std::string>* entries) const {
71 Data::const_iterator it = data_.find(folder);
72 if (it == data_.end()) return false;
73 for (Folder::const_iterator fit = it->second.begin();
74 fit != it->second.end(); ++fit)
75 entries->push_back(fit->first);
76 return true;
79 // Read the password data for a given password in a given password folder.
80 bool readEntry(const std::string& folder, const std::string& key,
81 Blob* value) const {
82 Data::const_iterator it = data_.find(folder);
83 if (it == data_.end()) return false;
84 Folder::const_iterator fit = it->second.find(key);
85 if (fit == it->second.end()) return false;
86 *value = fit->second;
87 return true;
90 // Create the given password folder.
91 bool createFolder(const std::string& folder) {
92 if (reject_local_folders_ && folder.find('(') != std::string::npos)
93 return false;
94 return data_.insert(make_pair(folder, Folder())).second;
97 // Remove the given password from the given password folder.
98 bool removeEntry(const std::string& folder, const std::string& key) {
99 Data::iterator it = data_.find(folder);
100 if (it == data_.end()) return false;
101 return it->second.erase(key) > 0;
104 // Write the given password data to the given password folder.
105 bool writeEntry(const std::string& folder, const std::string& key,
106 const Blob& value) {
107 Data::iterator it = data_.find(folder);
108 if (it == data_.end()) return false;
109 it->second[key] = value;
110 return true;
113 private:
114 typedef std::map<std::string, Blob> Folder;
115 typedef std::map<std::string, Folder> Data;
117 Data data_;
118 // "Local" folders are folders containing local profile IDs in their names. We
119 // can reject attempts to create them in order to make it easier to create
120 // legacy shared passwords in these tests, for testing the migration code.
121 bool reject_local_folders_;
123 // No need to disallow copy and assign. This class is safe to copy and assign.
126 // Runs |backend->GetAutofillableLogins(forms)| and expects that the return
127 // value is false.
128 void CheckGetAutofillableLoginsFails(
129 PasswordStoreX::NativeBackend* backend,
130 ScopedVector<autofill::PasswordForm>* forms) {
131 EXPECT_FALSE(backend->GetAutofillableLogins(forms));
134 void CheckTrue(bool result) {
135 EXPECT_TRUE(result);
138 } // anonymous namespace
140 // Obscure magic: we need to declare storage for this constant because we use it
141 // in ways that require its address in this test, but not in the actual code.
142 const int NativeBackendKWallet::kInvalidKWalletHandle;
144 // Subclass NativeBackendKWallet to promote some members to public for testing.
145 class NativeBackendKWalletStub : public NativeBackendKWallet {
146 public:
147 explicit NativeBackendKWalletStub(LocalProfileId id)
148 : NativeBackendKWallet(id) {
150 using NativeBackendKWallet::InitWithBus;
151 using NativeBackendKWallet::kInvalidKWalletHandle;
152 using NativeBackendKWallet::DeserializeValue;
155 // Provide some test forms to avoid having to set them up in each test.
156 class NativeBackendKWalletTestBase : public testing::Test {
157 protected:
158 NativeBackendKWalletTestBase() {
159 old_form_google_.origin = GURL("http://www.google.com/");
160 old_form_google_.action = GURL("http://www.google.com/login");
161 old_form_google_.username_element = UTF8ToUTF16("user");
162 old_form_google_.username_value = UTF8ToUTF16("joeschmoe");
163 old_form_google_.password_element = UTF8ToUTF16("pass");
164 old_form_google_.password_value = UTF8ToUTF16("seekrit");
165 old_form_google_.submit_element = UTF8ToUTF16("submit");
166 old_form_google_.signon_realm = "Google";
167 old_form_google_.date_created = base::Time::Now();
169 form_google_ = old_form_google_;
170 form_google_.times_used = 3;
171 form_google_.type = PasswordForm::TYPE_GENERATED;
172 form_google_.form_data.name = UTF8ToUTF16("form_name");
173 form_google_.date_synced = base::Time::Now();
174 form_google_.date_created = old_form_google_.date_created;
175 form_google_.display_name = UTF8ToUTF16("Joe Schmoe");
176 form_google_.icon_url = GURL("http://www.google.com/icon");
177 form_google_.federation_url = GURL("http://www.google.com/federation_url");
178 form_google_.skip_zero_click = true;
179 form_google_.generation_upload_status = PasswordForm::NEGATIVE_SIGNAL_SENT;
181 form_isc_.origin = GURL("http://www.isc.org/");
182 form_isc_.action = GURL("http://www.isc.org/auth");
183 form_isc_.username_element = UTF8ToUTF16("id");
184 form_isc_.username_value = UTF8ToUTF16("janedoe");
185 form_isc_.password_element = UTF8ToUTF16("passwd");
186 form_isc_.password_value = UTF8ToUTF16("ihazabukkit");
187 form_isc_.submit_element = UTF8ToUTF16("login");
188 form_isc_.signon_realm = "ISC";
189 form_isc_.date_synced = base::Time::Now();
190 form_isc_.date_created = base::Time::Now();
193 static void CheckPasswordForm(const PasswordForm& expected,
194 const PasswordForm& actual,
195 bool check_date_created);
196 static void CheckPasswordChanges(const PasswordStoreChangeList& expected,
197 const PasswordStoreChangeList& actual);
198 static void CheckPasswordChangesWithResult(
199 const PasswordStoreChangeList* expected,
200 const PasswordStoreChangeList* actual,
201 bool result);
203 PasswordForm old_form_google_;
204 PasswordForm form_google_;
205 PasswordForm form_isc_;
208 // static
209 void NativeBackendKWalletTestBase::CheckPasswordForm(
210 const PasswordForm& expected,
211 const PasswordForm& actual,
212 bool check_date_created) {
213 EXPECT_EQ(expected.origin, actual.origin);
214 EXPECT_EQ(expected.password_value, actual.password_value);
215 EXPECT_EQ(expected.action, actual.action);
216 EXPECT_EQ(expected.username_element, actual.username_element);
217 EXPECT_EQ(expected.username_value, actual.username_value);
218 EXPECT_EQ(expected.password_element, actual.password_element);
219 EXPECT_EQ(expected.submit_element, actual.submit_element);
220 EXPECT_EQ(expected.signon_realm, actual.signon_realm);
221 EXPECT_EQ(expected.ssl_valid, actual.ssl_valid);
222 EXPECT_EQ(expected.preferred, actual.preferred);
223 if (check_date_created) {
224 EXPECT_EQ(expected.date_created, actual.date_created);
226 EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user);
227 EXPECT_EQ(expected.type, actual.type);
228 EXPECT_EQ(expected.times_used, actual.times_used);
229 EXPECT_EQ(expected.scheme, actual.scheme);
230 EXPECT_EQ(expected.date_synced, actual.date_synced);
231 EXPECT_EQ(expected.display_name, actual.display_name);
232 EXPECT_EQ(expected.icon_url, actual.icon_url);
233 EXPECT_EQ(expected.federation_url, actual.federation_url);
234 EXPECT_EQ(expected.skip_zero_click, actual.skip_zero_click);
235 EXPECT_EQ(expected.generation_upload_status, actual.generation_upload_status);
238 // static
239 void NativeBackendKWalletTestBase::CheckPasswordChanges(
240 const PasswordStoreChangeList& expected,
241 const PasswordStoreChangeList& actual) {
242 ASSERT_EQ(expected.size(), actual.size());
243 for (size_t i = 0; i < expected.size(); ++i) {
244 EXPECT_EQ(expected[i].type(), actual[i].type());
245 CheckPasswordForm(expected[i].form(), actual[i].form(), true);
249 // static
250 void NativeBackendKWalletTestBase::CheckPasswordChangesWithResult(
251 const PasswordStoreChangeList* expected,
252 const PasswordStoreChangeList* actual,
253 bool result) {
254 EXPECT_TRUE(result);
255 CheckPasswordChanges(*expected, *actual);
258 class NativeBackendKWalletTest : public NativeBackendKWalletTestBase {
259 protected:
260 NativeBackendKWalletTest()
261 : ui_thread_(BrowserThread::UI, &message_loop_),
262 db_thread_(BrowserThread::DB), klauncher_ret_(0),
263 klauncher_contacted_(false), kwallet_runnable_(true),
264 kwallet_running_(true), kwallet_enabled_(true) {
267 void SetUp() override;
268 void TearDown() override;
270 // Let the DB thread run to completion of all current tasks.
271 void RunDBThread() {
272 base::WaitableEvent event(false, false);
273 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
274 base::Bind(ThreadDone, &event));
275 event.Wait();
276 // Some of the tests may post messages to the UI thread, but we don't need
277 // to run those until after the DB thread is finished. So run it here.
278 message_loop_.RunUntilIdle();
280 static void ThreadDone(base::WaitableEvent* event) {
281 event->Signal();
284 // Utilities to help verify sets of expectations.
285 typedef std::vector<
286 std::pair<std::string,
287 std::vector<const PasswordForm*> > > ExpectationArray;
288 void CheckPasswordForms(const std::string& folder,
289 const ExpectationArray& sorted_expected);
291 enum RemoveBetweenMethod {
292 CREATED,
293 SYNCED,
296 // Tests RemoveLoginsCreatedBetween or RemoveLoginsSyncedBetween.
297 void TestRemoveLoginsBetween(RemoveBetweenMethod date_to_test);
299 base::MessageLoopForUI message_loop_;
300 content::TestBrowserThread ui_thread_;
301 content::TestBrowserThread db_thread_;
303 scoped_refptr<dbus::MockBus> mock_session_bus_;
304 scoped_refptr<dbus::MockObjectProxy> mock_klauncher_proxy_;
305 scoped_refptr<dbus::MockObjectProxy> mock_kwallet_proxy_;
307 int klauncher_ret_;
308 std::string klauncher_error_;
309 bool klauncher_contacted_;
311 bool kwallet_runnable_;
312 bool kwallet_running_;
313 bool kwallet_enabled_;
315 TestKWallet wallet_;
317 // For all method names contained in |failing_methods_|, the mocked KWallet
318 // will return a null response.
319 std::set<std::string> failing_methods_;
321 private:
322 dbus::Response* KLauncherMethodCall(
323 dbus::MethodCall* method_call, testing::Unused);
325 dbus::Response* KWalletMethodCall(
326 dbus::MethodCall* method_call, testing::Unused);
329 void NativeBackendKWalletTest::SetUp() {
330 ASSERT_TRUE(db_thread_.Start());
332 dbus::Bus::Options options;
333 options.bus_type = dbus::Bus::SESSION;
334 mock_session_bus_ = new dbus::MockBus(options);
336 mock_klauncher_proxy_ =
337 new dbus::MockObjectProxy(mock_session_bus_.get(),
338 "org.kde.klauncher",
339 dbus::ObjectPath("/KLauncher"));
340 EXPECT_CALL(*mock_klauncher_proxy_.get(), MockCallMethodAndBlock(_, _))
341 .WillRepeatedly(
342 Invoke(this, &NativeBackendKWalletTest::KLauncherMethodCall));
344 mock_kwallet_proxy_ =
345 new dbus::MockObjectProxy(mock_session_bus_.get(),
346 "org.kde.kwalletd",
347 dbus::ObjectPath("/modules/kwalletd"));
348 EXPECT_CALL(*mock_kwallet_proxy_.get(), MockCallMethodAndBlock(_, _))
349 .WillRepeatedly(
350 Invoke(this, &NativeBackendKWalletTest::KWalletMethodCall));
352 EXPECT_CALL(
353 *mock_session_bus_.get(),
354 GetObjectProxy("org.kde.klauncher", dbus::ObjectPath("/KLauncher")))
355 .WillRepeatedly(Return(mock_klauncher_proxy_.get()));
356 EXPECT_CALL(
357 *mock_session_bus_.get(),
358 GetObjectProxy("org.kde.kwalletd", dbus::ObjectPath("/modules/kwalletd")))
359 .WillRepeatedly(Return(mock_kwallet_proxy_.get()));
361 EXPECT_CALL(*mock_session_bus_.get(), ShutdownAndBlock()).WillOnce(Return())
362 .WillRepeatedly(Return());
365 void NativeBackendKWalletTest::TearDown() {
366 base::ThreadTaskRunnerHandle::Get()->PostTask(
367 FROM_HERE, base::MessageLoop::QuitClosure());
368 base::MessageLoop::current()->Run();
369 db_thread_.Stop();
372 void NativeBackendKWalletTest::TestRemoveLoginsBetween(
373 RemoveBetweenMethod date_to_test) {
374 NativeBackendKWalletStub backend(42);
375 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
377 form_google_.date_synced = base::Time();
378 form_isc_.date_synced = base::Time();
379 form_google_.date_created = base::Time();
380 form_isc_.date_created = base::Time();
381 base::Time now = base::Time::Now();
382 base::Time next_day = now + base::TimeDelta::FromDays(1);
383 if (date_to_test == CREATED) {
384 form_google_.date_created = now;
385 form_isc_.date_created = next_day;
386 } else {
387 form_google_.date_synced = now;
388 form_isc_.date_synced = next_day;
391 BrowserThread::PostTask(
392 BrowserThread::DB,
393 FROM_HERE,
394 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
395 base::Unretained(&backend),
396 form_google_));
397 BrowserThread::PostTask(
398 BrowserThread::DB,
399 FROM_HERE,
400 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
401 base::Unretained(&backend),
402 form_isc_));
404 PasswordStoreChangeList expected_changes;
405 expected_changes.push_back(
406 PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_));
407 PasswordStoreChangeList changes;
408 bool (NativeBackendKWallet::*method)(
409 base::Time, base::Time, password_manager::PasswordStoreChangeList*) =
410 date_to_test == CREATED
411 ? &NativeBackendKWalletStub::RemoveLoginsCreatedBetween
412 : &NativeBackendKWalletStub::RemoveLoginsSyncedBetween;
413 BrowserThread::PostTaskAndReplyWithResult(
414 BrowserThread::DB,
415 FROM_HERE,
416 base::Bind(
417 method, base::Unretained(&backend), base::Time(), next_day, &changes),
418 base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes));
419 RunDBThread();
421 std::vector<const PasswordForm*> forms;
422 forms.push_back(&form_isc_);
423 ExpectationArray expected;
424 expected.push_back(make_pair(std::string(form_isc_.signon_realm), forms));
425 CheckPasswordForms("Chrome Form Data (42)", expected);
427 // Remove form_isc_.
428 expected_changes.clear();
429 expected_changes.push_back(
430 PasswordStoreChange(PasswordStoreChange::REMOVE, form_isc_));
431 BrowserThread::PostTaskAndReplyWithResult(
432 BrowserThread::DB,
433 FROM_HERE,
434 base::Bind(
435 method, base::Unretained(&backend), next_day, base::Time(), &changes),
436 base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes));
437 RunDBThread();
439 CheckPasswordForms("Chrome Form Data (42)", ExpectationArray());
442 dbus::Response* NativeBackendKWalletTest::KLauncherMethodCall(
443 dbus::MethodCall* method_call, testing::Unused) {
444 EXPECT_EQ("org.kde.KLauncher", method_call->GetInterface());
445 EXPECT_EQ("start_service_by_desktop_name", method_call->GetMember());
447 klauncher_contacted_ = true;
449 dbus::MessageReader reader(method_call);
450 std::string service_name;
451 std::vector<std::string> urls;
452 std::vector<std::string> envs;
453 std::string startup_id;
454 bool blind = false;
456 EXPECT_TRUE(reader.PopString(&service_name));
457 EXPECT_TRUE(reader.PopArrayOfStrings(&urls));
458 EXPECT_TRUE(reader.PopArrayOfStrings(&envs));
459 EXPECT_TRUE(reader.PopString(&startup_id));
460 EXPECT_TRUE(reader.PopBool(&blind));
462 EXPECT_EQ("kwalletd", service_name);
463 EXPECT_TRUE(urls.empty());
464 EXPECT_TRUE(envs.empty());
465 EXPECT_TRUE(startup_id.empty());
466 EXPECT_FALSE(blind);
468 if (kwallet_runnable_)
469 kwallet_running_ = true;
471 scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
472 dbus::MessageWriter writer(response.get());
473 writer.AppendInt32(klauncher_ret_);
474 writer.AppendString(std::string()); // dbus_name
475 writer.AppendString(klauncher_error_);
476 writer.AppendInt32(1234); // pid
477 return response.release();
480 dbus::Response* NativeBackendKWalletTest::KWalletMethodCall(
481 dbus::MethodCall* method_call, testing::Unused) {
482 if (!kwallet_running_)
483 return nullptr;
484 EXPECT_EQ("org.kde.KWallet", method_call->GetInterface());
486 if (ContainsKey(failing_methods_, method_call->GetMember()))
487 return nullptr;
488 scoped_ptr<dbus::Response> response;
489 if (method_call->GetMember() == "isEnabled") {
490 response = dbus::Response::CreateEmpty();
491 dbus::MessageWriter writer(response.get());
492 writer.AppendBool(kwallet_enabled_);
493 } else if (method_call->GetMember() == "networkWallet") {
494 response = dbus::Response::CreateEmpty();
495 dbus::MessageWriter writer(response.get());
496 writer.AppendString("test_wallet"); // Should match |open| below.
497 } else if (method_call->GetMember() == "open") {
498 dbus::MessageReader reader(method_call);
499 std::string wallet_name;
500 int64_t wallet_id;
501 std::string app_name;
502 EXPECT_TRUE(reader.PopString(&wallet_name));
503 EXPECT_TRUE(reader.PopInt64(&wallet_id));
504 EXPECT_TRUE(reader.PopString(&app_name));
505 EXPECT_EQ("test_wallet", wallet_name); // Should match |networkWallet|.
506 response = dbus::Response::CreateEmpty();
507 dbus::MessageWriter writer(response.get());
508 writer.AppendInt32(1); // Can be anything but kInvalidKWalletHandle.
509 } else if (method_call->GetMember() == "hasFolder" ||
510 method_call->GetMember() == "createFolder") {
511 dbus::MessageReader reader(method_call);
512 int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
513 std::string folder_name;
514 std::string app_name;
515 EXPECT_TRUE(reader.PopInt32(&handle));
516 EXPECT_TRUE(reader.PopString(&folder_name));
517 EXPECT_TRUE(reader.PopString(&app_name));
518 EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
519 response = dbus::Response::CreateEmpty();
520 dbus::MessageWriter writer(response.get());
521 if (method_call->GetMember() == "hasFolder")
522 writer.AppendBool(wallet_.hasFolder(folder_name));
523 else
524 writer.AppendBool(wallet_.createFolder(folder_name));
525 } else if (method_call->GetMember() == "hasEntry" ||
526 method_call->GetMember() == "removeEntry") {
527 dbus::MessageReader reader(method_call);
528 int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
529 std::string folder_name;
530 std::string key;
531 std::string app_name;
532 EXPECT_TRUE(reader.PopInt32(&handle));
533 EXPECT_TRUE(reader.PopString(&folder_name));
534 EXPECT_TRUE(reader.PopString(&key));
535 EXPECT_TRUE(reader.PopString(&app_name));
536 EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
537 response = dbus::Response::CreateEmpty();
538 dbus::MessageWriter writer(response.get());
539 if (method_call->GetMember() == "hasEntry")
540 writer.AppendBool(wallet_.hasEntry(folder_name, key));
541 else
542 writer.AppendInt32(wallet_.removeEntry(folder_name, key) ? 0 : 1);
543 } else if (method_call->GetMember() == "entryList") {
544 dbus::MessageReader reader(method_call);
545 int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
546 std::string folder_name;
547 std::string app_name;
548 EXPECT_TRUE(reader.PopInt32(&handle));
549 EXPECT_TRUE(reader.PopString(&folder_name));
550 EXPECT_TRUE(reader.PopString(&app_name));
551 EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
552 std::vector<std::string> entries;
553 if (wallet_.entryList(folder_name, &entries)) {
554 response = dbus::Response::CreateEmpty();
555 dbus::MessageWriter writer(response.get());
556 writer.AppendArrayOfStrings(entries);
558 } else if (method_call->GetMember() == "readEntry") {
559 dbus::MessageReader reader(method_call);
560 int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
561 std::string folder_name;
562 std::string key;
563 std::string app_name;
564 EXPECT_TRUE(reader.PopInt32(&handle));
565 EXPECT_TRUE(reader.PopString(&folder_name));
566 EXPECT_TRUE(reader.PopString(&key));
567 EXPECT_TRUE(reader.PopString(&app_name));
568 EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
569 TestKWallet::Blob value;
570 if (wallet_.readEntry(folder_name, key, &value)) {
571 response = dbus::Response::CreateEmpty();
572 dbus::MessageWriter writer(response.get());
573 writer.AppendArrayOfBytes(value.data(), value.size());
575 } else if (method_call->GetMember() == "writeEntry") {
576 dbus::MessageReader reader(method_call);
577 int handle = NativeBackendKWalletStub::kInvalidKWalletHandle;
578 std::string folder_name;
579 std::string key;
580 const uint8_t* bytes = nullptr;
581 size_t length = 0;
582 std::string app_name;
583 EXPECT_TRUE(reader.PopInt32(&handle));
584 EXPECT_TRUE(reader.PopString(&folder_name));
585 EXPECT_TRUE(reader.PopString(&key));
586 EXPECT_TRUE(reader.PopArrayOfBytes(&bytes, &length));
587 EXPECT_TRUE(reader.PopString(&app_name));
588 EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle);
589 response = dbus::Response::CreateEmpty();
590 dbus::MessageWriter writer(response.get());
591 writer.AppendInt32(
592 wallet_.writeEntry(folder_name, key,
593 TestKWallet::Blob(bytes, length)) ? 0 : 1);
596 EXPECT_TRUE(response);
597 return response.release();
600 void NativeBackendKWalletTest::CheckPasswordForms(
601 const std::string& folder, const ExpectationArray& sorted_expected) {
602 EXPECT_TRUE(wallet_.hasFolder(folder));
603 std::vector<std::string> entries;
604 EXPECT_TRUE(wallet_.entryList(folder, &entries));
605 EXPECT_EQ(sorted_expected.size(), entries.size());
606 std::sort(entries.begin(), entries.end());
607 for (size_t i = 0; i < entries.size() && i < sorted_expected.size(); ++i) {
608 EXPECT_EQ(sorted_expected[i].first, entries[i]);
609 TestKWallet::Blob value;
610 EXPECT_TRUE(wallet_.readEntry(folder, entries[i], &value));
611 base::Pickle pickle(reinterpret_cast<const char*>(value.data()),
612 value.size());
613 ScopedVector<autofill::PasswordForm> forms =
614 NativeBackendKWalletStub::DeserializeValue(entries[i], pickle);
615 const std::vector<const PasswordForm*>& expect = sorted_expected[i].second;
616 EXPECT_EQ(expect.size(), forms.size());
617 for (size_t j = 0; j < forms.size() && j < expect.size(); ++j)
618 CheckPasswordForm(*expect[j], *forms[j], true);
622 TEST_F(NativeBackendKWalletTest, NotEnabled) {
623 NativeBackendKWalletStub kwallet(42);
624 kwallet_enabled_ = false;
625 EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_));
626 EXPECT_FALSE(klauncher_contacted_);
629 TEST_F(NativeBackendKWalletTest, NotRunnable) {
630 NativeBackendKWalletStub kwallet(42);
631 kwallet_runnable_ = false;
632 kwallet_running_ = false;
633 EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_));
634 EXPECT_TRUE(klauncher_contacted_);
637 TEST_F(NativeBackendKWalletTest, NotRunningOrEnabled) {
638 NativeBackendKWalletStub kwallet(42);
639 kwallet_running_ = false;
640 kwallet_enabled_ = false;
641 EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_));
642 EXPECT_TRUE(klauncher_contacted_);
645 TEST_F(NativeBackendKWalletTest, NotRunning) {
646 NativeBackendKWalletStub kwallet(42);
647 kwallet_running_ = false;
648 EXPECT_TRUE(kwallet.InitWithBus(mock_session_bus_));
649 EXPECT_TRUE(klauncher_contacted_);
652 TEST_F(NativeBackendKWalletTest, BasicStartup) {
653 NativeBackendKWalletStub kwallet(42);
654 EXPECT_TRUE(kwallet.InitWithBus(mock_session_bus_));
655 EXPECT_FALSE(klauncher_contacted_);
658 TEST_F(NativeBackendKWalletTest, BasicAddLogin) {
659 NativeBackendKWalletStub backend(42);
660 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
662 BrowserThread::PostTaskAndReplyWithResult(
663 BrowserThread::DB, FROM_HERE,
664 base::Bind(&NativeBackendKWalletStub::AddLogin,
665 base::Unretained(&backend), form_google_),
666 base::Bind(&CheckPasswordChanges,
667 PasswordStoreChangeList(1, PasswordStoreChange(
668 PasswordStoreChange::ADD, form_google_))));
670 RunDBThread();
672 EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
674 std::vector<const PasswordForm*> forms;
675 forms.push_back(&form_google_);
676 ExpectationArray expected;
677 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
678 CheckPasswordForms("Chrome Form Data (42)", expected);
681 TEST_F(NativeBackendKWalletTest, BasicUpdateLogin) {
682 NativeBackendKWalletStub backend(42);
683 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
685 BrowserThread::PostTask(
686 BrowserThread::DB, FROM_HERE,
687 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
688 base::Unretained(&backend), form_google_));
690 RunDBThread();
692 PasswordForm new_form_google(form_google_);
693 new_form_google.times_used = 10;
694 new_form_google.action = GURL("http://www.google.com/different/login");
696 // Update login
697 PasswordStoreChangeList changes;
698 PasswordStoreChangeList expected_changes(
699 1, PasswordStoreChange(PasswordStoreChange::UPDATE, new_form_google));
700 BrowserThread::PostTaskAndReplyWithResult(
701 BrowserThread::DB, FROM_HERE,
702 base::Bind(&NativeBackendKWalletStub::UpdateLogin,
703 base::Unretained(&backend),
704 new_form_google,
705 &changes),
706 base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes));
707 RunDBThread();
709 ASSERT_EQ(1u, changes.size());
710 EXPECT_EQ(PasswordStoreChange::UPDATE, changes.front().type());
711 EXPECT_EQ(new_form_google, changes.front().form());
713 std::vector<const PasswordForm*> forms;
714 forms.push_back(&new_form_google);
715 ExpectationArray expected;
716 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
717 CheckPasswordForms("Chrome Form Data (42)", expected);
720 TEST_F(NativeBackendKWalletTest, BasicListLogins) {
721 NativeBackendKWalletStub backend(42);
722 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
724 BrowserThread::PostTask(
725 BrowserThread::DB, FROM_HERE,
726 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
727 base::Unretained(&backend), form_google_));
729 ScopedVector<autofill::PasswordForm> form_list;
730 BrowserThread::PostTaskAndReplyWithResult(
731 BrowserThread::DB, FROM_HERE,
732 base::Bind(&NativeBackendKWalletStub::GetAutofillableLogins,
733 base::Unretained(&backend), &form_list),
734 base::Bind(&CheckTrue));
736 RunDBThread();
738 // Quick check that we got something back.
739 EXPECT_EQ(1u, form_list.size());
741 EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
743 std::vector<const PasswordForm*> forms;
744 forms.push_back(&form_google_);
745 ExpectationArray expected;
746 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
747 CheckPasswordForms("Chrome Form Data (42)", expected);
750 TEST_F(NativeBackendKWalletTest, BasicRemoveLogin) {
751 NativeBackendKWalletStub backend(42);
752 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
754 BrowserThread::PostTask(
755 BrowserThread::DB, FROM_HERE,
756 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
757 base::Unretained(&backend), form_google_));
759 RunDBThread();
761 EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
763 std::vector<const PasswordForm*> forms;
764 forms.push_back(&form_google_);
765 ExpectationArray expected;
766 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
767 CheckPasswordForms("Chrome Form Data (42)", expected);
769 PasswordStoreChangeList changes;
770 PasswordStoreChangeList expected_changes(
771 1, PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_));
772 BrowserThread::PostTaskAndReplyWithResult(
773 BrowserThread::DB, FROM_HERE,
774 base::Bind(&NativeBackendKWalletStub::RemoveLogin,
775 base::Unretained(&backend), form_google_, &changes),
776 base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes));
778 RunDBThread();
780 expected.clear();
781 CheckPasswordForms("Chrome Form Data (42)", expected);
784 TEST_F(NativeBackendKWalletTest, UpdateNonexistentLogin) {
785 NativeBackendKWalletStub backend(42);
786 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
788 // First add an unrelated login.
789 BrowserThread::PostTask(
790 BrowserThread::DB, FROM_HERE,
791 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
792 base::Unretained(&backend), form_google_));
794 RunDBThread();
796 std::vector<const PasswordForm*> forms;
797 forms.push_back(&form_google_);
798 ExpectationArray expected;
799 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
800 CheckPasswordForms("Chrome Form Data (42)", expected);
802 // Attempt to update a login that doesn't exist.
803 PasswordStoreChangeList changes;
804 BrowserThread::PostTaskAndReplyWithResult(
805 BrowserThread::DB, FROM_HERE,
806 base::Bind(&NativeBackendKWalletStub::UpdateLogin,
807 base::Unretained(&backend),
808 form_isc_,
809 &changes),
810 base::Bind(&CheckPasswordChangesWithResult,
811 base::Owned(new PasswordStoreChangeList), &changes));
813 RunDBThread();
815 EXPECT_EQ(PasswordStoreChangeList(), changes);
816 CheckPasswordForms("Chrome Form Data (42)", expected);
819 TEST_F(NativeBackendKWalletTest, RemoveNonexistentLogin) {
820 NativeBackendKWalletStub backend(42);
821 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
823 // First add an unrelated login.
824 BrowserThread::PostTask(
825 BrowserThread::DB, FROM_HERE,
826 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
827 base::Unretained(&backend), form_google_));
829 RunDBThread();
831 EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
833 std::vector<const PasswordForm*> forms;
834 forms.push_back(&form_google_);
835 ExpectationArray expected;
836 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
837 CheckPasswordForms("Chrome Form Data (42)", expected);
839 // Attempt to remove a login that doesn't exist.
840 PasswordStoreChangeList changes;
841 BrowserThread::PostTaskAndReplyWithResult(
842 BrowserThread::DB, FROM_HERE,
843 base::Bind(&NativeBackendKWalletStub::RemoveLogin,
844 base::Unretained(&backend), form_isc_, &changes),
845 base::Bind(&CheckPasswordChangesWithResult,
846 base::Owned(new PasswordStoreChangeList), &changes));
848 // Make sure we can still get the first form back.
849 ScopedVector<autofill::PasswordForm> form_list;
850 BrowserThread::PostTaskAndReplyWithResult(
851 BrowserThread::DB, FROM_HERE,
852 base::Bind(&NativeBackendKWalletStub::GetAutofillableLogins,
853 base::Unretained(&backend), &form_list),
854 base::Bind(&CheckTrue));
856 RunDBThread();
858 // Quick check that we got something back.
859 EXPECT_EQ(1u, form_list.size());
861 CheckPasswordForms("Chrome Form Data (42)", expected);
864 TEST_F(NativeBackendKWalletTest, AddDuplicateLogin) {
865 NativeBackendKWalletStub backend(42);
866 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
868 PasswordStoreChangeList changes;
869 changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD,
870 form_google_));
871 BrowserThread::PostTaskAndReplyWithResult(
872 BrowserThread::DB, FROM_HERE,
873 base::Bind(&NativeBackendKWalletStub::AddLogin,
874 base::Unretained(&backend), form_google_),
875 base::Bind(&NativeBackendKWalletTest::CheckPasswordChanges,
876 changes));
878 changes.clear();
879 changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
880 form_google_));
881 form_google_.times_used++;
882 form_google_.submit_element = UTF8ToUTF16("submit2");
883 changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD,
884 form_google_));
886 BrowserThread::PostTaskAndReplyWithResult(
887 BrowserThread::DB, FROM_HERE,
888 base::Bind(&NativeBackendKWalletStub::AddLogin,
889 base::Unretained(&backend), form_google_),
890 base::Bind(&NativeBackendKWalletTest::CheckPasswordChanges,
891 changes));
893 RunDBThread();
895 EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data"));
897 std::vector<const PasswordForm*> forms;
898 forms.push_back(&form_google_);
899 ExpectationArray expected;
900 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
901 CheckPasswordForms("Chrome Form Data (42)", expected);
904 TEST_F(NativeBackendKWalletTest, AndroidCredentials) {
905 NativeBackendKWalletStub backend(42);
906 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
908 PasswordForm observed_android_form;
909 observed_android_form.scheme = PasswordForm::SCHEME_HTML;
910 observed_android_form.signon_realm =
911 "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/";
912 PasswordForm saved_android_form = observed_android_form;
913 saved_android_form.username_value = base::UTF8ToUTF16("randomusername");
914 saved_android_form.password_value = base::UTF8ToUTF16("password");
916 BrowserThread::PostTaskAndReplyWithResult(
917 BrowserThread::DB, FROM_HERE,
918 base::Bind(&NativeBackendKWalletStub::AddLogin,
919 base::Unretained(&backend), saved_android_form),
920 base::Bind(&CheckPasswordChanges,
921 PasswordStoreChangeList(1, PasswordStoreChange(
922 PasswordStoreChange::ADD, saved_android_form))));
924 ScopedVector<autofill::PasswordForm> form_list;
925 BrowserThread::PostTaskAndReplyWithResult(
926 BrowserThread::DB, FROM_HERE,
927 base::Bind(&NativeBackendKWalletStub::GetLogins,
928 base::Unretained(&backend), observed_android_form, &form_list),
929 base::Bind(&CheckTrue));
931 RunDBThread();
933 EXPECT_EQ(1u, form_list.size());
935 std::vector<const PasswordForm*> forms;
936 forms.push_back(&saved_android_form);
937 ExpectationArray expected;
938 expected.push_back(
939 make_pair(std::string(saved_android_form.signon_realm), forms));
940 CheckPasswordForms("Chrome Form Data (42)", expected);
943 TEST_F(NativeBackendKWalletTest, RemoveLoginsCreatedBetween) {
944 TestRemoveLoginsBetween(CREATED);
947 TEST_F(NativeBackendKWalletTest, RemoveLoginsSyncedBetween) {
948 TestRemoveLoginsBetween(SYNCED);
951 TEST_F(NativeBackendKWalletTest, ReadDuplicateForms) {
952 NativeBackendKWalletStub backend(42);
953 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
955 // Add 2 slightly different password forms.
956 const char unique_string[] = "unique_unique_string";
957 const char unique_string_replacement[] = "uniKue_unique_string";
958 form_google_.origin =
959 GURL(std::string("http://www.google.com/") + unique_string);
960 BrowserThread::PostTask(
961 BrowserThread::DB, FROM_HERE,
962 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
963 base::Unretained(&backend), form_google_));
964 form_google_.origin =
965 GURL(std::string("http://www.google.com/") + unique_string_replacement);
966 BrowserThread::PostTask(
967 BrowserThread::DB, FROM_HERE,
968 base::Bind(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin),
969 base::Unretained(&backend), form_google_));
970 RunDBThread();
972 // Read the raw value back. Change the |unique_string| to
973 // |unique_string_replacement| so the forms become unique.
974 TestKWallet::Blob value;
975 ASSERT_TRUE(wallet_.readEntry("Chrome Form Data (42)",
976 form_google_.signon_realm, &value));
977 TestKWallet::Blob sample(reinterpret_cast<const uint8_t*>(unique_string));
978 size_t position = value.find(sample);
979 ASSERT_NE(TestKWallet::Blob::npos, position);
980 value.replace(position, sample.length(),
981 reinterpret_cast<const uint8_t*>(unique_string_replacement));
982 wallet_.writeEntry("Chrome Form Data (42)", form_google_.signon_realm, value);
984 // Now test that GetAutofillableLogins returns only one form.
985 ScopedVector<autofill::PasswordForm> form_list;
986 BrowserThread::PostTaskAndReplyWithResult(
987 BrowserThread::DB, FROM_HERE,
988 base::Bind(&NativeBackendKWalletStub::GetAutofillableLogins,
989 base::Unretained(&backend), &form_list),
990 base::Bind(&CheckTrue));
991 RunDBThread();
993 EXPECT_EQ(1u, form_list.size());
994 EXPECT_EQ(form_google_, *form_list[0]);
996 std::vector<const PasswordForm*> forms;
997 forms.push_back(&form_google_);
998 ExpectationArray expected;
999 expected.push_back(make_pair(std::string(form_google_.signon_realm), forms));
1000 CheckPasswordForms("Chrome Form Data (42)", expected);
1003 // TODO(mdm): add more basic tests here at some point.
1004 // (For example tests for storing >1 password per realm pickle.)
1006 class NativeBackendKWalletPickleTest : public NativeBackendKWalletTestBase {
1007 protected:
1008 // Based on |form|, fills |pickle| with data conforming to
1009 // |effective_version|, but marking the pickle version as |stored_version|. In
1010 // most cases the two versions should be the same.
1011 void CreateVersion1PlusPickle(const PasswordForm& form,
1012 base::Pickle* pickle,
1013 int stored_version,
1014 int effective_version);
1015 void CreateVersion0Pickle(bool size_32,
1016 const PasswordForm& form,
1017 base::Pickle* pickle);
1018 // As explained in http://crbug.com/494229#c11, version 6 added a new optional
1019 // field to version 5. This field became required in version 7. Depending on
1020 // |with_optional_field|, this method checks deserialization with or without
1021 // the optional field.
1022 void CheckVersion6Pickle(bool with_optional_field);
1023 void CheckVersion5Pickle();
1024 void CheckVersion3Pickle();
1025 void CheckVersion2Pickle();
1026 void CheckVersion1Pickle();
1027 void CheckVersion0Pickle(bool size_32, PasswordForm::Scheme scheme);
1029 private:
1030 // Creates a Pickle from |form|. If |size_32| is true, stores the number of
1031 // forms in the pickle as a 32bit uint, otherwise as 64 bit size_t. The latter
1032 // should be the case for versions > 0. If |date_created_internal| is true,
1033 // stores |date_created| as base::Time's internal value, otherwise as time_t.
1034 void CreatePickle(bool size_32,
1035 bool date_created_internal,
1036 const PasswordForm& form,
1037 base::Pickle* pickle);
1040 void NativeBackendKWalletPickleTest::CreateVersion1PlusPickle(
1041 const PasswordForm& form,
1042 base::Pickle* pickle,
1043 int stored_version,
1044 int effective_version) {
1045 pickle->WriteInt(stored_version);
1046 CreatePickle(false, true, form, pickle);
1047 if (effective_version < 2)
1048 return;
1049 pickle->WriteInt(form.type);
1050 pickle->WriteInt(form.times_used);
1051 autofill::SerializeFormData(form.form_data, pickle);
1052 if (effective_version < 3)
1053 return;
1054 pickle->WriteInt64(form.date_synced.ToInternalValue());
1055 if (effective_version < 4)
1056 return;
1057 pickle->WriteString16(form.display_name);
1058 pickle->WriteString(form.icon_url.spec());
1059 pickle->WriteString(form.federation_url.spec());
1060 pickle->WriteBool(form.skip_zero_click);
1061 if (effective_version < 7)
1062 return;
1063 pickle->WriteInt(form.generation_upload_status);
1066 void NativeBackendKWalletPickleTest::CreateVersion0Pickle(
1067 bool size_32,
1068 const PasswordForm& form,
1069 base::Pickle* pickle) {
1070 pickle->WriteInt(0);
1071 CreatePickle(size_32, false, form, pickle);
1074 void NativeBackendKWalletPickleTest::CreatePickle(bool size_32,
1075 bool date_created_internal,
1076 const PasswordForm& form,
1077 base::Pickle* pickle) {
1078 if (size_32)
1079 pickle->WriteUInt32(1); // Size of form list. 32 bits.
1080 else
1081 pickle->WriteSizeT(1); // Size of form list. 64 bits.
1082 pickle->WriteInt(form.scheme);
1083 pickle->WriteString(form.origin.spec());
1084 pickle->WriteString(form.action.spec());
1085 pickle->WriteString16(form.username_element);
1086 pickle->WriteString16(form.username_value);
1087 pickle->WriteString16(form.password_element);
1088 pickle->WriteString16(form.password_value);
1089 pickle->WriteString16(form.submit_element);
1090 pickle->WriteBool(form.ssl_valid);
1091 pickle->WriteBool(form.preferred);
1092 pickle->WriteBool(form.blacklisted_by_user);
1093 if (date_created_internal)
1094 pickle->WriteInt64(form.date_created.ToInternalValue());
1095 else
1096 pickle->WriteInt64(form.date_created.ToTimeT());
1099 void NativeBackendKWalletPickleTest::CheckVersion6Pickle(
1100 bool with_optional_field) {
1101 base::Pickle pickle;
1102 PasswordForm form = form_google_;
1103 if (!with_optional_field) {
1104 PasswordForm default_values;
1105 form.generation_upload_status = default_values.generation_upload_status;
1107 CreateVersion1PlusPickle(form, &pickle, 6, with_optional_field ? 7 : 5);
1109 ScopedVector<PasswordForm> form_list =
1110 NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
1112 EXPECT_EQ(1u, form_list.size());
1113 if (form_list.size() > 0)
1114 CheckPasswordForm(form, *form_list[0], true);
1118 void NativeBackendKWalletPickleTest::CheckVersion5Pickle() {
1119 base::Pickle pickle;
1120 PasswordForm default_values;
1121 PasswordForm form = form_google_;
1122 // Remove the field which was not present in version #5.
1123 form.generation_upload_status = default_values.generation_upload_status;
1124 CreateVersion1PlusPickle(form, &pickle, 5, 5);
1126 ScopedVector<PasswordForm> form_list =
1127 NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
1129 EXPECT_EQ(1u, form_list.size());
1130 if (form_list.size() > 0)
1131 CheckPasswordForm(form, *form_list[0], true);
1134 void NativeBackendKWalletPickleTest::CheckVersion3Pickle() {
1135 base::Pickle pickle;
1136 PasswordForm default_values;
1137 PasswordForm form = form_google_;
1138 // Remove the fields which were not present in version #3.
1139 form.display_name = default_values.display_name;
1140 form.icon_url = default_values.icon_url;
1141 form.federation_url = default_values.federation_url;
1142 form.skip_zero_click = default_values.skip_zero_click;
1143 form.generation_upload_status = default_values.generation_upload_status;
1144 CreateVersion1PlusPickle(form, &pickle, 3, 3);
1146 ScopedVector<PasswordForm> form_list =
1147 NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
1149 EXPECT_EQ(1u, form_list.size());
1150 if (form_list.size() > 0)
1151 CheckPasswordForm(form, *form_list[0], false);
1154 void NativeBackendKWalletPickleTest::CheckVersion2Pickle() {
1155 base::Pickle pickle;
1156 PasswordForm form = old_form_google_;
1157 form.times_used = form_google_.times_used;
1158 form.type = form_google_.type;
1159 form.form_data = form_google_.form_data;
1160 CreateVersion1PlusPickle(form, &pickle, 2, 2);
1162 ScopedVector<PasswordForm> form_list =
1163 NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
1165 EXPECT_EQ(1u, form_list.size());
1166 if (form_list.size() > 0)
1167 CheckPasswordForm(form, *form_list[0], false);
1170 // Make sure that we can still read version 1 pickles.
1171 void NativeBackendKWalletPickleTest::CheckVersion1Pickle() {
1172 base::Pickle pickle;
1173 PasswordForm form = form_google_;
1174 CreateVersion1PlusPickle(form, &pickle, 1, 1);
1176 ScopedVector<autofill::PasswordForm> form_list =
1177 NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
1179 // This will match |old_form_google_| because not all the fields present in
1180 // |form_google_| will be deserialized.
1181 EXPECT_EQ(1u, form_list.size());
1182 if (form_list.size() > 0)
1183 CheckPasswordForm(old_form_google_, *form_list[0], false);
1186 void NativeBackendKWalletPickleTest::CheckVersion0Pickle(
1187 bool size_32, PasswordForm::Scheme scheme) {
1188 base::Pickle pickle;
1189 PasswordForm form = old_form_google_;
1190 form.scheme = scheme;
1191 CreateVersion0Pickle(size_32, form, &pickle);
1192 ScopedVector<autofill::PasswordForm> form_list =
1193 NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle);
1194 EXPECT_EQ(1u, form_list.size());
1195 if (form_list.size() > 0)
1196 CheckPasswordForm(form, *form_list[0], false);
1199 // Check that if KWallet fails to respond, the backend propagates the error.
1200 TEST_F(NativeBackendKWalletTest, GetAllLoginsErrorHandling) {
1201 NativeBackendKWalletStub backend(42);
1202 EXPECT_TRUE(backend.InitWithBus(mock_session_bus_));
1203 // Make KWallet fail on calling readEntry.
1204 failing_methods_.insert("readEntry");
1206 // Store some non-blacklisted logins to be potentially returned.
1207 BrowserThread::PostTaskAndReplyWithResult(
1208 BrowserThread::DB, FROM_HERE,
1209 base::Bind(&NativeBackendKWalletStub::AddLogin,
1210 base::Unretained(&backend), form_google_),
1211 base::Bind(&CheckPasswordChanges,
1212 PasswordStoreChangeList(1, PasswordStoreChange(
1213 PasswordStoreChange::ADD, form_google_))));
1215 // Verify that nothing is in fact returned, because KWallet fails to respond.
1216 ScopedVector<autofill::PasswordForm> form_list;
1217 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
1218 base::Bind(&CheckGetAutofillableLoginsFails,
1219 base::Unretained(&backend), &form_list));
1220 RunDBThread();
1221 EXPECT_EQ(0u, form_list.size());
1224 // We try both SCHEME_HTML and SCHEME_BASIC since the scheme is stored right
1225 // after the size in the pickle, so it's what gets read as part of the count
1226 // when reading 32-bit pickles on 64-bit systems. SCHEME_HTML is 0 (so we'll
1227 // detect errors later) while SCHEME_BASIC is 1 (so we'll detect it then). We
1228 // try both 32-bit and 64-bit pickles since only one will be the "other" size
1229 // for whatever architecture we're running on, but we want to make sure we can
1230 // read all combinations in any event.
1232 TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTMLPickles) {
1233 CheckVersion0Pickle(true, PasswordForm::SCHEME_HTML);
1236 TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTTPPickles) {
1237 CheckVersion0Pickle(true, PasswordForm::SCHEME_BASIC);
1240 TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTMLPickles) {
1241 CheckVersion0Pickle(false, PasswordForm::SCHEME_HTML);
1244 TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTTPPickles) {
1245 CheckVersion0Pickle(false, PasswordForm::SCHEME_BASIC);
1248 TEST_F(NativeBackendKWalletPickleTest, CheckVersion1Pickle) {
1249 CheckVersion1Pickle();
1252 TEST_F(NativeBackendKWalletPickleTest, CheckVersion2Pickle) {
1253 CheckVersion2Pickle();
1256 TEST_F(NativeBackendKWalletPickleTest, CheckVersion3Pickle) {
1257 CheckVersion3Pickle();
1260 TEST_F(NativeBackendKWalletPickleTest, CheckVersion5Pickle) {
1261 CheckVersion5Pickle();
1264 TEST_F(NativeBackendKWalletPickleTest, CheckVersion6Pickle) {
1265 CheckVersion6Pickle(false);
1266 CheckVersion6Pickle(true);