]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[897-add-infinite-valid-lifetime] Checkpoint: todo server unit tests
authorFrancis Dupont <fdupont@isc.org>
Thu, 12 Sep 2019 07:23:42 +0000 (09:23 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 12 Sep 2019 07:23:42 +0000 (09:23 +0200)
doc/sphinx/arm/dhcp4-srv.rst
doc/sphinx/arm/dhcp6-srv.rst
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp6/dhcp6_srv.cc
src/lib/dhcpsrv/alloc_engine.cc
src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc
src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc
src/lib/dhcpsrv/tests/alloc_engine_utils.cc
src/lib/dhcpsrv/tests/alloc_engine_utils.h

index 98bb466b9189c7557ebc9167cdff10a25a9760e8..4298ebd3269ea891a6433f4e38f53bdbdc516182 100644 (file)
@@ -1227,7 +1227,8 @@ is not being sent and T1 is less than the valid lease time.
 Calculating the values is controlled by the following three parameters.
 
 -  ``calculate-tee-times`` - when true, T1 and T2 will be calculated as
-   percentages of the valid lease time. It defaults to false.
+   percentages of the valid lease time. It defaults to false and
+   is ignored for infinite (0xFFFFFFFF) valid lease times.
 
 -  ``t1-percent`` - the percentage of the valid lease time to use for
    T1. It is expressed as a real number between 0.0 and 1.0 and must be
index c94c0404bdea6d14bbde778a29c2f6ff1b32f6b7..3cb7ebc8cafede4932e73035dc6bb517193ea76f 100644 (file)
@@ -2160,7 +2160,8 @@ However, there may be some rare business cases when this is desired
 Calculation of the values is controlled by the following three parameters:
 
 -  ``calculate-tee-times`` - when true, T1 and T2 will be calculated as
-   percentages of the valid lease time. It defaults to true.
+   percentages of the valid lease time. It defaults to true and is
+   ignored for infinite (0xFFFFFFFF) valid lease times.
 
 -  ``t1-percent`` - the percentage of the valid lease time to use for
    T1. It is expressed as a real number between 0.0 and 1.0 and must be
index 0557ba4061b8191200939085aba78ec06b6fa673..773b537e3d81eda2901f61c1de858c32253f5ec6 100644 (file)
@@ -2333,6 +2333,9 @@ Dhcpv4Srv::setTeeTimes(const Lease4Ptr& lease, const Subnet4Ptr& subnet, Pkt4Ptr
     // If T2 is explicitly configured we'll use try value.
     if (!subnet->getT2().unspecified()) {
         t2_time = subnet->getT2();
+    } else if (lease->valid_lft_ == Lease::INFINITY_LFT) {
+        // Do not calculate with infinite values.
+        t2_time = subnet->getT2();
     } else if (subnet->getCalculateTeeTimes()) {
         // Calculating tee times is enabled, so calculated it.
         t2_time = static_cast<uint32_t>(round(subnet->getT2Percent() * (lease->valid_lft_)));
@@ -2352,6 +2355,9 @@ Dhcpv4Srv::setTeeTimes(const Lease4Ptr& lease, const Subnet4Ptr& subnet, Pkt4Ptr
     // If T1 is explicitly configured we'll use try value.
     if (!subnet->getT1().unspecified()) {
         t1_time = subnet->getT1();
+    } else if (lease->valid_lft_== Lease::INFINITY_LFT) {
+        // Do not calculate with infinite values.
+        t1_time = subnet->getT1();
     } else if (subnet->getCalculateTeeTimes()) {
         // Calculating tee times is enabled, so calculate it.
         t1_time = static_cast<uint32_t>(round(subnet->getT1Percent() * (lease->valid_lft_)));
index 470e34e45641012bcdffd97abfa3d834bac9476d..46b050fed9852d889f488ae1d8b0c401445ebce6 100644 (file)
@@ -4002,6 +4002,9 @@ Dhcpv6Srv::setTeeTimes(uint32_t preferred_lft, const Subnet6Ptr& subnet, Option6
     // If T2 is explicitly configured we'll use that value.
     if (!subnet->getT2().unspecified()) {
         t2_time = subnet->getT2();
+    } else if (preferred_lft == Lease::INFINITY_LFT) {
+        // Do not calculate with infinite values.
+        t2_time = subnet->getT2();
     } else if (subnet->getCalculateTeeTimes()) {
         // Calculating tee times is enabled, so calculate it.
         t2_time = static_cast<uint32_t>(round(subnet->getT2Percent() * preferred_lft));
@@ -4016,6 +4019,9 @@ Dhcpv6Srv::setTeeTimes(uint32_t preferred_lft, const Subnet6Ptr& subnet, Option6
     // If T1 is explicitly configured we'll use try value.
     if (!subnet->getT1().unspecified()) {
         t1_time = subnet->getT1();
+    } else if (preferred_lft == Lease::INFINITY_LFT) {
+        // Do not calculate with infinite values.
+        t1_time = subnet->getT1();
     } else if (subnet->getCalculateTeeTimes()) {
         // Calculating tee times is enabled, so calculate it.
         t1_time = static_cast<uint32_t>(round(subnet->getT1Percent() * preferred_lft));
index 9032974972654e756a5cd9cbd22451722b5ae5e3..6a3aa48906e18ed1d688f595be9cf23129b4f63c 100644 (file)
@@ -1626,7 +1626,13 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
     if (!ctx.currentIA().hints_.empty() &&
         ctx.currentIA().hints_[0].getPreferred()) {
         uint32_t preferred = ctx.currentIA().hints_[0].getPreferred();
-        expired->preferred_lft_ = ctx.subnet_->getPreferred().get(preferred);
+        if ((preferred == Lease::INFINITY_LFT) &&
+            ctx.subnet_->getAllowStaticLeases()) {
+            expired->preferred_lft_ = Lease::INFINITY_LFT;
+        } else {
+            expired->preferred_lft_ =
+                ctx.subnet_->getPreferred().get(preferred);
+        }
     } else {
         expired->preferred_lft_ = ctx.subnet_->getPreferred();
     }
@@ -1635,7 +1641,12 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
     if (!ctx.currentIA().hints_.empty() &&
         ctx.currentIA().hints_[0].getValid()) {
         uint32_t valid = ctx.currentIA().hints_[0].getValid();
-        expired->valid_lft_ = ctx.subnet_->getValid().get(valid);
+        if ((valid == Lease::INFINITY_LFT) &&
+            ctx.subnet_->getAllowStaticLeases()) {
+            expired->valid_lft_ = Lease::INFINITY_LFT;
+        } else {
+            expired->valid_lft_ = ctx.subnet_->getValid().get(valid);
+        }
     } else {
         expired->valid_lft_ = ctx.subnet_->getValid();
     }
@@ -1738,13 +1749,19 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx,
     if (!ctx.currentIA().hints_.empty() &&
         ctx.currentIA().hints_[0].getPreferred()) {
         preferred = ctx.currentIA().hints_[0].getPreferred();
-        preferred = ctx.subnet_->getPreferred().get(preferred);
+        if ((preferred != Lease::INFINITY_LFT) ||
+            !ctx.subnet_->getAllowStaticLeases()) {
+          preferred = ctx.subnet_->getPreferred().get(preferred);
+        }
     }
     uint32_t valid = ctx.subnet_->getValid();
     if (!ctx.currentIA().hints_.empty() &&
         ctx.currentIA().hints_[0].getValid()) {
         valid = ctx.currentIA().hints_[0].getValid();
-        valid = ctx.subnet_->getValid().get(valid);
+        if ((valid != Lease::INFINITY_LFT) ||
+            !ctx.subnet_->getAllowStaticLeases()) {
+          valid = ctx.subnet_->getValid().get(valid);
+        }
     }
     Lease6Ptr lease(new Lease6(ctx.currentIA().type_, addr, ctx.duid_,
                                ctx.currentIA().iaid_, preferred,
@@ -1991,14 +2008,24 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
     if (!ctx.currentIA().hints_.empty() &&
         ctx.currentIA().hints_[0].getPreferred()) {
         uint32_t preferred = ctx.currentIA().hints_[0].getPreferred();
-        lease->preferred_lft_ = ctx.subnet_->getPreferred().get(preferred);
+        if ((preferred == Lease::INFINITY_LFT) &&
+            ctx.subnet_->getAllowStaticLeases()) {
+            lease->preferred_lft_ = Lease::INFINITY_LFT;
+        } else {
+            lease->preferred_lft_ = ctx.subnet_->getPreferred().get(preferred);
+        }
     } else {
         lease->preferred_lft_ = ctx.subnet_->getPreferred();
     }
     if (!ctx.currentIA().hints_.empty() &&
         ctx.currentIA().hints_[0].getValid()) {
         uint32_t valid = ctx.currentIA().hints_[0].getValid();
-        lease->valid_lft_ = ctx.subnet_->getValid().get(valid);
+        if ((valid == Lease::INFINITY_LFT) &&
+            ctx.subnet_->getAllowStaticLeases()) {
+            lease->valid_lft_ = Lease::INFINITY_LFT;
+        } else {
+            lease->valid_lft_ = ctx.subnet_->getValid().get(valid);
+        }
     } else {
         lease->valid_lft_ = ctx.subnet_->getValid();
     }
@@ -3509,7 +3536,13 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr,
         opt_lft = boost::dynamic_pointer_cast<OptionInt<uint32_t> >(opt);
     }
     if (opt_lft) {
-        valid_lft = ctx.subnet_->getValid().get(opt_lft->getValue());
+        uint32_t valid = opt_lft->getValue();
+        if ((valid == Lease::INFINITY_LFT) &&
+            ctx.subnet_->getAllowStaticLeases()) {
+            valid_lft = Lease::INFINITY_LFT;
+        } else {
+            valid_lft = ctx.subnet_->getValid().get(valid);
+        }
     }
 
     time_t now = time(NULL);
@@ -3933,7 +3966,13 @@ AllocEngine::updateLease4Information(const Lease4Ptr& lease,
         opt_lft = boost::dynamic_pointer_cast<OptionInt<uint32_t> >(opt);
     }
     if (opt_lft) {
-        lease->valid_lft_ = ctx.subnet_->getValid().get(opt_lft->getValue());
+        uint32_t valid = opt_lft->getValue();
+        if ((valid == Lease::INFINITY_LFT) &&
+            ctx.subnet_->getAllowStaticLeases()) {
+            lease->valid_lft_ = Lease::INFINITY_LFT;
+        } else {
+            lease->valid_lft_ = ctx.subnet_->getValid().get(valid);
+        }
     } else {
         lease->valid_lft_ = ctx.subnet_->getValid();
     }
index ac5dea7da2abe9e2869a1943be500f778af150cf..8dd534021c839a41faf7b7ba8b6a08336bd89dac 100644 (file)
@@ -276,6 +276,46 @@ TEST_F(AllocEngine4Test, maxAlloc4) {
     detailCompareLease(lease, from_mgr);
 }
 
+// This test checks that simple allocation handles static leases.
+TEST_F(AllocEngine4Test, staticAlloc4) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 0, false)));
+    ASSERT_TRUE(engine);
+
+    AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
+                                    false, true, "somehost.example.com.", false);
+    subnet_->setValid(Triplet<uint32_t>(1, 3, 5));
+    subnet_->setAllowStaticLeases(true);
+    ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+    // Speficy an infinite valid lifetime.
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    OptionUint32Ptr opt(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME,
+                                         infinity_lft));
+    ctx.query_->addOption(opt);
+
+    Lease4Ptr lease = engine->allocateLease4(ctx);
+    // The new lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(ctx.old_lease_);
+
+    // Check that we got a lease
+    ASSERT_TRUE(lease);
+
+    // Do all checks on the lease
+    checkLease4(lease, true);
+
+    // Check the valid lifetime has the wanted value.
+    EXPECT_EQ(infinity_lft, lease->valid_lft_);
+
+    // Check that the lease is indeed in LeaseMgr
+    Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_);
+    ASSERT_TRUE(from_mgr);
+
+    // Now check that the lease in LeaseMgr has the same parameters
+    detailCompareLease(lease, from_mgr);
+}
+
 // This test checks if the fake allocation (for DHCPDISCOVER) can succeed
 TEST_F(AllocEngine4Test, fakeAlloc4) {
     boost::scoped_ptr<AllocEngine> engine;
@@ -681,6 +721,52 @@ TEST_F(AllocEngine4Test, maxRenew4) {
     EXPECT_EQ(subnet_->getValid().getMax(), lease2->valid_lft_);
 }
 
+// This test checks simple renewal handles static leases.
+TEST_F(AllocEngine4Test, staticRenew4) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
+                                                 0, false)));
+    ASSERT_TRUE(engine);
+
+    AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, IOAddress("0.0.0.0"),
+                                    false, true, "somehost.example.com.", false);
+    subnet_->setValid(Triplet<uint32_t>(1, 3, 5));
+    subnet_->setAllowStaticLeases(true);
+    ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234));
+
+    // Speficy the valid lifetime we want, as it is greater than the max value
+    // we'll get this max value instead.
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    OptionUint32Ptr opt(new OptionUint32(Option::V4, DHO_DHCP_LEASE_TIME,
+                                         infinity_lft));
+    ctx.query_->addOption(opt);
+
+    Lease4Ptr lease = engine->allocateLease4(ctx);
+
+    // Check that we got a lease and it's sane
+    ASSERT_TRUE(lease);
+    checkLease4(lease, true);
+
+    // Check the valid lifetime has the max value.
+    EXPECT_EQ(infinity_lft, lease->valid_lft_);
+
+    // The new lease has been allocated, so the old lease should not exist.
+    EXPECT_FALSE(ctx.old_lease_);
+
+    // Do it again, this should amount to the renew of an existing lease
+    Lease4Ptr lease2 = engine->allocateLease4(ctx);
+
+    // Check that we got a lease and it's sane
+    ASSERT_TRUE(lease2);
+    checkLease4(lease2, true);
+
+    // Lease already existed, so old_lease should be set.
+    EXPECT_TRUE(ctx.old_lease_);
+
+    // Check the renewed valid lifetime has the infinite value.
+    EXPECT_EQ(infinity_lft, lease2->valid_lft_);
+}
+
 // This test verifies that the allocator picks addresses that belong to the
 // pool
 TEST_F(AllocEngine4Test, IterativeAllocator) {
index d35985a73653d51f0030bec08cea1b8a492958d0..d865c6de0ec57a516f95f00d60cd20c9af0abe2f 100644 (file)
@@ -124,6 +124,13 @@ TEST_F(AllocEngine6Test, maxAlloc6) {
     simpleAlloc6Test(pd_pool_, IOAddress("::"), 500, 600, 400, 500);
 }
 
+// This test checks that simple allocation handles static leases.
+TEST_F(AllocEngine6Test, staticAlloc6) {
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    simpleAlloc6Test(pool_, IOAddress("::"), infinity_lft, infinity_lft,
+                     infinity_lft, infinity_lft);
+}
+
 // This test checks if the simple PD allocation (REQUEST) can succeed
 // and the stats counter is properly bumped by 1
 TEST_F(AllocEngine6Test, pdSimpleAlloc6) {
@@ -1097,6 +1104,54 @@ TEST_F(AllocEngine6Test, maxReuseExpiredLease6) {
     EXPECT_EQ(500, lease->valid_lft_);
 }
 
+// This test checks if an expired lease can be reused using infinite lifetimes.
+TEST_F(AllocEngine6Test, staticReuseExpiredLease6) {
+    boost::scoped_ptr<AllocEngine> engine;
+    ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+    ASSERT_TRUE(engine);
+
+    IOAddress addr("2001:db8:1::ad");
+
+    // Create one subnet with a pool holding one address.
+    initSubnet(IOAddress("2001:db8:1::"), addr, addr);
+    subnet_->setPreferred(Triplet<uint32_t>(200, 300, 400));
+    subnet_->setValid(Triplet<uint32_t>(300, 400, 500));
+    subnet_->setAllowStaticLeases(true);
+
+    // Initialize FQDN data for the lease.
+    initFqdn("myhost.example.com", true, true);
+
+    // Just a different duid
+    DuidPtr other_duid = DuidPtr(new DUID(vector<uint8_t>(12, 0xff)));
+    const uint32_t other_iaid = 3568;
+    Lease6Ptr lease(new Lease6(Lease::TYPE_NA, addr, other_duid, other_iaid,
+                               501, 502, subnet_->getID(),
+                               HWAddrPtr(), 0));
+    lease->cltt_ = time(NULL) - 500; // Allocated 500 seconds ago
+    lease->valid_lft_ = 495; // Lease was valid for 495 seconds
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+    // Make sure that we really created expired lease
+    ASSERT_TRUE(lease->expired());
+
+    // Asking specifically for this address with zero lifetimes
+    AllocEngine::ClientContext6 ctx2(subnet_, duid_, false, false, "", true,
+                                     Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234)));
+    ctx2.currentIA().iaid_ = iaid_;
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    ctx2.currentIA().addHint(addr, 128, infinity_lft, infinity_lft);
+
+    EXPECT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx2)));
+
+    // Check that we got that single lease
+    ASSERT_TRUE(lease);
+    EXPECT_EQ(addr, lease->addr_);
+
+    // Check lifetimes: infinite values are expected.
+    EXPECT_EQ(infinity_lft, lease->preferred_lft_);
+    EXPECT_EQ(infinity_lft, lease->valid_lft_);
+}
+
 // This test checks if an expired lease can be reused in REQUEST (actual allocation)
 TEST_F(AllocEngine6Test, requestReuseExpiredLease6) {
     boost::scoped_ptr<AllocEngine> engine;
@@ -1390,6 +1445,43 @@ TEST_F(AllocEngine6Test, maxRenewLeaseLifetime) {
     EXPECT_EQ(500, renewed[0]->valid_lft_);
 }
 
+// Checks that a renewed lease handles static leases.
+TEST_F(AllocEngine6Test, staticRenewLeaseLifetime) {
+    // Create a lease for the client.
+    Lease6Ptr lease(new Lease6(Lease::TYPE_NA, IOAddress("2001:db8:1::15"),
+                               duid_, iaid_, 300, 400,
+                               subnet_->getID(), HWAddrPtr(), 128));
+
+    // Allocated 200 seconds ago - half of the lifetime.
+    time_t lease_cltt = time(NULL) - 200;
+    lease->cltt_ = lease_cltt;
+
+    ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+
+    AllocEngine engine(AllocEngine::ALLOC_ITERATIVE, 100);
+    subnet_->setPreferred(Triplet<uint32_t>(200, 300, 400));
+    subnet_->setValid(Triplet<uint32_t>(300, 400, 500));
+    subnet_->setAllowStaticLeases(true);
+
+    // This is what the client will send in his renew message.
+    AllocEngine::HintContainer hints;
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1::15"),
+                                          128, infinity_lft, infinity_lft));
+
+    // Client should receive a lease.
+    Lease6Collection renewed = renewTest(engine, pool_, hints, true, true);
+    ASSERT_EQ(1, renewed.size());
+
+    // And the lease lifetime should be extended.
+    EXPECT_GT(renewed[0]->cltt_, lease_cltt)
+        << "Lease lifetime was not extended, but it should";
+
+    // Checks that infinite values are used for lifetimes.
+    EXPECT_EQ(infinity_lft, renewed[0]->preferred_lft_);
+    EXPECT_EQ(infinity_lft, renewed[0]->valid_lft_);
+}
+
 // Checks if the lease lifetime is extended when the client sends the
 // Renew and the client has a reservation for the lease.
 TEST_F(AllocEngine6Test, renewExtendLeaseLifetimeForReservation) {
index b283f6c999b1d103b2fb127fbdd0d01e9697302c..2617a0ab0f954d44bddde10c7961578135997730 100644 (file)
@@ -296,6 +296,8 @@ AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const IOAddress& hint,
     ctx.currentIA().addHint(hint, expected_len, preferred, valid);
     subnet_->setPreferred(Triplet<uint32_t>(200, 300, 400));
     subnet_->setValid(Triplet<uint32_t>(300, 400, 500));
+    uint32_t infinity_lft = Lease::INFINITY_LFT;
+    subnet_->setAllowStaticLeases(exp_valid == infinity_lft);
 
     // Set some non-standard callout status to make sure it doesn't affect the
     // allocation.
@@ -313,7 +315,8 @@ AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const IOAddress& hint,
     }
 
     // Do all checks on the lease
