memfile_lease_mgr_unittest.cc 73.8 KB
Newer Older
1
// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
2
//
3
4
5
// 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/.
6
7

#include <config.h>
8

9
#include <boost/asio.hpp>
10
11
#include <asiolink/io_address.h>
#include <dhcp/duid.h>
12
#include <dhcp/iface_mgr.h>
13
#include <dhcpsrv/cfgmgr.h>
14
#include <dhcpsrv/lease_mgr.h>
15
#include <dhcpsrv/lease_mgr_factory.h>
16
#include <dhcpsrv/memfile_lease_mgr.h>
17
#include <dhcpsrv/timer_mgr.h>
18
#include <dhcpsrv/tests/lease_file_io.h>
19
#include <dhcpsrv/tests/test_utils.h>
Tomek Mrugalski's avatar
Tomek Mrugalski committed
20
#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
21
#include <util/pid_file.h>
22
#include <util/range_utilities.h>
23
#include <util/stopwatch.h>
24
25
#include <gtest/gtest.h>

26
27
#include <boost/bind.hpp>

28
#include <cstdlib>
29
#include <iostream>
30
#include <fstream>
31
#include <queue>
32
33
#include <sstream>
#include <unistd.h>
34
35
36
37
38

using namespace std;
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
39
using namespace isc::dhcp::test;
40
using namespace isc::util;
41
42

namespace {
43

44
/// @brief Class derived from @c Memfile_LeaseMgr to test LFC timer.
45
46
47
48
///
/// This class provides a custom callback function which is invoked
/// when the timer for Lease File Cleanup goes off. It is used to
/// test that the timer is correctly installed.
49
class LFCMemfileLeaseMgr : public Memfile_LeaseMgr {
50
51
52
53
54
public:

    /// @brief Constructor.
    ///
    /// Sets the counter for callbacks to 0.
55
    LFCMemfileLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
56
        : Memfile_LeaseMgr(parameters), lfc_cnt_(0) {
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
    }

    /// @brief Returns the number of callback executions.
    int getLFCCount() {
        return (lfc_cnt_);
    }

protected:

    /// @brief Custom callback.
    ///
    /// This callback function increases the counter of callback executions.
    /// By examining the counter value a test may verify that the callback
    /// was triggered an expected number of times.
    virtual void lfcCallback() {
        ++lfc_cnt_;
    }

private:

    /// @brief Counter of callback function executions.
    int lfc_cnt_;

};

82
83
84
85
86
87
88
/// @brief A derivation of the lease manager exposing protected methods.
class NakedMemfileLeaseMgr : public Memfile_LeaseMgr {
public:

    /// @brief Constructor.
    ///
    /// Creates instance of the lease manager.
89
    NakedMemfileLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
90
91
92
93
94
95
        : Memfile_LeaseMgr(parameters) {
    }

    using Memfile_LeaseMgr::lfcCallback;
};

96
/// @brief Test fixture class for @c Memfile_LeaseMgr
97
class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
98
public:
99
100
101
102

    /// @brief memfile lease mgr test constructor
    ///
    /// Creates memfile and stores it in lmptr_ pointer
103
104
    MemfileLeaseMgrTest() :
        io4_(getLeaseFilePath("leasefile4_0.csv")),
105
106
        io6_(getLeaseFilePath("leasefile6_0.csv")),
        timer_mgr_(TimerMgr::instance()) {
107

108
109
110
111
        std::ostringstream s;
        s << KEA_LFC_BUILD_DIR << "/kea-lfc";
        setenv("KEA_LFC_EXECUTABLE", s.str().c_str(), 1);

112
113
114
        // Remove lease files and products of Lease File Cleanup.
        removeFiles(getLeaseFilePath("leasefile4_0.csv"));
        removeFiles(getLeaseFilePath("leasefile6_0.csv"));
115
    }
116

117
118
119
120
121
122
123
124
    /// @brief Reopens the connection to the backend.
    ///
    /// This function is called by unit tests to force reconnection of the
    /// backend to check that the leases are stored and can be retrieved
    /// from the storage.
    ///
    /// @param u Universe (V4 or V6)
    virtual void reopen(Universe u) {
125
        LeaseMgrFactory::destroy();
126
        startBackend(u);
127
128
129
130
131
    }

    /// @brief destructor
    ///
    /// destroys lease manager backend.
132
    virtual ~MemfileLeaseMgrTest() {
133
        // Stop TimerMgr worker thread if it is running.
134
        timer_mgr_->stopThread();
135
        // Make sure there are no timers registered.
136
        timer_mgr_->unregisterTimers();
137
        LeaseMgrFactory::destroy();
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
        // Remove lease files and products of Lease File Cleanup.
        removeFiles(getLeaseFilePath("leasefile4_0.csv"));
        removeFiles(getLeaseFilePath("leasefile6_0.csv"));
    }


