Browse Source

[3677] alloc_engine_unittest.cc split into serveral smaller files.

Tomek Mrugalski 10 years ago
parent
commit
16153c9e76

+ 4 - 1
src/lib/dhcpsrv/tests/Makefile.am

@@ -53,7 +53,10 @@ TESTS += libdhcpsrv_unittests
 
 libdhcpsrv_unittests_SOURCES  = run_unittests.cc
 libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
-libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
+libdhcpsrv_unittests_SOURCES += alloc_engine_utils.cc alloc_engine_utils.h
+libdhcpsrv_unittests_SOURCES += alloc_engine_hooks_unittest.cc
+libdhcpsrv_unittests_SOURCES += alloc_engine4_unittest.cc
+libdhcpsrv_unittests_SOURCES += alloc_engine6_unittest.cc
 libdhcpsrv_unittests_SOURCES += callout_handle_store_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_hosts_unittest.cc
 libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc

File diff suppressed because it is too large
+ 1311 - 0
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc


File diff suppressed because it is too large
+ 1238 - 0
src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc


+ 480 - 0
src/lib/dhcpsrv/tests/alloc_engine_hooks_unittest.cc

@@ -0,0 +1,480 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <dhcpsrv/tests/alloc_engine_utils.h>
+#include <dhcpsrv/tests/test_utils.h>
+
+#include <hooks/server_hooks.h>
+#include <hooks/callout_manager.h>
+#include <hooks/hooks_manager.h>
+
+using namespace std;
+using namespace isc::hooks;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief helper class used in Hooks testing in AllocEngine6
+///
+/// It features a couple of callout functions and buffers to store
+/// the data that is accessible via callouts.
+class HookAllocEngine6Test : public AllocEngine6Test {
+public:
+    HookAllocEngine6Test() {
+        resetCalloutBuffers();
+    }
+
+    virtual ~HookAllocEngine6Test() {
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+            "lease6_select");
+    }
+
+    /// @brief clears out buffers, so callouts can store received arguments
+    void resetCalloutBuffers() {
+        callback_name_ = string("");
+        callback_subnet6_.reset();
+        callback_fake_allocation_ = false;
+        callback_lease6_.reset();
+        callback_argument_names_.clear();
+        callback_addr_original_ = IOAddress("::");
+        callback_addr_updated_ = IOAddress("::");
+    }
+
+    /// callback that stores received callout name and received values
+    static int
+    lease6_select_callout(CalloutHandle& callout_handle) {
+
+        callback_name_ = string("lease6_select");
+
+        callout_handle.getArgument("subnet6", callback_subnet6_);
+        callout_handle.getArgument("fake_allocation", callback_fake_allocation_);
+        callout_handle.getArgument("lease6", callback_lease6_);
+
+        callback_addr_original_ = callback_lease6_->addr_;
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// callback that overrides the lease with different values
+    static int
+    lease6_select_different_callout(CalloutHandle& callout_handle) {
+
+        // Let's call the basic callout, so it can record all parameters
+        lease6_select_callout(callout_handle);
+
+        // Now we need to tweak the least a bit
+        Lease6Ptr lease;
+        callout_handle.getArgument("lease6", lease);
+        callback_addr_updated_ = addr_override_;
+        lease->addr_ = callback_addr_updated_;
+        lease->t1_ = t1_override_;
+        lease->t2_ = t2_override_;
+        lease->preferred_lft_ = pref_override_;
+        lease->valid_lft_ = valid_override_;
+
+        return (0);
+    }
+
+    // Values to be used in callout to override lease6 content
+    static const IOAddress addr_override_;
+    static const uint32_t t1_override_;
+    static const uint32_t t2_override_;
+    static const uint32_t pref_override_;
+    static const uint32_t valid_override_;
+
+    // Callback will store original and overridden values here
+    static IOAddress callback_addr_original_;
+    static IOAddress callback_addr_updated_;
+
+    // Buffers (callback will store received values here)
+    static string callback_name_;
+    static Subnet6Ptr callback_subnet6_;
+    static Lease6Ptr callback_lease6_;
+    static bool callback_fake_allocation_;
+    static vector<string> callback_argument_names_;
+};
+
+// For some reason intialization within a class makes the linker confused.
+// linker complains about undefined references if they are defined within
+// the class declaration.
+const IOAddress HookAllocEngine6Test::addr_override_("2001:db8::abcd");
+const uint32_t HookAllocEngine6Test::t1_override_ = 6000;
+const uint32_t HookAllocEngine6Test::t2_override_ = 7000;
+const uint32_t HookAllocEngine6Test::pref_override_ = 8000;
+const uint32_t HookAllocEngine6Test::valid_override_ = 9000;
+
+IOAddress HookAllocEngine6Test::callback_addr_original_("::");
+IOAddress HookAllocEngine6Test::callback_addr_updated_("::");
+
+string HookAllocEngine6Test::callback_name_;
+Subnet6Ptr HookAllocEngine6Test::callback_subnet6_;
+Lease6Ptr HookAllocEngine6Test::callback_lease6_;
+bool HookAllocEngine6Test::callback_fake_allocation_;
+vector<string> HookAllocEngine6Test::callback_argument_names_;
+
+// This test checks if the lease6_select callout is executed and expected
+// parameters as passed.
+TEST_F(HookAllocEngine6Test, lease6_select) {
+
+    // Note: The following order is working as expected:
+    // 1. create AllocEngine (that register hook points)
+    // 2. call loadLibraries()
+    //
+    // This order, however, causes segfault in HooksManager
+    // 1. call loadLibraries()
+    // 2. create AllocEngine (that register hook points)
+
+    // Create allocation engine (hook names are registered in its ctor)
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    // Initialize Hooks Manager
+    vector<string> libraries; // no libraries at this time
+    HooksManager::loadLibraries(libraries);
+
+    // Install pkt6_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease6_select", lease6_select_callout));
+
+    CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+
+    Lease6Ptr lease;
+    AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"),
+                                    Lease::TYPE_NA, false, false, "", false);
+    ctx.callout_handle_ = callout_handle;
+    EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // Do all checks on the lease
+    checkLease6(lease, Lease::TYPE_NA, 128);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+                                                               lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Check that callouts were indeed called
+    EXPECT_EQ("lease6_select", callback_name_);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    ASSERT_TRUE(callback_lease6_);
+    detailCompareLease(callback_lease6_, from_mgr);
+
+    ASSERT_TRUE(callback_subnet6_);
+    EXPECT_EQ(subnet_->toText(), callback_subnet6_->toText());
+
+    EXPECT_FALSE(callback_fake_allocation_);
+
+    // Check if all expected parameters are reported. It's a bit tricky, because
+    // order may be different. If the test starts failing, because someone tweaked
+    // hooks engine, we'll have to implement proper vector matching (ignoring order)
+    vector<string> expected_argument_names;
+    expected_argument_names.push_back("fake_allocation");
+    expected_argument_names.push_back("lease6");
+    expected_argument_names.push_back("subnet6");
+
+    sort(callback_argument_names_.begin(), callback_argument_names_.end());
+    sort(expected_argument_names.begin(), expected_argument_names.end());
+
+    EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+}
+
+// This test checks if lease6_select callout is able to override the values
+// in a lease6.
+TEST_F(HookAllocEngine6Test, change_lease6_select) {
+
+    // Make sure that the overridden values are different than the ones from
+    // subnet originally used to create the lease
+    ASSERT_NE(t1_override_, subnet_->getT1());
+    ASSERT_NE(t2_override_, subnet_->getT2());
+    ASSERT_NE(pref_override_, subnet_->getPreferred());
+    ASSERT_NE(valid_override_, subnet_->getValid());
+    ASSERT_FALSE(subnet_->inRange(addr_override_));
+
+    // Create allocation engine (hook names are registered in its ctor)
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    // Initialize Hooks Manager
+    vector<string> libraries; // no libraries at this time
+    HooksManager::loadLibraries(libraries);
+
+    // Install a callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease6_select", lease6_select_different_callout));
+
+    // Normally, dhcpv6_srv would passed the handle when calling allocateLeases6,
+    // but in tests we need to create it on our own.
+    CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+
+    // Call allocateLeases6. Callouts should be triggered here.
+    Lease6Ptr lease;
+    AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"),
+                                    Lease::TYPE_NA, false, false, "", false);
+    ctx.callout_handle_ = callout_handle;
+    EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // See if the values overridden by callout are there
+    EXPECT_TRUE(lease->addr_.equals(addr_override_));
+    EXPECT_EQ(t1_override_, lease->t1_);
+    EXPECT_EQ(t2_override_, lease->t2_);
+    EXPECT_EQ(pref_override_, lease->preferred_lft_);
+    EXPECT_EQ(valid_override_, lease->valid_lft_);
+
+    // Now check if the lease is in the database
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+                                                               lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Check if values in the database are overridden
+    EXPECT_TRUE(from_mgr->addr_.equals(addr_override_));
+    EXPECT_EQ(t1_override_, from_mgr->t1_);
+    EXPECT_EQ(t2_override_, from_mgr->t2_);
+    EXPECT_EQ(pref_override_, from_mgr->preferred_lft_);
+    EXPECT_EQ(valid_override_, from_mgr->valid_lft_);
+}
+
+
+/// @brief helper class used in Hooks testing in AllocEngine4
+///
+/// It features a couple of callout functions and buffers to store
+/// the data that is accessible via callouts.
+///
+/// Note: lease4_renew callout is tested from DHCPv4 server.
+/// See HooksDhcpv4SrvTest.basic_lease4_renew in
+/// src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+class HookAllocEngine4Test : public AllocEngine4Test {
+public:
+    HookAllocEngine4Test() {
+        resetCalloutBuffers();
+    }
+
+    virtual ~HookAllocEngine4Test() {
+        HooksManager::preCalloutsLibraryHandle().deregisterAllCallouts(
+            "lease4_select");
+    }
+
+    /// @brief clears out buffers, so callouts can store received arguments
+    void resetCalloutBuffers() {
+        callback_name_ = string("");
+        callback_subnet4_.reset();
+        callback_fake_allocation_ = false;
+        callback_lease4_.reset();
+        callback_argument_names_.clear();
+        callback_addr_original_ = IOAddress("::");
+        callback_addr_updated_ = IOAddress("::");
+    }
+
+    /// callback that stores received callout name and received values
+    static int
+    lease4_select_callout(CalloutHandle& callout_handle) {
+
+        callback_name_ = string("lease4_select");
+
+        callout_handle.getArgument("subnet4", callback_subnet4_);
+        callout_handle.getArgument("fake_allocation", callback_fake_allocation_);
+        callout_handle.getArgument("lease4", callback_lease4_);
+
+        callback_addr_original_ = callback_lease4_->addr_;
+
+        callback_argument_names_ = callout_handle.getArgumentNames();
+        return (0);
+    }
+
+    /// callback that overrides the lease with different values
+    static int
+    lease4_select_different_callout(CalloutHandle& callout_handle) {
+
+        // Let's call the basic callout, so it can record all parameters
+        lease4_select_callout(callout_handle);
+
+        // Now we need to tweak the least a bit
+        Lease4Ptr lease;
+        callout_handle.getArgument("lease4", lease);
+        callback_addr_updated_ = addr_override_;
+        lease->addr_ = callback_addr_updated_;
+        lease->t1_ = t1_override_;
+        lease->t2_ = t2_override_;
+        lease->valid_lft_ = valid_override_;
+
+        return (0);
+    }
+
+    // Values to be used in callout to override lease4 content
+    static const IOAddress addr_override_;
+    static const uint32_t t1_override_;
+    static const uint32_t t2_override_;
+    static const uint32_t valid_override_;
+
+    // Callback will store original and overridden values here
+    static IOAddress callback_addr_original_;
+    static IOAddress callback_addr_updated_;
+
+    // Buffers (callback will store received values here)
+    static string callback_name_;
+    static Subnet4Ptr callback_subnet4_;
+    static Lease4Ptr callback_lease4_;
+    static bool callback_fake_allocation_;
+    static vector<string> callback_argument_names_;
+};
+
+// For some reason intialization within a class makes the linker confused.
+// linker complains about undefined references if they are defined within
+// the class declaration.
+const IOAddress HookAllocEngine4Test::addr_override_("192.0.3.1");
+const uint32_t HookAllocEngine4Test::t1_override_ = 4000;
+const uint32_t HookAllocEngine4Test::t2_override_ = 7000;
+const uint32_t HookAllocEngine4Test::valid_override_ = 9000;
+
+IOAddress HookAllocEngine4Test::callback_addr_original_("::");
+IOAddress HookAllocEngine4Test::callback_addr_updated_("::");
+
+string HookAllocEngine4Test::callback_name_;
+Subnet4Ptr HookAllocEngine4Test::callback_subnet4_;
+Lease4Ptr HookAllocEngine4Test::callback_lease4_;
+bool HookAllocEngine4Test::callback_fake_allocation_;
+vector<string> HookAllocEngine4Test::callback_argument_names_;
+
+// This test checks if the lease4_select callout is executed and expected
+// parameters as passed.
+TEST_F(HookAllocEngine4Test, lease4_select) {
+
+    // Note: The following order is working as expected:
+    // 1. create AllocEngine (that register hook points)
+    // 2. call loadLibraries()
+    //
+    // This order, however, causes segfault in HooksManager
+    // 1. call loadLibraries()
+    // 2. create AllocEngine (that register hook points)
+
+    // Create allocation engine (hook names are registered in its ctor)
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
+    ASSERT_TRUE(engine);
+
+    // Initialize Hooks Manager
+    vector<string> libraries; // no libraries at this time
+    HooksManager::loadLibraries(libraries);
+
+    // Install pkt4_receive_callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease4_select", lease4_select_callout));
+
+    CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+
+    Lease4Ptr lease = engine->allocateLease4(subnet_, clientid_, hwaddr_,
+                                               IOAddress("0.0.0.0"),
+                                               false, false, "",
+                                               false, callout_handle,
+                                               old_lease_);
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // Do all checks on the lease
+    checkLease4(lease);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Check that callouts were indeed called
+    EXPECT_EQ("lease4_select", callback_name_);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    ASSERT_TRUE(callback_lease4_);
+    detailCompareLease(callback_lease4_, from_mgr);
+
+    ASSERT_TRUE(callback_subnet4_);
+    EXPECT_EQ(subnet_->toText(), callback_subnet4_->toText());
+
+    EXPECT_EQ(callback_fake_allocation_, false);
+
+    // Check if all expected parameters are reported. It's a bit tricky, because
+    // order may be different. If the test starts failing, because someone tweaked
+    // hooks engine, we'll have to implement proper vector matching (ignoring order)
+    vector<string> expected_argument_names;
+    expected_argument_names.push_back("fake_allocation");
+    expected_argument_names.push_back("lease4");
+    expected_argument_names.push_back("subnet4");
+    EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+}
+
+// This test checks if lease4_select callout is able to override the values
+// in a lease4.
+TEST_F(HookAllocEngine4Test, change_lease4_select) {
+
+    // Make sure that the overridden values are different than the ones from
+    // subnet originally used to create the lease
+    ASSERT_NE(t1_override_, subnet_->getT1());
+    ASSERT_NE(t2_override_, subnet_->getT2());
+    ASSERT_NE(valid_override_, subnet_->getValid());
+    ASSERT_FALSE(subnet_->inRange(addr_override_));
+
+    // Create allocation engine (hook names are registered in its ctor)
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100, false)));
+    ASSERT_TRUE(engine);
+
+    // Initialize Hooks Manager
+    vector<string> libraries; // no libraries at this time
+    HooksManager::loadLibraries(libraries);
+
+    // Install a callout
+    EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().registerCallout(
+                        "lease4_select", lease4_select_different_callout));
+
+    // Normally, dhcpv4_srv would passed the handle when calling allocateLease4,
+    // but in tests we need to create it on our own.
+    CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
+
+    // Call allocateLease4. Callouts should be triggered here.
+    Lease4Ptr lease = engine->allocateLease4(subnet_, clientid_, hwaddr_,
+                                             IOAddress("0.0.0.0"),
+                                             false, false, "",
+                                             false, callout_handle,
+                                             old_lease_);
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // See if the values overridden by callout are there
+    EXPECT_TRUE(lease->addr_.equals(addr_override_));
+    EXPECT_EQ(t1_override_, lease->t1_);
+    EXPECT_EQ(t2_override_, lease->t2_);
+    EXPECT_EQ(valid_override_, lease->valid_lft_);
+
+    // Now check if the lease is in the database
+    Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Check if values in the database are overridden
+    EXPECT_TRUE(from_mgr->addr_.equals(addr_override_));
+    EXPECT_EQ(t1_override_, from_mgr->t1_);
+    EXPECT_EQ(t2_override_, from_mgr->t2_);
+    EXPECT_EQ(valid_override_, from_mgr->valid_lft_);
+}
+
+}; // namespace test
+}; // namespace dhcp
+}; // namespace isc

