Implement a better data structure to store policies 21/25221/4
authorAleksander Zdyb <a.zdyb@partner.samsung.com>
Thu, 31 Jul 2014 13:01:13 +0000 (15:01 +0200)
committerAleksander Zdyb <a.zdyb@partner.samsung.com>
Thu, 31 Jul 2014 13:01:13 +0000 (15:01 +0200)
A new map-based structure was used to store policies
in Cynara::PolicyBucket. This allows policy checks
to be much faster.

PolicyBucket interface was changed, so the operation
required a lot of refactorings across many storage classes.
Most of functions are now simpler, clearer and decoupled
from each other. Tests has been adjusted. No public API changes
were required.

Change-Id: Ida9dc8eb31120b27cf9547e56840dd27390de247

20 files changed:
src/common/CMakeLists.txt
src/common/types/PolicyBucket.cpp
src/common/types/PolicyBucket.h
src/common/types/PolicyCollection.h
src/service/storage/InMemoryStorageBackend.cpp
src/service/storage/Storage.cpp
src/service/storage/StorageDeserializer.cpp
src/service/storage/StorageSerializer.cpp
test/CMakeLists.txt
test/common/types/policybucket.cpp
test/helpers.h
test/storage/inmemorystoragebackend/buckets.cpp
test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h
test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
test/storage/inmemorystoragebackend/search.cpp
test/storage/serializer/deserialize.cpp
test/storage/serializer/dump.cpp
test/storage/serializer/dump_load.cpp
test/storage/storage/check.cpp
test/storage/storage/policies.cpp

index 92874a7..5f25aea 100644 (file)
@@ -45,6 +45,7 @@ SET(COMMON_SOURCES
     ${COMMON_PATH}/system/signals.cpp
     ${COMMON_PATH}/types/PolicyBucket.cpp
     ${COMMON_PATH}/types/PolicyKey.cpp
+    ${COMMON_PATH}/types/PolicyKeyHelpers.cpp
     )
 
 IF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
index 4aea491..ab60604 100644 (file)
  * @brief       Implementation of Cynara::PolicyBucket methods
  */
 
+#include <sstream>
+
+#include <types/PolicyCollection.h>
+#include <types/PolicyKeyHelpers.h>
 
 #include "PolicyBucket.h"
 
@@ -28,15 +32,50 @@ namespace Cynara {
 PolicyBucket PolicyBucket::filtered(const PolicyKey &key) const {
     PolicyBucket result;
 
-    const auto &policies = policyCollection();
-    std::copy_if(policies.begin(), policies.end(), std::back_inserter(result.policyCollection()),
-        [=] (PolicyCollection::value_type policy) {
-            return policy->key() == key;
-    });
+    const auto &policies = m_policyCollection;
+    const auto variants = PolicyKeyHelpers::keyVariants(key);
+
+    for (const auto &variant : variants) {
+        const auto policyIter = policies.find(variant);
+        if (policyIter != policies.end()) {
+            result.m_policyCollection[policyIter->first] = policyIter->second;
+        }
+    }
 
     // Inherit original policy
     result.setDefaultPolicy(defaultPolicy());
     return result;
 }
 
+void PolicyBucket::insertPolicy(PolicyPtr policy) {
+    const auto gluedKey = PolicyKeyHelpers::glueKey(policy->key());
+    m_policyCollection[gluedKey] = policy;
+}
+
+void PolicyBucket::deletePolicy(const PolicyKey &key) {
+    const auto gluedKey = PolicyKeyHelpers::glueKey(key);
+    m_policyCollection.erase(gluedKey);
+}
+
+void PolicyBucket::deletePolicy(std::function<bool(PolicyPtr)> predicate) {
+    auto &policies = m_policyCollection;
+
+    for (auto iter = policies.begin(); iter != policies.end(); ) {
+        if (predicate(iter->second)) {
+            policies.erase(iter++);
+        } else {
+            ++iter;
+        }
+    }
+}
+
+PolicyMap PolicyBucket::makePolicyMap(const PolicyCollection &policies) {
+    PolicyMap result;
+    for (const auto &policy : policies) {
+        const auto gluedKey = PolicyKeyHelpers::glueKey(policy->key());
+        result[gluedKey] = policy;
+    }
+    return result;
+}
+
 }  // namespace Cynara
index 120cf36..b865d9e 100644 (file)
 #ifndef SRC_COMMON_TYPES_POLICYBUCKET_H_
 #define SRC_COMMON_TYPES_POLICYBUCKET_H_
 
-#include "PolicyCollection.h"
-#include "PolicyKey.h"
-#include "Policy.h"
-#include "exceptions/NotImplementedException.h"
-#include "types/pointers.h"
-#include "types/PolicyType.h"
-#include "PolicyBucketId.h"
-
-#include <string>
-#include <memory>
 #include <algorithm>