    /// @brief Remove files being products of Lease File Cleanup.
    ///
    /// @param base_name Path to the lease file name. This file is removed
    /// and all files which names are crated from this name (having specific
    /// suffixes used by Lease File Cleanup mechanism).
    void removeFiles(const std::string& base_name) const {
        // Generate suffixes and append them to the base name. The
        // resulting file names are the ones that may exist as a
        // result of LFC.
        for (int i = static_cast<int>(Memfile_LeaseMgr::FILE_CURRENT);
             i <= static_cast<int>(Memfile_LeaseMgr::FILE_FINISH);
             ++i) {
            Memfile_LeaseMgr::LFCFileType type = static_cast<
                Memfile_LeaseMgr::LFCFileType>(i);
            LeaseFileIO io(Memfile_LeaseMgr::appendSuffix(base_name, type));
            io.removeFile();
        }
161
162
    }

163
164
165
166
167
168
    /// @brief Return path to the lease file used by unit tests.
    ///
    /// @param filename Name of the lease file appended to the path to the
    /// directory where test data is held.
    ///
    /// @return Full path to the lease file.
169
    static std::string getLeaseFilePath(const std::string& filename) {
170
171
172
173
174
        std::ostringstream s;
        s << TEST_DATA_BUILDDIR << "/" << filename;
        return (s.str());
    }

175
176
177
178
179
180
    /// @brief Returns the configuration string for the backend.
    ///
    /// This string configures the @c LeaseMgrFactory to create the memfile
    /// backend and use leasefile4_0.csv and leasefile6_0.csv files as
    /// storage for leases.
    ///
181
182
183
    /// @param no_universe Indicates whether universe parameter should be
    /// included (false), or not (true).
    ///
184
    /// @return Configuration string for @c LeaseMgrFactory.
185
    static std::string getConfigString(Universe u) {
186
        std::ostringstream s;
187
        s << "type=memfile " << (u == V4 ? "universe=4 " : "universe=6 ")
188
          << "name="
189
          << getLeaseFilePath(u == V4 ? "leasefile4_0.csv" : "leasefile6_0.csv");
190
191
192
        return (s.str());
    }

193
194
195
196
197
198
199
200
201
202
203
204
205
206
    /// @brief Creates instance of the backend.
    ///
    /// @param u Universe (v4 or V6).
    void startBackend(Universe u) {
        try {
            LeaseMgrFactory::create(getConfigString(u));
        } catch (...) {
            std::cerr << "*** ERROR: unable to create instance of the Memfile\n"
                " lease database backend.\n";
            throw;
        }
        lmptr_ = &(LeaseMgrFactory::instance());
    }

207
208
209
    /// @brief Runs @c IfaceMgr::receive6 in a look for a specified time.
    ///
    /// @param ms Duration in milliseconds.
210
    void setTestTime(const uint32_t ms) {
211
212
213
        // Measure test time and exit if timeout hit.
        Stopwatch stopwatch;
        while (stopwatch.getTotalMilliseconds() < ms) {
214
215
            // Block for one 1 millisecond.
            IfaceMgr::instance().receive6(0, 1000);
216
217
218
        }
    }

219
220
221
222
223
224
    /// @brief Waits for the specified process to finish.
    ///
    /// @param process An object which started the process.
    /// @param timeout Timeout in seconds.
    ///
    /// @return true if the process ended, false otherwise
225
    bool waitForProcess(const Memfile_LeaseMgr& lease_mgr,
226
227
228
                        const uint8_t timeout) {
        uint32_t iterations = 0;
        const uint32_t iterations_max = timeout * 1000;
229
        while (lease_mgr.isLFCRunning() && (iterations < iterations_max)) {
230
231
232
233
234
235
            usleep(1000);
            ++iterations;
        }
        return (iterations < iterations_max);
    }

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
    /// @brief Generates a DHCPv4 lease with random content.
    ///
    /// The following lease parameters are randomly generated:
    /// - HW address,
    /// - client identifier,
    /// - hostname,
    /// - subnet identifier,
    /// - client last transmission time,
    ///
    /// The following lease parameters are set to constant values:
    /// - valid lifetime = 1200,
    /// - T1 = 600,
    /// - T2 = 900,
    /// - DNS update forward flag = false,
    /// - DNS update reverse flag = false,
    ///
    /// The lease address is set to address passed as function
    /// argument.
    ///
    /// @param address Lease address.
    ///
    /// @return new lease with random content
    Lease4Ptr initiateRandomLease4(const IOAddress& address) {

        // Randomize HW address.
        vector<uint8_t> mac(6);
        fillRandom(mac.begin(), mac.end());
        HWAddrPtr hwaddr(new HWAddr(mac, HTYPE_ETHER));

        // Let's generate clientid of random length
266
        vector<uint8_t> clientid(4 + random()%20);
267
268
269
270
271
272
        // And then fill it with random value.
        fillRandom(clientid.begin(), clientid.end());

        uint32_t valid_lft = 1200;
        uint32_t t1 = 600;
        uint32_t t2 = 900;
273
        time_t timestamp = time(NULL) - 86400 + random()%86400;
274
275
        bool fqdn_fwd = false;
        bool fqdn_rev = false;
276
        uint32_t subnet_id = 1000 + random()%16;
277

278
        std::ostringstream hostname;
279
        hostname << "hostname" << (random() % 2048);
280
281
282
283
284

        // Return created lease.
        return (Lease4Ptr(new Lease4(address, hwaddr, &clientid[0],
                                     clientid.size(), valid_lft, t1, t2,
                                     timestamp, subnet_id, fqdn_fwd,
285
                                     fqdn_rev, hostname.str())));
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
    }

    /// @brief Generates a DHCPv6 lease with random content.
    ///
    /// The following lease parameters are randomly generated:
    /// - DUID,
    /// - IAID,
    /// - hostname,
    /// - subnet identifier,
    /// - client last transmission time,
    ///
    /// The following lease parameters are set to constant values:
    /// - lease type = IA_NA
    /// - valid lifetime = 1200,
    /// - preferred lifetime = 1000
    /// - T1 = 600,
    /// - T2 = 900,
    /// - DNS update forward flag = false,
    /// - DNS update reverse flag = false,
    ///
    /// The lease address is set to address passed as function
    /// argument.
    ///
    /// @param address Lease address.
    ///
    /// @return new lease with random content
    Lease6Ptr initiateRandomLease6(const IOAddress& address) {
        // Let's generate DUID of random length.
314
        std::vector<uint8_t> duid_vec(8 + random()%20);
315
316
317
318
319
        // And then fill it with random value.
        fillRandom(duid_vec.begin(), duid_vec.end());
        DuidPtr duid(new DUID(duid_vec));

        Lease::Type lease_type = Lease::TYPE_NA;
320
        uint32_t iaid = 1 + random()%100;
321
322
323
324
        uint32_t valid_lft = 1200;
        uint32_t preferred_lft = 1000;
        uint32_t t1 = 600;
        uint32_t t2 = 900;
325
        time_t timestamp = time(NULL) - 86400 + random()%86400;
326
327
        bool fqdn_fwd = false;
        bool fqdn_rev = false;
328
        uint32_t subnet_id = 1000 + random()%16;
329

330
        std::ostringstream hostname;
331
        hostname << "hostname" << (random() % 2048);
332

333
334
335
        // Return created lease.
        Lease6Ptr lease(new Lease6(lease_type, address, duid, iaid,
                                   preferred_lft, valid_lft, t1, t2,
336
337
                                   subnet_id, fqdn_fwd, fqdn_rev,
                                   hostname.str()));
338
339
340
341
        lease->cltt_ = timestamp;
        return (lease);
    }

342
    /// @brief Object providing access to v4 lease IO.
343
344
345
346
347
    LeaseFileIO io4_;

    /// @brief Object providing access to v6 lease IO.
    LeaseFileIO io6_;

348
349
    /// @brief Pointer to the instance of the @c TimerMgr.
    TimerMgrPtr timer_mgr_;
350
351
352
353
354
};