File diff suppressed because it is too large
+ 0 - 3589
src/lib/dhcpsrv/tests/alloc_engine_unittest.cc


+ 325 - 0
src/lib/dhcpsrv/tests/alloc_engine_utils.cc

@@ -0,0 +1,325 @@
+// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <dhcp/duid.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
+#include <dhcpsrv/host_mgr.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/memfile_lease_mgr.h>
+
+#include <dhcpsrv/tests/test_utils.h>
+#include <dhcpsrv/tests/alloc_engine_utils.h>
+
+#include <hooks/hooks_manager.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <set>
+#include <time.h>
+
+using namespace std;
+using namespace isc::hooks;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+AllocEngine6Test::AllocEngine6Test() {
+    CfgMgr::instance().clear();
+
+    duid_ = DuidPtr(new DUID(std::vector<uint8_t>(8, 0x42)));
+    iaid_ = 42;
+
+    // Initialize a subnet and short address pool.
+    initSubnet(IOAddress("2001:db8:1::"),
+               IOAddress("2001:db8:1::10"),
+               IOAddress("2001:db8:1::20"));
+
+    initFqdn("", false, false);
+
+    factory_.create("type=memfile universe=6 persist=false");
+}
+
+Lease6Collection
+AllocEngine6Test::allocateTest(AllocEngine& engine, const Pool6Ptr& pool,
+                               const asiolink::IOAddress& hint, bool fake,
+                               bool in_pool) {
+    Lease::Type type = pool->getType();
+    uint8_t expected_len = pool->getLength();
+
+    AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type,
+                                    false, false, "", fake);
+
+    Lease6Collection leases;
+    EXPECT_NO_THROW(leases = engine.allocateLeases6(ctx));
+
+    for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
+
+        // Do all checks on the lease
+        checkLease6(*it, type, expected_len, in_pool, in_pool);
+
+        // Check that the lease is indeed in LeaseMgr
+        Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type,
+                                                                   (*it)->addr_);
+        if (!fake) {
+            // This is a real (REQUEST) allocation, the lease must be in the DB
+            EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText()
+                                  << " returned by allocateLeases6(), "
+                                  << "but was not present in LeaseMgr";
+            if (!from_mgr) {
+                return (leases);
+            }
+            
+            // Now check that the lease in LeaseMgr has the same parameters
+            detailCompareLease(*it, from_mgr);
+        } else {
+            // This is a fake (SOLICIT) allocation, the lease must not be in DB
+            EXPECT_FALSE(from_mgr) << "Lease " << from_mgr->addr_.toText()
+                                   << " returned by allocateLeases6(), "
+                                   << "was present in LeaseMgr (expected to be"
+                                   << " not present)";
+            if (from_mgr) {
+                return (leases);
+            }
+        }
+    }
+    
+    return (leases);
+}
+
+Lease6Ptr
+AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const IOAddress& hint,
+                                   bool fake, bool in_pool) {
+    Lease::Type type = pool->getType();
+    uint8_t expected_len = pool->getLength();
+
+    boost::scoped_ptr<AllocEngine> engine;
+    EXPECT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 100)));
+    // We can't use ASSERT macros in non-void methods
+    EXPECT_TRUE(engine);
+    if (!engine) {
+        return (Lease6Ptr());
+    }
+
+    Lease6Ptr lease;
+    AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type,
+                                    false, false, "", fake);
+
+    EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+    
+    // Check that we got a lease
+    EXPECT_TRUE(lease);
+    if (!lease) {
+        return (Lease6Ptr());
+    }
+
+    // Do all checks on the lease
+    checkLease6(lease, type, expected_len, in_pool, in_pool);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type, lease->addr_);
+    if (!fake) {
+        // This is a real (REQUEST) allocation, the lease must be in the DB
+        EXPECT_TRUE(from_mgr);
+        if (!from_mgr) {
+            return (Lease6Ptr());
+        }
+
+        // Now check that the lease in LeaseMgr has the same parameters
+        detailCompareLease(lease, from_mgr);
+    } else {
+        // This is a fake (SOLICIT) allocation, the lease must not be in DB
+        EXPECT_FALSE(from_mgr);
+        if (from_mgr) {
+            return (Lease6Ptr());
+        }
+    }
+
+    return (lease);
+}
+
+Lease6Collection
+AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool,
+                            AllocEngine::HintContainer& hints,
+                            bool allow_new_leases_in_renewal,
+                            bool in_pool) {
+
+    Lease::Type type = pool->getType();
+    uint8_t expected_len = pool->getLength();
+
+    AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, IOAddress("::"),
+                                    type, false, false, "", false);
+    ctx.hints_ = hints;
+    ctx.query_.reset(new Pkt6(DHCPV6_RENEW, 123));
+    ctx.allow_new_leases_in_renewals_ = allow_new_leases_in_renewal;
+
+    Lease6Collection leases = engine.renewLeases6(ctx);
+
+    for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
+
+        // Do all checks on the lease
+        checkLease6(*it, type, expected_len, in_pool, in_pool);
+
+        // Check that the lease is indeed in LeaseMgr
+        Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(type,
+                                                                   (*it)->addr_);
+
+        // This is a real (REQUEST) allocation, the lease must be in the DB
+        EXPECT_TRUE(from_mgr) << "Lease " << from_mgr->addr_.toText()
+                              << " returned by allocateLeases6(), "
+                              << "but was not present in LeaseMgr";
+        if (!from_mgr) {
+            return (leases);
+        }
+
+        // Now check that the lease in LeaseMgr has the same parameters
+        detailCompareLease(*it, from_mgr);
+    }
+
+    return (leases);
+}
+
+void
+AllocEngine6Test::allocWithUsedHintTest(Lease::Type type, IOAddress used_addr,
+                                        IOAddress requested,
+                                        uint8_t expected_pd_len) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    // Let's create a lease and put it in the LeaseMgr
+    DuidPtr duid2 = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xff)));
+    time_t now = time(NULL);
+    Lease6Ptr used(new Lease6(type, used_addr,
+                              duid2, 1, 2, 3, 4, now, subnet_->getID()));
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
+    
+    // Another client comes in and request an address that is in pool, but
+    // unfortunately it is used already. The same address must not be allocated
+    // twice.
+    Lease6Ptr lease;
+    AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, requested, type,
+                                    false, false, "", false);
+    EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+    
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+        
+    // Allocated address must be different
+    EXPECT_NE(used_addr, lease->addr_);
+
+    // We should NOT get what we asked for, because it is used already
+    EXPECT_NE(requested, lease->addr_);
+
+    // Do all checks on the lease
+    checkLease6(lease, type, expected_pd_len);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+                                                               lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease(lease, from_mgr);
+}
+
+void
+AllocEngine6Test::allocBogusHint6(Lease::Type type, asiolink::IOAddress hint,
+                                  uint8_t expected_pd_len) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    // Client would like to get a 3000::abc lease, which does not belong to any
+    // supported lease. Allocation engine should ignore it and carry on
+    // with the normal allocation
+    Lease6Ptr lease;
+    AllocEngine::ClientContext6 ctx(subnet_, duid_, iaid_, hint, type, false,
+                                    false, "", false);
+    EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx)));
+
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // We should NOT get what we asked for, because it is used already
+    EXPECT_NE(hint, lease->addr_);
+
+    // Do all checks on the lease
+    checkLease6(lease, type, expected_pd_len);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->type_,
+                                                               lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease(lease, from_mgr);
+}
+
+void
+AllocEngine4Test::initSubnet(const asiolink::IOAddress& pool_start,
+                             const asiolink::IOAddress& pool_end) {
+    CfgMgr& cfg_mgr = CfgMgr::instance();
+    
+    subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
+    pool_ = Pool4Ptr(new Pool4(pool_start, pool_end));
+    subnet_->addPool(pool_);
+
+    cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
+}
+
+AllocEngine4Test::AllocEngine4Test() {
+    // Create fresh instance of the HostMgr, and drop any previous HostMgr state.
+    HostMgr::instance().create();
+
+    clientid_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x44)));
+    uint8_t mac[] = { 0, 1, 22, 33, 44, 55};
+
+    // Let's use odd hardware type to check if there is no Ethernet
+    // hardcoded anywhere.
+    hwaddr_ = HWAddrPtr(new HWAddr(mac, sizeof(mac), HTYPE_FDDI));
+
+    // Allocate different MAC address for the tests that require two
+    // different MAC addresses.
+    ++mac[sizeof(mac) - 1];
+    hwaddr2_ = HWAddrPtr(new HWAddr(mac, sizeof (mac), HTYPE_FDDI));
+
+    // instantiate cfg_mgr
+    CfgMgr& cfg_mgr = CfgMgr::instance();
+
+    initSubnet(IOAddress("192.0.2.100"), IOAddress("192.0.2.109"));
+    cfg_mgr.commit();
+
+    factory_.create("type=memfile universe=4 persist=false");
+
+    // Create a default context. Note that remaining parameters must be
+    // assigned when needed.
+    ctx_.subnet_ = subnet_;
+    ctx_.clientid_ = clientid_;
+    ctx_.hwaddr_ = hwaddr_;
+    ctx_.callout_handle_ = HooksManager::createCalloutHandle();
+}
+
+}; // namespace test
+}; // namespace dhcp
+}; // namespace isc

