]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#395,!201] Added audit entry collection and unit tests.
authorMarcin Siodelski <marcin@isc.org>
Tue, 15 Jan 2019 18:31:48 +0000 (19:31 +0100)
committerMarcin Siodelski <marcin@isc.org>
Tue, 15 Jan 2019 18:31:48 +0000 (19:31 +0100)
src/lib/database/audit_entry.h
src/lib/database/tests/audit_entry_unittest.cc

index aa651996ceb5d9ec07709ab9a558ef8d12efcb49..3271a2e733c03c10feea964ce99062b924851ebf 100644 (file)
@@ -8,6 +8,10 @@
 #define AUDIT_ENTRY_H
 
 #include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/ordered_index.hpp>
 #include <boost/shared_ptr.hpp>
 #include <cstdint>
 #include <string>
@@ -151,6 +155,42 @@ private:
 /// @brief Pointer to the @c AuditEntry object.
 typedef boost::shared_ptr<AuditEntry> AuditEntryPtr;
 
+/// @brief Tag used to access index by object type.
+struct AuditEntryObjectTypeTag { };
+
+/// @brief Tag used to access index by modification time.
+struct AuditEntryModificationTimeTag { };
+
+/// @brief Multi idnex container holding @c AuditEntry instances.
+///
+/// This container provides indexes to access the audit entries
+/// by object type and modification time.
+typedef boost::multi_index_container<
+    // The container holds pointers to @c AuditEntry objects.
+    AuditEntryPtr,
+    // First index allows for accessing by the object type.
+    boost::multi_index::indexed_by<
+        boost::multi_index::hashed_non_unique<
+            boost::multi_index::tag<AuditEntryObjectTypeTag>,
+            boost::multi_index::const_mem_fun<
+                AuditEntry,
+                std::string,
+                &AuditEntry::getObjectType
+            >
+        >,
+
+        // Second index allows for accessing by the modification time.
+        boost::multi_index::ordered_non_unique<
+            boost::multi_index::tag<AuditEntryModificationTimeTag>,
+            boost::multi_index::const_mem_fun<
+                AuditEntry,
+                boost::posix_time::ptime,
+                &AuditEntry::getModificationTime
+            >
+        >
+    >
+> AuditEntryCollection;
+
 } // end of namespace isc::db
 } // end of namespace isc
 
index 4817ff3b26a27593e12f90e149c17d013a40f222..2060b2c263705102e6473bdc49556f2145fb6356 100644 (file)
@@ -131,4 +131,155 @@ TEST_F(AuditEntryTest, createFailures) {
     }
 }
 