// This test checks if the LeaseMgr can be instantiated and that it
// parses parameters string properly.
TEST_F(MemfileLeaseMgrTest, constructor) {
355
    DatabaseConnection::ParameterMap pmap;
356
357
    pmap["universe"] = "4";
    pmap["persist"] = "false";
358
359
    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;

360
361
    EXPECT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));

362
    pmap["lfc-interval"] = "10";
363
    pmap["persist"] = "true";
364
    pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
365
366
367
368
    EXPECT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));

    // Expecting that persist parameter is yes or no. Everything other than
    // that is wrong.
369
    pmap["persist"] = "bogus";
370
    pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
371
    EXPECT_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)), isc::BadValue);
372
373

    // The lfc-interval must be an integer.
Francis Dupont's avatar
Francis Dupont committed
374
    pmap["persist"] = "true";
375
376
    pmap["lfc-interval"] = "bogus";
    EXPECT_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)), isc::BadValue);
377
378
}

379
380
// Checks if the getType() and getName() methods both return "memfile".
TEST_F(MemfileLeaseMgrTest, getTypeAndName) {
381
    startBackend(V4);
382
383
    EXPECT_EQ(std::string("memfile"), lmptr_->getType());
    EXPECT_EQ(std::string("memory"),  lmptr_->getName());
384
385
}

386
387
// Checks if the path to the lease files is initialized correctly.
TEST_F(MemfileLeaseMgrTest, getLeaseFilePath) {
388
389
390
391
392
    // Initialize IO objects, so as the test csv files get removed after the
    // test (when destructors are called).
    LeaseFileIO io4(getLeaseFilePath("leasefile4_1.csv"));
    LeaseFileIO io6(getLeaseFilePath("leasefile6_1.csv"));

393
    DatabaseConnection::ParameterMap pmap;
394
    pmap["universe"] = "4";
395
    pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
396
397
    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));

398
    EXPECT_EQ(pmap["name"],
399
400
              lease_mgr->getLeaseFilePath(Memfile_LeaseMgr::V4));

401
    pmap["persist"] = "false";
402
    lease_mgr.reset(new Memfile_LeaseMgr(pmap));
403
404
    EXPECT_TRUE(lease_mgr->getLeaseFilePath(Memfile_LeaseMgr::V4).empty());
    EXPECT_TRUE(lease_mgr->getLeaseFilePath(Memfile_LeaseMgr::V6).empty());
405
406
407
}

// Check if the persitLeases correctly checks that leases should not be written
408
// to disk when disabled through configuration.
409
TEST_F(MemfileLeaseMgrTest, persistLeases) {
410
411
412
413
414
    // Initialize IO objects, so as the test csv files get removed after the
    // test (when destructors are called).
    LeaseFileIO io4(getLeaseFilePath("leasefile4_1.csv"));
    LeaseFileIO io6(getLeaseFilePath("leasefile6_1.csv"));

415
    DatabaseConnection::ParameterMap pmap;
416
    pmap["universe"] = "4";
417
    // Specify the names of the lease files. Leases will be written.
418
    pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
419
420
421
422
    boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));

    lease_mgr.reset(new Memfile_LeaseMgr(pmap));
    EXPECT_TRUE(lease_mgr->persistLeases(Memfile_LeaseMgr::V4));
423
424
425
    EXPECT_FALSE(lease_mgr->persistLeases(Memfile_LeaseMgr::V6));

    pmap["universe"] = "6";
426
    pmap["name"] = getLeaseFilePath("leasefile6_1.csv");
427
428
    lease_mgr.reset(new Memfile_LeaseMgr(pmap));
    EXPECT_FALSE(lease_mgr->persistLeases(Memfile_LeaseMgr::V4));
429
430
    EXPECT_TRUE(lease_mgr->persistLeases(Memfile_LeaseMgr::V6));

431
    // This should disable writes of leases to disk.
432
    pmap["persist"] = "false";
433
434
435
436
437
    lease_mgr.reset(new Memfile_LeaseMgr(pmap));
    EXPECT_FALSE(lease_mgr->persistLeases(Memfile_LeaseMgr::V4));
    EXPECT_FALSE(lease_mgr->persistLeases(Memfile_LeaseMgr::V6));
}

438
439
440
// Check if it is possible to schedule the timer to perform the Lease
// File Cleanup periodically.
TEST_F(MemfileLeaseMgrTest, lfcTimer) {
441
    DatabaseConnection::ParameterMap pmap;
442
443
444
445
446
447
    pmap["type"] = "memfile";
    pmap["universe"] = "4";
    // Specify the names of the lease files. Leases will be written.
    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
    pmap["lfc-interval"] = "1";

448
449
    boost::scoped_ptr<LFCMemfileLeaseMgr>
        lease_mgr(new LFCMemfileLeaseMgr(pmap));
450

451
    // Start worker thread to execute LFC periodically.
452
    ASSERT_NO_THROW(timer_mgr_->startThread());
453
454
455
456

    // Run the test for at most 2.9 seconds.
    setTestTime(2900);

457
    // Stop worker thread.
458
    ASSERT_NO_THROW(timer_mgr_->stopThread());
459
460
461
462

    // Within 2.9 we should record two LFC executions.
    EXPECT_EQ(2, lease_mgr->getLFCCount());
}
463

464
465
466
467

// This test checks if the LFC timer is disabled (doesn't trigger)
// cleanups when the lfc-interval is set to 0.
TEST_F(MemfileLeaseMgrTest, lfcTimerDisabled) {
468
    DatabaseConnection::ParameterMap pmap;
469
470
471
472
473
474
475
476
477
    pmap["type"] = "memfile";
    pmap["universe"] = "4";
    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
    // Set the LFC interval to 0, which should effectively disable it.
    pmap["lfc-interval"] = "0";

    boost::scoped_ptr<LFCMemfileLeaseMgr>
        lease_mgr(new LFCMemfileLeaseMgr(pmap));

478
    // Start worker thread to execute LFC periodically.
479
    ASSERT_NO_THROW(timer_mgr_->startThread());
480
481
482
483

    // Run the test for at most 1.9 seconds.
    setTestTime(1900);

484
485
486
    // Stop worker thread to make sure it is not running when lease
    // manager is destroyed. The lease manager will be unable to
    // unregster timer when the thread is active.
487
    ASSERT_NO_THROW(timer_mgr_->stopThread());
488
489
490
491
492

    // There should be no LFC execution recorded.
    EXPECT_EQ(0, lease_mgr->getLFCCount());
}

