| Index: chrome/browser/chromeos/login/owner_manager_unittest.cc
|
| diff --git a/chrome/browser/chromeos/login/owner_manager_unittest.cc b/chrome/browser/chromeos/login/owner_manager_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1db81e91d8d2b5ea724a6449b1e6a72b78c8fa3a
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/login/owner_manager_unittest.cc
|
| @@ -0,0 +1,352 @@
|
| +// 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 "chrome/browser/chromeos/login/owner_manager.h"
|
| +
|
| +#include <cert.h>
|
| +#include <keyhi.h>
|
| +#include <keythi.h> // KeyType enum
|
| +#include <pk11pub.h>
|
| +#include <stdlib.h>
|
| +
|
| +#include <string>
|
| +
|
| +#include "base/file_path.h"
|
| +#include "base/file_util.h"
|
| +#include "base/logging.h"
|
| +#include "base/nss_util_internal.h"
|
| +#include "base/nss_util.h"
|
| +#include "base/scoped_temp_dir.h"
|
| +#include "chrome/browser/chrome_thread.h"
|
| +#include "chrome/common/notification_registrar.h"
|
| +#include "chrome/common/notification_service.h"
|
| +#include "chrome/common/notification_type.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using ::testing::DoAll;
|
| +using ::testing::Invoke;
|
| +using ::testing::Return;
|
| +using ::testing::SetArgumentPointee;
|
| +using ::testing::_;
|
| +
|
| +namespace chromeos {
|
| +
|
| +namespace {
|
| +
|
| +class MockKeyUtils : public OwnerKeyUtils {
|
| + public:
|
| + MockKeyUtils() {}
|
| + ~MockKeyUtils() {}
|
| + MOCK_METHOD2(GenerateKeyPair, bool(SECKEYPrivateKey** private_key_out,
|
| + SECKEYPublicKey** public_key_out));
|
| + MOCK_METHOD1(ExportPublicKeyViaDbus, bool(SECKEYPublicKey* key));
|
| + MOCK_METHOD2(ExportPublicKeyToFile, bool(SECKEYPublicKey* key,
|
| + const FilePath& key_file));
|
| + MOCK_METHOD1(ImportPublicKey, SECKEYPublicKey*(const FilePath& key_file));
|
| + MOCK_METHOD1(FindPrivateKey, SECKEYPrivateKey*(SECKEYPublicKey* key));
|
| + MOCK_METHOD2(DestroyKeys, void(SECKEYPrivateKey* private_key,
|
| + SECKEYPublicKey* public_key));
|
| + MOCK_METHOD0(GetOwnerKeyFilePath, FilePath());
|
| +};
|
| +
|
| +class MockInjector : public OwnerKeyUtils::Factory {
|
| + public:
|
| + // Takes ownership of |mock|.
|
| + explicit MockInjector(MockKeyUtils* mock) :
|
| + transient_(mock),
|
| + delete_transient_(true) {
|
| + }
|
| +
|
| + virtual ~MockInjector() {
|
| + if (delete_transient_)
|
| + delete transient_;
|
| + }
|
| +
|
| + // If this is called, its caller takes ownership of |transient_|.
|
| + // If it's never called, |transient_| remains our problem.
|
| + OwnerKeyUtils* CreateOwnerKeyUtils() {
|
| + delete_transient_ = false;
|
| + return transient_;
|
| + }
|
| +
|
| + private:
|
| + MockKeyUtils* transient_;
|
| + bool delete_transient_;
|
| +};
|
| +
|
| +class KeyUser : public OwnerManager::Delegate {
|
| + public:
|
| + explicit KeyUser(const OwnerManager::KeyOpCode expected)
|
| + : expected_(expected) {
|
| + }
|
| +
|
| + virtual ~KeyUser() {}
|
| +
|
| + void OnKeyOpComplete(const OwnerManager::KeyOpCode return_code,
|
| + const std::string& payload) {
|
| + MessageLoop::current()->Quit();
|
| + EXPECT_EQ(expected_, return_code);
|
| + }
|
| +
|
| + const OwnerManager::KeyOpCode expected_;
|
| +};
|
| +
|
| +static bool Win(SECKEYPublicKey* key) {
|
| + MessageLoop::current()->Quit();
|
| + return true;
|
| +}
|
| +
|
| +static bool Fail(SECKEYPublicKey* key) {
|
| + MessageLoop::current()->Quit();
|
| + return false;
|
| +}
|
| +
|
| +} // anonymous namespace
|
| +
|
| +class OwnerManagerTest : public ::testing::Test,
|
| + public NotificationObserver {
|
| + public:
|
| + OwnerManagerTest()
|
| + : message_loop_(MessageLoop::TYPE_UI),
|
| + ui_thread_(ChromeThread::UI, &message_loop_),
|
| + file_thread_(ChromeThread::FILE),
|
| + fake_public_key_(reinterpret_cast<SECKEYPublicKey*>(7)),
|
| + fake_private_key_(reinterpret_cast<SECKEYPrivateKey*>(7)),
|
| + success_expected_(false),
|
| + quit_on_observe_(true),
|
| + mock_(new MockKeyUtils),
|
| + injector_(mock_) /* injector_ takes ownership of mock_ */ {
|
| + registrar_.Add(
|
| + this,
|
| + NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE,
|
| + NotificationService::AllSources());
|
| + }
|
| + virtual ~OwnerManagerTest() {}
|
| +
|
| + virtual void SetUp() {
|
| + // Mimic ownership.
|
| + ASSERT_TRUE(tmpdir_.CreateUniqueTempDir());
|
| + ASSERT_TRUE(file_util::CreateTemporaryFileInDir(tmpdir_.path(), &tmpfile_));
|
| +
|
| + file_thread_.Start();
|
| + OwnerKeyUtils::set_factory(&injector_);
|
| + }
|
| +
|
| + virtual void TearDown() {
|
| + OwnerKeyUtils::set_factory(NULL);
|
| + }
|
| +
|
| + void StartUnowned() {
|
| + file_util::Delete(tmpfile_, false);
|
| + }
|
| +
|
| + void InjectKeys(OwnerManager* manager) {
|
| + manager->public_key_ = fake_public_key_;
|
| + manager->private_key_ = fake_private_key_;
|
| + }
|
| +
|
| + // NotificationObserver implementation.
|
| + virtual void Observe(NotificationType type,
|
| + const NotificationSource& source,
|
| + const NotificationDetails& details) {
|
| + if (type == NotificationType::OWNER_KEY_FETCH_ATTEMPT_COMPLETE) {
|
| + EXPECT_EQ(success_expected_,
|
| + NULL != *Details<SECKEYPublicKey*>(details).ptr());
|
| + if (quit_on_observe_)
|
| + MessageLoop::current()->Quit();
|
| + }
|
| + }
|
| +
|
| + void ExpectKeyFetchSuccess(bool should_succeed) {
|
| + success_expected_ = should_succeed;
|
| + }
|
| + void SetQuitOnKeyFetch(bool should_quit) { quit_on_observe_ = should_quit; }
|
| +
|
| + ScopedTempDir tmpdir_;
|
| + FilePath tmpfile_;
|
| +
|
| + MessageLoop message_loop_;
|
| + ChromeThread ui_thread_;
|
| + ChromeThread file_thread_;
|
| +
|
| + SECKEYPublicKey* fake_public_key_;
|
| + SECKEYPrivateKey* fake_private_key_;
|
| +
|
| + NotificationRegistrar registrar_;
|
| + bool success_expected_;
|
| + bool quit_on_observe_;
|
| +
|
| + MockKeyUtils* mock_;
|
| + MockInjector injector_;
|
| +};
|
| +
|
| +TEST_F(OwnerManagerTest, LoadKeyUnowned) {
|
| + StartUnowned();
|
| +
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + EXPECT_FALSE(manager->StartLoadOwnerKeyAttempt());
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, LoadOwnerKeyFail) {
|
| + SECKEYPublicKey* to_return = NULL;
|
| +
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_))
|
| + .WillOnce(Return(to_return))
|
| + .RetiresOnSaturation();
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + EXPECT_TRUE(manager->StartLoadOwnerKeyAttempt());
|
| +
|
| + // Run remaining events, until ExportPublicKeyViaDbus().
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, LoadOwnerKey) {
|
| + ExpectKeyFetchSuccess(true);
|
| +
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_))
|
| + .WillOnce(Return(fake_public_key_))
|
| + .RetiresOnSaturation();
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + EXPECT_TRUE(manager->StartLoadOwnerKeyAttempt());
|
| +
|
| + // Run remaining events, until ExportPublicKeyViaDbus().
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, TakeOwnershipAlreadyOwned) {
|
| +
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + EXPECT_FALSE(manager->StartTakeOwnershipAttempt());
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, KeyGenerationFail) {
|
| + StartUnowned();
|
| +
|
| + EXPECT_CALL(*mock_, GenerateKeyPair(_, _))
|
| + .WillOnce(Return(false))
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + EXPECT_TRUE(manager->StartTakeOwnershipAttempt());
|
| +
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, KeyExportFail) {
|
| + StartUnowned();
|
| +
|
| + EXPECT_CALL(*mock_, GenerateKeyPair(_, _))
|
| + .WillOnce(Return(true))
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*mock_, ExportPublicKeyViaDbus(_))
|
| + .WillOnce(Invoke(Fail))
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*mock_, DestroyKeys(_, _))
|
| + .Times(1)
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + EXPECT_TRUE(manager->StartTakeOwnershipAttempt());
|
| +
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, TakeOwnership) {
|
| + StartUnowned();
|
| + ExpectKeyFetchSuccess(true);
|
| +
|
| + EXPECT_CALL(*mock_, GenerateKeyPair(_, _))
|
| + .WillOnce(DoAll(SetArgumentPointee<1>(fake_public_key_),
|
| + Return(true)))
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*mock_, ExportPublicKeyViaDbus(_))
|
| + .WillOnce(Invoke(Win))
|
| + .RetiresOnSaturation();
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + EXPECT_TRUE(manager->StartTakeOwnershipAttempt());
|
| +
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, NotYetOwnedVerify) {
|
| + StartUnowned();
|
| +
|
| + // Since this shouldn't happen, don't want it to end the test if it does.
|
| + SetQuitOnKeyFetch(false);
|
| +
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + KeyUser delegate(OwnerManager::KEY_UNAVAILABLE);
|
| + EXPECT_FALSE(manager->StartVerifyAttempt("", "", &delegate));
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, AlreadyHaveKeysVerify) {
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + InjectKeys(manager.get());
|
| + KeyUser delegate(OwnerManager::SUCCESS);
|
| + EXPECT_TRUE(manager->StartVerifyAttempt("", "", &delegate));
|
| +
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, GetKeyFailDuringVerify) {
|
| + ExpectKeyFetchSuccess(false);
|
| + SECKEYPublicKey* to_return = NULL;
|
| +
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_))
|
| + .WillOnce(Return(to_return))
|
| + .RetiresOnSaturation();
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + KeyUser delegate(OwnerManager::KEY_UNAVAILABLE);
|
| + EXPECT_TRUE(manager->StartVerifyAttempt("", "", &delegate));
|
| +
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +TEST_F(OwnerManagerTest, GetKeyAndVerify) {
|
| + ExpectKeyFetchSuccess(true);
|
| + SetQuitOnKeyFetch(false);
|
| +
|
| + EXPECT_CALL(*mock_, GetOwnerKeyFilePath())
|
| + .WillRepeatedly(Return(tmpfile_));
|
| + EXPECT_CALL(*mock_, ImportPublicKey(tmpfile_))
|
| + .WillOnce(Return(fake_public_key_))
|
| + .RetiresOnSaturation();
|
| +
|
| + scoped_refptr<OwnerManager> manager(new OwnerManager);
|
| + KeyUser delegate(OwnerManager::SUCCESS);
|
| + EXPECT_TRUE(manager->StartVerifyAttempt("", "", &delegate));
|
| +
|
| + message_loop_.Run();
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|