blob: 020d1dc73f9ff1df6d397a9f9ca2650f8888f126 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS 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 "chaps/object_pool_impl.h"
#include <map>
#include <string>
#include <vector>
#include <base/memory/scoped_ptr.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "chaps/chaps_factory_mock.h"
#include "chaps/handle_generator_mock.h"
#include "chaps/object_importer_mock.h"
#include "chaps/object_mock.h"
#include "chaps/object_store_mock.h"
#include "chaps/proto_bindings/attributes.pb.h"
using chromeos::SecureBlob;
using std::map;
using std::string;
using std::vector;
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SetArgumentPointee;
namespace chaps {
namespace {
Object* CreateObjectMock() {
ObjectMock* o = new ObjectMock();
o->SetupFake();
EXPECT_CALL(*o, GetObjectClass()).Times(AnyNumber());
EXPECT_CALL(*o, SetAttributes(_, _)).Times(AnyNumber());
EXPECT_CALL(*o, FinalizeNewObject()).WillRepeatedly(Return(CKR_OK));
EXPECT_CALL(*o, Copy(_)).WillRepeatedly(Return(CKR_OK));
EXPECT_CALL(*o, IsTokenObject()).Times(AnyNumber());
EXPECT_CALL(*o, IsPrivate()).Times(AnyNumber());
EXPECT_CALL(*o, IsAttributePresent(_)).Times(AnyNumber());
EXPECT_CALL(*o, GetAttributeString(_)).Times(AnyNumber());
EXPECT_CALL(*o, GetAttributeInt(_, _)).Times(AnyNumber());
EXPECT_CALL(*o, GetAttributeBool(_, _)).Times(AnyNumber());
EXPECT_CALL(*o, SetAttributeString(_, _)).Times(AnyNumber());
EXPECT_CALL(*o, SetAttributeInt(_, _)).Times(AnyNumber());
EXPECT_CALL(*o, SetAttributeBool(_, _)).Times(AnyNumber());
EXPECT_CALL(*o, GetAttributeMap()).Times(AnyNumber());
EXPECT_CALL(*o, set_handle(_)).Times(AnyNumber());
EXPECT_CALL(*o, set_store_id(_)).Times(AnyNumber());
EXPECT_CALL(*o, handle()).Times(AnyNumber());
EXPECT_CALL(*o, store_id()).Times(AnyNumber());
return o;
}
int CreateHandle() {
static int last_handle = 0;
return ++last_handle;
}
} // namespace
// A test fixture for object pools.
class TestObjectPool : public ::testing::Test {
public:
TestObjectPool() {
// Setup the factory to return functional fake objects.
EXPECT_CALL(factory_, CreateObject())
.WillRepeatedly(Invoke(CreateObjectMock));
EXPECT_CALL(handle_generator_, CreateHandle())
.WillRepeatedly(Invoke(CreateHandle));
// Create object pools to test with.
store_ = new ObjectStoreMock();
importer_ = new ObjectImporterMock();
pool_.reset(
new ObjectPoolImpl(&factory_, &handle_generator_, store_, importer_));
pool2_.reset(new ObjectPoolImpl(&factory_, &handle_generator_, NULL, NULL));
}
ChapsFactoryMock factory_;
ObjectStoreMock* store_;
ObjectImporterMock* importer_;
HandleGeneratorMock handle_generator_;
scoped_ptr<ObjectPoolImpl> pool_;
scoped_ptr<ObjectPoolImpl> pool2_;
};
// Test object pool initialization when using an object store.
TEST_F(TestObjectPool, Init) {
// Create some fake persistent objects for the mock store to return.
map<int, ObjectBlob> persistent_objects;
AttributeList l;
Attribute* a = l.add_attribute();
a->set_type(CKA_ID);
a->set_value("value");
string s;
l.SerializeToString(&s);
persistent_objects[1].blob = s;
persistent_objects[1].is_private = true;
persistent_objects[2].blob = "not_valid_protobuf";
persistent_objects[2].is_private = false;
string tmp(32, 'A');
SecureBlob key(tmp.begin(), tmp.end());
EXPECT_CALL(*store_, GetInternalBlob(_, _)).WillRepeatedly(Return(false));
EXPECT_CALL(*store_, SetInternalBlob(_, _)).WillRepeatedly(Return(true));
EXPECT_CALL(*store_, SetEncryptionKey(key))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, LoadPublicObjectBlobs(_))
.WillOnce(Return(false))
.WillRepeatedly(DoAll(SetArgumentPointee<0>(persistent_objects),
Return(true)));
EXPECT_CALL(*store_, LoadPrivateObjectBlobs(_))
.WillOnce(Return(false))
.WillRepeatedly(DoAll(SetArgumentPointee<0>(persistent_objects),
Return(true)));
EXPECT_CALL(*importer_, ImportObjects(pool_.get()))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
EXPECT_CALL(*importer_, FinishImportAsync(pool_.get()))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
// Loading of public objects happens when the pool is initialized.
EXPECT_TRUE(pool2_->Init());
EXPECT_FALSE(pool_->Init());
EXPECT_TRUE(pool_->Init());
EXPECT_TRUE(pool_->Init());
// Loading of private objects happens when the encryption key is set.
EXPECT_TRUE(pool2_->SetEncryptionKey(key));
EXPECT_FALSE(pool_->SetEncryptionKey(key));
EXPECT_TRUE(pool_->SetEncryptionKey(key));
EXPECT_TRUE(pool_->SetEncryptionKey(key));
vector<const Object*> v;
scoped_ptr<Object> find_all(CreateObjectMock());
EXPECT_TRUE(pool_->Find(find_all.get(), &v));
ASSERT_EQ(3, v.size());
EXPECT_TRUE(v[0]->GetAttributeString(CKA_ID) == string("value"));
EXPECT_TRUE(v[1]->GetAttributeString(CKA_ID) == string("value"));
EXPECT_TRUE(v[2]->GetAttributeString(CKA_ID) == string("value"));
}
// Test the methods that should just pass through to the object store.
TEST_F(TestObjectPool, StorePassThrough) {
string s("test");
SecureBlob blob("test");
EXPECT_CALL(*store_, GetInternalBlob(1, _))
.WillOnce(Return(false))
.WillOnce(Return(true));
EXPECT_CALL(*store_, SetInternalBlob(1, s))
.WillOnce(Return(false))
.WillOnce(Return(true));
EXPECT_CALL(*store_, LoadPublicObjectBlobs(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, LoadPrivateObjectBlobs(_))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, SetEncryptionKey(blob))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
EXPECT_FALSE(pool2_->GetInternalBlob(1, &s));
EXPECT_FALSE(pool2_->SetInternalBlob(1, s));
EXPECT_TRUE(pool2_->SetEncryptionKey(blob));
EXPECT_FALSE(pool_->GetInternalBlob(1, &s));
EXPECT_TRUE(pool_->GetInternalBlob(1, &s));
EXPECT_FALSE(pool_->SetInternalBlob(1, s));
EXPECT_TRUE(pool_->SetInternalBlob(1, s));
EXPECT_FALSE(pool_->SetEncryptionKey(blob));
EXPECT_TRUE(pool_->SetEncryptionKey(blob));
}
// Test basic object management operations.
TEST_F(TestObjectPool, InsertFindUpdateDelete) {
EXPECT_CALL(*store_, InsertObjectBlob(_, _))
.WillOnce(Return(false))
.WillRepeatedly(DoAll(SetArgumentPointee<1>(3), Return(true)));
EXPECT_CALL(*store_, UpdateObjectBlob(3, _))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
EXPECT_CALL(*store_, DeleteObjectBlob(3))
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
vector<const Object*> v;
scoped_ptr<Object> find_all(CreateObjectMock());
EXPECT_TRUE(pool2_->Find(find_all.get(), &v));
EXPECT_EQ(0, v.size());
EXPECT_TRUE(pool2_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool2_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool2_->Find(find_all.get(), &v));
ASSERT_EQ(2, v.size());
Object* o = pool2_->GetModifiableObject(v[0]);
EXPECT_TRUE(pool2_->Flush(o));
EXPECT_TRUE(pool2_->Delete(v[0]));
EXPECT_TRUE(pool2_->Delete(v[1]));
v.clear();
EXPECT_TRUE(pool2_->Find(find_all.get(), &v));
EXPECT_EQ(0, v.size());
// Now with the persistent pool.
EXPECT_TRUE(pool_->Find(find_all.get(), &v));
EXPECT_EQ(0, v.size());
Object* tmp = CreateObjectMock();
EXPECT_FALSE(pool_->Insert(tmp));
EXPECT_TRUE(pool_->Insert(tmp));
EXPECT_TRUE(pool_->Find(find_all.get(), &v));
ASSERT_EQ(1, v.size());
o = pool_->GetModifiableObject(v[0]);
EXPECT_FALSE(pool_->Flush(o));
EXPECT_TRUE(pool_->Flush(o));
EXPECT_FALSE(pool_->Delete(v[0]));
EXPECT_TRUE(pool_->Delete(v[0]));
v.clear();
EXPECT_TRUE(pool_->Find(find_all.get(), &v));
EXPECT_EQ(0, v.size());
}
// Test handling of an invalid object pointer.
TEST_F(TestObjectPool, UnknownObject) {
scoped_ptr<Object> o(CreateObjectMock());
EXPECT_FALSE(pool_->Flush(o.get()));
EXPECT_FALSE(pool_->Delete(o.get()));
EXPECT_FALSE(pool2_->Flush(o.get()));
EXPECT_FALSE(pool2_->Delete(o.get()));
}
// Test multiple insertion of the same object pointer.
TEST_F(TestObjectPool, DuplicateObject) {
Object* o = CreateObjectMock();
EXPECT_CALL(*store_, InsertObjectBlob(_, _))
.WillRepeatedly(DoAll(SetArgumentPointee<1>(3), Return(true)));
EXPECT_TRUE(pool_->Insert(o));
EXPECT_FALSE(pool_->Insert(o));
Object* o2 = CreateObjectMock();
EXPECT_TRUE(pool2_->Insert(o2));
EXPECT_FALSE(pool2_->Insert(o2));
}
TEST_F(TestObjectPool, DeleteAll) {
EXPECT_CALL(*store_, InsertObjectBlob(_, _))
.WillRepeatedly(DoAll(SetArgumentPointee<1>(3), Return(true)));
EXPECT_CALL(*store_, DeleteAllObjectBlobs())
.WillOnce(Return(false))
.WillRepeatedly(Return(true));
EXPECT_TRUE(pool_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool_->Insert(CreateObjectMock()));
vector<const Object*> v;
scoped_ptr<Object> find_all(CreateObjectMock());
EXPECT_TRUE(pool_->Find(find_all.get(), &v));
EXPECT_EQ(3, v.size());
// Test the store failure is passed back but cached objects are still deleted.
EXPECT_FALSE(pool_->DeleteAll());
v.clear();
EXPECT_TRUE(pool_->Find(find_all.get(), &v));
EXPECT_EQ(0, v.size());
EXPECT_TRUE(pool_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool_->Insert(CreateObjectMock()));
// Test with store success.
EXPECT_TRUE(pool_->DeleteAll());
v.clear();
EXPECT_TRUE(pool_->Find(find_all.get(), &v));
EXPECT_EQ(0, v.size());
// Test with session pool.
EXPECT_CALL(*store_, InsertObjectBlob(_, _)).Times(0);
EXPECT_CALL(*store_, DeleteAllObjectBlobs()).Times(0);
EXPECT_TRUE(pool2_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool2_->Insert(CreateObjectMock()));
EXPECT_TRUE(pool2_->Insert(CreateObjectMock()));
v.clear();
EXPECT_TRUE(pool2_->Find(find_all.get(), &v));
EXPECT_EQ(3, v.size());
EXPECT_TRUE(pool2_->DeleteAll());
v.clear();
EXPECT_TRUE(pool2_->Find(find_all.get(), &v));
EXPECT_EQ(0, v.size());
}
} // namespace chaps
int main(int argc, char** argv) {
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}