Add serializer for InMemoryStorageBackend::Buckets 16/24316/3
authorAleksander Zdyb <a.zdyb@partner.samsung.com>
Mon, 14 Jul 2014 12:23:26 +0000 (14:23 +0200)
committerAleksander Zdyb <a.zdyb@partner.samsung.com>
Wed, 16 Jul 2014 10:38:37 +0000 (12:38 +0200)
Change-Id: Ia5def8f5c8b5bb1e16c20f2adc1757849f440866

src/service/storage/StorageSerializer.cpp
src/service/storage/StorageSerializer.h
test/CMakeLists.txt
test/storage/serializer/dump.cpp
test/storage/serializer/serialize.cpp [new file with mode: 0644]

index 8813fc9..e7857b6 100644 (file)
  * @brief       Implementation of Cynara::StorageSerializer methods
  */
 
-#include "StorageSerializer.h"
+#include <algorithm>
+#include <ios>
+#include <iostream>
 
 #include "types/PolicyBucket.h"
 #include "types/PolicyCollection.h"
 
-#include <algorithm>
+#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) {
index 33108a4..789f263 100644 (file)
@@ -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<std::shared_ptr<StorageSerializer>(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<typename Arg1, typename... Args>
-    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();
index 52117a5..f3eee4b 100644 (file)
@@ -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
 )
index b75928e..d85950f 100644 (file)
@@ -17,7 +17,7 @@
  * @file        dump.cpp
  * @author      Aleksander Zdyb <a.zdyb@partner.samsung.com>
  * @version     1.0
- * @brief       Test for dumping feature of Cynara::Serializer
+ * @brief       Tests for dumping feature of Cynara::StorageSerializer
  */
 
 #include <gtest/gtest.h>
@@ -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 (file)
index 0000000..dddd30d
--- /dev/null
@@ -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 <a.zdyb@partner.samsung.com>
+ * @version     1.0
+ * @brief       Tests for dumping feature of Cynara::StorageSerializer
+ */
+
+#include <iterator>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <storage/InMemoryStorageBackend.h>
+#include <storage/StorageSerializer.h>
+#include <types/PolicyBucketId.h>
+
+class FakeStreamForBucketId {
+public:
+    MOCK_METHOD1(streamForBucketId,
+                 std::shared_ptr<Cynara::StorageSerializer>(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<FakeStorageSerializer>();
+
+    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<std::string> expectedRecords = {
+        "bucket1;0x0;",
+        "bucket2;0x0;",
+        "bucket3;0xFFFE;bucket2"
+    };
+
+    // Split stream into records
+    auto actualRecords = std::vector<std::string>(std::istream_iterator<std::string>(outStream),
+                                                  std::istream_iterator<std::string>());
+
+    ASSERT_THAT(actualRecords, UnorderedElementsAreArray(expectedRecords));
+}