493
// This test checks that the callback function executing the cleanup of the
494
495
496
497
498
// DHCPv4 lease file works as expected.
TEST_F(MemfileLeaseMgrTest, leaseFileCleanup4) {
    // This string contains the lease file header, which matches
    // the contents of the new file in which no leases have been
    // stored.
499
500
    std::string new_file_contents =
        "address,hwaddr,client_id,valid_lifetime,expire,"
501
        "subnet_id,fqdn_fwd,fqdn_rev,hostname,state\n";
502

503
504
505
    // This string contains the contents of the lease file with exactly
    // one lease, but two entries. One of the entries should be removed
    // as a result of lease file cleanup.
506
    std::string current_file_contents = new_file_contents +
507
508
        "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n"
        "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,1\n";
509
510
511
    LeaseFileIO current_file(getLeaseFilePath("leasefile4_0.csv"));
    current_file.writeFile(current_file_contents);

512
    std::string previous_file_contents = new_file_contents +
513
514
        "192.0.2.3,03:03:03:03:03:03,,200,200,8,1,1,,1\n"
        "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,1\n";
515
516
517
518
    LeaseFileIO previous_file(getLeaseFilePath("leasefile4_0.csv.2"));
    previous_file.writeFile(previous_file_contents);

    // Create the backend.
519
    DatabaseConnection::ParameterMap pmap;
520
521
522
523
    pmap["type"] = "memfile";
    pmap["universe"] = "4";
    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
    pmap["lfc-interval"] = "1";
524
    boost::scoped_ptr<NakedMemfileLeaseMgr> lease_mgr(new NakedMemfileLeaseMgr(pmap));
525

526
    // Try to run the lease file cleanup.
527
528
    ASSERT_NO_THROW(lease_mgr->lfcCallback());

529
530
531
532
533
534
    // The new lease file should have been created and it should contain
    // no leases.
    ASSERT_TRUE(current_file.exists());
    EXPECT_EQ(new_file_contents, current_file.readFile());

    // Wait for the LFC process to complete.
535
    ASSERT_TRUE(waitForProcess(*lease_mgr, 2));
536
537

    // And make sure it has returned an exit status of 0.
538
539
540
    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
        << "Executing the LFC process failed: make sure that"
        " the kea-lfc program has been compiled.";
541

542
543
544
545
546
547
548
549
    // Check if we can still write to the lease file.
    std::vector<uint8_t> hwaddr_vec(6);
    HWAddrPtr hwaddr(new HWAddr(hwaddr_vec, HTYPE_ETHER));
    Lease4Ptr new_lease(new Lease4(IOAddress("192.0.2.45"), hwaddr, 0, 0,
                                   100, 50, 60, 0, 1));
    ASSERT_NO_THROW(lease_mgr->addLease(new_lease));

    std::string updated_file_contents = new_file_contents +
550
        "192.0.2.45,00:00:00:00:00:00,,100,100,1,0,0,,0\n";
551
552
    EXPECT_EQ(updated_file_contents, current_file.readFile());

553
554
555
556
    // This string contains the contents of the lease file we
    // expect after the LFC run.  It has two leases with one
    // entry each.
    std::string result_file_contents = new_file_contents +
557
558
        "192.0.2.2,02:02:02:02:02:02,,200,800,8,1,1,,1\n"
        "192.0.2.3,03:03:03:03:03:03,,200,800,8,1,1,,1\n";
559
560
561
562

    // The LFC should have created a file with the two leases and moved it
    // to leasefile4_0.csv.2
    LeaseFileIO input_file(getLeaseFilePath("leasefile4_0.csv.2"), false);
563
    ASSERT_TRUE(input_file.exists());
564
565
    // And this file should contain the contents of the result file.
    EXPECT_EQ(result_file_contents, input_file.readFile());
566
567
}

568
// This test checks that the callback function executing the cleanup of the
569
570
571
572
573
574
575
576
// DHCPv6 lease file works as expected.
TEST_F(MemfileLeaseMgrTest, leaseFileCleanup6) {
    // This string contains the lease file header, which matches
    // the contents of the new file in which no leases have been
    // stored.
    std::string new_file_contents =
        "address,duid,valid_lifetime,expire,subnet_id,"
        "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
577
        "fqdn_rev,hostname,hwaddr,state\n";
578
579
580
581
582
583

    // This string contains the contents of the lease file with exactly
    // one lease, but two entries. One of the entries should be removed
    // as a result of lease file cleanup.
    std::string current_file_contents = new_file_contents +
        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,200,"
584
        "8,100,0,7,0,1,1,,,1\n"
585
        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
586
        "8,100,0,7,0,1,1,,,1\n";
587
588
    LeaseFileIO current_file(getLeaseFilePath("leasefile6_0.csv"));
    current_file.writeFile(current_file_contents);
589

590
591
    std::string previous_file_contents = new_file_contents +
        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,200,"
592
        "8,100,0,7,0,1,1,,,1\n"
593
        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
594
        "8,100,0,7,0,1,1,,,1\n";
595
596
597
598
    LeaseFileIO previous_file(getLeaseFilePath("leasefile6_0.csv.2"));
    previous_file.writeFile(previous_file_contents);

    // Create the backend.
599
    DatabaseConnection::ParameterMap pmap;
600
601
602
603
604
605
606
607
608
609
610
    pmap["type"] = "memfile";
    pmap["universe"] = "6";
    pmap["name"] = getLeaseFilePath("leasefile6_0.csv");
    pmap["lfc-interval"] = "1";
    boost::scoped_ptr<NakedMemfileLeaseMgr> lease_mgr(new NakedMemfileLeaseMgr(pmap));

    // Try to run the lease file cleanup.
    ASSERT_NO_THROW(lease_mgr->lfcCallback());

    // The new lease file should have been created and it should contain
    // no leases.
611
612
    ASSERT_TRUE(current_file.exists());
    EXPECT_EQ(new_file_contents, current_file.readFile());
613

614
    // Wait for the LFC process to complete.
615
    ASSERT_TRUE(waitForProcess(*lease_mgr, 2));
616

617
    // And make sure it has returned an exit status of 0.
618
619
620
621
    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
        << "Executing the LFC process failed: make sure that"
        " the kea-lfc program has been compiled.";

622

623
624
625
626
627
628
629
630
631
632
    // Check if we can still write to the lease file.
    std::vector<uint8_t> duid_vec(13);
    DuidPtr duid(new DUID(duid_vec));
    Lease6Ptr new_lease(new Lease6(Lease::TYPE_NA, IOAddress("3000::1"),duid,
                                   123, 300, 400, 100, 300, 2));
    new_lease->cltt_ = 0;
    ASSERT_NO_THROW(lease_mgr->addLease(new_lease));

    std::string update_file_contents = new_file_contents +
        "3000::1,00:00:00:00:00:00:00:00:00:00:00:00:00,400,"
633
        "400,2,300,0,123,128,0,0,,,0\n";
634
635
    EXPECT_EQ(update_file_contents, current_file.readFile());

636
637
638
639
640
    // This string contains the contents of the lease file we
    // expect after the LFC run.  It has two leases with one
    // entry each.
    std::string result_file_contents = new_file_contents +
        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
641
        "8,100,0,7,0,1,1,,,1\n"
642
        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
643
        "8,100,0,7,0,1,1,,,1\n";
644

645
646
647
    // The LFC should have created a file with the two leases and moved it
    // to leasefile6_0.csv.2
    LeaseFileIO input_file(getLeaseFilePath("leasefile6_0.csv.2"), false);
648
    ASSERT_TRUE(input_file.exists());
649
650
    // And this file should contain the contents of the result file.
    EXPECT_EQ(result_file_contents, input_file.readFile());
651
652
653
654
655
656
657
658
659
660
}