+/// @brief Test fixture class for testing @c AuditEntryCollection.
+class AuditEntryCollectionTest : public AuditEntryTest {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Creates a collection of audit entries used in the tests.
+    AuditEntryCollectionTest()
+        : AuditEntryTest(), audit_entries_() {
+        createTestAuditEntries();
+    }
+
+    /// @brief Returns a time value being being a specified number of
+    /// seconds later or earlier than the time returned by @c fixedTime.
+    ///
+    /// @param secs offset in seconds since the @c fixedTime output. If
+    /// the parameter is negative, the returned time is earlier than the
+    /// fixed time. Otherwise, it is later than fixed time.
+    boost::posix_time::ptime diffTime(const long secs) {
+        if (secs < 0) {
+            return (fixedTime() - boost::posix_time::seconds(-secs));
+        }
+        return (fixedTime() + boost::posix_time::seconds(secs));
+    }
+
+    /// @brief Creates an @c AuditEntry instance and inserts it to
+    /// the @c audit_entries_ collection.
+    ///
+    /// @tparam Args types of the arguments to be passed to the @c AuditEntry
+    /// constructors.
+    /// @param args arguments to be passed to the @c AuditEntry constructors.
+    template<typename... Args>
+    void create(Args&& ...args) {
+        audit_entries_.insert(boost::make_shared<AuditEntry>(args...));
+    }
+
+    /// @brief Creates a collection of @c AuditEntry objects to be used by
+    /// the tests.
+    void createTestAuditEntries() {
+        create("dhcp4_subnet", 10, AuditEntry::ModificationType::CREATE,
+               diffTime(-5), "added subnet 10");
+        create("dhcp4_shared_network", 1, AuditEntry::ModificationType::CREATE,
+               diffTime(-5), "added shared network 1");
+        create("dhcp4_shared_network", 120, AuditEntry::ModificationType::UPDATE,
+               diffTime(-8), "updated shared network 120");
+        create("dhcp4_subnet", 120, AuditEntry::ModificationType::DELETE,
+               diffTime(8), "deleted subnet 120");
+        create("dhcp4_subnet", 1000, AuditEntry::ModificationType::CREATE,
+               diffTime(4), "created subnet 1000");
+        create("dhcp4_option", 15, AuditEntry::ModificationType::UPDATE,
+               diffTime(16), "updated option 15");
+    }
+
+    /// @brief Checks if the returned results range contains an @c AuditEntry
+    /// with a given object type and identifier.
+    ///
+    /// @param object_type expected object type.
+    /// @param object_id expected object id.
+    /// @param begin beginning of the results range to be examined.
+    /// @param end end of the results range to be examined.
+    template<typename Iterator>
+    bool includes(const std::string& object_type, const uint64_t object_id,
+                  Iterator begin, Iterator end) {
+        // Iterate over the results range and look for the entry.
+        for (auto it = begin; it != end; ++it) {
+            if (((*it)->getObjectType() == object_type) &&
+                ((*it)->getObjectId() == object_id)) {
+                // Entry found.
+                return (true);
+            }
+        }
+
+        // Entry not found.
+        return (false);
+    }
+
+    /// @brief Audit entries used in the tests.
+    AuditEntryCollection audit_entries_;
+
+};
+
+// Checks that entries can be found by object type.
+TEST_F(AuditEntryCollectionTest, getByObjectType) {
+    const auto& object_type_idx = audit_entries_.get<AuditEntryObjectTypeTag>();
+
+    // Search for "dhcp4_subnet" objects.
+    auto range = object_type_idx.equal_range("dhcp4_subnet");
+    ASSERT_EQ(3, std::distance(range.first, range.second));
+    EXPECT_TRUE(includes("dhcp4_subnet", 10, range.first, range.second));
+    EXPECT_TRUE(includes("dhcp4_subnet", 120, range.first, range.second));
+    EXPECT_TRUE(includes("dhcp4_subnet", 1000, range.first, range.second));
+
+    // Search for "dhcp4_shared_network" objects.
+    range = object_type_idx.equal_range("dhcp4_shared_network");
+    ASSERT_EQ(2, std::distance(range.first, range.second));
+    EXPECT_TRUE(includes("dhcp4_shared_network", 1, range.first, range.second));
+    EXPECT_TRUE(includes("dhcp4_shared_network", 120, range.first, range.second));
+
+    // Search for "dhcp4_option" objects.
+    range = object_type_idx.equal_range("dhcp4_option");
+    ASSERT_EQ(1, std::distance(range.first, range.second));
+    EXPECT_TRUE(includes("dhcp4_option", 15, range.first, range.second));
+}
+
+// Checks that entries can be found by modification time.
+TEST_F(AuditEntryCollectionTest, getByModificationTime) {
+    const auto& mod_time_idx = audit_entries_.get<AuditEntryModificationTimeTag>();
+
+    // Search for objects later than fixed time - 10s.
+    auto lb = mod_time_idx.lower_bound(diffTime(-10));
+    ASSERT_EQ(6, std::distance(lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 10, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 120, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 1000, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_shared_network", 1, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_shared_network", 120, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_option", 15, lb, mod_time_idx.end()));
+
+    // Search for objects later than fixed time - 7s.
+    lb = mod_time_idx.lower_bound(diffTime(-7));
+    ASSERT_EQ(5, std::distance(lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 10, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 120, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 1000, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_shared_network", 1, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_option", 15, lb, mod_time_idx.end()));
+
+    // Search for objects later than fixed time - 1s.
+    lb = mod_time_idx.lower_bound(diffTime(-1));
+    ASSERT_EQ(3, std::distance(lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 120, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 1000, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_option", 15, lb, mod_time_idx.end()));
+
+    // Search for objects later than fixed time + 6s.
+    lb = mod_time_idx.lower_bound(diffTime(6));
+    ASSERT_EQ(2, std::distance(lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_subnet", 120, lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_option", 15, lb, mod_time_idx.end()));
+
+    // Search for objects later than fixed time + 10s.
+    lb = mod_time_idx.lower_bound(diffTime(10));
+    ASSERT_EQ(1, std::distance(lb, mod_time_idx.end()));
+    EXPECT_TRUE(includes("dhcp4_option", 15, lb, mod_time_idx.end()));
+
+    // Search for objects later than fixed time + 20s.
+    lb = mod_time_idx.lower_bound(diffTime(20));
+    // None found.
+    ASSERT_EQ(0, std::distance(lb, mod_time_idx.end()));
+}
+
 }