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..c5f7e4d29f2465c44343bdc8e16dfff170052f62 |
--- /dev/null |
+++ b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc |
@@ -0,0 +1,265 @@ |
+// 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/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 ModeList = std::vector<QuickUnlockMode>; |
+ |
+namespace chromeos { |
+namespace { |
+const char* kTestUserEmail = "testuser@gmail.com"; |
+const char* kTestUserEmailHash = "testuser@gmail.com-hash"; |
+const char* kValidPassword = "valid"; |
+const char* kInvalidPassword = "invalid"; |
+} |
+ |
+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 fake authenticator so quickUnlockPrivate.checkPassword doesn't |
+ // call cryptohome methods. |
+ QuickUnlockPrivateSetModesFunction::SetCreateAuthenticatorForTesting( |
+ [](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; |
+ }); |
+ |
+ // Stub out event handling since we are not setting up an event router. |
+ // Some tests can and do override this by installing their own event |
+ // handler. |
+ SetModesChangedEventHandler([](const ModeList& modes) {}); |
+ |
+ // 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({}, {}); |
+ } |
+ |
+ void TearDown() override { |
+ QuickUnlockPrivateSetModesFunction::SetCreateAuthenticatorForTesting( |
+ nullptr); |
+ SetModesChangedEventHandler(nullptr); |
+ |
+ ExtensionApiUnittest::TearDown(); |
+ } |
+ |
+ void SetModesChangedEventHandler( |
+ QuickUnlockPrivateSetModesFunction::ModesChangedEventHandler handler) { |
+ QuickUnlockPrivateSetModesFunction::SetModesChangedEventHandlerForTesting( |
+ handler); |
+ } |
+ |
+ // Wrapper for chrome.quickUnlockPrivate.getAvailableModes. |
+ ModeList GetAvailableModes() { |
+ // Run the function. |
+ std::unique_ptr<base::Value> result = |
+ RunFunction(new QuickUnlockPrivateGetAvailableModesFunction(), |
+ new base::ListValue()); |
+ |
+ // Extract the results. |
+ ModeList 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. |
+ ModeList GetActiveModes() { |
+ std::unique_ptr<base::Value> result = RunFunction( |
+ new QuickUnlockPrivateGetActiveModesFunction(), new base::ListValue()); |
+ |
+ ModeList 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 ModeList& modes, |
+ const std::vector<std::string>& passwords) { |
+ return SetModesUsingPassword(kValidPassword, modes, passwords); |
+ } |
+ |
+ // Wrapper for chrome.quickUnlockPrivate.setModes. |
+ bool SetModesUsingPassword(const std::string& password, |
+ const ModeList& modes, |
+ const std::vector<std::string>& passwords) { |
+ // Serialize the parameters. |
+ auto params = 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)); |
+ |
+ // Run function and extract the result. |
+ std::unique_ptr<base::Value> func_result = |
+ RunFunction(new QuickUnlockPrivateSetModesFunction(), params); |
+ bool result; |
+ EXPECT_TRUE(func_result->GetAsBoolean(&result)); |
+ return result; |
+ } |
+ |
+ std::string SetModesWithError(const std::string& args) { |
+ return api_test_utils::RunFunctionAndReturnError( |
+ new QuickUnlockPrivateSetModesFunction(), 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, {}, {}); |
+ } |
+ |
+ private: |
+ // Runs the given |func| with the given |params|. This function takes |
+ // ownership over |func| and |params|; they are passed as raw pointers for |
+ // caller convenience. |
+ std::unique_ptr<base::Value> RunFunction(UIThreadExtensionFunction* func, |
+ base::ListValue* params) { |
+ return std::unique_ptr<base::Value>( |
+ api_test_utils::RunFunctionWithDelegateAndReturnSingleResult( |
+ func, base::WrapUnique(params), profile(), |
+ base::WrapUnique(new ExtensionFunctionDispatcher(profile())), |
+ api_test_utils::NONE)); |
+ } |
+ |
+ FakeChromeUserManager* fake_user_manager_; |
+ ScopedUserManagerEnabler scoped_user_manager_; |
+ |
+ 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(), |
+ ModeList{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(), ModeList{}); |
+ |
+ // Try to enable PIN, but use an invalid password. Verify that no event is |
+ // raised and GetActiveModes still returns an empty set. |
+ SetModesChangedEventHandler([](const ModeList& modes) { FAIL(); }); |
+ EXPECT_FALSE(SetModesUsingPassword( |
+ kInvalidPassword, {QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"})); |
+ EXPECT_EQ(GetActiveModes(), ModeList{}); |
+} |
+ |
+// 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({}, {})); |
+ SetModesChangedEventHandler([](const ModeList& modes) { FAIL(); }); |
+ EXPECT_TRUE(SetModes({}, {})); |
+ |
+ // Turn on PIN unlock, and then verify turning it on again and also changing |
+ // the password does not trigger an event. |
+ SetModesChangedEventHandler([](const ModeList& modes) {}); |
+ EXPECT_TRUE(SetModes({QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"})); |
+ SetModesChangedEventHandler([](const ModeList& modes) { FAIL(); }); |
+ EXPECT_TRUE(SetModes({QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"22"})); |
+ EXPECT_TRUE(SetModes({QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {""})); |
+} |
+ |
+TEST_F(QuickUnlockPrivateUnitTest, SetModesAndGetActiveModes) { |
+ // Update mode to PIN raises an event and updates GetActiveModes. |
+ SetModesChangedEventHandler([](const ModeList& modes) { |
+ EXPECT_EQ(modes, ModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}); |
+ }); |
+ EXPECT_TRUE(SetModes({QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"})); |
+ EXPECT_EQ(GetActiveModes(), ModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}); |
+ |
+ // SetModes can be used to turn off a quick unlock mode. |
+ SetModesChangedEventHandler( |
+ [](const ModeList& modes) { EXPECT_EQ(modes, ModeList{}); }); |
+ EXPECT_TRUE(SetModes({}, {})); |
+ EXPECT_EQ(GetActiveModes(), ModeList{}); |
+} |
+ |
+// 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({}, {})); |
+ EXPECT_FALSE(pin_storage->IsPinSet()); |
+ |
+ EXPECT_TRUE(SetModes({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")); |
+} |
+ |
+TEST_F(QuickUnlockPrivateUnitTest, ThrowErrorOnMismatchedParameterCount) { |
+ EXPECT_FALSE(SetModesWithError("[\"valid\", [\"PIN\"], []]").empty()); |
+ EXPECT_FALSE(SetModesWithError("[\"valid\", [], [\"11\"]]").empty()); |
+} |
+ |
+} // namespace chromeos |