Add Cynara::StorageDeserializer
authorAleksander Zdyb <a.zdyb@partner.samsung.com>
Wed, 2 Jul 2014 07:29:02 +0000 (09:29 +0200)
committerRafal Krypa <r.krypa@samsung.com>
Thu, 3 Jul 2014 12:19:10 +0000 (14:19 +0200)
Change-Id: I4a981bea8b2a43641ff213cbce9cb09fa24cd2dc

src/common/types/PolicyBucket.h
src/service/storage/BucketDeserializer.h
src/service/storage/StorageDeserializer.cpp [new file with mode: 0644]
src/service/storage/StorageDeserializer.h [new file with mode: 0644]
test/CMakeLists.txt
test/storage/serializer/deserialize.cpp [new file with mode: 0644]

index 4607fd4..2e76713 100644 (file)
@@ -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_ */
index 16ccaa3..2c50fab 100644 (file)
 
 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 (file)
index 0000000..af5e3c0
--- /dev/null
@@ -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 <a.zdyb@partner.samsung.com>
+ * @version     1.0
+ * @brief       Implementation for Cynara::StorageDeserializer
+ */
+
+#include <service/storage/StorageDeserializer.h>
+
+#include <exceptions/BucketRecordCorruptedException.h>
+#include <service/storage/BucketDeserializer.h>
+#include <service/storage/StorageSerializer.h>
+
+#include <iostream>
+#include <string>
+
+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 (file)
index 0000000..e7e799b
--- /dev/null
@@ -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 <a.zdyb@partner.samsung.com>
+ * @version     1.0
+ * @brief       Headers for Cynara::StorageDeserializer
+ */
+#ifndef SRC_SERVICE_STORAGE_STORAGEDESERIALIZER_H_
+#define SRC_SERVICE_STORAGE_STORAGEDESERIALIZER_H_
+
+#include <service/storage/InMemoryStorageBackend.h>
+
+#include <istream>
+#include <memory>
+#include <functional>
+
+namespace Cynara {
+
+class StorageDeserializer {
+public:
+    typedef std::function<std::shared_ptr<std::istream>(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_ */
index 4f43fdb..0b53fe5 100644 (file)
@@ -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 (file)
index 0000000..5bcc773
--- /dev/null
@@ -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 <a.zdyb@partner.samsung.com>
+ * @version     1.0
+ * @brief       Tests for Cynara::StorageDeserializer
+ */
+
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <common/types/PolicyBucket.h>
+#include <service/storage/StorageDeserializer.h>
+
+#include <tuple>
+#include <memory>
+#include <istream>
+
+
+// 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<PolicyBucketId, PolicyBucket>((id), (bucket)))
+
+
+class FakeStreamForBucketId {
+public:
+    MOCK_METHOD1(streamForBucketId, std::shared_ptr<std::istream>(const std::string &));
+};
+
+class StorageDeserializerFixture : public ::testing::Test {
+public:
+    Cynara::StorageDeserializer::BucketStreamOpener nullStreamOpener =
+            [] (const std::string &) -> std::shared_ptr<std::istream> {
+                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<std::istringstream>("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<Policy>(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);
+}