-    checkLease6(duid_, lease, type, expected_len, true, true);
+    checkLease6(duid_, lease, type, expected_len, true, true,
+                exp_valid == infinity_lft);
 
     // Check expected preferred and valid lifetimes.
     EXPECT_EQ(exp_preferred, lease->preferred_lft_);
@@ -389,7 +392,7 @@ AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const DuidPtr& duid,
 Lease6Collection
 AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool,
                             AllocEngine::HintContainer& hints,
-                            bool in_pool) {
+                            bool in_pool, bool is_static) {
 
     Lease::Type type = pool->getType();
     uint8_t expected_len = pool->getLength();
@@ -407,7 +410,8 @@ AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool,
     for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) {
 
         // Do all checks on the lease
-        checkLease6(duid_, *it, type, expected_len, in_pool, in_pool);
+        checkLease6(duid_, *it, type, expected_len,
+                    in_pool, in_pool, is_static);
 
         // Check that context has been updated with allocated addresses or
         // prefixes.
index ad148b0611ba86a1bd505422845ab6954f32ee54..5c02e73ae455e6f10541910aae18dd4ac8fb44d8 100644 (file)
@@ -168,11 +168,13 @@ public:
     /// @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
+    /// @param expected_in_pool whether the lease is expected to be in pool
+    /// @param expected_static whether the lease is expected to be static
     void checkLease6(const DuidPtr& duid, const Lease6Ptr& lease,
                      Lease::Type exp_type, uint8_t exp_pd_len = 128,
                      bool expected_in_subnet = true,
-                     bool expected_in_pool = true) {
+                     bool expected_in_pool = true,
+                     bool expected_static = false) {
 
         // that is belongs to the right subnet
         EXPECT_EQ(lease->subnet_id_, subnet_->getID());
@@ -194,13 +196,17 @@ public:
         // that it have proper parameters
         EXPECT_EQ(exp_type, lease->type_);
         EXPECT_EQ(iaid_, lease->iaid_);
-        if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
+        if (expected_static) {
+            EXPECT_EQ(0xffffffff, lease->valid_lft_);
+        } else if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
             EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
         } else {
             EXPECT_LE(subnet_->getValid().getMin(), lease->valid_lft_);
             EXPECT_GE(subnet_->getValid().getMax(), lease->valid_lft_);
         }
-        if (subnet_->getPreferred().getMin() == subnet_->getPreferred().getMax()) {
+        if (expected_static) {
+            EXPECT_EQ(0xffffffff, lease->preferred_lft_);
+        } else if (subnet_->getPreferred().getMin() == subnet_->getPreferred().getMax()) {
             EXPECT_EQ(subnet_->getPreferred(), lease->preferred_lft_);
         } else {
             EXPECT_LE(subnet_->getPreferred().getMin(), lease->preferred_lft_);
@@ -324,10 +330,12 @@ public:
     /// @param pool pool from which the lease will be allocated from
     /// @param hints address to be used as a hint
     /// @param in_pool specifies whether the lease is expected to be in pool
+    /// @param is_static specifies whether the lease is expected to be static
     /// @return allocated lease(s) (may be empty)
     Lease6Collection renewTest(AllocEngine& engine, const Pool6Ptr& pool,
                                AllocEngine::HintContainer& hints,
-                               bool in_pool = true);
+                               bool in_pool = true,
+                               bool is_static = false);
 
     /// @brief Checks if the address allocation with a hint that is in range,
     ///        in pool, but is currently used, can succeed
@@ -478,14 +486,17 @@ public:
     /// @brief checks if Lease4 matches expected configuration
     ///
     /// @param lease lease to be checked
-    void checkLease4(const Lease4Ptr& lease) {
+    /// @param expected_static whether the lease is expected to be static
+    void checkLease4(const Lease4Ptr& lease, bool expected_static = false) {
         // 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
-        if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
+        if (expected_static) {
+            EXPECT_EQ(0xffffffff, lease->valid_lft_);
+        } else if (subnet_->getValid().getMin() == subnet_->getValid().getMax()) {
             EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
         } else {
             EXPECT_LE(subnet_->getValid().getMin(), lease->valid_lft_);