// This test verifies that EXIT_FAILURE status code is returned when
// the LFC process fails to start.
TEST_F(MemfileLeaseMgrTest, leaseFileCleanupStartFail) {
    // This string contains the lease file header, which matches
    // the contents of the new file in which no leases have been
    // stored.
    std::string new_file_contents =
        "address,hwaddr,client_id,valid_lifetime,expire,"
661
        "subnet_id,fqdn_fwd,fqdn_rev,hostname,state\n";
662
663
664

    // Create the lease file to be used by the backend.
    std::string current_file_contents = new_file_contents +
665
        "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n";
666
667
668
669
670
671
672
673
    LeaseFileIO current_file(getLeaseFilePath("leasefile4_0.csv"));
    current_file.writeFile(current_file_contents);

    // Specify invalid path to the kea-lfc executable. This should result
    // in failure status code returned by the child process.
    setenv("KEA_LFC_EXECUTABLE", "foobar", 1);

    // Create the backend.
674
    DatabaseConnection::ParameterMap pmap;
675
676
677
678
679
680
681
682
683
684
    pmap["type"] = "memfile";
    pmap["universe"] = "4";
    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
    pmap["lfc-interval"] = "1";
    boost::scoped_ptr<NakedMemfileLeaseMgr> lease_mgr(new NakedMemfileLeaseMgr(pmap));

    // Try to run the lease file cleanup.
    ASSERT_NO_THROW(lease_mgr->lfcCallback());

    // Wait for the LFC process to complete.
685
    ASSERT_TRUE(waitForProcess(*lease_mgr, 2));
686
687

    // And make sure it has returned an error.
688
689
690
    EXPECT_EQ(EXIT_FAILURE, lease_mgr->getLFCExitStatus())
        << "Executing the LFC process failed: make sure that"
        " the kea-lfc program has been compiled.";
691
692
}

693
694
695
696
697
698
699
700
701
// This test checks that the callback function executing the cleanup of the
// files doesn't move the current file if the finish file exists
TEST_F(MemfileLeaseMgrTest, leaseFileFinish) {
    // This string contains the lease file header, which matches
    // the contents of the new file in which no leases have been
    // stored.
    std::string new_file_contents =
        "address,duid,valid_lifetime,expire,subnet_id,"
        "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
702
        "fqdn_rev,hostname,hwaddr,state\n";
703
704
705
706
707

    // This string contains the contents of the current lease file.
    // It should not be moved.
    std::string current_file_contents = new_file_contents +
        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,200,"
708
        "8,100,0,7,0,1,1,,,1\n"
709
        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
710
        "8,100,0,7,0,1,1,,,1\n";
711
712
713
    LeaseFileIO current_file(getLeaseFilePath("leasefile6_0.csv"));
    current_file.writeFile(current_file_contents);

714
    // This string contains the contents of the finish file.  It should
715
716
717
    // be moved to the previous file.
    std::string finish_file_contents = new_file_contents +
        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
718
        "8,100,0,7,0,1,1,,,1\n";
719
720
721
722
    LeaseFileIO finish_file(getLeaseFilePath("leasefile6_0.csv.completed"));
    finish_file.writeFile(finish_file_contents);

    // Create the backend.
723
    DatabaseConnection::ParameterMap pmap;
724
725
726
727
728
729
730
731
732
733
734
735
736
737
    pmap["type"] = "memfile";
    pmap["universe"] = "6";
    pmap["name"] = getLeaseFilePath("leasefile6_0.csv");
    pmap["lfc-interval"] = "1";
    boost::scoped_ptr<NakedMemfileLeaseMgr> lease_mgr(new NakedMemfileLeaseMgr(pmap));

    // Try to run the lease file cleanup.
    ASSERT_NO_THROW(lease_mgr->lfcCallback());

    // The current lease file should not have been touched.
    ASSERT_TRUE(current_file.exists());
    EXPECT_EQ(current_file_contents, current_file.readFile());

    // Wait for the LFC process to complete.
738
    ASSERT_TRUE(waitForProcess(*lease_mgr, 5));
739
740
741
742
743
744
745
746
747
748
749
750

    // And make sure it has returned an exit status of 0.
    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
        << "Executing the LFC process failed: make sure that"
        " the kea-lfc program has been compiled.";

    // The LFC should have moved the finish file to the previous file -
    // leasefile6_0.csv.2
    LeaseFileIO previous_file(getLeaseFilePath("leasefile6_0.csv.2"), false);
    ASSERT_TRUE(previous_file.exists());
    // And this file should contain the contents of the finish file.
    EXPECT_EQ(finish_file_contents, previous_file.readFile());
751
752
753

    // The finish file should have been removed
    ASSERT_FALSE(finish_file.exists());
754
755
756
757
758
759
760
761
762
763
764
}

