blob: 776efb7d1dd6ddba2bd94c17342dd966daae6f7a [file] [log] [blame]
// Copyright 2014 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.
package org.chromium.chrome.browser.preferences.password;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.containsString;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.Espresso;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.PasswordManagerHandler;
import org.chromium.chrome.browser.SavedPasswordEntry;
import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.preferences.Preferences;
import org.chromium.chrome.browser.preferences.PreferencesTest;
import org.chromium.chrome.browser.test.ChromeBrowserTestRule;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import java.util.ArrayList;
/**
* Tests for the "Save Passwords" settings screen.
*/
@RunWith(BaseJUnit4ClassRunner.class)
public class SavePasswordsPreferencesTest {
@Rule
public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
@Rule
public TestRule mProcessor = new Features.InstrumentationProcessor();
private static final class FakePasswordManagerHandler implements PasswordManagerHandler {
// This class has exactly one observer, set on construction and expected to last at least as
// long as this object (a good candidate is the owner of this object).
private final PasswordListObserver mObserver;
// The faked contents of the password store to be displayed.
private ArrayList<SavedPasswordEntry> mSavedPasswords;
public void setSavedPasswords(ArrayList<SavedPasswordEntry> savedPasswords) {
mSavedPasswords = savedPasswords;
}
/**
* Constructor.
* @param PasswordListObserver The only observer.
*/
public FakePasswordManagerHandler(PasswordListObserver observer) {
mObserver = observer;
}
// Pretends that the updated lists are |mSavedPasswords| for the saved passwords and an
// empty list for exceptions and immediately calls the observer.
@Override
public void updatePasswordLists() {
mObserver.passwordListAvailable(mSavedPasswords.size());
}
@Override
public SavedPasswordEntry getSavedPasswordEntry(int index) {
return mSavedPasswords.get(index);
}
@Override
public String getSavedPasswordException(int index) {
// Define this method before starting to use it in tests.
assert false;
return null;
}
@Override
public void removeSavedPasswordEntry(int index) {
// Define this method before starting to use it in tests.
assert false;
return;
}
@Override
public void removeSavedPasswordException(int index) {
// Define this method before starting to use it in tests.
assert false;
return;
}
}
/**
* Ensure that resetting of empty passwords list works.
*/
@Test
@SmallTest
@Feature({"Preferences"})
public void testResetListEmpty() throws Exception {
// Load the preferences, they should show the empty list.
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
SavePasswordsPreferences savePasswordPreferences =
(SavePasswordsPreferences) preferences.getFragmentForTest();
// Emulate an update from PasswordStore. This should not crash.
savePasswordPreferences.passwordListAvailable(0);
}
});
}
/**
* Ensure that the on/off switch in "Save Passwords" settings actually enables and disables
* password saving.
*/
@Test
@SmallTest
@Feature({"Preferences"})
public void testSavePasswordsSwitch() throws Exception {
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
PrefServiceBridge.getInstance().setRememberPasswordsEnabled(true);
}
});
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
SavePasswordsPreferences savedPasswordPrefs =
(SavePasswordsPreferences) preferences.getFragmentForTest();
ChromeSwitchPreference onOffSwitch = (ChromeSwitchPreference)
savedPasswordPrefs.findPreference(
SavePasswordsPreferences.PREF_SAVE_PASSWORDS_SWITCH);
Assert.assertTrue(onOffSwitch.isChecked());
PreferencesTest.clickPreference(savedPasswordPrefs, onOffSwitch);
Assert.assertFalse(PrefServiceBridge.getInstance().isRememberPasswordsEnabled());
PreferencesTest.clickPreference(savedPasswordPrefs, onOffSwitch);
Assert.assertTrue(PrefServiceBridge.getInstance().isRememberPasswordsEnabled());
preferences.finish();
PrefServiceBridge.getInstance().setRememberPasswordsEnabled(false);
}
});
final Preferences preferences2 =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
SavePasswordsPreferences savedPasswordPrefs =
(SavePasswordsPreferences) preferences2.getFragmentForTest();
ChromeSwitchPreference onOffSwitch = (ChromeSwitchPreference)
savedPasswordPrefs.findPreference(
SavePasswordsPreferences.PREF_SAVE_PASSWORDS_SWITCH);
Assert.assertFalse(onOffSwitch.isChecked());
}
});
}
/**
* Ensure that the "Auto Sign-in" switch in "Save Passwords" settings actually enables and
* disables auto sign-in.
*/
@Test
@SmallTest
@Feature({"Preferences"})
public void testAutoSignInCheckbox() throws Exception {
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
PrefServiceBridge.getInstance().setPasswordManagerAutoSigninEnabled(true);
}
});
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
SavePasswordsPreferences passwordPrefs =
(SavePasswordsPreferences) preferences.getFragmentForTest();
ChromeBaseCheckBoxPreference onOffSwitch =
(ChromeBaseCheckBoxPreference) passwordPrefs.findPreference(
SavePasswordsPreferences.PREF_AUTOSIGNIN_SWITCH);
Assert.assertTrue(onOffSwitch.isChecked());
PreferencesTest.clickPreference(passwordPrefs, onOffSwitch);
Assert.assertFalse(
PrefServiceBridge.getInstance().isPasswordManagerAutoSigninEnabled());
PreferencesTest.clickPreference(passwordPrefs, onOffSwitch);
Assert.assertTrue(
PrefServiceBridge.getInstance().isPasswordManagerAutoSigninEnabled());
preferences.finish();
PrefServiceBridge.getInstance().setPasswordManagerAutoSigninEnabled(false);
}
});
final Preferences preferences2 =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
SavePasswordsPreferences passwordPrefs =
(SavePasswordsPreferences) preferences2.getFragmentForTest();
ChromeBaseCheckBoxPreference onOffSwitch =
(ChromeBaseCheckBoxPreference) passwordPrefs.findPreference(
SavePasswordsPreferences.PREF_AUTOSIGNIN_SWITCH);
Assert.assertFalse(onOffSwitch.isChecked());
}
});
}
/**
* Check that the export menu item is included and hidden behind the overflow menu. Check that
* the menu displays the warning before letting the user export passwords.
*/
@Test
@SmallTest
@Feature({"Preferences"})
@EnableFeatures("password-export")
public void testExportMenuItem() throws Exception {
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
ReauthenticationManager.OverrideState.AVAILABLE);
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
Espresso.openActionBarOverflowOrOptionsMenu(
InstrumentationRegistry.getInstrumentation().getTargetContext());
// Before tapping the menu item for export, pretend that the last successful
// reauthentication just happened. This will allow the export flow to continue.
ReauthenticationManager.setLastReauthTimeMillis(System.currentTimeMillis());
Espresso.onView(withText(R.string.save_password_preferences_export_action_title))
.perform(click());
Espresso.onView(withText(R.string.settings_passwords_export_description))
.check(matches(isDisplayed()));
}
/**
* Check whether the user is asked to set up a screen lock if attempting to export passwords.
*/
@Test
@SmallTest
@Feature({"Preferences"})
@EnableFeatures("password-export")
public void testExportMenuItemNoLock() throws Exception {
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
ReauthenticationManager.OverrideState.UNAVAILABLE);
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
Espresso.openActionBarOverflowOrOptionsMenu(
InstrumentationRegistry.getInstrumentation().getTargetContext());
Espresso.onView(withText(R.string.save_password_preferences_export_action_title))
.perform(click());
Espresso.onView(withText(R.string.password_export_set_lock_screen))
.inRoot(withDecorView(isEnabled()))
.check(matches(isDisplayed()));
}
/**
* Check whether the user is asked to set up a screen lock if attempting to view passwords.
*/
@Test
@SmallTest
@Feature({"Preferences"})
public void testViewPasswordNoLock() throws Exception {
FakePasswordManagerHandler handler =
new FakePasswordManagerHandler(PasswordManagerHandlerProvider.getInstance());
ArrayList<SavedPasswordEntry> entries = new ArrayList<SavedPasswordEntry>();
entries.add(new SavedPasswordEntry("https://example.com", "test user", "password"));
handler.setSavedPasswords(entries);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
PasswordManagerHandlerProvider.getInstance().setPasswordManagerHandlerForTest(
handler);
}
});
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
ReauthenticationManager.OverrideState.UNAVAILABLE);
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
Espresso.onView(withText(containsString("test user"))).perform(click());
Espresso.onView(withContentDescription(R.string.password_entry_editor_copy_stored_password))
.perform(click());
Espresso.onView(withText(R.string.password_entry_editor_set_lock_screen))
.inRoot(withDecorView(isEnabled()))
.check(matches(isDisplayed()));
handler.setSavedPasswords(null);
}
/**
* Check whether the user can view a saved password.
*/
@Test
@SmallTest
@Feature({"Preferences"})
public void testViewPassword() throws Exception {
FakePasswordManagerHandler handler =
new FakePasswordManagerHandler(PasswordManagerHandlerProvider.getInstance());
ArrayList<SavedPasswordEntry> entries = new ArrayList<SavedPasswordEntry>();
entries.add(new SavedPasswordEntry("https://example.com", "test user", "test password"));
handler.setSavedPasswords(entries);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
PasswordManagerHandlerProvider.getInstance().setPasswordManagerHandlerForTest(
handler);
}
});
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
ReauthenticationManager.OverrideState.AVAILABLE);
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
Espresso.onView(withText(containsString("test user"))).perform(click());
// Before tapping the view button, pretend that the last successful reauthentication just
// happened. This will allow the export flow to continue.
ReauthenticationManager.setLastReauthTimeMillis(System.currentTimeMillis());
Espresso.onView(withContentDescription(R.string.password_entry_editor_view_stored_password))
.perform(click());
Espresso.onView(withText("test password")).check(matches(isDisplayed()));
handler.setSavedPasswords(null);
}
}