Chromium Code Reviews| 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 |
| index 13cbf2d989828ed76abc232bf2888e19a5e651d5..f3e8d9fdff652ad9ac220ce9b30e0db1c487089d 100644 |
| --- 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 |
| @@ -10,14 +10,22 @@ |
| #include "base/bind.h" |
| #include "base/memory/ptr_util.h" |
| +#include "base/stl_util.h" |
| +#include "base/threading/thread_task_runner_handle.h" |
| +#include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h" |
| +#include "chrome/browser/chromeos/login/quick_unlock/pin_storage_prefs.h" |
| #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h" |
| #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h" |
| #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.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/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/extensions/extension_api_unittest.h" |
| #include "chrome/common/pref_names.h" |
| +#include "chromeos/cryptohome/mock_homedir_methods.h" |
| +#include "chromeos/cryptohome/system_salt_getter.h" |
| #include "chromeos/login/auth/fake_extended_authenticator.h" |
| +#include "content/public/test/test_utils.h" |
| #include "extensions/browser/api_test_utils.h" |
| #include "extensions/browser/extension_function_dispatcher.h" |
| @@ -30,6 +38,10 @@ using QuickUnlockMode = quick_unlock_private::QuickUnlockMode; |
| using QuickUnlockModeList = std::vector<QuickUnlockMode>; |
| using CredentialList = std::vector<std::string>; |
| +using ::testing::Invoke; |
| +using ::testing::WithArgs; |
| +using ::testing::_; |
| + |
| namespace chromeos { |
| namespace { |
| @@ -66,7 +78,9 @@ enum ExpectedPinState { |
| } // namespace |
| -class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest { |
| +class QuickUnlockPrivateUnitTest |
| + : public ExtensionApiUnittest, |
| + public ::testing::WithParamInterface<quick_unlock::PinStorageType> { |
| public: |
| QuickUnlockPrivateUnitTest() |
| : fake_user_manager_(new FakeChromeUserManager()), |
| @@ -76,17 +90,60 @@ class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest { |
| void SetUp() override { |
| ExtensionApiUnittest::SetUp(); |
| - quick_unlock::EnableForTesting(quick_unlock::PinStorageType::kPrefs); |
| + quick_unlock::EnableForTesting(GetParam()); |
| + |
| + quick_unlock::PinBackend::ResetForTesting(); |
| + run_loop_ = base::MakeUnique<base::RunLoop>(); |
| + |
| + // PinBackend will run cryptohome routines even if we're just using the pref |
| + // backend. Make sure it has the globals needed. |
| + SystemSaltGetter::Initialize(); |
| + SystemSaltGetter::Get()->SetRawSaltForTesting({1, 2, 3, 4, 5, 6, 7, 8}); |
| + |
| + homedir_methods_ = new cryptohome::MockHomedirMethods(); |
| + ON_CALL(*homedir_methods_, GetKeyDataEx(_, _, _)) |
| + .WillByDefault(WithArgs<2>( |
| + Invoke(this, &QuickUnlockPrivateUnitTest::DoGetKeyDataCallback))); |
| + ON_CALL(*homedir_methods_, AddKeyEx(_, _, _, _, _)) |
| + .WillByDefault(WithArgs<2, 4>( |
| + Invoke(this, &QuickUnlockPrivateUnitTest::DoAddKeyCallback))); |
| + ON_CALL(*homedir_methods_, RemoveKeyEx(_, _, _, _)) |
| + .WillByDefault(WithArgs<2, 3>( |
| + Invoke(this, &QuickUnlockPrivateUnitTest::DoRemoveKeyCallback))); |
| + |
| + // InitializeForTesting takes ownership over |homedir_methods_|. |
| + cryptohome::HomedirMethods::InitializeForTesting(homedir_methods_); |
| // Setup a primary user. |
| auto test_account = AccountId::FromUserEmail(kTestUserEmail); |
| fake_user_manager_->AddUser(test_account); |
| fake_user_manager_->UserLoggedIn(test_account, kTestUserEmailHash, false); |
| + chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting( |
| + fake_user_manager_->GetPrimaryUser(), GetProfile()); |
| + modes_changed_handler_ = base::Bind(&DoNothing); |
| // Ensure that quick unlock is turned off. |
| SetModes(QuickUnlockModeList{}, CredentialList{}); |
| + } |
| - modes_changed_handler_ = base::Bind(&DoNothing); |
| + void TearDown() override { |
| + PumpRunLoop(); |
| + run_loop_.reset(); |
| + |
| + homedir_methods_ = nullptr; |
| + fake_user_manager_ = nullptr; |
| + |
| + ExtensionApiUnittest::TearDown(); |
| + SystemSaltGetter::Shutdown(); |
| + cryptohome::HomedirMethods::Shutdown(); |
| + } |
| + |
| + // Executes all pending tasks. |
| + void PumpRunLoop() { |
| + base::ThreadTaskRunnerHandle::Get()->PostTask( |
| + FROM_HERE, run_loop_->QuitWhenIdleClosure()); |
| + run_loop_->Run(); |
| + run_loop_ = base::MakeUnique<base::RunLoop>(); |
| } |
| // If a mode change event is raised, fail the test. |
| @@ -273,16 +330,34 @@ class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest { |
| CredentialList{}); |
| } |
| + // Returns if the pin is set in the backend. |
| + bool IsPinSetInBackend() { |
|
achuithb
2017/05/13 01:01:58
nit const
jdufault
2017/06/06 18:17:06
This calls PumpRunLoop() which cannot be constant.
|
| + AccountId account_id = AccountId::FromUserEmail(kTestUserEmail); |
|
achuithb
2017/05/13 01:01:57
nit const
jdufault
2017/06/06 18:17:06
Done.
|
| + |
| + bool is_set = false; |
| + quick_unlock::PinBackend::IsSet( |
| + account_id, |
| + base::Bind([](bool* result, bool is_set) { *result = is_set; }, |
| + &is_set)); |
| + |
| + PumpRunLoop(); |
| + |
| + return is_set; |
| + } |
| + |
| 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>( |
| + PumpRunLoop(); |
| + auto result = std::unique_ptr<base::Value>( |
| api_test_utils::RunFunctionWithDelegateAndReturnSingleResult( |
| func, std::move(params), profile(), |
| base::MakeUnique<ExtensionFunctionDispatcher>(profile()), |
| api_test_utils::NONE)); |
| + PumpRunLoop(); |
| + return result; |
| } |
| // Verifies a mode change event is raised and that |expected| is now the |
| @@ -293,7 +368,33 @@ class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest { |
| expect_modes_changed_ = false; |
| } |
| - FakeChromeUserManager* fake_user_manager_; |
| + // Methods used to setup the mock homedir methods instance. |
| + void DoGetKeyDataCallback( |
| + const cryptohome::HomedirMethods::GetKeyDataCallback& callback) { |
| + callback.Run(true, cryptohome::MountError::MOUNT_ERROR_NONE, keys_); |
| + } |
| + void DoAddKeyCallback(const cryptohome::KeyDefinition& key, |
|
achuithb
2017/05/13 01:01:58
let's add some newlines between methods
jdufault
2017/06/06 18:17:06
Done.
|
| + const cryptohome::HomedirMethods::Callback& callback) { |
| + keys_.push_back(key); |
| + callback.Run(true, cryptohome::MountError::MOUNT_ERROR_NONE); |
| + } |
| + void DoRemoveKeyCallback( |
| + const std::string& label, |
| + const cryptohome::HomedirMethods::Callback& callback) { |
| + base::EraseIf(keys_, [&label](const cryptohome::KeyDefinition& key) { |
| + return key.label == label; |
| + }); |
| + callback.Run(true, cryptohome::MountError::MOUNT_ERROR_NONE); |
| + } |
| + |
| + // Run loop that collects all pending tasks. Use |PumpRunLoop| to run them. |
| + std::unique_ptr<base::RunLoop> run_loop_; |
| + |
| + // Keys registered on cryptohome. |
| + std::vector<cryptohome::KeyDefinition> keys_; |
| + |
| + cryptohome::MockHomedirMethods* homedir_methods_ = nullptr; // Unowned |
| + FakeChromeUserManager* fake_user_manager_ = nullptr; |
| ScopedUserManagerEnabler scoped_user_manager_; |
| QuickUnlockPrivateSetModesFunction::ModesChangedEventHandler |
| modes_changed_handler_; |
| @@ -303,19 +404,19 @@ class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest { |
| }; |
| // Verify that password checking works. |
| -TEST_F(QuickUnlockPrivateUnitTest, CheckPassword) { |
| +TEST_P(QuickUnlockPrivateUnitTest, CheckPassword) { |
| EXPECT_TRUE(CheckPassword(kValidPassword)); |
| EXPECT_FALSE(CheckPassword(kInvalidPassword)); |
| } |
| // Verifies that this returns PIN for GetAvailableModes. |
| -TEST_F(QuickUnlockPrivateUnitTest, GetAvailableModes) { |
| +TEST_P(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) { |
| +TEST_P(QuickUnlockPrivateUnitTest, SetModesFailsWithInvalidPassword) { |
| // Verify there is no active mode. |
| EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{}); |
| @@ -330,7 +431,7 @@ TEST_F(QuickUnlockPrivateUnitTest, SetModesFailsWithInvalidPassword) { |
| // Verifies that the quickUnlockPrivate.onActiveModesChanged is only raised when |
| // the active set of modes changes. |
| -TEST_F(QuickUnlockPrivateUnitTest, ModeChangeEventOnlyRaisedWhenModesChange) { |
| +TEST_P(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{})); |
| @@ -352,10 +453,7 @@ TEST_F(QuickUnlockPrivateUnitTest, ModeChangeEventOnlyRaisedWhenModesChange) { |
| // Ensures that quick unlock can be enabled and disabled by checking the result |
| // of quickUnlockPrivate.GetActiveModes and PinStorage::IsPinSet. |
| -TEST_F(QuickUnlockPrivateUnitTest, SetModesAndGetActiveModes) { |
| - quick_unlock::QuickUnlockStorage* quick_unlock_storage = |
| - quick_unlock::QuickUnlockFactory::GetForProfile(profile()); |
| - |
| +TEST_P(QuickUnlockPrivateUnitTest, SetModesAndGetActiveModes) { |
| // Update mode to PIN raises an event and updates GetActiveModes. |
| ExpectModesChanged( |
| QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}); |
| @@ -363,42 +461,49 @@ TEST_F(QuickUnlockPrivateUnitTest, SetModesAndGetActiveModes) { |
| QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"111111"})); |
| EXPECT_EQ(GetActiveModes(), |
| QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}); |
| - EXPECT_TRUE(quick_unlock_storage->pin_storage()->IsPinSet()); |
| + EXPECT_TRUE(IsPinSetInBackend()); |
| // SetModes can be used to turn off a quick unlock mode. |
| ExpectModesChanged(QuickUnlockModeList{}); |
| EXPECT_TRUE(SetModes(QuickUnlockModeList{}, CredentialList{})); |
| EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{}); |
| - EXPECT_FALSE(quick_unlock_storage->pin_storage()->IsPinSet()); |
| + EXPECT_FALSE(IsPinSetInBackend()); |
| } |
| // Verifies that enabling PIN quick unlock actually talks to the PIN subsystem. |
| -TEST_F(QuickUnlockPrivateUnitTest, VerifyAuthenticationAgainstPIN) { |
| +TEST_P(QuickUnlockPrivateUnitTest, VerifyAuthenticationAgainstPIN) { |
| + // Cryptohome authentication does not go through PinBackend at the moment and |
| + // cannot be easily tested. |
| + if (GetParam() == quick_unlock::PinStorageType::kCryptohome) |
| + return; |
| + |
| quick_unlock::QuickUnlockStorage* quick_unlock_storage = |
| quick_unlock::QuickUnlockFactory::GetForProfile(profile()); |
| + quick_unlock::PinStoragePrefs* pin_storage = |
| + quick_unlock_storage->pin_storage_prefs(); |
| EXPECT_TRUE(SetModes(QuickUnlockModeList{}, CredentialList{})); |
| - EXPECT_FALSE(quick_unlock_storage->pin_storage()->IsPinSet()); |
| + EXPECT_FALSE(IsPinSetInBackend()); |
| EXPECT_TRUE(SetModes( |
| QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"111111"})); |
| - EXPECT_TRUE(quick_unlock_storage->pin_storage()->IsPinSet()); |
| + EXPECT_TRUE(IsPinSetInBackend()); |
| quick_unlock_storage->MarkStrongAuth(); |
| - quick_unlock_storage->pin_storage()->ResetUnlockAttemptCount(); |
| - EXPECT_TRUE(quick_unlock_storage->TryAuthenticatePin("111111")); |
| - EXPECT_FALSE(quick_unlock_storage->TryAuthenticatePin("000000")); |
| + pin_storage->ResetUnlockAttemptCount(); |
| + EXPECT_TRUE(pin_storage->TryAuthenticatePin("111111")); |
| + EXPECT_FALSE(pin_storage->TryAuthenticatePin("000000")); |
| } |
| // Verifies that the number of modes and the number of passwords given must be |
| // the same. |
| -TEST_F(QuickUnlockPrivateUnitTest, ThrowErrorOnMismatchedParameterCount) { |
| +TEST_P(QuickUnlockPrivateUnitTest, ThrowErrorOnMismatchedParameterCount) { |
| EXPECT_FALSE(SetModesWithError("[\"valid\", [\"PIN\"], []]").empty()); |
| EXPECT_FALSE(SetModesWithError("[\"valid\", [], [\"11\"]]").empty()); |
| } |
| // Validates PIN error checking in conjuction with policy-related prefs. |
| -TEST_F(QuickUnlockPrivateUnitTest, CheckCredentialProblemReporting) { |
| +TEST_P(QuickUnlockPrivateUnitTest, CheckCredentialProblemReporting) { |
| PrefService* pref_service = profile()->GetPrefs(); |
| // Verify the pin checks work with the default preferences which are minimum |
| @@ -470,7 +575,7 @@ TEST_F(QuickUnlockPrivateUnitTest, CheckCredentialProblemReporting) { |
| CheckPin(PIN_TOO_SHORT | PIN_WEAK_ERROR, "234"); |
| } |
| -TEST_F(QuickUnlockPrivateUnitTest, GetCredentialRequirements) { |
| +TEST_P(QuickUnlockPrivateUnitTest, GetCredentialRequirements) { |
| PrefService* pref_service = profile()->GetPrefs(); |
| // Verify that trying out PINs under the minimum/maximum lengths will send the |
| @@ -490,4 +595,11 @@ TEST_F(QuickUnlockPrivateUnitTest, GetCredentialRequirements) { |
| pref_service->SetInteger(prefs::kPinUnlockMaximumLength, -3); |
| CheckGetCredentialRequirements(1, 0); |
| } |
| + |
| +INSTANTIATE_TEST_CASE_P( |
| + StorageProviders, |
| + QuickUnlockPrivateUnitTest, |
| + ::testing::Values(quick_unlock::PinStorageType::kPrefs, |
| + quick_unlock::PinStorageType::kCryptohome)); |
| + |
| } // namespace chromeos |