summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv/testutils/generic_backend_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcpsrv/testutils/generic_backend_unittest.cc')
-rw-r--r--src/lib/dhcpsrv/testutils/generic_backend_unittest.cc284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/testutils/generic_backend_unittest.cc b/src/lib/dhcpsrv/testutils/generic_backend_unittest.cc
new file mode 100644
index 0000000..344d215
--- /dev/null
+++ b/src/lib/dhcpsrv/testutils/generic_backend_unittest.cc
@@ -0,0 +1,284 @@
+// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option_vendor.h>
+#include <dhcpsrv/testutils/generic_backend_unittest.h>
+#include <util/buffer.h>
+#include <typeinfo>
+#include <testutils/gtest_utils.h>
+
+using namespace isc::data;
+using namespace isc::db;
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+GenericBackendTest::GenericBackendTest()
+ : timestamps_(), audit_entries_() {
+ LibDHCP::clearRuntimeOptionDefs();
+ initTimestamps();
+}
+
+GenericBackendTest::~GenericBackendTest() {
+ LibDHCP::clearRuntimeOptionDefs();
+}
+
+OptionDescriptor
+GenericBackendTest::createEmptyOption(const Option::Universe& universe,
+ const uint16_t option_type,
+ const bool persist) const {
+ OptionPtr option(new Option(universe, option_type));
+ OptionDescriptor desc(option, persist);
+ return (desc);
+}
+
+OptionDescriptor
+GenericBackendTest::createVendorOption(const Option::Universe& universe,
+ const bool persist,
+ const bool formatted,
+ const uint32_t vendor_id) const {
+ OptionVendorPtr option(new OptionVendor(universe, vendor_id));
+
+ std::ostringstream s;
+ if (formatted) {
+ // Vendor id comprises vendor-id field, for which we need to
+ // assign a value in the textual (formatted) format.
+ s << vendor_id;
+ }
+
+ OptionDescriptor desc(option, persist, s.str());
+ return (desc);
+}
+
+void
+GenericBackendTest::testOptionsEquivalent(const OptionDescriptor& ref_option,
+ const OptionDescriptor& tested_option) const {
+ // Make sure that all pointers are non-null.
+ ASSERT_TRUE(ref_option.option_);
+ ASSERT_TRUE(tested_option.option_);
+
+ // Get the reference to the tested option. Make should it has
+ // generic type.
+ Option& tested_option_reference = *tested_option.option_;
+ EXPECT_TRUE(typeid(tested_option_reference) == typeid(Option));
+
+ // Only test the binary data if the formatted value is not provided.
+ if (tested_option.formatted_value_.empty()) {
+
+ // Prepare on-wire data of the option under test.
+ isc::util::OutputBuffer tested_option_buf(1);
+ tested_option.option_->pack(tested_option_buf);
+ const uint8_t* tested_option_buf_data = static_cast<const uint8_t*>
+ (tested_option_buf.getData());
+ std::vector<uint8_t> tested_option_buf_vec(tested_option_buf_data,
+ tested_option_buf_data + tested_option_buf.getLength());
+
+ // Prepare on-wire data of the reference option.
+ isc::util::OutputBuffer ref_option_buf(1);
+ ref_option.option_->pack(ref_option_buf);
+ const uint8_t* ref_option_buf_data = static_cast<const uint8_t*>
+ (ref_option_buf.getData());
+ std::vector<uint8_t> ref_option_buf_vec(ref_option_buf_data,
+ ref_option_buf_data + ref_option_buf.getLength());
+
+ // Compare the on-wire data.
+ EXPECT_EQ(ref_option_buf_vec, tested_option_buf_vec);
+
+ } else {
+ // If the formatted value is non-empty the buffer should be empty.
+ EXPECT_TRUE(tested_option.option_->getData().empty());
+ }
+
+ // Compare other members of the @c OptionDescriptor, e.g. the
+ // tested option may contain formatted option data which can be
+ // later used to turn this option instance into a formatted
+ // option when an option definition is available.
+ EXPECT_EQ(ref_option.formatted_value_, tested_option.formatted_value_);
+ EXPECT_EQ(ref_option.persistent_, tested_option.persistent_);
+ EXPECT_EQ(ref_option.space_name_, tested_option.space_name_);
+}
+
+void
+GenericBackendTest::checkConfiguredGlobal(const SrvConfigPtr& srv_cfg,
+ const std::string &name,
+ ConstElementPtr exp_value) {
+ ConstCfgGlobalsPtr globals = srv_cfg->getConfiguredGlobals();
+ ConstElementPtr found_global = globals->get(name);
+ ASSERT_TRUE(found_global) << "expected global: "
+ << name << " not found";
+
+ ASSERT_EQ(exp_value->getType(), found_global->getType())
+ << "expected global: " << name << " has wrong type";
+
+ ASSERT_EQ(*exp_value, *found_global)
+ << "expected global: " << name << " has wrong value";
+}
+
+void
+GenericBackendTest::checkConfiguredGlobal(const SrvConfigPtr& srv_cfg,
+ StampedValuePtr& exp_global) {
+ checkConfiguredGlobal(srv_cfg, exp_global->getName(), exp_global->getElementValue());
+}
+
+
+void
+GenericBackendTest::testNewAuditEntry(const std::string& exp_object_type,
+ const AuditEntry::ModificationType& exp_modification_type,
+ const std::string& exp_log_message,
+ const ServerSelector& server_selector,
+ const size_t new_entries_num,
+ const size_t max_tested_entries) {
+ // Get the server tag for which the entries are fetched.
+ std::string tag;
+ if (server_selector.getType() == ServerSelector::Type::ALL) {
+ // Server tag is 'all'.
+ tag = "all";
+ } else {
+ const auto& tags = server_selector.getTags();
+ // This test is not meant to handle multiple server tags all at once.
+ if (tags.size() > 1) {
+ ADD_FAILURE() << "Test error: do not use multiple server tags";
+ } else if (tags.size() == 1) {
+ // Get the server tag for which we run the current test.
+ tag = tags.begin()->get();
+ }
+ }
+
+ auto audit_entries_size_save = audit_entries_[tag].size();
+
+ // Audit entries for different server tags are stored in separate
+ // containers.
+ ASSERT_NO_THROW_LOG(audit_entries_[tag]
+ = getRecentAuditEntries(server_selector, timestamps_["two days ago"], 0));
+
+ ASSERT_EQ(audit_entries_size_save + new_entries_num, audit_entries_[tag].size())
+ << logExistingAuditEntries(tag);
+
+ auto& mod_time_idx = audit_entries_[tag].get<AuditEntryModificationTimeIdTag>();
+
+ // Iterate over specified number of entries starting from the most recent
+ // one and check they have correct values.
+ for (auto audit_entry_it = mod_time_idx.rbegin();
+ ((std::distance(mod_time_idx.rbegin(), audit_entry_it) < new_entries_num) &&
+ (std::distance(mod_time_idx.rbegin(), audit_entry_it) < max_tested_entries));
+ ++audit_entry_it) {
+ auto audit_entry = *audit_entry_it;
+ EXPECT_EQ(exp_object_type, audit_entry->getObjectType())
+ << logExistingAuditEntries(tag);
+ EXPECT_EQ(exp_modification_type, audit_entry->getModificationType())
+ << logExistingAuditEntries(tag);
+ EXPECT_EQ(exp_log_message, audit_entry->getLogMessage())
+ << logExistingAuditEntries(tag);
+ }
+}
+
+void
+GenericBackendTest::testNewAuditEntry(const std::vector<ExpAuditEntry>& exp_entries,
+ const ServerSelector& server_selector) {
+ // Get the server tag for which the entries are fetched.
+ std::string tag;
+ if (server_selector.getType() == ServerSelector::Type::ALL) {
+ // Server tag is 'all'.
+ tag = "all";
+ } else {
+ const auto& tags = server_selector.getTags();
+ // This test is not meant to handle multiple server tags all at once.
+ if (tags.size() != 1) {
+ ADD_FAILURE() << "Test error: tags.size(): " << tags.size()
+ << ", you must specify one and only one server tag";
+ }
+
+ // Get the server tag for which we run the current test.
+ tag = tags.begin()->get();
+ }
+
+ size_t new_entries_num = exp_entries.size();
+
+ auto audit_entries_size_save = audit_entries_[tag].size();
+
+ // Audit entries for different server tags are stored in separate
+ // containers.
+ ASSERT_NO_THROW_LOG(audit_entries_[tag]
+ = getRecentAuditEntries(server_selector, timestamps_["two days ago"], 0));
+
+ ASSERT_EQ(audit_entries_size_save + new_entries_num, audit_entries_[tag].size())
+ << logExistingAuditEntries(tag);
+
+ auto& mod_time_idx = audit_entries_[tag].get<AuditEntryModificationTimeIdTag>();
+
+ // Iterate over specified number of entries starting from the most recent
+ // one and check they have correct values.
+ auto exp_entry = exp_entries.rbegin();
+ for (auto audit_entry_it = mod_time_idx.rbegin();
+ ((std::distance(mod_time_idx.rbegin(), audit_entry_it) < new_entries_num));
+ ++audit_entry_it) {
+
+ auto audit_entry = *audit_entry_it;
+ EXPECT_EQ((*exp_entry).object_type, audit_entry->getObjectType())
+ << logExistingAuditEntries(tag);
+ EXPECT_EQ((*exp_entry).modification_type, audit_entry->getModificationType())
+ << logExistingAuditEntries(tag);
+ EXPECT_EQ((*exp_entry).log_message, audit_entry->getLogMessage())
+ << logExistingAuditEntries(tag);
+
+ ++exp_entry;
+ }
+}
+
+void
+GenericBackendTest::initTimestamps() {
+ // Current time minus 1 hour to make sure it is in the past.
+ timestamps_["today"] = boost::posix_time::second_clock::local_time()
+ - boost::posix_time::hours(1);
+ // One second after today.
+ timestamps_["after today"] = timestamps_["today"] + boost::posix_time::seconds(1);
+ // Yesterday.
+ timestamps_["yesterday"] = timestamps_["today"] - boost::posix_time::hours(24);
+ // One second after yesterday.
+ timestamps_["after yesterday"] = timestamps_["yesterday"] + boost::posix_time::seconds(1);
+ // Two days ago.
+ timestamps_["two days ago"] = timestamps_["today"] - boost::posix_time::hours(48);
+ // Tomorrow.
+ timestamps_["tomorrow"] = timestamps_["today"] + boost::posix_time::hours(24);
+ // One second after tomorrow.
+ timestamps_["after tomorrow"] = timestamps_["tomorrow"] + boost::posix_time::seconds(1);
+}
+
+std::string
+GenericBackendTest::logExistingAuditEntries(const std::string& server_tag) {
+ std::ostringstream s;
+
+ auto& mod_time_idx = audit_entries_[server_tag].get<AuditEntryModificationTimeIdTag>();
+
+ for (auto audit_entry_it = mod_time_idx.begin();
+ audit_entry_it != mod_time_idx.end();
+ ++audit_entry_it) {
+ auto audit_entry = *audit_entry_it;
+ s << audit_entry->getObjectType() << ", "
+ << audit_entry->getObjectId() << ", "
+ << static_cast<int>(audit_entry->getModificationType()) << ", "
+ << audit_entry->getModificationTime() << ", "
+ << audit_entry->getRevisionId() << ", "
+ << audit_entry->getLogMessage()
+ << std::endl;
+ }
+
+ return (s.str());
+}
+
+AuditEntryCollection
+GenericBackendTest::getRecentAuditEntries(const ServerSelector&, const boost::posix_time::ptime&,
+ const uint64_t&) const {
+ return (AuditEntryCollection());
+}
+
+} // end of namespace isc::dhcp::test
+} // end of namespace isc::dhcp
+} // end of namespace isc