// This test checks that the callback function executing the cleanup of the
// files doesn't move the current file if the copy file exists
TEST_F(MemfileLeaseMgrTest, leaseFileCopy) {
    // This string contains the lease file header, which matches
    // the contents of the new file in which no leases have been
    // stored.
    std::string new_file_contents =
        "address,duid,valid_lifetime,expire,subnet_id,"
        "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
765
        "fqdn_rev,hostname,hwaddr,state\n";
766
767
768
769
770

    // This string contains the contents of the current lease file.
    // It should not be moved.
    std::string current_file_contents = new_file_contents +
        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,200,"
771
        "8,100,0,7,0,1,1,,,1\n"
772
        "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,800,"
773
        "8,100,0,7,0,1,1,,,1\n";
774
775
776
777
778
779
780
781
782
    LeaseFileIO current_file(getLeaseFilePath("leasefile6_0.csv"));
    current_file.writeFile(current_file_contents);

    // This string contains the contents of the copy file.  It should
    // be processed and moved to the previous file.  As there is only
    // one lease the processing should result in the previous file being
    // the same.
    std::string input_file_contents = new_file_contents +
        "2001:db8:1::2,01:01:01:01:01:01:01:01:01:01:01:01:01,200,800,"
783
        "8,100,0,7,0,1,1,,,1\n";
784
785
786
787
    LeaseFileIO input_file(getLeaseFilePath("leasefile6_0.csv.1"));
    input_file.writeFile(input_file_contents);

    // Create the backend.
788
    DatabaseConnection::ParameterMap pmap;
789
790
791
792
793
794
795
796
797
798
799
800
801
802
    pmap["type"] = "memfile";
    pmap["universe"] = "6";
    pmap["name"] = getLeaseFilePath("leasefile6_0.csv");
    pmap["lfc-interval"] = "1";
    boost::scoped_ptr<NakedMemfileLeaseMgr> lease_mgr(new NakedMemfileLeaseMgr(pmap));

    // Try to run the lease file cleanup.
    ASSERT_NO_THROW(lease_mgr->lfcCallback());

    // The current lease file should not have been touched.
    ASSERT_TRUE(current_file.exists());
    EXPECT_EQ(current_file_contents, current_file.readFile());

    // Wait for the LFC process to complete.
803
    ASSERT_TRUE(waitForProcess(*lease_mgr, 5));
804
805
806
807
808
809
810
811
812
813
814
815

    // And make sure it has returned an exit status of 0.
    EXPECT_EQ(0, lease_mgr->getLFCExitStatus())
        << "Executing the LFC process failed: make sure that"
        " the kea-lfc program has been compiled.";

    // The LFC should have processed the lease and moved it to the previous
    // file - leasefile6_0.csv.2
    LeaseFileIO previous_file(getLeaseFilePath("leasefile6_0.csv.2"), false);
    ASSERT_TRUE(previous_file.exists());
    // And this file should contain the contents of the copy file.
    EXPECT_EQ(input_file_contents, previous_file.readFile());
816
817
818

    // The input file should have been removed
    ASSERT_FALSE(input_file.exists());
819
820
}

821
// Checks that adding/getting/deleting a Lease6 object works.
822
TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
823
    startBackend(V6);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
824
825
826
    testAddGetDelete6(true); // true - check T1,T2 values
    // memfile is able to preserve those values, but some other
    // backends can't do that.
827
}
828

829
830
831
832
833
/// @brief Basic Lease4 Checks
///
/// Checks that the addLease, getLease4 (by address) and deleteLease (with an
/// IPv4 address) works.
TEST_F(MemfileLeaseMgrTest, basicLease4) {
834
    startBackend(V4);
835
    testBasicLease4();
836
837
}

838
/// @todo Write more memfile tests
839
840
841

// Simple test about lease4 retrieval through client id method
TEST_F(MemfileLeaseMgrTest, getLease4ClientId) {
842
    startBackend(V4);
843
    testGetLease4ClientId();
844
845
846
847
}

// Checks that lease4 retrieval client id is null is working
TEST_F(MemfileLeaseMgrTest, getLease4NullClientId) {
848
    startBackend(V4);
849
    testGetLease4NullClientId();
850
851
852
}

// Checks lease4 retrieval through HWAddr
853
TEST_F(MemfileLeaseMgrTest, getLease4HWAddr1) {
854
    startBackend(V4);
855
856
857
858
859
860
861
862
    testGetLease4HWAddr1();
}

/// @brief Check GetLease4 methods - access by Hardware Address
///
/// Adds leases to the database and checks that they can be accessed via
/// a combination of DUID and IAID.
TEST_F(MemfileLeaseMgrTest, getLease4HWAddr2) {
863
    startBackend(V4);
864
    testGetLease4HWAddr2();
865
}
866

867
868
// Checks lease4 retrieval with clientId, HWAddr and subnet_id
TEST_F(MemfileLeaseMgrTest, getLease4ClientIdHWAddrSubnetId) {
869
    startBackend(V4);
870
    testGetLease4ClientIdHWAddrSubnetId();
871
872
}

873
874
875
876
877
/// @brief Basic Lease4 Checks
///
/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
/// updateLease4() and deleteLease (IPv4 address) can handle NULL client-id.
/// (client-id is optional and may not be present)
878
TEST_F(MemfileLeaseMgrTest, lease4NullClientId) {
879
    startBackend(V4);
880
881
882
    testLease4NullClientId();
}

883
884
885
886
887
888
889
/// @brief Check GetLease4 methods - access by Hardware Address & Subnet ID
///
/// Adds leases to the database and checks that they can be accessed via
/// a combination of hardware address and subnet ID
TEST_F(MemfileLeaseMgrTest, DISABLED_getLease4HwaddrSubnetId) {

    /// @todo: fails on memfile. It's probably a memfile bug.
890
    startBackend(V4);
891
892
893
894
895
896
897
898
    testGetLease4HWAddrSubnetId();
}

