| Index: chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
|
| diff --git a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f527ea2e06f4543dc5a835989ea54cd4b4dce08d
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc
|
| @@ -0,0 +1,317 @@
|
| +// Copyright 2016 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.
|
| +
|
| +// This file tests the chromeos.quickUnlockPrivate extension API.
|
| +
|
| +#include "chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.h"
|
| +
|
| +#include "base/bind.h"
|
| +
|
| +#include "base/memory/ptr_util.h"
|
| +#include "chrome/browser/chromeos/login/quick_unlock/pin_storage.h"
|
| +#include "chrome/browser/chromeos/login/quick_unlock/pin_storage_factory.h"
|
| +#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
|
| +#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
|
| +#include "chrome/browser/extensions/extension_api_unittest.h"
|
| +#include "chromeos/login/auth/fake_extended_authenticator.h"
|
| +#include "extensions/browser/api_test_utils.h"
|
| +#include "extensions/browser/extension_function_dispatcher.h"
|
| +
|
| +using namespace extensions;
|
| +namespace quick_unlock_private = extensions::api::quick_unlock_private;
|
| +using QuickUnlockMode = quick_unlock_private::QuickUnlockMode;
|
| +using QuickUnlockModeList = std::vector<QuickUnlockMode>;
|
| +using CredentialList = std::vector<std::string>;
|
| +
|
| +namespace chromeos {
|
| +namespace {
|
| +
|
| +const char* kTestUserEmail = "testuser@gmail.com";
|
| +const char* kTestUserEmailHash = "testuser@gmail.com-hash";
|
| +const char* kValidPassword = "valid";
|
| +const char* kInvalidPassword = "invalid";
|
| +
|
| +chromeos::ExtendedAuthenticator* CreateFakeAuthenticator(
|
| + chromeos::AuthStatusConsumer* auth_status_consumer) {
|
| + AccountId account_id = AccountId::FromUserEmail(kTestUserEmail);
|
| + chromeos::UserContext expected_context(account_id);
|
| + expected_context.SetKey(Key(kValidPassword));
|
| +
|
| + chromeos::ExtendedAuthenticator* authenticator =
|
| + new chromeos::FakeExtendedAuthenticator(auth_status_consumer,
|
| + expected_context);
|
| + return authenticator;
|
| +}
|
| +
|
| +void DoNothing(const QuickUnlockModeList& modes) {}
|
| +
|
| +void FailIfCalled(const QuickUnlockModeList& modes) {
|
| + FAIL();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest {
|
| + public:
|
| + QuickUnlockPrivateUnitTest()
|
| + : fake_user_manager_(new FakeChromeUserManager()),
|
| + scoped_user_manager_(fake_user_manager_) {}
|
| +
|
| + protected:
|
| + void SetUp() override {
|
| + ExtensionApiUnittest::SetUp();
|
| +
|
| + // Setup a primary user.
|
| + auto test_account = AccountId::FromUserEmail(kTestUserEmail);
|
| + fake_user_manager_->AddUser(test_account);
|
| + fake_user_manager_->UserLoggedIn(test_account, kTestUserEmailHash, false);
|
| +
|
| + // Ensure that quick unlock is turned off.
|
| + SetModes(QuickUnlockModeList{}, CredentialList{});
|
| +
|
| + modes_changed_handler_ = base::Bind(&DoNothing);
|
| + }
|
| +
|
| + // If a mode change event is raised, fail the test.
|
| + void FailIfModesChanged() {
|
| + modes_changed_handler_ = base::Bind(&FailIfCalled);
|
| + }
|
| +
|
| + // If a mode change event is raised, expect the given |modes|.
|
| + void ExpectModesChanged(const QuickUnlockModeList& modes) {
|
| + modes_changed_handler_ =
|
| + base::Bind(&QuickUnlockPrivateUnitTest::ExpectModeList,
|
| + base::Unretained(this), modes);
|
| + expect_modes_changed_ = true;
|
| + }
|
| +
|
| + // Wrapper for chrome.quickUnlockPrivate.getAvailableModes.
|
| + QuickUnlockModeList GetAvailableModes() {
|
| + // Run the function.
|
| + std::unique_ptr<base::Value> result =
|
| + RunFunction(new QuickUnlockPrivateGetAvailableModesFunction(),
|
| + base::WrapUnique(new base::ListValue()));
|
| +
|
| + // Extract the results.
|
| + QuickUnlockModeList modes;
|
| +
|
| + base::ListValue* list = nullptr;
|
| + EXPECT_TRUE(result->GetAsList(&list));
|
| + // Consume the unique_ptr by reference so we don't take ownership.
|
| + for (const std::unique_ptr<base::Value>& value : (*list)) {
|
| + std::string mode;
|
| + EXPECT_TRUE(value->GetAsString(&mode));
|
| + modes.push_back(quick_unlock_private::ParseQuickUnlockMode(mode));
|
| + }
|
| +
|
| + return modes;
|
| + }
|
| +
|
| + // Wrapper for chrome.quickUnlockPrivate.getActiveModes.
|
| + QuickUnlockModeList GetActiveModes() {
|
| + std::unique_ptr<base::Value> result =
|
| + RunFunction(new QuickUnlockPrivateGetActiveModesFunction(),
|
| + base::WrapUnique(new base::ListValue()));
|
| +
|
| + QuickUnlockModeList modes;
|
| +
|
| + base::ListValue* list = nullptr;
|
| + EXPECT_TRUE(result->GetAsList(&list));
|
| + for (const std::unique_ptr<base::Value>& value : *list) {
|
| + std::string mode;
|
| + EXPECT_TRUE(value->GetAsString(&mode));
|
| + modes.push_back(quick_unlock_private::ParseQuickUnlockMode(mode));
|
| + }
|
| +
|
| + return modes;
|
| + }
|
| +
|
| + // Wrapper for chrome.quickUnlockPrivate.setModes that automatically uses a
|
| + // valid password.
|
| + bool SetModes(const QuickUnlockModeList& modes,
|
| + const CredentialList& passwords) {
|
| + return SetModesUsingPassword(kValidPassword, modes, passwords);
|
| + }
|
| +
|
| + // Wrapper for chrome.quickUnlockPrivate.setModes.
|
| + bool SetModesUsingPassword(const std::string& password,
|
| + const QuickUnlockModeList& modes,
|
| + const CredentialList& passwords) {
|
| + // Serialize parameters.
|
| + auto params = base::WrapUnique(new base::ListValue());
|
| + params->AppendString(password);
|
| +
|
| + auto serialized_modes = base::WrapUnique(new base::ListValue());
|
| + for (QuickUnlockMode mode : modes)
|
| + serialized_modes->AppendString(quick_unlock_private::ToString(mode));
|
| + params->Append(std::move(serialized_modes));
|
| +
|
| + auto serialized_passwords = base::WrapUnique(new base::ListValue());
|
| + for (const std::string& password : passwords)
|
| + serialized_passwords->AppendString(password);
|
| + params->Append(std::move(serialized_passwords));
|
| +
|
| + // Setup a fake authenticator so quickUnlockPrivate.checkPassword doesn't
|
| + // call cryptohome methods.
|
| + auto* func = new QuickUnlockPrivateSetModesFunction();
|
| + func->SetAuthenticatorAllocatorForTesting(
|
| + base::Bind(&CreateFakeAuthenticator));
|
| +
|
| + // Stub out event handling since we are not setting up an event router.
|
| + func->SetModesChangedEventHandlerForTesting(modes_changed_handler_);
|
| +
|
| + // Run function and extract the result.
|
| + std::unique_ptr<base::Value> func_result =
|
| + RunFunction(func, std::move(params));
|
| + bool result;
|
| + EXPECT_TRUE(func_result->GetAsBoolean(&result));
|
| +
|
| + // Verify that the mode change event handler was run if it was registered.
|
| + // ExpectModesChanged will set expect_modes_changed_ to true and the event
|
| + // handler will set it to false; so if the handler never runs,
|
| + // expect_modes_changed_ will still be true.
|
| + EXPECT_FALSE(expect_modes_changed_) << "Mode change event was not raised";
|
| +
|
| + return result;
|
| + }
|
| +
|
| + std::string SetModesWithError(const std::string& args) {
|
| + auto func = new QuickUnlockPrivateSetModesFunction();
|
| + func->SetAuthenticatorAllocatorForTesting(
|
| + base::Bind(&CreateFakeAuthenticator));
|
| + func->SetModesChangedEventHandlerForTesting(base::Bind(&DoNothing));
|
| +
|
| + return api_test_utils::RunFunctionAndReturnError(func, args, profile());
|
| + }
|
| +
|
| + // Returns true if |password| is correct. This calls into SetModes to do so.
|
| + // This will turn off any active quick unlock modes.
|
| + bool CheckPassword(const std::string& password) {
|
| + return SetModesUsingPassword(password, QuickUnlockModeList{},
|
| + CredentialList{});
|
| + }
|
| +
|
| + private:
|
| + // Runs the given |func| with the given |params|.
|
| + std::unique_ptr<base::Value> RunFunction(
|
| + scoped_refptr<UIThreadExtensionFunction> func,
|
| + std::unique_ptr<base::ListValue> params) {
|
| + return std::unique_ptr<base::Value>(
|
| + api_test_utils::RunFunctionWithDelegateAndReturnSingleResult(
|
| + func, std::move(params), profile(),
|
| + base::WrapUnique(new ExtensionFunctionDispatcher(profile())),
|
| + api_test_utils::NONE));
|
| + }
|
| +
|
| + // Verifies a mode change event is raised and that |expected| is now the
|
| + // active set of quick unlock modes.
|
| + void ExpectModeList(const QuickUnlockModeList& expected,
|
| + const QuickUnlockModeList& actual) {
|
| + EXPECT_EQ(expected, actual);
|
| + expect_modes_changed_ = false;
|
| + }
|
| +
|
| + FakeChromeUserManager* fake_user_manager_;
|
| + ScopedUserManagerEnabler scoped_user_manager_;
|
| + QuickUnlockPrivateSetModesFunction::ModesChangedEventHandler
|
| + modes_changed_handler_;
|
| + bool expect_modes_changed_ = false;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(QuickUnlockPrivateUnitTest);
|
| +};
|
| +
|
| +// Verify that password checking works.
|
| +TEST_F(QuickUnlockPrivateUnitTest, CheckPassword) {
|
| + EXPECT_TRUE(CheckPassword(kValidPassword));
|
| + EXPECT_FALSE(CheckPassword(kInvalidPassword));
|
| +}
|
| +
|
| +// Verifies that this returns PIN for GetAvailableModes.
|
| +TEST_F(QuickUnlockPrivateUnitTest, GetAvailableModes) {
|
| + EXPECT_EQ(GetAvailableModes(),
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN});
|
| +}
|
| +
|
| +// Verifies that an invalid password cannot be used to update the mode list.
|
| +TEST_F(QuickUnlockPrivateUnitTest, SetModesFailsWithInvalidPassword) {
|
| + // Verify there is no active mode.
|
| + EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{});
|
| +
|
| + // Try to enable PIN, but use an invalid password. Verify that no event is
|
| + // raised and GetActiveModes still returns an empty set.
|
| + FailIfModesChanged();
|
| + EXPECT_FALSE(SetModesUsingPassword(
|
| + kInvalidPassword,
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"}));
|
| + EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{});
|
| +}
|
| +
|
| +// Verifies that the quickUnlockPrivate.onActiveModesChanged is only raised when
|
| +// the active set of modes changes.
|
| +TEST_F(QuickUnlockPrivateUnitTest, ModeChangeEventOnlyRaisedWhenModesChange) {
|
| + // Make sure quick unlock is turned off, and then verify that turning it off
|
| + // again does not trigger an event.
|
| + EXPECT_TRUE(SetModes(QuickUnlockModeList{}, CredentialList{}));
|
| + FailIfModesChanged();
|
| + EXPECT_TRUE(SetModes(QuickUnlockModeList{}, CredentialList{}));
|
| +
|
| + // Turn on PIN unlock, and then verify turning it on again and also changing
|
| + // the password does not trigger an event.
|
| + ExpectModesChanged(
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN});
|
| + EXPECT_TRUE(SetModes(
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"}));
|
| + FailIfModesChanged();
|
| + EXPECT_TRUE(SetModes(
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"22"}));
|
| + EXPECT_TRUE(SetModes(
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {""}));
|
| +}
|
| +
|
| +// Ensures that quick unlock can be enabled and disabled by checking the result
|
| +// of quickUnlockPrivate.GetActiveModes and PinStorage::IsPinSet.
|
| +TEST_F(QuickUnlockPrivateUnitTest, SetModesAndGetActiveModes) {
|
| + PinStorage* pin_storage = PinStorageFactory::GetForProfile(profile());
|
| +
|
| + // Update mode to PIN raises an event and updates GetActiveModes.
|
| + ExpectModesChanged(
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN});
|
| + EXPECT_TRUE(SetModes(
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"}));
|
| + EXPECT_EQ(GetActiveModes(),
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN});
|
| + EXPECT_TRUE(pin_storage->IsPinSet());
|
| +
|
| + // SetModes can be used to turn off a quick unlock mode.
|
| + ExpectModesChanged(QuickUnlockModeList{});
|
| + EXPECT_TRUE(SetModes(QuickUnlockModeList{}, CredentialList{}));
|
| + EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{});
|
| + EXPECT_FALSE(pin_storage->IsPinSet());
|
| +}
|
| +
|
| +// Verifies that enabling PIN quick unlock actually talks to the PIN subsystem.
|
| +TEST_F(QuickUnlockPrivateUnitTest, VerifyAuthenticationAgainstPIN) {
|
| + PinStorage* pin_storage = PinStorageFactory::GetForProfile(profile());
|
| +
|
| + EXPECT_TRUE(SetModes(QuickUnlockModeList{}, CredentialList{}));
|
| + EXPECT_FALSE(pin_storage->IsPinSet());
|
| +
|
| + EXPECT_TRUE(SetModes(
|
| + QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"}));
|
| + EXPECT_TRUE(pin_storage->IsPinSet());
|
| +
|
| + pin_storage->MarkStrongAuth();
|
| + pin_storage->ResetUnlockAttemptCount();
|
| + EXPECT_TRUE(pin_storage->TryAuthenticatePin("11"));
|
| + EXPECT_FALSE(pin_storage->TryAuthenticatePin("00"));
|
| +}
|
| +
|
| +// Verifies that the number of modes and the number of passwords given must be
|
| +// the same.
|
| +TEST_F(QuickUnlockPrivateUnitTest, ThrowErrorOnMismatchedParameterCount) {
|
| + EXPECT_FALSE(SetModesWithError("[\"valid\", [\"PIN\"], []]").empty());
|
| + EXPECT_FALSE(SetModesWithError("[\"valid\", [], [\"11\"]]").empty());
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|