From 5aa2755d07baff6c9f53c676453889c5e6872866 Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Wed, 2 Jul 2014 09:29:02 +0200 Subject: [PATCH] Add Cynara::StorageDeserializer Change-Id: I4a981bea8b2a43641ff213cbce9cb09fa24cd2dc --- src/common/types/PolicyBucket.h | 12 +- src/service/storage/BucketDeserializer.h | 4 + src/service/storage/StorageDeserializer.cpp | 86 ++++++++++++++ src/service/storage/StorageDeserializer.h | 50 ++++++++ test/CMakeLists.txt | 2 + test/storage/serializer/deserialize.cpp | 178 ++++++++++++++++++++++++++++ 6 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 src/service/storage/StorageDeserializer.cpp create mode 100644 src/service/storage/StorageDeserializer.h create mode 100644 test/storage/serializer/deserialize.cpp diff --git a/src/common/types/PolicyBucket.h b/src/common/types/PolicyBucket.h index 4607fd4..2e76713 100644 --- a/src/common/types/PolicyBucket.h +++ b/src/common/types/PolicyBucket.h @@ -22,8 +22,8 @@ entity name */ -#ifndef CYNARA_COMMON_TYPES_POLICYBUCKET_H -#define CYNARA_COMMON_TYPES_POLICYBUCKET_H +#ifndef SRC_COMMON_TYPES_POLICYBUCKET_H_ +#define SRC_COMMON_TYPES_POLICYBUCKET_H_ #include "PolicyCollection.h" #include "PolicyKey.h" @@ -46,6 +46,8 @@ class PolicyBucket { public: PolicyBucket() : m_defaultPolicy(PredefinedPolicyType::DENY) {} + PolicyBucket(const PolicyBucketId &id, const PolicyResult &defaultPolicy) + : m_defaultPolicy(defaultPolicy), m_id(id) {} PolicyBucket(const PolicyCollection &policies) : m_policyCollection(policies), m_defaultPolicy(PredefinedPolicyType::DENY) {} @@ -77,7 +79,11 @@ public: void setDefaultPolicy(const PolicyResult &defaultPolicy) { m_defaultPolicy = defaultPolicy; } + + void setPolicyCollection(const PolicyCollection &policies) { + m_policyCollection = policies; + } }; } /* namespace Cynara */ -#endif /* CYNARA_COMMON_TYPES_POLICYBUCKET_H */ +#endif /* SRC_COMMON_TYPES_POLICYBUCKET_H_ */ diff --git a/src/service/storage/BucketDeserializer.h b/src/service/storage/BucketDeserializer.h index 16ccaa3..2c50fab 100644 --- a/src/service/storage/BucketDeserializer.h +++ b/src/service/storage/BucketDeserializer.h @@ -31,7 +31,11 @@ namespace Cynara { +class StorageDeserializer; + class BucketDeserializer { +friend StorageDeserializer; + public: static PolicyCollection loadPolicies(std::istream &is); diff --git a/src/service/storage/StorageDeserializer.cpp b/src/service/storage/StorageDeserializer.cpp new file mode 100644 index 0000000..af5e3c0 --- /dev/null +++ b/src/service/storage/StorageDeserializer.cpp @@ -0,0 +1,86 @@ +/* + * 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 StorageDeserializer.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Implementation for Cynara::StorageDeserializer + */ + +#include + +#include +#include +#include + +#include +#include + +namespace Cynara { + +StorageDeserializer::StorageDeserializer(std::istream &inStream, + BucketStreamOpener bucketStreamOpener) + : m_inStream(inStream), m_bucketStreamOpener(bucketStreamOpener) {} + +void StorageDeserializer::initBuckets(InMemoryStorageBackend::Buckets &buckets) { + buckets.clear(); + + for(std::size_t lineNum = 1; !m_inStream.eof(); ++lineNum) { + std::string line; + std::getline(m_inStream, line, StorageSerializer::recordSeparator()); + + if (line.empty()) + break; + + size_t beginToken = 0; + auto bucketId = StorageDeserializer::parseBucketId(line, beginToken); + auto policyType = BucketDeserializer::parsePolicyType(line, beginToken); + auto metadata = BucketDeserializer::parseMetadata(line, beginToken); + + buckets[bucketId] = PolicyBucket(bucketId, PolicyResult(policyType, metadata)); + } +} + +void StorageDeserializer::loadBuckets(InMemoryStorageBackend::Buckets &buckets) { + for (auto &bucketIter : buckets) { + const auto &bucketId = bucketIter.first; + auto &bucket = bucketIter.second; + + auto inStream = m_bucketStreamOpener(bucketId); + + if (inStream != nullptr && inStream->good()) { + auto policies = BucketDeserializer::loadPolicies(*inStream); + bucket.setPolicyCollection(policies); + } else { + // TODO: Throw? + } + } +} + +PolicyBucketId StorageDeserializer::parseBucketId(const std::string &line, + std::size_t &beginToken) { + auto bucketNameEndToken = line.find(StorageSerializer::fieldSeparator(), beginToken); + if (bucketNameEndToken != std::string::npos) { + auto bucketName = line.substr(beginToken, bucketNameEndToken - beginToken); + beginToken = bucketNameEndToken + 1; + return bucketName; + } + + // TODO: Should throw other exception + throw BucketRecordCorruptedException(line); +} + +} /* namespace Cynara */ diff --git a/src/service/storage/StorageDeserializer.h b/src/service/storage/StorageDeserializer.h new file mode 100644 index 0000000..e7e799b --- /dev/null +++ b/src/service/storage/StorageDeserializer.h @@ -0,0 +1,50 @@ +/* + * 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 StorageDeserializer.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief Headers for Cynara::StorageDeserializer + */ +#ifndef SRC_SERVICE_STORAGE_STORAGEDESERIALIZER_H_ +#define SRC_SERVICE_STORAGE_STORAGEDESERIALIZER_H_ + +#include + +#include +#include +#include + +namespace Cynara { + +class StorageDeserializer { +public: + typedef std::function(const std::string &)> BucketStreamOpener; + StorageDeserializer(std::istream &inStream, BucketStreamOpener m_bucketStreamOpener); + void initBuckets(InMemoryStorageBackend::Buckets &buckets); + void loadBuckets(InMemoryStorageBackend::Buckets &buckets); + +protected: + static PolicyBucketId parseBucketId(const std::string &line, std::size_t &beginToken); + +private: + std::istream &m_inStream; + BucketStreamOpener m_bucketStreamOpener; +}; + +} /* namespace Cynara */ + +#endif /* SRC_SERVICE_STORAGE_STORAGEDESERIALIZER_H_ */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4f43fdb..0b53fe5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -29,6 +29,7 @@ SET(CYNARA_SOURCES_FOR_TESTS ${CYNARA_SRC}/common/types/PolicyBucket.cpp ${CYNARA_SRC}/service/storage/InMemoryStorageBackend.cpp ${CYNARA_SRC}/service/storage/BucketDeserializer.cpp + ${CYNARA_SRC}/service/storage/StorageDeserializer.cpp ${CYNARA_SRC}/service/storage/StorageSerializer.cpp ${CYNARA_SRC}/common/types/PolicyKey.cpp ${CYNARA_SRC}/common/types/PolicyType.cpp @@ -44,6 +45,7 @@ SET(CYNARA_TESTS_SOURCES storage/inmemorystoragebackend/search.cpp storage/inmemorystoragebackend/buckets.cpp storage/serializer/bucket_load.cpp + storage/serializer/deserialize.cpp storage/serializer/dump.cpp common/types/policybucket.cpp helpers.cpp diff --git a/test/storage/serializer/deserialize.cpp b/test/storage/serializer/deserialize.cpp new file mode 100644 index 0000000..5bcc773 --- /dev/null +++ b/test/storage/serializer/deserialize.cpp @@ -0,0 +1,178 @@ +/* + * 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 deserialize.cpp + * @author Aleksander Zdyb + * @version 1.0 + * @brief Tests for Cynara::StorageDeserializer + */ + + +#include +#include + +#include +#include + +#include +#include +#include + + +// TODO: Move to .h, because it's used also in bucket_load.cpp +MATCHER_P(PolicyPtrEq, policy, "") { + return std::tie(policy->key(), policy->result()) + == std::tie(arg->key(), arg->result()); +} + +MATCHER_P(PolicyBucketIdPolicyEq, expected, "") { + auto bucket1 = expected.second; + auto bucket2 = arg.second; + return std::tie(expected.first, bucket1.id(), bucket1.defaultPolicy()) + == std::tie(arg.first, bucket2.id(), bucket2.defaultPolicy()); +} + +#define COMPARE_BUCKETS(id, bucket) \ + PolicyBucketIdPolicyEq(std::pair((id), (bucket))) + + +class FakeStreamForBucketId { +public: + MOCK_METHOD1(streamForBucketId, std::shared_ptr(const std::string &)); +}; + +class StorageDeserializerFixture : public ::testing::Test { +public: + Cynara::StorageDeserializer::BucketStreamOpener nullStreamOpener = + [] (const std::string &) -> std::shared_ptr { + return nullptr; + }; +}; + +using namespace Cynara; + +TEST_F(StorageDeserializerFixture, init_default_only) { + using ::testing::UnorderedElementsAre; + + std::istringstream ss(";0"); + StorageDeserializer deserializer(ss, nullStreamOpener); + + InMemoryStorageBackend::Buckets buckets; + deserializer.initBuckets(buckets); + + ASSERT_THAT(buckets, UnorderedElementsAre( + COMPARE_BUCKETS("", PolicyBucket("", PredefinedPolicyType::DENY)) + )); +} + +TEST_F(StorageDeserializerFixture, init_more) { + using ::testing::UnorderedElementsAre; + + std::istringstream ss(";0\n" + "bucket2;0\n" + "bucket3;0xFFFE;bucket2\n"); + + StorageDeserializer deserializer(ss, nullStreamOpener); + InMemoryStorageBackend::Buckets buckets; + deserializer.initBuckets(buckets); + + ASSERT_THAT(buckets, UnorderedElementsAre( + COMPARE_BUCKETS("", PolicyBucket("", PredefinedPolicyType::DENY)), + COMPARE_BUCKETS("bucket2", PolicyBucket("bucket2", PredefinedPolicyType::DENY)), + COMPARE_BUCKETS("bucket3", PolicyBucket("bucket3", + PolicyResult(PredefinedPolicyType::BUCKET, "bucket2"))) + )); +} + +// Add bucket and check, if it's overwritten if exists in file +TEST_F(StorageDeserializerFixture, init_overwrite) { + using ::testing::UnorderedElementsAre; + + std::istringstream ss(";0"); + StorageDeserializer deserializer(ss, nullStreamOpener); + + InMemoryStorageBackend::Buckets buckets; + buckets.insert({ "", PolicyBucket("fakeId", PredefinedPolicyType::ALLOW) }); + deserializer.initBuckets(buckets); + + ASSERT_THAT(buckets, UnorderedElementsAre( + COMPARE_BUCKETS("", PolicyBucket("", PredefinedPolicyType::DENY)) + )); +} + +TEST_F(StorageDeserializerFixture, load_buckets_plus_policies) { + using ::testing::_; + using ::testing::Return; + using ::testing::UnorderedElementsAre; + + InMemoryStorageBackend::Buckets buckets; + buckets.insert({ "", PolicyBucket("", PredefinedPolicyType::DENY) }); + + std::istringstream bucketsStream; // Won't be used; buckets are pre-inserted above + FakeStreamForBucketId streamOpener; + auto streamOpenerFunc = std::bind(&FakeStreamForBucketId::streamForBucketId, &streamOpener, + std::placeholders::_1); + StorageDeserializer deserializer(bucketsStream, streamOpenerFunc); + + auto defaultBucketStream = std::make_shared("c;u;p;0;meta"); + EXPECT_CALL(streamOpener, streamForBucketId("")) + .WillOnce(Return(defaultBucketStream)); + + deserializer.loadBuckets(buckets); + + // Check if our bucket is still there + ASSERT_THAT(buckets, UnorderedElementsAre( + COMPARE_BUCKETS("", PolicyBucket("", PredefinedPolicyType::DENY)) + )); + + auto expectedPolicy = std::make_shared(PolicyKey("c", "u", "p"), + PolicyResult(PredefinedPolicyType::DENY, "meta")); + + // Check policy was inserted into bucket + ASSERT_THAT(buckets.at("").policyCollection(), UnorderedElementsAre( + PolicyPtrEq(expectedPolicy) + )); +} + +TEST_F(StorageDeserializerFixture, load_buckets) { + using ::testing::_; + using ::testing::Return; + using ::testing::UnorderedElementsAre; + + // Pre-insert some buckets + InMemoryStorageBackend::Buckets buckets; + buckets.insert({ "", PolicyBucket("", PredefinedPolicyType::DENY) }); + buckets.insert({ "bucket1", PolicyBucket("bucket1", PredefinedPolicyType::DENY) }); + buckets.insert({ "bucket2", PolicyBucket("bucket2", PredefinedPolicyType::DENY) }); + + std::istringstream bucketsStream; // Won't be used; buckets are pre-inserted above + FakeStreamForBucketId streamOpener; + auto streamOpenerFunc = std::bind(&FakeStreamForBucketId::streamForBucketId, &streamOpener, + std::placeholders::_1); + StorageDeserializer deserializer(bucketsStream, streamOpenerFunc); + + // Check, if streamOpener was called for each bucket + EXPECT_CALL(streamOpener, streamForBucketId("")) + .WillOnce(Return(nullptr)); + + EXPECT_CALL(streamOpener, streamForBucketId("bucket1")) + .WillOnce(Return(nullptr)); + + EXPECT_CALL(streamOpener, streamForBucketId("bucket2")) + .WillOnce(Return(nullptr)); + + deserializer.loadBuckets(buckets); +} -- 2.7.4