From 3120b1dd3b649009988768f4a067afc0957a43b6 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 14 Jul 2014 14:23:26 +0200 Subject: [PATCH] Add serializer for InMemoryStorageBackend::Buckets Change-Id: Ia5def8f5c8b5bb1e16c20f2adc1757849f440866 --- src/service/storage/StorageSerializer.cpp | 33 ++++++++- src/service/storage/StorageSerializer.h | 12 +++- test/CMakeLists.txt | 1 + test/storage/serializer/dump.cpp | 23 ++++-- test/storage/serializer/serialize.cpp | 116 ++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 test/storage/serializer/serialize.cpp diff --git a/src/service/storage/StorageSerializer.cpp b/src/service/storage/StorageSerializer.cpp index 8813fc9..e7857b6 100644 --- a/src/service/storage/StorageSerializer.cpp +++ b/src/service/storage/StorageSerializer.cpp @@ -20,12 +20,14 @@ * @brief Implementation of Cynara::StorageSerializer methods */ -#include "StorageSerializer.h" +#include +#include +#include #include "types/PolicyBucket.h" #include "types/PolicyCollection.h" -#include +#include "StorageSerializer.h" namespace Cynara { @@ -34,6 +36,29 @@ char StorageSerializer::m_recordSeparator = '\n'; StorageSerializer::StorageSerializer(std::ostream &os) : m_outStream(os) {} +void StorageSerializer::dump(const InMemoryStorageBackend::Buckets &buckets, + BucketStreamOpener streamOpener) { + + for (const auto bucketIter : buckets) { + const auto &bucket = bucketIter.second; + + dumpFields(bucket.id(), bucket.defaultPolicy().policyType(), + bucket.defaultPolicy().metadata()); + } + + for (const auto bucketIter : buckets) { + const auto &bucketId = bucketIter.first; + const auto &bucket = bucketIter.second; + auto bucketSerializer = streamOpener(bucketId); + + if (bucketSerializer != nullptr) { + bucketSerializer->dump(bucket); + } else { + // TODO: Throw? + } + } +} + void StorageSerializer::dump(const PolicyBucket& bucket) { const auto &policies = bucket.policyCollection(); @@ -48,7 +73,9 @@ void StorageSerializer::dump(const PolicyKey &key) { } void StorageSerializer::dump(const PolicyType &policyType) { - outStream() << policyType; + auto oldFormat = m_outStream.flags(); + outStream() << "0x" << std::uppercase << std::hex << policyType; + m_outStream.flags(oldFormat); } void StorageSerializer::dump(const PolicyResult::PolicyMetadata &metadata) { diff --git a/src/service/storage/StorageSerializer.h b/src/service/storage/StorageSerializer.h index 33108a4..789f263 100644 --- a/src/service/storage/StorageSerializer.h +++ b/src/service/storage/StorageSerializer.h @@ -23,6 +23,7 @@ #ifndef SRC_SERVICE_STORAGE_STORAGESERIALIZER_H_ #define SRC_SERVICE_STORAGE_STORAGESERIALIZER_H_ +#include "InMemoryStorageBackend.h" #include "types/PolicyBucketId.h" #include "types/PolicyCollection.h" #include "types/PolicyResult.h" @@ -37,12 +38,19 @@ class PolicyKey; class StorageSerializer { public: + typedef std::function(const PolicyBucketId &)> + BucketStreamOpener; + StorageSerializer(std::ostream &os); - void dump(const PolicyBucket &bucket); + virtual ~StorageSerializer() = default; + + virtual void dump(const InMemoryStorageBackend::Buckets &buckets, + BucketStreamOpener streamOpener); + virtual void dump(const PolicyBucket &bucket); protected: template - inline void dumpFields(const Arg1 arg1, const Args&... args) { + inline void dumpFields(const Arg1 &arg1, const Args&... args) { dump(arg1); if (sizeof...(Args) > 0) { outStream() << fieldSeparator(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 52117a5..f3eee4b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -70,6 +70,7 @@ SET(CYNARA_TESTS_SOURCES storage/serializer/bucket_load.cpp storage/serializer/deserialize.cpp storage/serializer/dump.cpp + storage/serializer/serialize.cpp common/types/policybucket.cpp helpers.cpp ) diff --git a/test/storage/serializer/dump.cpp b/test/storage/serializer/dump.cpp index b75928e..d85950f 100644 --- a/test/storage/serializer/dump.cpp +++ b/test/storage/serializer/dump.cpp @@ -17,7 +17,7 @@ * @file dump.cpp * @author Aleksander Zdyb * @version 1.0 - * @brief Test for dumping feature of Cynara::Serializer + * @brief Tests for dumping feature of Cynara::StorageSerializer */ #include @@ -49,7 +49,6 @@ TEST(serializer_dump, dump_bucket) { PolicyKey pk1 = Helpers::generatePolicyKey("1"); PolicyKey pk2 = Helpers::generatePolicyKey("2"); - PolicyBucket bucket = {{ Policy::simpleWithKey(pk1, PredefinedPolicyType::ALLOW), Policy::simpleWithKey(pk2, PredefinedPolicyType::DENY) }}; @@ -57,9 +56,14 @@ TEST(serializer_dump, dump_bucket) { StorageSerializer serializer(outputStream); serializer.dump(bucket); + // TODO: Cynara::PolicyCollection is a vector, but in future version this may change + // and so, we should not expect the exact order of records in serialized stream + // See: StorageSerializerFixture::dump_buckets in serialize.cpp std::stringstream expected; - expected << pk1.toString() << ";" << PredefinedPolicyType::ALLOW << ";" << "\n" - << pk2.toString() << ";" << PredefinedPolicyType::DENY << ";" << "\n"; + expected + << std::hex << std::uppercase + << pk1.toString() << ";" << "0x" << PredefinedPolicyType::ALLOW << ";" << "\n" + << pk2.toString() << ";" << "0x" << PredefinedPolicyType::DENY << ";" << "\n"; ASSERT_EQ(expected.str(), outputStream.str()); } @@ -78,10 +82,15 @@ TEST(serializer_dump, dump_bucket_bucket) { StorageSerializer serializer(outputStream); serializer.dump(bucket); + // TODO: Cynara::PolicyCollection is a vector, but in future version this may change + // and so, we should not expect the exact order of records in serialized stream + // See: StorageSerializerFixture::dump_buckets in serialize.cpp std::stringstream expected; - expected << pk1.toString() << ";" << PredefinedPolicyType::BUCKET << ";" << bucketId << "\n" - << pk2.toString() << ";" << PredefinedPolicyType::DENY << ";" << "\n" - << pk3.toString() << ";" << PredefinedPolicyType::BUCKET << ";" << bucketId << "\n"; + expected + << std::hex << std::uppercase + << pk1.toString() << ";" << "0x" << PredefinedPolicyType::BUCKET << ";" << bucketId << "\n" + << pk2.toString() << ";" << "0x" << PredefinedPolicyType::DENY << ";" << "\n" + << pk3.toString() << ";" << "0x" << PredefinedPolicyType::BUCKET << ";" << bucketId << "\n"; ASSERT_EQ(expected.str(), outputStream.str()); } diff --git a/test/storage/serializer/serialize.cpp b/test/storage/serializer/serialize.cpp new file mode 100644 index 0000000..dddd30d --- /dev/null +++ b/test/storage/serializer/serialize.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file serialize.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Tests for dumping feature of Cynara::StorageSerializer + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +class FakeStreamForBucketId { +public: + MOCK_METHOD1(streamForBucketId, + std::shared_ptr(const Cynara::PolicyBucketId &)); + + Cynara::StorageSerializer::BucketStreamOpener streamOpener() { + return std::bind(&FakeStreamForBucketId::streamForBucketId, this, std::placeholders::_1); + } +}; + +// Fake StorageSerializer for Cynara::PolicyBucket +class FakeStorageSerializer : public Cynara::StorageSerializer { +public: + FakeStorageSerializer() : Cynara::StorageSerializer(outStream) {} + MOCK_METHOD1(dump, void(const Cynara::PolicyBucket &bucket)); + std::ostringstream outStream; +}; + +class StorageSerializerFixture : public ::testing::Test { +public: + virtual ~StorageSerializerFixture() = default; + + Cynara::InMemoryStorageBackend::Buckets buckets; + FakeStreamForBucketId fakeStreamOpener; +}; + +using namespace Cynara; + +// Be sure no calls to streamForBucketId() are made +// and output stream is not touched +TEST_F(StorageSerializerFixture, dump_buckets_empty) { + std::ostringstream outStream; + StorageSerializer serializer(outStream); + serializer.dump(InMemoryStorageBackend::Buckets(), fakeStreamOpener.streamOpener()); + + // Stream should be empty + ASSERT_EQ(0, outStream.tellp()); +} + +TEST_F(StorageSerializerFixture, dump_buckets) { + using ::testing::_; + using ::testing::Property; + using ::testing::Return; + using ::testing::UnorderedElementsAreArray; + + // Will be returned as serializer for buckets + auto fakeBucketSerializer = std::make_shared(); + + buckets = { + { "bucket1", PolicyBucket("bucket1", PredefinedPolicyType::DENY) }, + { "bucket2", PolicyBucket("bucket2", PredefinedPolicyType::DENY) }, + { "bucket3", + PolicyBucket("bucket3", PolicyResult(PredefinedPolicyType::BUCKET, "bucket2")) } + }; + + std::stringstream outStream; + StorageSerializer dbSerializer(outStream); + + // Make sure stream was opened for each bucket + EXPECT_CALL(fakeStreamOpener, streamForBucketId(_)) + .Times(buckets.size()).WillRepeatedly(Return(fakeBucketSerializer)); + + // Make sure every bucket was dumped + for (const auto &bucket : buckets) { + EXPECT_CALL(*fakeBucketSerializer, dump(Property(&PolicyBucket::id, bucket.first))); + } + + dbSerializer.dump(buckets, fakeStreamOpener.streamOpener()); + + std::vector expectedRecords = { + "bucket1;0x0;", + "bucket2;0x0;", + "bucket3;0xFFFE;bucket2" + }; + + // Split stream into records + auto actualRecords = std::vector(std::istream_iterator(outStream), + std::istream_iterator()); + + ASSERT_THAT(actualRecords, UnorderedElementsAreArray(expectedRecords)); +} -- 2.7.4