/// @brief Check GetLease4 methods - access by Client ID
///
/// Adds leases to the database and checks that they can be accessed via
/// the Client ID.
TEST_F(MemfileLeaseMgrTest, getLease4ClientId2) {
899
    startBackend(V4);
900
901
902
    testGetLease4ClientId2();
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
903
// @brief Get Lease4 by client ID
904
905
906
//
// Check that the system can cope with a client ID of any size.
TEST_F(MemfileLeaseMgrTest, getLease4ClientIdSize) {
907
    startBackend(V4);
908
909
910
911
912
913
914
915
    testGetLease4ClientIdSize();
}

/// @brief Check GetLease4 methods - access by Client ID & Subnet ID
///
/// Adds leases to the database and checks that they can be accessed via
/// a combination of client and subnet IDs.
TEST_F(MemfileLeaseMgrTest, getLease4ClientIdSubnetId) {
916
    startBackend(V4);
917
918
919
    testGetLease4ClientIdSubnetId();
}

920
921
922
923
924
/// @brief Basic Lease6 Checks
///
/// Checks that the addLease, getLease6 (by address) and deleteLease (with an
/// IPv6 address) works.
TEST_F(MemfileLeaseMgrTest, basicLease6) {
925
    startBackend(V6);
926
927
928
929
    testBasicLease6();
}


930
931
932
933
/// @brief Check GetLease6 methods - access by DUID/IAID
///
/// Adds leases to the database and checks that they can be accessed via
/// a combination of DUID and IAID.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
934
935
/// @todo: test disabled, because Memfile_LeaseMgr::getLeases6(Lease::Type,
/// const DUID& duid, uint32_t iaid) const is not implemented yet.
936
TEST_F(MemfileLeaseMgrTest, getLeases6DuidIaid) {
937
    startBackend(V6);
938
939
940
    testGetLeases6DuidIaid();
}

941
/// @brief Check that the system can cope with a DUID of allowed size.
942
TEST_F(MemfileLeaseMgrTest, getLeases6DuidSize) {
943
    startBackend(V6);
944
945
946
    testGetLeases6DuidSize();
}

947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
/// @brief Check that the expired DHCPv4 leases can be retrieved.
///
/// This test adds a number of leases to the lease database and marks
/// some of them as expired. Then it queries for expired leases and checks
/// whether only expired leases are returned, and that they are returned in
/// the order from most to least expired. It also checks that the lease
/// which is marked as 'reclaimed' is not returned.
TEST_F(MemfileLeaseMgrTest, getExpiredLeases4) {
    startBackend(V4);
    testGetExpiredLeases4();
}

/// @brief Check that the expired DHCPv6 leases can be retrieved.
///
/// This test adds a number of leases to the lease database and marks
/// some of them as expired. Then it queries for expired leases and checks
/// whether only expired leases are returned, and that they are returned in
/// the order from most to least expired. It also checks that the lease
/// which is marked as 'reclaimed' is not returned.
TEST_F(MemfileLeaseMgrTest, getExpiredLeases6) {
    startBackend(V6);
    testGetExpiredLeases6();
}

971
972
973
974
975
976
977
978
979
980
981
982
/// @brief Check that expired reclaimed DHCPv6 leases are removed.
TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases6) {
    startBackend(V6);
    testDeleteExpiredReclaimedLeases6();
}

/// @brief Check that expired reclaimed DHCPv4 leases are removed.
TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases4) {
    startBackend(V4);
    testDeleteExpiredReclaimedLeases4();
}

983
984
985
986
987
988
/// @brief Check that getLease6 methods discriminate by lease type.
///
/// Adds six leases, two per lease type all with the same duid and iad but
/// with alternating subnet_ids.
/// It then verifies that all of getLeases6() method variants correctly
/// discriminate between the leases based on lease type alone.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
989
990
/// @todo: Disabled, because type parameter in Memfile_LeaseMgr::getLease6
/// (Lease::Type, const isc::asiolink::IOAddress& addr) const is not used.
991
TEST_F(MemfileLeaseMgrTest, lease6LeaseTypeCheck) {
992
    startBackend(V6);
993
994
995
996
997
998
999
1000
    testLease6LeaseTypeCheck();
}