+#include <memory>
+#include <string>
+
+#include <exceptions/NotImplementedException.h>
+#include <types/pointers.h>
+#include <types/Policy.h>
+#include <types/PolicyBucketId.h>
+#include <types/PolicyCollection.h>
+#include <types/PolicyKey.h>
+#include <types/PolicyType.h>
 
 namespace Cynara {
 
@@ -45,45 +45,60 @@ const PolicyBucketId defaultPolicyBucketId("");
 class PolicyBucket {
 public:
 
+    typedef PolicyCollection::value_type value_type;
+    typedef const_policy_iterator const_iterator;
+
     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_policyCollection(makePolicyMap(policies)),
           m_defaultPolicy(PredefinedPolicyType::DENY) {}
 
     PolicyBucket filtered(const PolicyKey &key) const;
+    void insertPolicy(PolicyPtr policy);
+    void deletePolicy(const PolicyKey &key);
+
+    // TODO: Try to change interface, so this method is not needed
+    void deletePolicy(std::function<bool(PolicyPtr)> predicate);
+
+    static PolicyMap makePolicyMap(const PolicyCollection &policies);
 
 private:
-    PolicyCollection m_policyCollection;
+    PolicyMap m_policyCollection;
     PolicyResult m_defaultPolicy;
     PolicyBucketId m_id;
 
 public:
-    const PolicyResult &defaultPolicy() const {
-        return m_defaultPolicy;
+
+    const_policy_iterator begin(void) const {
+        return const_policy_iterator(m_policyCollection.begin());
     }
 
-    const PolicyBucketId &id() const {
-        return m_id;
+    const_policy_iterator end(void) const {
+        return const_policy_iterator(m_policyCollection.end());
+    }
+
+    PolicyMap::size_type size(void) const noexcept {
+        return m_policyCollection.size();
+    }
+
+    bool empty(void) const noexcept {
+        return m_policyCollection.empty();
     }
 
-    PolicyCollection &policyCollection() {
-        return m_policyCollection;
+    const PolicyResult &defaultPolicy(void) const {
+        return m_defaultPolicy;
     }
 
-    const PolicyCollection &policyCollection() const {
-        return m_policyCollection;
+    const PolicyBucketId &id(void) const {
+        return m_id;
     }
 
     // TODO: Consider StorageBackend to be only one to alter this property
     void setDefaultPolicy(const PolicyResult &defaultPolicy) {
         m_defaultPolicy = defaultPolicy;
     }
-
-    void setPolicyCollection(const PolicyCollection &policies) {
-        m_policyCollection = policies;
-    }
 };
 
 } /* namespace Cynara */
index 0c864d0..bb25ee0 100644 (file)
  * @brief       This file defines a collection of policies
  */
 
-#ifndef CYNARA_COMMON_TYPES_POLICYCOLLECTION_H
-#define CYNARA_COMMON_TYPES_POLICYCOLLECTION_H
-
-#include "types/pointers.h"
+#ifndef SRC_COMMON_TYPES_POLICYCOLLECTION_H_
+#define SRC_COMMON_TYPES_POLICYCOLLECTION_H_
 
+#include <unordered_map>
 #include <vector>
 
+#include "types/pointers.h"
+
 namespace Cynara {
 
 typedef std::vector<PolicyPtr> PolicyCollection;
+typedef std::unordered_map<std::string, PolicyPtr> PolicyMap;
+
+class const_policy_iterator : public PolicyMap::const_iterator
+{
+  public:
+    const_policy_iterator() : PolicyMap::const_iterator() {};
+    const_policy_iterator(const PolicyMap::const_iterator &other)
+        : PolicyMap::const_iterator(other) {};
+
+    PolicyPtr operator*(void) {
+        return PolicyMap::const_iterator::operator*().second;
+    }
+};
 
 } // namespace Cynara
 
-#endif /* CYNARA_COMMON_TYPES_POLICYCOLLECTION_H     */
+#endif /* SRC_COMMON_TYPES_POLICYCOLLECTION_H_     */
index a0283f7..e46e485 100644 (file)
@@ -108,8 +108,7 @@ PolicyBucket InMemoryStorageBackend::searchBucket(const PolicyBucketId &bucketId
 void InMemoryStorageBackend::insertPolicy(const PolicyBucketId &bucketId, PolicyPtr policy) {
     try {
         auto &bucket = buckets().at(bucketId);
-        auto &policies = bucket.policyCollection();
-        policies.push_back(policy);
+        bucket.insertPolicy(policy);
     } catch (const std::out_of_range &) {
         throw BucketNotExistsException(bucketId);
     }
@@ -147,11 +146,7 @@ void InMemoryStorageBackend::deletePolicy(const PolicyBucketId &bucketId, const
     try {
         // TODO: Move the erase code to PolicyCollection maybe?
         auto &bucket = buckets().at(bucketId);
-        auto &policies = bucket.policyCollection();
-        policies.erase(remove_if(policies.begin(), policies.end(),
-                [key](PolicyPtr policy) -> bool {
-                    return policy->key() == key;
-            }), policies.end());
+        bucket.deletePolicy(key);
     } catch (const std::out_of_range &) {
         throw BucketNotExistsException(bucketId);
     }
@@ -170,11 +165,8 @@ void InMemoryStorageBackend::deleteLinking(const PolicyBucketId &bucketId) {
     };
 
     for (auto &bucketIter : buckets()) {
-        // TODO: Move the erase code to PolicyCollection maybe?
         auto &bucket = bucketIter.second;
-        auto &policies = bucket.policyCollection();
-        policies.erase(remove_if(policies.begin(), policies.end(), bucketIdMatches),
-                policies.end());
+        bucket.deletePolicy(bucketIdMatches);
     }
 }
 
index 7bf3f9c..f8e7b8a 100644 (file)
@@ -46,8 +46,6 @@ PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey
     bool hasMinimal = false;
     PolicyResult minimal = bucket.defaultPolicy();
 
-    const auto &policies = bucket.policyCollection();
-
     auto proposeMinimal = [&minimal, &hasMinimal](const PolicyResult &candidate) {
         if (hasMinimal == false) {
             minimal = candidate;
@@ -57,8 +55,8 @@ PolicyResult Storage::minimalPolicy(const PolicyBucket &bucket, const PolicyKey
         hasMinimal = true;
     };
 
-    for (const auto &policyRecord : policies) {
-        const auto &policyResult = policyRecord->result();
+    for (const auto policy : bucket) {
+        const auto &policyResult = policy->result();
 
         switch (policyResult.policyType()) {
             case PredefinedPolicyType::DENY:
@@ -85,10 +83,6 @@ void Storage::insertPolicies(const std::map<PolicyBucketId, std::vector<Policy>>
         const PolicyBucketId &bucketId = group.first;
         const auto &policies = group.second;
         for (const auto &policy : policies) {
-            auto existingPolicies = m_backend.searchBucket(bucketId, policy.key());
-            for (auto existingPolicy : existingPolicies.policyCollection()) {
-                m_backend.deletePolicy(bucketId, existingPolicy->key());
-            }
             m_backend.insertPolicy(bucketId, std::make_shared<Policy>(policy));
         }
     }
index b0522e8..1f2181d 100644 (file)
@@ -67,7 +67,10 @@ void StorageDeserializer::loadBuckets(Buckets &buckets) {
 
         auto bucketDeserializer = m_bucketStreamOpener(bucketId);
         if (bucketDeserializer != nullptr) {
-            bucket.setPolicyCollection(bucketDeserializer->loadPolicies());
+            const auto policies = bucketDeserializer->loadPolicies();
+            for (const auto policy : policies) {
+                bucket.insertPolicy(policy);
+            }
         } else {
             throw BucketDeserializationException(bucketId);
         }
index db5f331..5d458d4 100644 (file)
@@ -65,9 +65,7 @@ void StorageSerializer::dump(const Buckets &buckets,
 }
 
 void StorageSerializer::dump(const PolicyBucket& bucket) {
-    const auto &policies = bucket.policyCollection();
-
-    for (auto it = std::begin(policies); it != std::end(policies); ++it) {
+    for (auto it = std::begin(bucket); it != std::end(bucket); ++it) {
         const auto &policy = *it;
         dump(policy);
     }
index 72c77fd..b391a4c 100644 (file)
@@ -50,6 +50,7 @@ SET(CYNARA_SRC ${PROJECT_SOURCE_DIR}/../src)
 SET(CYNARA_SOURCES_FOR_TESTS
     ${CYNARA_SRC}/service/storage/Storage.cpp
     ${CYNARA_SRC}/common/types/PolicyBucket.cpp
+    ${CYNARA_SRC}/common/types/PolicyKeyHelpers.cpp
     ${CYNARA_SRC}/service/storage/InMemoryStorageBackend.cpp
     ${CYNARA_SRC}/service/storage/BucketDeserializer.cpp
     ${CYNARA_SRC}/service/storage/StorageDeserializer.cpp
index 9e47c21..52916e8 100644 (file)
  * @brief       Tests for Cynara::PolicyBucket
  */
 
-#include <gtest/gtest.h>
+#include <algorithm>
+#include <tuple>
+#include <vector>
+
 #include <gmock/gmock.h>
+#include <gtest/gtest.h>
 
 #include "types/PolicyBucket.h"
-#include "types/PolicyKey.h"
 #include "types/PolicyCollection.h"
+#include "types/PolicyKey.h"
 
 #include "../../helpers.h"
 
-#include <algorithm>
-#include <tuple>
-
 using namespace Cynara;
 
 class PolicyBucketFixture : public ::testing::Test {
@@ -56,45 +57,23 @@ protected:
         Policy::simpleWithKey(PolicyKey("*", "*", "p1"), PredefinedPolicyType::ALLOW),
         Policy::simpleWithKey(PolicyKey("*", "*", "*"), PredefinedPolicyType::ALLOW)
     };
-
-    PolicyCollection filterHelper(const PolicyCollection &original,
-            std::function<bool(const PolicyCollection::value_type &)> pred) {
-        PolicyCollection filtered(original.size());
-        auto endIt = std::copy_if(std::begin(original), std::end(original),
-            std::begin(filtered), pred);
-        filtered.resize(std::distance(std::begin(filtered), endIt));
-        return filtered;
-    }
-
-    PolicyCollection filterHelper(const PolicyCollection &original, std::vector<unsigned> idx) {
-        PolicyCollection filtered;
-        filtered.reserve(idx.size());
-        for (const auto &i : idx) {
-            filtered.push_back(original.at(i));
-        }
-        return filtered;
-    }
 };
 
 TEST_F(PolicyBucketFixture, filtered) {
-    using ::testing::UnorderedElementsAreArray;
     using ::testing::UnorderedElementsAre;
-    using ::testing::IsEmpty;
 
     PolicyBucket bucket(pkPolicies);
     bucket.setDefaultPolicy(PredefinedPolicyType::DENY);
     auto filtered = bucket.filtered(pk1);
 
     // Elements match
-    ASSERT_THAT(filtered.policyCollection(), UnorderedElementsAre(pkPolicies.at(0)));
+    ASSERT_THAT(filtered, UnorderedElementsAre(pkPolicies.at(0)));
 
     // default policy matches
     ASSERT_EQ(PredefinedPolicyType::DENY, filtered.defaultPolicy());
 }
 
 TEST_F(PolicyBucketFixture, filtered_other) {
-    using ::testing::UnorderedElementsAreArray;
-    using ::testing::UnorderedElementsAre;
     using ::testing::IsEmpty;
 
     PolicyBucket bucket(pkPolicies);
@@ -102,7 +81,7 @@ TEST_F(PolicyBucketFixture, filtered_other) {
     auto filtered = bucket.filtered(otherPk);
 
     // No policies should be found
-    ASSERT_THAT(filtered.policyCollection(), IsEmpty());
+    ASSERT_THAT(filtered, IsEmpty());
 
     // default policy should be preserved
     ASSERT_EQ(PredefinedPolicyType::DENY, filtered.defaultPolicy());
@@ -112,45 +91,45 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_1) {
     using ::testing::UnorderedElementsAreArray;
 
     // Leave policies with given client, given user and any privilege
-    auto policiesToStay = filterHelper(wildcardPolicies, { 0, 1, 3 });
+    auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 0, 1, 3 });
 
     PolicyBucket bucket(wildcardPolicies);
     auto filtered = bucket.filtered(PolicyKey("c1", "u1", "p2"));
-    ASSERT_THAT(filtered.policyCollection(), UnorderedElementsAreArray(policiesToStay));
+    ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay));
 }
 
 TEST_F(PolicyBucketFixture, filtered_wildcard_2) {
     using ::testing::UnorderedElementsAreArray;
 
     // Leave policies with given client, given user and any privilege
-    auto policiesToStay = filterHelper(wildcardPolicies, std::vector<unsigned>{ 2, 3 });
+    auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 2, 3 });
 
     PolicyBucket bucket(wildcardPolicies);
     auto filtered = bucket.filtered(PolicyKey("cccc", "u1", "p1"));
 
-    ASSERT_THAT(filtered.policyCollection(), UnorderedElementsAreArray(policiesToStay));
+    ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay));
 }
 
 TEST_F(PolicyBucketFixture, filtered_wildcard_3) {
     using ::testing::UnorderedElementsAreArray;
 
     // Leave policies with given client, given user and any privilege
-    auto policiesToStay = filterHelper(wildcardPolicies, std::vector<unsigned>{ 0, 3 });
+    auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 0, 3 });
 
     PolicyBucket bucket(wildcardPolicies);
     auto filtered = bucket.filtered(PolicyKey("c1", "u1", "pppp"));
-    ASSERT_THAT(filtered.policyCollection(), UnorderedElementsAreArray(policiesToStay));
+    ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay));
 }
 
 TEST_F(PolicyBucketFixture, filtered_wildcard_4) {
     using ::testing::UnorderedElementsAreArray;
 
     // Leave policies with given client, given user and any privilege
-    auto policiesToStay = filterHelper(wildcardPolicies, std::vector<unsigned>{ 3 });
+    auto policiesToStay = Helpers::pickFromCollection(wildcardPolicies, { 3 });
 
     PolicyBucket bucket(wildcardPolicies);
     auto filtered = bucket.filtered(PolicyKey("cccc", "uuuu", "pppp"));
-    ASSERT_THAT(filtered.policyCollection(), UnorderedElementsAreArray(policiesToStay));
+    ASSERT_THAT(filtered, UnorderedElementsAreArray(policiesToStay));
 }
 
 TEST_F(PolicyBucketFixture, filtered_wildcard_none) {
@@ -158,5 +137,5 @@ TEST_F(PolicyBucketFixture, filtered_wildcard_none) {
 
     PolicyBucket bucket({ wildcardPolicies.begin(), wildcardPolicies.begin() + 3 });
     auto filtered = bucket.filtered(PolicyKey("cccc", "uuuu", "pppp"));
-    ASSERT_THAT(filtered.policyCollection(), IsEmpty());
+    ASSERT_THAT(filtered, IsEmpty());
 }
index 1f678d5..69940ff 100644 (file)
 #ifndef HELPERS_H
 #define HELPERS_H
 
+#include <vector>
+
 #include "types/PolicyKey.h"
 #include "types/PolicyBucketId.h"
 
 namespace Cynara {
+
 namespace Helpers {
 
 PolicyKey generatePolicyKey(const PolicyKeyFeature::ValueType &sufix = "");
 PolicyBucketId generateBucketId(const PolicyBucketId &sufix = "");
 
+template <class Collection>
+Collection pickFromCollection(const Collection &original, const std::vector<unsigned> &idx) {
+    Collection filtered;
+    filtered.reserve(idx.size());
+    for (const auto &i : idx) {
+        filtered.push_back(original.at(i));
+    }
+    return filtered;
+}
+
 } // namespace Helpers
+
 } // namespace Cynara
 
 #endif // HELPERS_H
index 9028d1a..860660f 100644 (file)
@@ -47,7 +47,7 @@ TEST_F(InMemeoryStorageBackendFixture, createBucket) {
     ASSERT_EQ(1, m_buckets.size());
     ASSERT_NE(m_buckets.end(), m_buckets.find(bucketId));
     ASSERT_EQ(defaultPolicy, m_buckets.at(bucketId).defaultPolicy());
-    ASSERT_THAT(m_buckets.at(bucketId).policyCollection(), IsEmpty());
+    ASSERT_THAT(m_buckets.at(bucketId), IsEmpty());
 }
 
 TEST_F(InMemeoryStorageBackendFixture, updateBucket) {
index b194006..2c6e593 100644 (file)
@@ -39,9 +39,17 @@ protected:
         return m_buckets.insert({ bucketId, bucket }).first->second;
     }
 
+    Cynara::Buckets::mapped_type &
+    createBucket(const Cynara::PolicyBucketId &bucketId, const Cynara::PolicyCollection &policies) {
+        auto bucket = Cynara::PolicyBucket(policies);
+        return m_buckets.insert({ bucketId, bucket }).first->second;
+    }
+
     void addToBucket(Cynara::PolicyBucketId bucketId, const Cynara::PolicyCollection &policies) {
-        std::copy(policies.begin(), policies.end(),
-                std::back_inserter(m_buckets[bucketId].policyCollection()));
+        // TODO: Consider altering PolicyMap directly
+        for (const auto &policy : policies) {
+            m_buckets[bucketId].insertPolicy(policy);
+        }
     }
 
     virtual ~InMemeoryStorageBackendFixture() {}
index 34a3c42..6e84475 100644 (file)
  * @brief       Tests of InMemeoryStorageBackend
  */
 
-#include <gtest/gtest.h>
 #include <gmock/gmock.h>
+#include <gtest/gtest.h>
 
-#include "types/PolicyType.h"
-#include "types/PolicyKey.h"
-#include "types/PolicyResult.h"
-#include "types/PolicyCollection.h"
 #include "exceptions/DefaultBucketDeletionException.h"
 #include "exceptions/BucketNotExistsException.h"
-#include "storage/StorageBackend.h"
 #include "storage/InMemoryStorageBackend.h"
+#include "storage/StorageBackend.h"
+#include "types/PolicyCollection.h"
+#include "types/PolicyKey.h"
+#include "types/PolicyResult.h"
+#include "types/PolicyType.h"
 
 #include "../../helpers.h"
 #include "fakeinmemorystoragebackend.h"
@@ -54,6 +54,7 @@ TEST_F(InMemeoryStorageBackendFixture, defaultPolicyIsDeny) {
     ASSERT_EQ(PredefinedPolicyType::DENY, defaultPolicy.policyType());
 }
 
+// TODO: Refactorize this test to be shorter and clearer
 TEST_F(InMemeoryStorageBackendFixture, deleteLinking) {
     using ::testing::ReturnRef;
     using ::testing::IsEmpty;
@@ -102,17 +103,17 @@ TEST_F(InMemeoryStorageBackendFixture, deleteLinking) {
     // Should delete 1st and 2nd policy from 1st bucket
     backend.deleteLinking(testBucket2);
 
-    ASSERT_THAT(m_buckets.at(testBucket1).policyCollection(),
+    ASSERT_THAT(m_buckets.at(testBucket1),
             UnorderedElementsAre(policiesToStay.at(0)));
-    ASSERT_THAT(m_buckets.at(testBucket2).policyCollection(),
+    ASSERT_THAT(m_buckets.at(testBucket2),
             UnorderedElementsAre(policiesToStay.at(1), policiesToStay.at(2)));
-    ASSERT_THAT(m_buckets.at(testBucket3).policyCollection(), IsEmpty());
+    ASSERT_THAT(m_buckets.at(testBucket3), IsEmpty());
 }
 
 TEST_F(InMemeoryStorageBackendFixture, insertPolicy) {
     using ::testing::ReturnRef;
-    using ::testing::IsEmpty;
     using ::testing::UnorderedElementsAre;
+    using PredefinedPolicyType::ALLOW;
 
     FakeInMemoryStorageBackend backend;
     EXPECT_CALL(backend, buckets())
@@ -121,16 +122,14 @@ TEST_F(InMemeoryStorageBackendFixture, insertPolicy) {
     PolicyBucketId bucketId = "test-bucket";
     createBucket(bucketId);
 
-    auto policyToAdd = Policy::simpleWithKey(Helpers::generatePolicyKey(), PredefinedPolicyType::ALLOW);
+    auto policyToAdd = Policy::simpleWithKey(Helpers::generatePolicyKey(), ALLOW);
     backend.insertPolicy(bucketId, policyToAdd);
 
-    ASSERT_THAT(m_buckets.at(bucketId).policyCollection(), UnorderedElementsAre(policyToAdd));
+    ASSERT_THAT(m_buckets.at(bucketId), UnorderedElementsAre(policyToAdd));
 }
 
 TEST_F(InMemeoryStorageBackendFixture, insertPolicyToNonexistentBucket) {
     using ::testing::ReturnRef;
-    using ::testing::IsEmpty;
-    using ::testing::UnorderedElementsAre;
 
     FakeInMemoryStorageBackend backend;
     EXPECT_CALL(backend, buckets())
@@ -143,7 +142,9 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicy) {
     using ::testing::ReturnRef;
     using ::testing::IsEmpty;
     using ::testing::UnorderedElementsAre;
+    using ::testing::UnorderedElementsAreArray;
     using ::testing::ContainerEq;
+    using PredefinedPolicyType::ALLOW;
 
     FakeInMemoryStorageBackend backend;
     EXPECT_CALL(backend, buckets())
@@ -152,12 +153,12 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicy) {
     PolicyBucketId bucketId = "test-bucket";
     createBucket(bucketId);
 
-    auto policyToDelete = Policy::simpleWithKey(Helpers::generatePolicyKey(), PredefinedPolicyType::ALLOW);
+    auto policyToDelete = Policy::simpleWithKey(Helpers::generatePolicyKey(), ALLOW);
 
     PolicyCollection otherPolicies = {
-        Policy::simpleWithKey(Helpers::generatePolicyKey("other-policy-1"), PredefinedPolicyType::ALLOW),
-        Policy::simpleWithKey(Helpers::generatePolicyKey("other-policy-2"), PredefinedPolicyType::ALLOW),
-        Policy::simpleWithKey(Helpers::generatePolicyKey("other-policy-3"), PredefinedPolicyType::ALLOW),
+        Policy::simpleWithKey(Helpers::generatePolicyKey("other-policy-1"), ALLOW),
+        Policy::simpleWithKey(Helpers::generatePolicyKey("other-policy-2"), ALLOW),
+        Policy::simpleWithKey(Helpers::generatePolicyKey("other-policy-3"), ALLOW),
     };
 
     addToBucket(bucketId, {
@@ -170,7 +171,7 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicy) {
     backend.deletePolicy(bucketId, policyToDelete->key());
 
     // Check if only policyToDelete has been deleted
-    EXPECT_THAT(m_buckets.at(bucketId).policyCollection(), ContainerEq(otherPolicies));
+    EXPECT_THAT(m_buckets.at(bucketId), UnorderedElementsAreArray(otherPolicies));
 }
 
 TEST_F(InMemeoryStorageBackendFixture, deletePolicyFromNonexistentBucket) {
@@ -182,5 +183,6 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicyFromNonexistentBucket) {
     EXPECT_CALL(backend, buckets())
         .WillOnce(ReturnRef(m_buckets));
 
-    EXPECT_THROW(backend.deletePolicy("non-existent", Helpers::generatePolicyKey()), BucketNotExistsException);
+    EXPECT_THROW(backend.deletePolicy("non-existent", Helpers::generatePolicyKey()),
+                 BucketNotExistsException);
 }
index 65c9057..c9f9dfd 100644 (file)
  * @brief       Tests of search in InMemeoryStorageBackend
  */
 
+#include <memory>
+
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-#include "inmemeorystoragebackendfixture.h"
-#include "fakeinmemorystoragebackend.h"
-
 #include "types/PolicyBucket.h"
 
 #include "../../helpers.h"
-
-#include <memory>
+#include "fakeinmemorystoragebackend.h"
+#include "inmemeorystoragebackendfixture.h"
 
 using namespace Cynara;
 
 TEST_F(InMemeoryStorageBackendFixture, searchDefault) {
     using ::testing::ReturnRef;
-    using ::testing::UnorderedElementsAre;
+    using ::testing::UnorderedElementsAreArray;
     using ::testing::IsEmpty;
 
     auto pk1 = Helpers::generatePolicyKey("1");
     auto pk2 = Helpers::generatePolicyKey("2");
+    auto pk3 = PolicyKey(PolicyKeyFeature::createWildcard(), pk1.user(), pk1.privilege());
     auto otherPk = Helpers::generatePolicyKey("-");
 
-    const auto &defaultBucket = createBucket(defaultPolicyBucketId);
-
-    addToBucket(defaultPolicyBucketId, {
+    PolicyCollection policies = {
        Policy::simpleWithKey(pk1, PredefinedPolicyType::ALLOW),
        Policy::simpleWithKey(pk2, PredefinedPolicyType::DENY),
-       Policy::simpleWithKey(pk1, PredefinedPolicyType::DENY),
-    });
+       Policy::simpleWithKey(pk3, PredefinedPolicyType::DENY),
+    };
+
+    createBucket(defaultPolicyBucketId, policies);
 
     // Just override buckets() accessor
     FakeInMemoryStorageBackend backend;
     EXPECT_CALL(backend, buckets())
         .WillRepeatedly(ReturnRef(m_buckets));
 
-    auto searchDefaultBucket = [&backend](const PolicyKey &key) -> PolicyCollection {
-        return backend.searchDefaultBucket(key).policyCollection();
-    };
-
-    auto defaultPolicyAt = [&defaultBucket] (PolicyCollection::size_type idx) {
-        return defaultBucket.policyCollection().at(idx);
-    };
+    auto policiesToStay1 = Helpers::pickFromCollection(policies, { 0, 2 });
+    auto policiesToStay2 = Helpers::pickFromCollection(policies, { 1 });
 
-    ASSERT_THAT(searchDefaultBucket(pk1),
-            UnorderedElementsAre(defaultPolicyAt(0),defaultPolicyAt(2)));
-    ASSERT_THAT(searchDefaultBucket(pk2), UnorderedElementsAre(defaultPolicyAt(1)));
-    ASSERT_THAT(searchDefaultBucket(otherPk), IsEmpty());
+    ASSERT_THAT(backend.searchDefaultBucket(pk1), UnorderedElementsAreArray(policiesToStay1));
+    ASSERT_THAT(backend.searchDefaultBucket(pk2), UnorderedElementsAreArray(policiesToStay2));
+    ASSERT_THAT(backend.searchDefaultBucket(otherPk), IsEmpty());
 }
index 140242b..931a5ab 100644 (file)
@@ -147,7 +147,7 @@ TEST_F(StorageDeserializerFixture, load_buckets_plus_policies) {
     ));
 
     // Check policy was inserted into bucket
-    ASSERT_THAT(buckets.at("").policyCollection(), UnorderedElementsAre(
+    ASSERT_THAT(buckets.at(""), UnorderedElementsAre(
        Pointee(Policy(PolicyKey("c", "u", "p"), PolicyResult(PredefinedPolicyType::DENY, "meta")))
    ));
 }
index 2a0bfd0..90144e4 100644 (file)
@@ -58,54 +58,59 @@ TEST(serializer_dump, dump_empty_bucket) {
 }
 
 TEST(serializer_dump, dump_bucket) {
+    using ::testing::UnorderedElementsAreArray;
+    using PredefinedPolicyType::ALLOW;
+    using PredefinedPolicyType::DENY;
+
     PolicyKey pk1 = Helpers::generatePolicyKey("1");
     PolicyKey pk2 = Helpers::generatePolicyKey("2");
 
-    PolicyBucket bucket = {{ Policy::simpleWithKey(pk1, PredefinedPolicyType::ALLOW),
-                             Policy::simpleWithKey(pk2, PredefinedPolicyType::DENY) }};
+    PolicyBucket bucket = {{ Policy::simpleWithKey(pk1, ALLOW),
+                             Policy::simpleWithKey(pk2, DENY) }};
 
-    auto outputStream = std::make_shared<std::ostringstream>();
-    StorageSerializer serializer(outputStream);
+    auto outStream = std::make_shared<std::stringstream>();
+    StorageSerializer serializer(outStream);
     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
-        << expectedPolicyKey(pk1) << ";" << expectedPolicyType(PredefinedPolicyType::ALLOW)<< ";"
-        << std::endl
-        << expectedPolicyKey(pk2) << ";" << expectedPolicyType(PredefinedPolicyType::DENY) << ";"
-        << std::endl;
-
-    ASSERT_EQ(expected.str(), outputStream->str());
+    // Split stream into records
+    auto actualRecords = std::vector<std::string>(std::istream_iterator<std::string>(*outStream),
+                                                  std::istream_iterator<std::string>());
+
+    std::vector<std::string> expectedRecords = {
+        expectedPolicyKey(pk1) + ";" + expectedPolicyType(ALLOW) + ";",
+        expectedPolicyKey(pk2) + ";" + expectedPolicyType(DENY) + ";"
+    };
+
+    ASSERT_THAT(actualRecords, UnorderedElementsAreArray(expectedRecords));
 }
 
 TEST(serializer_dump, dump_bucket_bucket) {
+    using ::testing::UnorderedElementsAreArray;
+    using PredefinedPolicyType::BUCKET;
+    using PredefinedPolicyType::DENY;
+
     PolicyKey pk1 = Helpers::generatePolicyKey("1");
     PolicyKey pk2 = Helpers::generatePolicyKey("2");
     PolicyKey pk3 = Helpers::generatePolicyKey("3");
     PolicyBucketId bucketId = Helpers::generateBucketId();
 
     PolicyBucket bucket = {{ Policy::bucketWithKey(pk1, bucketId),
-                             Policy::simpleWithKey(pk2, PredefinedPolicyType::DENY),
+                             Policy::simpleWithKey(pk2, DENY),
                              Policy::bucketWithKey(pk3, bucketId) }};
 
-    auto outputStream = std::make_shared<std::ostringstream>();
-    StorageSerializer serializer(outputStream);
+    auto outStream = std::make_shared<std::stringstream>();
+    StorageSerializer serializer(outStream);
     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
-        << expectedPolicyKey(pk1) << ";" << expectedPolicyType(PredefinedPolicyType::BUCKET) << ";"
-        << bucketId << std::endl
-        << expectedPolicyKey(pk2) << ";" << expectedPolicyType(PredefinedPolicyType::DENY) << ";"
-        << std::endl
-        << expectedPolicyKey(pk3) << ";" << expectedPolicyType(PredefinedPolicyType::BUCKET) << ";"
-        << bucketId << std::endl;
-
-    ASSERT_EQ(expected.str(), outputStream->str());
+    // Split stream into records
+    auto actualRecords = std::vector<std::string>(std::istream_iterator<std::string>(*outStream),
+                                                  std::istream_iterator<std::string>());
+
+    std::vector<std::string> expectedRecords = {
+        expectedPolicyKey(pk1) + ";" + expectedPolicyType(BUCKET) + ";" + bucketId,
+        expectedPolicyKey(pk2) + ";" + expectedPolicyType(DENY) + ";",
+        expectedPolicyKey(pk3) + ";" + expectedPolicyType(BUCKET) + ";" + bucketId
+    };
+
+    ASSERT_THAT(actualRecords, UnorderedElementsAreArray(expectedRecords));
 }
index 02d90fd..36468ff 100644 (file)
@@ -59,7 +59,8 @@ TEST(dump_load, bucket) {
 
     BucketDeserializer deserializer(ioStream);
     const auto loadedPolicies = deserializer.loadPolicies();
-    const auto &expectedPolicies = bucket.policyCollection();
+    PolicyCollection expectedPolicies;
+    std::copy(bucket.begin(), bucket.end(), std::back_inserter(expectedPolicies));
 
     ASSERT_THAT(loadedPolicies, UnorderedElementsAre(
         PolicyAtPtrEq(expectedPolicies.at(0)),
index 492e7fb..e71e40f 100644 (file)
@@ -73,11 +73,11 @@ TEST(storage, checkSimple) {
     ASSERT_EQ(PredefinedPolicyType::DENY, storage.checkPolicy(pk).policyType());
 
     // Add ALLOW to default bucket -- return ALLOW
-    bucket.policyCollection().push_back(Policy::simpleWithKey(pk, PredefinedPolicyType::ALLOW));
+    bucket.insertPolicy(Policy::simpleWithKey(pk, PredefinedPolicyType::ALLOW));
     ASSERT_EQ(PredefinedPolicyType::ALLOW, storage.checkPolicy(pk).policyType());
 
     // Add DENY to default bucket -- return DENY
-    bucket.policyCollection().push_back(Policy::simpleWithKey(pk, PredefinedPolicyType::DENY));
+    bucket.insertPolicy(Policy::simpleWithKey(pk, PredefinedPolicyType::DENY));
     ASSERT_EQ(PredefinedPolicyType::DENY, storage.checkPolicy(pk).policyType());
 }
 
@@ -111,11 +111,11 @@ TEST(storage, checkBucket) {
     ASSERT_EQ(PredefinedPolicyType::DENY, storage.checkPolicy(pk).policyType());
 
     // Add ALLOW to bucket, so return ALLOW
-    additionalBucket.policyCollection().push_back(Policy::simpleWithKey(pk, PredefinedPolicyType::ALLOW));
+    additionalBucket.insertPolicy(Policy::simpleWithKey(pk, PredefinedPolicyType::ALLOW));
     ASSERT_EQ(PredefinedPolicyType::ALLOW, storage.checkPolicy(pk).policyType());
 
     // Add DENY to default bucket -- return DENY, even though ALLOW in other bucket
-    defaultBucket.policyCollection().push_back(Policy::simpleWithKey(pk, PredefinedPolicyType::DENY));
+    defaultBucket.insertPolicy(Policy::simpleWithKey(pk, PredefinedPolicyType::DENY));
     ASSERT_EQ(PredefinedPolicyType::DENY, storage.checkPolicy(pk).policyType());
 }
 
index 4125a6d..fbe40fa 100644 (file)
@@ -107,51 +107,6 @@ TEST(storage, insertPolicies) {
         const auto &policies = group.second;
 
         for (const auto &policy : policies) {
-            EXPECT_CALL(backend, searchBucket(bucketId, policy.key()))
-                .WillOnce(Return(PolicyBucket()));
-            EXPECT_CALL(backend, insertPolicy(bucketId, Pointee(policy)));
-        }
-    }
-
-    storage.insertPolicies(policiesToInsert);
-}
-
-TEST(storage, updatePolicies) {
-    using ::testing::Pointee;
-    using ::testing::Return;
-    FakeStorageBackend backend;
-    Storage storage(backend);
-
-    PolicyBucketId testBucket1 = "test-bucket-1";
-    PolicyBucketId testBucket2 = "test-bucket-2";
-
-    typedef std::pair<PolicyBucketId, std::vector<Policy>> BucketPolicyPair;
-
-    auto createPolicy = [] (const std::string &keySuffix, const PolicyType &type) -> Policy {
-        return Policy(Helpers::generatePolicyKey(keySuffix), type);
-    };
-
-    std::map<PolicyBucketId, std::vector<Policy>> policiesToInsert = {
-        BucketPolicyPair(testBucket1, {
-            createPolicy("1", PredefinedPolicyType::ALLOW),
-            createPolicy("2", PredefinedPolicyType::DENY),
-            createPolicy("3", PredefinedPolicyType::DENY)
-        }),
-        BucketPolicyPair(testBucket2, {
-            createPolicy("4", PredefinedPolicyType::ALLOW),
-            createPolicy("5", PredefinedPolicyType::ALLOW)
-        })
-    };
-
-    for (const auto &group : policiesToInsert) {
-        const auto &bucketId = group.first;
-        const auto &policies = group.second;
-
-        for (const auto &policy : policies) {
-            PolicyBucket searchResult(PolicyCollection { std::make_shared<Policy>(policy) });
-            EXPECT_CALL(backend, searchBucket(bucketId, policy.key()))
-                .WillOnce(Return(searchResult));
-            EXPECT_CALL(backend, deletePolicy(bucketId, policy.key()));
             EXPECT_CALL(backend, insertPolicy(bucketId, Pointee(policy)));
         }
     }