blob: 9f5acc35185fb443da9a945de4aa508304697445 [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/file_path.h"
#include "base/string_util.h"
#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/password_manager/password_manager_delegate.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
using webkit_glue::PasswordForm;
using testing::_;
using testing::DoAll;
using ::testing::Exactly;
using ::testing::WithArg;
using ::testing::Return;
class MockPasswordManagerDelegate : public PasswordManagerDelegate {
public:
MOCK_METHOD1(FillPasswordForm, void(
const webkit_glue::PasswordFormFillData&));
MOCK_METHOD1(AddSavePasswordInfoBar, void(PasswordFormManager*));
MOCK_METHOD0(GetProfileForPasswordManager, Profile*());
MOCK_METHOD0(DidLastPageLoadEncounterSSLErrors, bool());
};
class TestingProfileWithPasswordStore : public TestingProfile {
public:
explicit TestingProfileWithPasswordStore(PasswordStore* store)
: store_(store) {}
virtual PasswordStore* GetPasswordStore(ServiceAccessType access) {
return store_;
}
private:
PasswordStore* store_;
};
class MockPasswordStore : public PasswordStore {
public:
MOCK_METHOD1(RemoveLogin, void(const PasswordForm&));
MOCK_METHOD2(GetLogins, int(const PasswordForm&, PasswordStoreConsumer*));
MOCK_METHOD1(AddLogin, void(const PasswordForm&));
MOCK_METHOD1(UpdateLogin, void(const PasswordForm&));
MOCK_METHOD0(ReportMetrics, void());
MOCK_METHOD0(ReportMetricsImpl, void());
MOCK_METHOD1(AddLoginImpl, void(const PasswordForm&));
MOCK_METHOD1(UpdateLoginImpl, void(const PasswordForm&));
MOCK_METHOD1(RemoveLoginImpl, void(const PasswordForm&));
MOCK_METHOD2(RemoveLoginsCreatedBetweenImpl, void(const base::Time&,
const base::Time&));
MOCK_METHOD2(GetLoginsImpl, void(GetLoginsRequest*, const PasswordForm&));
MOCK_METHOD1(GetAutofillableLoginsImpl, void(GetLoginsRequest*));
MOCK_METHOD1(GetBlacklistLoginsImpl, void(GetLoginsRequest*));
MOCK_METHOD1(FillAutofillableLogins,
bool(std::vector<webkit_glue::PasswordForm*>*));
MOCK_METHOD1(FillBlacklistLogins,
bool(std::vector<webkit_glue::PasswordForm*>*));
};
ACTION_P2(InvokeConsumer, handle, forms) {
arg0->OnPasswordStoreRequestDone(handle, forms);
}
ACTION_P(SaveToScopedPtr, scoped) {
scoped->reset(arg0);
}
class PasswordManagerTest : public testing::Test {
public:
PasswordManagerTest() {}
protected:
virtual void SetUp() {
store_ = new MockPasswordStore();
profile_.reset(new TestingProfileWithPasswordStore(store_));
EXPECT_CALL(delegate_, GetProfileForPasswordManager())
.WillRepeatedly(Return(profile_.get()));
manager_.reset(new PasswordManager(&delegate_));
EXPECT_CALL(delegate_, DidLastPageLoadEncounterSSLErrors())
.WillRepeatedly(Return(false));
}
virtual void TearDown() {
manager_.reset();
store_ = NULL;
}
PasswordForm MakeSimpleForm() {
PasswordForm form;
form.origin = GURL("http://www.google.com/a/LoginAuth");
form.action = GURL("http://www.google.com/a/Login");
form.username_element = ASCIIToUTF16("Email");
form.password_element = ASCIIToUTF16("Passwd");
form.username_value = ASCIIToUTF16("google");
form.password_value = ASCIIToUTF16("password");
form.submit_element = ASCIIToUTF16("signIn");
form.signon_realm = "http://www.google.com";
return form;
}
PasswordManager* manager() { return manager_.get(); }
scoped_ptr<Profile> profile_;
scoped_refptr<MockPasswordStore> store_;
MockPasswordManagerDelegate delegate_; // Owned by manager_.
scoped_ptr<PasswordManager> manager_;
};
MATCHER_P(FormMatches, form, "") {
return form.signon_realm == arg.signon_realm &&
form.origin == arg.origin &&
form.action == arg.action &&
form.username_element == arg.username_element &&
form.password_element == arg.password_element &&
form.submit_element == arg.submit_element;
}
TEST_F(PasswordManagerTest, FormSubmitEmptyStore) {
// Test that observing a newly submitted form shows the save password bar.
std::vector<PasswordForm*> result; // Empty password store.
EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
EXPECT_CALL(*store_, GetLogins(_,_))
.WillOnce(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form);
manager()->PasswordFormsFound(observed); // The initial load.
manager()->PasswordFormsVisible(observed); // The initial layout.
// And the form submit contract is to call ProvisionallySavePassword.
manager()->ProvisionallySavePassword(form);
scoped_ptr<PasswordFormManager> form_to_save;
EXPECT_CALL(delegate_, AddSavePasswordInfoBar(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
// Now the password manager waits for the navigation to complete.
manager()->DidStopLoading();
ASSERT_FALSE(NULL == form_to_save.get());
EXPECT_CALL(*store_, AddLogin(FormMatches(form)));
// Simulate saving the form, as if the info bar was accepted.
form_to_save->Save();
}
TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
// Same as above, except with an existing form for the same signon realm,
// but different origin. Detailed cases like this are covered by
// PasswordFormManagerTest.
std::vector<PasswordForm*> result;
PasswordForm* existing_different = new PasswordForm(MakeSimpleForm());
existing_different->username_value = ASCIIToUTF16("google2");
result.push_back(existing_different);
EXPECT_CALL(delegate_, FillPasswordForm(_));
EXPECT_CALL(*store_, GetLogins(_,_))
.WillOnce(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form);
manager()->PasswordFormsFound(observed); // The initial load.
manager()->PasswordFormsVisible(observed); // The initial layout.
manager()->ProvisionallySavePassword(form);
// We still expect an add, since we didn't have a good match.
scoped_ptr<PasswordFormManager> form_to_save;
EXPECT_CALL(delegate_, AddSavePasswordInfoBar(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
manager()->DidStopLoading();
EXPECT_CALL(*store_, AddLogin(FormMatches(form)));
// Simulate saving the form.
form_to_save->Save();
}
TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
std::vector<PasswordForm*> result; // Empty password store.
EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
EXPECT_CALL(*store_, GetLogins(_,_))
.WillOnce(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form);
manager()->PasswordFormsFound(observed); // The initial load.
manager()->PasswordFormsVisible(observed); // The initial layout.
manager()->DidNavigate();
// No expected calls.
manager()->DidStopLoading();
}
TEST_F(PasswordManagerTest, FormSubmitFailedLogin) {
std::vector<PasswordForm*> result; // Empty password store.
EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
EXPECT_CALL(*store_, GetLogins(_,_))
.WillRepeatedly(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form);
manager()->PasswordFormsFound(observed); // The initial load.
manager()->PasswordFormsVisible(observed); // The initial layout.
manager()->ProvisionallySavePassword(form);
// The form reappears, and is visible in the layout:
manager()->PasswordFormsFound(observed);
manager()->PasswordFormsVisible(observed);
// No expected calls to the PasswordStore...
manager()->DidStopLoading();
}
TEST_F(PasswordManagerTest, FormSubmitInvisibleLogin) {
// Tests fix of issue 28911: if the login form reappears on the subsequent
// page, but is invisible, it shouldn't count as a failed login.
std::vector<PasswordForm*> result; // Empty password store.
EXPECT_CALL(delegate_, FillPasswordForm(_)).Times(Exactly(0));
EXPECT_CALL(*store_, GetLogins(_,_))
.WillRepeatedly(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form);
manager()->PasswordFormsFound(observed); // The initial load.
manager()->PasswordFormsVisible(observed); // The initial layout.
manager()->ProvisionallySavePassword(form);
// The form reappears, but is not visible in the layout:
manager()->PasswordFormsFound(observed);
// No call to PasswordFormsVisible.
// Expect info bar to appear:
scoped_ptr<PasswordFormManager> form_to_save;
EXPECT_CALL(delegate_, AddSavePasswordInfoBar(_))
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save)));
manager()->DidStopLoading();
ASSERT_FALSE(NULL == form_to_save.get());
EXPECT_CALL(*store_, AddLogin(FormMatches(form)));
// Simulate saving the form.
form_to_save->Save();
}
TEST_F(PasswordManagerTest, InitiallyInvisibleForm) {
// Make sure an invisible login form still gets autofilled.
std::vector<PasswordForm*> result;
PasswordForm* existing = new PasswordForm(MakeSimpleForm());
result.push_back(existing);
EXPECT_CALL(delegate_, FillPasswordForm(_));
EXPECT_CALL(*store_, GetLogins(_,_))
.WillRepeatedly(DoAll(WithArg<1>(InvokeConsumer(0, result)), Return(0)));
std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
observed.push_back(form);
manager()->PasswordFormsFound(observed); // The initial load.
// PasswordFormsVisible is not called.
manager()->DidStopLoading();
}