/// @brief Check GetLease6 methods - access by DUID/IAID/SubnetID
///
/// Adds leases to the database and checks that they can be accessed via
/// a combination of DIUID and IAID.
TEST_F(MemfileLeaseMgrTest, getLease6DuidIaidSubnetId) {
1001
    startBackend(V6);
1002
1003
1004
    testGetLease6DuidIaidSubnetId();
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
1005
1006
/// Checks that getLease6(type, duid, iaid, subnet-id) works with different
/// DUID sizes
1007
TEST_F(MemfileLeaseMgrTest, getLease6DuidIaidSubnetIdSize) {
1008
    startBackend(V6);
1009
1010
1011
1012
1013
1014
    testGetLease6DuidIaidSubnetIdSize();
}

/// @brief Lease4 update tests
///
/// Checks that we are able to update a lease in the database.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1015
1016
1017
/// @todo: Disabled, because memfile does not throw when lease is updated.
/// We should reconsider if lease{4,6} structures should have a limit
/// implemented in them.
1018
TEST_F(MemfileLeaseMgrTest, DISABLED_updateLease4) {
1019
    startBackend(V4);
1020
1021
1022
1023
1024
1025
    testUpdateLease4();
}

/// @brief Lease6 update tests
///
/// Checks that we are able to update a lease in the database.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
1026
1027
1028
/// @todo: Disabled, because memfile does not throw when lease is updated.
/// We should reconsider if lease{4,6} structures should have a limit
/// implemented in them.
1029
TEST_F(MemfileLeaseMgrTest, DISABLED_updateLease6) {
1030
    startBackend(V6);
1031
1032
1033
    testUpdateLease6();
}

1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
/// @brief DHCPv4 Lease recreation tests
///
/// Checks that the lease can be created, deleted and recreated with
/// different parameters. It also checks that the re-created lease is
/// correctly stored in the lease database.
TEST_F(MemfileLeaseMgrTest, testRecreateLease4) {
    startBackend(V4);
    testRecreateLease4();
}

/// @brief DHCPv6 Lease recreation tests
///
/// Checks that the lease can be created, deleted and recreated with
/// different parameters. It also checks that the re-created lease is
/// correctly stored in the lease database.
TEST_F(MemfileLeaseMgrTest, testRecreateLease6) {
    startBackend(V6);
    testRecreateLease6();
}
1053

1054
1055
1056
1057
1058
1059
// The following tests are not applicable for memfile. When adding
// new tests to the list here, make sure to provide brief explanation
// why they are not applicable:
//
// testGetLease4HWAddrSubnetIdSize() - memfile just keeps Lease structure
//     and does not do any checks of HWAddr content
1060

1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
/// @brief Checks that null DUID is not allowed.
/// Test is disabled as Memfile does not currently defend against a null DUID.
TEST_F(MemfileLeaseMgrTest, DISABLED_nullDuid) {
    // Create leases, although we need only one.
    vector<Lease6Ptr> leases = createLeases6();

    leases[1]->duid_.reset();
    ASSERT_THROW(lmptr_->addLease(leases[1]), DbOperationError);
}

1071
1072
1073
1074
1075
1076
/// @brief Tests whether memfile can store and retrieve hardware addresses
TEST_F(MemfileLeaseMgrTest, testLease6Mac) {
    startBackend(V6);
    testLease6MAC();
}

1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
// Check that memfile reports version correctly.
TEST_F(MemfileLeaseMgrTest, versionCheck) {

    // Check that V4 backend reports versions correctly.
    startBackend(V4);
    testVersion(Memfile_LeaseMgr::MAJOR_VERSION,
                Memfile_LeaseMgr::MINOR_VERSION);
    LeaseMgrFactory::destroy();

    // Check that V6 backends reports them ok, too.
    startBackend(V6);
    testVersion(Memfile_LeaseMgr::MAJOR_VERSION,
                Memfile_LeaseMgr::MINOR_VERSION);
    LeaseMgrFactory::destroy();
}

1093
// Checks that declined IPv4 leases can be returned correctly.
1094
1095
1096
1097
1098
TEST_F(MemfileLeaseMgrTest, getDeclined4) {
    startBackend(V4);
    testGetDeclinedLeases4();
}

1099
1100
1101
1102
1103
1104
// Checks that declined IPv6 leases can be returned correctly.
TEST_F(MemfileLeaseMgrTest, getDeclined6) {
    startBackend(V6);
    testGetDeclinedLeases6();
}

1105
1106
1107
// This test checks that the backend reads DHCPv4 lease data from multiple
// files.
TEST_F(MemfileLeaseMgrTest, load4MultipleLeaseFiles) {
1108
    LeaseFileIO io2(getLeaseFilePath("leasefile4_0.csv.2"));
1109
    io2.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
1110
1111
1112
                  "fqdn_fwd,fqdn_rev,hostname,state\n"
                  "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n"
                  "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,200,8,1,1,,1\n");
1113

1114
    LeaseFileIO io1(getLeaseFilePath("leasefile4_0.csv.1"));
1115
    io1.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
1116
1117
1118
1119
                  "fqdn_fwd,fqdn_rev,hostname,state\n"
                  "192.0.2.1,01:01:01:01:01:01,,200,200,8,1,1,,1\n"
                  "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,400,8,1,1,,1\n"
                  "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,200,8,1,1,,1\n");
1120

1121
    LeaseFileIO io(getLeaseFilePath("leasefile4_0.csv"));
1122
    io.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
1123
1124
1125
                 "fqdn_fwd,fqdn_rev,hostname,state\n"
                 "192.0.2.10,0a:0a:0a:0a:0a:0a,,200,200,8,1,1,,1\n"
                 "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,400,8,1,1,,1\n");
1126
1127
1128

    startBackend(V4);

1129
1130
    // This lease only exists in the second file and the cltt should
    // be 0.
1131
1132
1133
1134
    Lease4Ptr lease = lmptr_->getLease4(IOAddress("192.0.2.1"));
    ASSERT_TRUE(lease);
    EXPECT_EQ(0, lease->cltt_);

1135
1136
    // This lease only exists in the first file and the cltt should
    // be 0.
1137
1138
1139
1140
    lease = lmptr_->getLease4(IOAddress("192.0.2.2"));
    ASSERT_TRUE(lease);
    EXPECT_EQ(0, lease->cltt_);

1141
1142
    // This lease only exists in the third file and the cltt should
    // be 0.
1143
1144
1145
1146
    lease = lmptr_->getLease4(IOAddress("192.0.2.10"));
    ASSERT_TRUE(lease);
    EXPECT_EQ(0, lease->cltt_);

1147
1148
1149
    // This lease exists in the first and second file and the cltt
    // should be calculated using the expiration time and the
    // valid lifetime from the second file.
1150
1151
1152
1153
    lease = lmptr_->getLease4(IOAddress("192.0.2.11"));
    ASSERT_TRUE(lease);
    EXPECT_EQ(200, lease->cltt_);

1154
    // This lease exists in the second and third file and the cltt
1155
1156
    // should be calculated using the expiration time and the
    // valid lifetime from the third file.
1157
1158
1159
1160
1161
    lease = lmptr_->getLease4(IOAddress("192.0.2.12"));
    ASSERT_TRUE(lease);
    EXPECT_EQ(200, lease->cltt_);
}

1162
1163
1164
1165
// This test checks that the lease database backend loads the file with
// the .completed postfix instead of files with postfixes .1 and .2 if
// the file with .completed postfix exists.
TEST_F(MemfileLeaseMgrTest, load4CompletedFile) {
1166
    LeaseFileIO io2(getLeaseFilePath("leasefile4_0.csv.2"));
1167
    io2.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
1168
1169
1170
                  "fqdn_fwd,fqdn_rev,hostname,state\n"
                  "192.0.2.2,02:02:02:02:02:02,,200,200,8,1,1,,1\n"
                  "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,200,8,1,1,,1\n");
1171

1172
    LeaseFileIO io1(getLeaseFilePath("leasefile4_0.csv.1"));
1173
    io1.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
1174
1175
1176
1177
                  "fqdn_fwd,fqdn_rev,hostname,state\n"
                  "192.0.2.1,01:01:01:01:01:01,,200,200,8,1,1,,1\n"
                  "192.0.2.11,bb:bb:bb:bb:bb:bb,,200,400,8,1,1,,1\n"
                  "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,200,8,1,1,,1\n");
1178

1179
    LeaseFileIO io(getLeaseFilePath("leasefile4_0.csv"));
1180
    io.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
1181
1182
1183
                 "fqdn_fwd,fqdn_rev,hostname,state\n"
                 "192.0.2.10,0a:0a:0a:0a:0a:0a,,200,200,8,1,1,,1\n"
                 "192.0.2.12,cc:cc:cc:cc:cc:cc,,200,400,8,1,1,,1\n");
1184

1185
    LeaseFileIO ioc(getLeaseFilePath("leasefile4_0.csv.completed"));
1186
    ioc.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"