+ 390 - 0
src/lib/dhcpsrv/tests/alloc_engine_utils.h

@@ -0,0 +1,390 @@
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef LIBDHCPSRV_ALLOC_ENGINE_UTILS_H
+#define LIBDHCPSRV_ALLOC_ENGINE_UTILS_H
+
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <asiolink/io_address.h>
+#include <gtest/gtest.h>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @file   alloc_engine_utils.h
+/// 
+/// @brief This is a header file for all Allocation Engine tests.
+/// 
+/// There used to be one, huge (over 3kloc) alloc_engine_unittest.cc. It is now
+/// split into serveral smaller files:
+/// alloc_engine_utils.h - contains test class definitions (this file)
+/// alloc_engine_utils.cc - contains test class implementation
+/// alloc_engine4_unittest.cc - all unit-tests dedicated to IPv4
+/// alloc_engine6_unittest.cc - all unit-tests dedicated to IPv6
+/// alloc_engine_hooks_unittest.cc - all unit-tests dedicated to hooks
+
+/// @brief Allocation engine with some internal methods exposed
+class NakedAllocEngine : public AllocEngine {
+public:
+
+    /// @brief the sole constructor
+    /// @param engine_type specifies engine type (e.g. iterative)
+    /// @param attempts number of lease selection attempts before giving up
+    /// @param ipv6 specifies if the engine is IPv6 or IPv4
+    NakedAllocEngine(AllocEngine::AllocType engine_type,
+                     unsigned int attempts, bool ipv6 = true)
+        :AllocEngine(engine_type, attempts, ipv6) {
+    }
+
+    // Expose internal classes for testing purposes
+    using AllocEngine::Allocator;
+    using AllocEngine::IterativeAllocator;
+    using AllocEngine::getAllocator;
+
+    /// @brief IterativeAllocator with internal methods exposed
+    class NakedIterativeAllocator: public AllocEngine::IterativeAllocator {
+    public:
+
+        /// @brief constructor
+        /// @param type pool types that will be interated
+        NakedIterativeAllocator(Lease::Type type)
+            :IterativeAllocator(type) {
+        }
+
+        using AllocEngine::IterativeAllocator::increaseAddress;
+        using AllocEngine::IterativeAllocator::increasePrefix;
+    };
+};
+
+/// @brief Used in Allocation Engine tests for IPv6
+class AllocEngine6Test : public ::testing::Test {
+public:
+
+    /// @brief Default constructor
+    ///
+    /// Sets duid_, iaid_, subnet_, pool_ fields to example values used
+    /// in many tests, initializes cfg_mgr configuration and creates
+    /// lease database.
+    AllocEngine6Test();
+
+    /// @brief Configures a subnet and adds one pool to it.
+    ///
+    /// This function removes existing v6 subnets before configuring
+    /// a new one.
+    ///
+    /// @param subnet Address of a subnet to be configured.
+    /// @param pool_start First address in the address pool.
+    /// @param pool_end Last address in the address pool.
+    void initSubnet(const asiolink::IOAddress& subnet,
+                    const asiolink::IOAddress& pool_start,
+                    const asiolink::IOAddress& pool_end) {
+        CfgMgr& cfg_mgr = CfgMgr::instance();
+
+        subnet_ = Subnet6Ptr(new Subnet6(subnet, 56, 1, 2, 3, 4));
+        pool_ = Pool6Ptr(new Pool6(Lease::TYPE_NA, pool_start, pool_end));
+
+        subnet_->addPool(pool_);
+
+        pd_pool_ = Pool6Ptr(new Pool6(Lease::TYPE_PD, subnet, 56, 64));
+        subnet_->addPool(pd_pool_);
+
+        cfg_mgr.getStagingCfg()->getCfgSubnets6()->add(subnet_);
+        cfg_mgr.commit();
+
+    }
+
+    /// @brief Initializes FQDN data for a test.
+    ///
+    /// The initialized values are used by the test fixture class members to
+    /// verify the correctness of a lease.
+    ///
+    /// @param hostname Hostname to be assigned to a lease.
+    /// @param fqdn_fwd Indicates whether or not to perform forward DNS update
+    /// for a lease.
+    /// @param fqdn_fwd Indicates whether or not to perform reverse DNS update
+    /// for a lease.
+    void initFqdn(const std::string& hostname, const bool fqdn_fwd,
+                  const bool fqdn_rev) {
+        hostname_ = hostname;
+        fqdn_fwd_ = fqdn_fwd;
+        fqdn_rev_ = fqdn_rev;
+    }
+
+    /// @brief attempts to convert leases collection to a single lease
+    ///
+    /// This operation makes sense if there is at most one lease in the
+    /// collection. Otherwise it will throw.
+    ///
+    /// @param col collection of leases (zero or one leases allowed)
+    /// @throw MultipleRecords if there is more than one lease
+    /// @return Lease6 pointer (or NULL if collection was empty)
+    Lease6Ptr expectOneLease(const Lease6Collection& col) {
+        if (col.size() > 1) {
+            isc_throw(MultipleRecords, "More than one lease found in collection");
+        }
+        if (col.empty()) {
+            return (Lease6Ptr());
+        }
+        return (*col.begin());
+    }
+
+    /// @brief checks if Lease6 matches expected configuration
+    ///
+    /// @param lease lease to be checked
+    /// @param exp_type expected lease type
+    /// @param exp_pd_len expected prefix length
+    /// @param expected_in_subnet whether the lease is expected to be in subnet
+    /// @param expected_in_pool whether the lease is expected to be in dynamic
+    void checkLease6(const Lease6Ptr& lease, Lease::Type exp_type,
+                     uint8_t exp_pd_len = 128, bool expected_in_subnet = true,
+                     bool expected_in_pool = true) {
+
+        // that is belongs to the right subnet
+        EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+
+        if (expected_in_subnet) {
+            EXPECT_TRUE(subnet_->inRange(lease->addr_));
+        } else {
+            EXPECT_FALSE(subnet_->inRange(lease->addr_));
+        }
+
+        if (expected_in_pool) {
+            EXPECT_TRUE(subnet_->inPool(exp_type, lease->addr_));
+        } else {
+            EXPECT_FALSE(subnet_->inPool(exp_type, lease->addr_));
+        }
+
+        // that it have proper parameters
+        EXPECT_EQ(exp_type, lease->type_);
+        EXPECT_EQ(iaid_, lease->iaid_);
+        EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
+        EXPECT_EQ(subnet_->getPreferred(), lease->preferred_lft_);
+        EXPECT_EQ(subnet_->getT1(), lease->t1_);
+        EXPECT_EQ(subnet_->getT2(), lease->t2_);
+        EXPECT_EQ(exp_pd_len, lease->prefixlen_);
+        EXPECT_EQ(fqdn_fwd_, lease->fqdn_fwd_);
+        EXPECT_EQ(fqdn_rev_, lease->fqdn_rev_);
+        EXPECT_EQ(hostname_, lease->hostname_);
+        EXPECT_TRUE(*lease->duid_ == *duid_);
+        /// @todo: check cltt
+    }
+
+    /// @brief Checks if specified address is increased properly
+    ///
+    /// Method uses gtest macros to mark check failure.
+    ///
+    /// @param alloc IterativeAllocator that is tested
+    /// @param input address to be increased
+    /// @param exp_output expected address after increase
+    void
+    checkAddrIncrease(NakedAllocEngine::NakedIterativeAllocator& alloc,
+                      std::string input, std::string exp_output) {
+        EXPECT_EQ(exp_output, alloc.increaseAddress(asiolink::IOAddress(input))
+                  .toText());
+    }
+
+    /// @brief Checks if increasePrefix() works as expected
+    ///
+    /// Method uses gtest macros to mark check failure.
+    ///
+    /// @param alloc allocator to be tested
+    /// @param input IPv6 prefix (as a string)
+    /// @param prefix_len prefix len
+    /// @param exp_output expected output (string)
+    void
+    checkPrefixIncrease(NakedAllocEngine::NakedIterativeAllocator& alloc,
+                        std::string input, uint8_t prefix_len,
+                        std::string exp_output) {
+        EXPECT_EQ(exp_output, alloc.increasePrefix(asiolink::IOAddress(input),
+                                                   prefix_len).toText());
+    }
+
+    /// @brief Checks if the simple allocation can succeed
+    ///
+    /// The type of lease is determined by pool type (pool->getType()
+    ///
+    /// @param pool pool from which the lease will be allocated from
+    /// @param hint address to be used as a hint
+    /// @param fake true - this is fake allocation (SOLICIT)
+    /// @param in_pool specifies whether the lease is expected to be in pool
+    /// @return allocated lease (or NULL)
+    Lease6Ptr simpleAlloc6Test(const Pool6Ptr& pool,
+                               const asiolink::IOAddress& hint,
+                               bool fake, bool in_pool = true);
+
+    /// @brief Checks if the allocation can succeed.
+    ///
+    /// The type of lease is determined by pool type (pool->getType()).
+    /// This test is particularly useful in connection with @ref renewTest.
+    ///
+    /// @param engine a reference to Allocation Engine
+    /// @param pool pool from which the lease will be allocated from
+    /// @param hint address to be used as a hint
+    /// @param fake true - this is fake allocation (SOLICIT)
+    /// @param in_pool specifies whether the lease is expected to be in pool
+    /// @return allocated lease(s) (may be empty)
+    Lease6Collection allocateTest(AllocEngine& engine, const Pool6Ptr& pool,
+                                  const asiolink::IOAddress& hint, bool fake,
+                                  bool in_pool = true);
+
+    /// @brief Checks if the allocation can be renewed.
+    ///
+    /// The type of lease is determined by pool type (pool->getType()).
+    /// This test is particularly useful as a follow up to @ref allocateTest.
+    ///
+    /// @param engine a reference to Allocation Engine
+    /// @param pool pool from which the lease will be allocated from
+    /// @param hint address to be used as a hint
+    /// @param fake true - this is fake allocation (SOLICIT)
+    /// @param in_pool specifies whether the lease is expected to be in pool
+    /// @return allocated lease(s) (may be empty)
+    Lease6Collection renewTest(AllocEngine& engine, const Pool6Ptr& pool,
+                               AllocEngine::HintContainer& hints,
+                               bool allow_new_leases_in_renewal,
+                               bool in_pool = true);
+
+    /// @brief Checks if the address allocation with a hint that is in range,
+    ///        in pool, but is currently used, can succeed
+    ///
+    /// Method uses gtest macros to mark check failure.
+    ///
+    /// @param type lease type
+    /// @param used_addr address should be preallocated (simulates prior
+    ///        allocation by some other user)
+    /// @param requested address requested by the client
+    /// @param expected_pd_len expected PD len (128 for addresses)
+    void allocWithUsedHintTest(Lease::Type type, asiolink::IOAddress used_addr,
+                               asiolink::IOAddress requested,
+                               uint8_t expected_pd_len);
+
+    /// @brief checks if bogus hint can be ignored and the allocation succeeds
+    ///
+    /// This test checks if the allocation with a hing that is out of the blue
+    /// can succeed. The invalid hint should be ignored completely.
+    ///
+    /// @param type Lease type
+    /// @param hint hint (as send by a client)
+    /// @param expected_pd_len (used in validation)
+    void allocBogusHint6(Lease::Type type, asiolink::IOAddress hint,
+                         uint8_t expected_pd_len);
+
+    /// @brief Utility function that creates a host reservation
+    ///
+    /// @param add_to_host_mgr true if the reservation should be added
+    /// @param type specifies reservation type
+    /// @param addr specifies reserved address or prefix
+    /// @param prefix_len prefix length (should be 128 for addresses)
+    /// @return created Host object.
+    HostPtr
+    createHost6(bool add_to_host_mgr, IPv6Resrv::Type type,
+                const asiolink::IOAddress& addr, uint8_t prefix_len) {
+        HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(),
+                              Host::IDENT_DUID, SubnetID(0), subnet_->getID(),
+                              asiolink::IOAddress("0.0.0.0")));
+        IPv6Resrv resv(type, addr, prefix_len);
+        host->addReservation(resv);
+
+        if (add_to_host_mgr) {
+            CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host);
+            CfgMgr::instance().commit();
+        }
+        return (host);
+    }
+
+    virtual ~AllocEngine6Test() {
+        factory_.destroy();
+    }
+
+    DuidPtr duid_;            ///< client-identifier (value used in tests)
+    uint32_t iaid_;           ///< IA identifier (value used in tests)
+    Subnet6Ptr subnet_;       ///< subnet6 (used in tests)
+    Pool6Ptr pool_;           ///< NA pool belonging to subnet_
+    Pool6Ptr pd_pool_;        ///< PD pool belonging to subnet_
+    std::string hostname_;    ///< Hostname
+    bool fqdn_fwd_;           ///< Perform forward update for a lease.
+    bool fqdn_rev_;           ///< Perform reverse update for a lease.
+    LeaseMgrFactory factory_; ///< pointer to LeaseMgr factory
+};
+
+/// @brief Used in Allocation Engine tests for IPv4
+class AllocEngine4Test : public ::testing::Test {
+public:
+
+    /// @brief Default constructor
+    ///
+    /// Sets clientid_, hwaddr_, subnet_, pool_ fields to example values
+    /// used in many tests, initializes cfg_mgr configuration and creates
+    /// lease database.
+    ///
+    /// It also re-initializes the Host Manager.
+    AllocEngine4Test();
+
+    /// @brief checks if Lease4 matches expected configuration
+    ///
+    /// @param lease lease to be checked
+    void checkLease4(const Lease4Ptr& lease) {
+        // Check that is belongs to the right subnet
+        EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+        EXPECT_TRUE(subnet_->inRange(lease->addr_));
+        EXPECT_TRUE(subnet_->inPool(Lease::TYPE_V4, lease->addr_));
+
+        // Check that it has proper parameters
+        EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
+        EXPECT_EQ(subnet_->getT1(), lease->t1_);
+        EXPECT_EQ(subnet_->getT2(), lease->t2_);
+        if (lease->client_id_ && !clientid_) {
+            ADD_FAILURE() << "Lease4 has a client-id, while it should have none.";
+        } else
+        if (!lease->client_id_ && clientid_) {
+            ADD_FAILURE() << "Lease4 has no client-id, but it was expected to have one.";
+        } else
+        if (lease->client_id_ && clientid_) {
+            EXPECT_TRUE(*lease->client_id_ == *clientid_);
+        }
+        EXPECT_TRUE(*lease->hwaddr_ == *hwaddr_);
+        /// @todo: check cltt
+     }
+
+    /// @brief Create a subnet with a specified pool of addresses.
+    ///
+    /// @param pool_start First address in the pool.
+    /// @param pool_end Last address in the pool.
+    void initSubnet(const asiolink::IOAddress& pool_start,
+                    const asiolink::IOAddress& pool_end);
+
+    virtual ~AllocEngine4Test() {
+        factory_.destroy();
+    }
+
+    ClientIdPtr clientid_;      ///< Client-identifier (value used in tests)
+    HWAddrPtr hwaddr_;          ///< Hardware address (value used in tests)
+    HWAddrPtr hwaddr2_;         ///< Alternative hardware address.
+    Subnet4Ptr subnet_;         ///< Subnet4 (used in tests)
+    Pool4Ptr pool_;             ///< Pool belonging to subnet_
+    LeaseMgrFactory factory_;   ///< Pointer to LeaseMgr factory
+    Lease4Ptr old_lease_;       ///< Holds previous instance of the lease.
+    AllocEngine::ClientContext4 ctx_; ///< Context information passed to various
+                                     ///< allocation engine functions.
+};
+
+}; // namespace test
+}; // namespace dhcp
+}; // namespace isc
+
+#endif

+ 0 - 1
src/lib/dhcpsrv/tests/test_utils.h

@@ -16,7 +16,6 @@
 #define LIBDHCPSRV_TEST_UTILS_H
 
 #include <dhcpsrv/lease_mgr.h>
-#include <gtest/gtest.h>
 #include <vector>
 
 namespace isc {