generic_host_data_source_unittest.cc 31.6 KB
Newer Older
1
// Copyright (C) 2015-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 8 9 10 11 12 13 14 15 16 17 18 19 20 21

#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
#include <dhcpsrv/tests/test_utils.h>
#include <dhcpsrv/database_connection.h>
#include <asiolink/io_address.h>
#include <gtest/gtest.h>
#include <sstream>

using namespace std;
using namespace isc::asiolink;

namespace isc {
namespace dhcp {
namespace test {

GenericHostDataSourceTest::GenericHostDataSourceTest()
22
    :hdsptr_() {
23 24 25 26 27 28

}

GenericHostDataSourceTest::~GenericHostDataSourceTest() {
}

29
std::vector<uint8_t>
30
GenericHostDataSourceTest::generateHWAddr(const bool new_identifier) {
31 32 33 34 35 36
    /// @todo: Consider moving this somewhere to lib/testutils.

    // Let's use something that is easily printable. That's convenient
    // if you need to enter MySQL queries by hand.
    static uint8_t hwaddr[] = {65, 66, 67, 68, 69, 70};

37 38 39 40 41 42 43 44
    if (new_identifier) {
        // Increase the address for the next time we use it.
        // This is primitive, but will work for 65k unique
        // addresses.
        hwaddr[sizeof(hwaddr) - 1]++;
        if (hwaddr[sizeof(hwaddr) - 1] == 0) {
            hwaddr[sizeof(hwaddr) - 2]++;
        }
45
    }
46
    return (std::vector<uint8_t>(hwaddr, hwaddr + sizeof(hwaddr)));
47 48
}

49 50
std::vector<uint8_t>
GenericHostDataSourceTest::generateIdentifier(const bool new_identifier) {
51 52 53 54
    /// @todo: Consider moving this somewhere to lib/testutils.

    // Let's use something that is easily printable. That's convenient
    // if you need to enter MySQL queries by hand.
55
    static uint8_t ident[] = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 };
56

57
    // Increase the identifier for the next time we use it.
58
    // This is primitive, but will work for 65k unique
59
    // identifiers.
60
    if (new_identifier) {
61 62 63
        ident[sizeof(ident) - 1]++;
        if (ident[sizeof(ident) - 1] == 0) {
            ident[sizeof(ident) - 2]++;
64
        }
65
    }
66
    return (std::vector<uint8_t>(ident, ident + sizeof(ident)));
67 68
}

69 70 71 72 73
HostPtr
GenericHostDataSourceTest::initializeHost4(const std::string& address,
                                           const Host::IdentifierType& id) {
    std::vector<uint8_t> ident;
    if (id == Host::IDENT_HWADDR) {
74
        ident = generateHWAddr();
75

76
    } else {
77
        ident = generateIdentifier();
78 79 80 81 82 83 84 85 86 87 88
    }

    // Let's create ever increasing subnet-ids. Let's keep those different,
    // so subnet4 != subnet6. Useful for catching cases if the code confuses
    // subnet4 with subnet6.
    static SubnetID subnet4 = 0;
    static SubnetID subnet6 = 100;
    subnet4++;
    subnet6++;

    IOAddress addr(address);
89
    HostPtr host(new Host(&ident[0], ident.size(), id, subnet4, subnet6, addr));
90 91 92 93 94

    return (host);
}

HostPtr GenericHostDataSourceTest::initializeHost6(std::string address,
95
                                                   Host::IdentifierType identifier,
96 97
                                                   bool prefix,
                                                   bool new_identifier) {
98
    std::vector<uint8_t> ident;
99
    switch (identifier) {
100
    case Host::IDENT_HWADDR:
101
        ident = generateHWAddr(new_identifier);
102
        break;
103
    case Host::IDENT_DUID:
104
        ident = generateIdentifier(new_identifier);
105 106 107 108 109 110 111 112 113 114 115 116 117 118
        break;
    default:
        ADD_FAILURE() << "Unknown IdType: " << identifier;
        return HostPtr();
    }

    // Let's create ever increasing subnet-ids. Let's keep those different,
    // so subnet4 != subnet6. Useful for catching cases if the code confuses
    // subnet4 with subnet6.
    static SubnetID subnet4 = 0;
    static SubnetID subnet6 = 100;
    subnet4++;
    subnet6++;

119 120
    HostPtr host(new Host(&ident[0], ident.size(), identifier, subnet4,
                          subnet6, IOAddress("0.0.0.0")));
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

    if (!prefix) {
        // Create IPv6 reservation (for an address)
        IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress(address), 128);
        host->addReservation(resv);
    } else {
        // Create IPv6 reservation for a /64 prefix
        IPv6Resrv resv(IPv6Resrv::TYPE_PD, IOAddress(address), 64);
        host->addReservation(resv);
    }
    return (host);
}

void
GenericHostDataSourceTest::compareHwaddrs(const ConstHostPtr& host1,
                                          const ConstHostPtr& host2,
                                          bool expect_match) {
    ASSERT_TRUE(host1);
    ASSERT_TRUE(host2);

    // Compare if both have or have not HWaddress set.
    if ((host1->getHWAddress() && !host2->getHWAddress()) ||
        (!host1->getHWAddress() && host2->getHWAddress())) {

        // One host has hardware address set while the other has not.
        // Let's see if it's a problem.
        if (expect_match) {
            ADD_FAILURE() << "Host comparison failed: host1 hwaddress="
                          << host1->getHWAddress() << ", host2 hwaddress="
                          << host2->getHWAddress();
        }
        return;
    }

    // Now we know that either both or neither have hw address set.
    // If host1 has it, we can proceed to value comparison.
    if (host1->getHWAddress()) {

        if (expect_match) {
            // Compare the actual address if they match.
            EXPECT_TRUE(*host1->getHWAddress() == *host2->getHWAddress());
        } else {
            EXPECT_FALSE(*host1->getHWAddress() == *host2->getHWAddress());
        }
        if (*host1->getHWAddress() != *host2->getHWAddress()) {
            cout << host1->getHWAddress()->toText(true) << endl;
            cout << host2->getHWAddress()->toText(true) << endl;
        }
    }
}

void
GenericHostDataSourceTest::compareDuids(const ConstHostPtr& host1,
                                        const ConstHostPtr& host2,
                                        bool expect_match) {
    ASSERT_TRUE(host1);
    ASSERT_TRUE(host2);

    // compare if both have or have not DUID set
    if ((host1->getDuid() && !host2->getDuid()) ||
        (!host1->getDuid() && host2->getDuid())) {

        // One host has a DUID and the other doesn't.
        // Let's see if it's a problem.
        if (expect_match) {
            ADD_FAILURE() << "DUID comparison failed: host1 duid="
                          << host1->getDuid() << ", host2 duid="
                          << host2->getDuid();
        }
        return;
    }

    // Now we know that either both or neither have DUID set.
    // If host1 has it, we can proceed to value comparison.
    if (host1->getDuid()) {

        if (expect_match) {
            EXPECT_TRUE(*host1->getDuid() == *host2->getDuid());
        } else {
            EXPECT_FALSE(*host1->getDuid() == *host2->getDuid());
        }
        if (*host1->getDuid() != *host2->getDuid()) {
            cout << host1->getDuid()->toText() << endl;
            cout << host2->getDuid()->toText() << endl;
        }
    }
}

void GenericHostDataSourceTest::compareHosts(const ConstHostPtr& host1,
                                             const ConstHostPtr& host2) {

    // Let's compare HW addresses and expect match.
    compareHwaddrs(host1, host2, true);

    // Now compare DUIDs
    compareDuids(host1, host2, true);

    // Now check that the identifiers returned as vectors are the same
    EXPECT_EQ(host1->getIdentifierType(), host2->getIdentifierType());
220
    EXPECT_TRUE(host1->getIdentifier() == host2->getIdentifier());
221 222 223 224 225 226 227 228 229

    // Check host parameters
    EXPECT_EQ(host1->getIPv4SubnetID(), host2->getIPv4SubnetID());
    EXPECT_EQ(host1->getIPv6SubnetID(), host2->getIPv6SubnetID());
    EXPECT_EQ(host1->getIPv4Reservation(), host2->getIPv4Reservation());
    EXPECT_EQ(host1->getHostname(), host2->getHostname());

    // Compare IPv6 reservations
    compareReservations6(host1->getIPv6Reservations(),
230
                         host2->getIPv6Reservations());
231 232 233 234 235 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

    // And compare client classification details
    compareClientClasses(host1->getClientClasses4(),
                         host2->getClientClasses4());

    compareClientClasses(host1->getClientClasses6(),
                         host2->getClientClasses6());
}

DuidPtr
GenericHostDataSourceTest::HWAddrToDuid(const HWAddrPtr& hwaddr) {
    if (!hwaddr) {
        return (DuidPtr());
    }

    return (DuidPtr(new DUID(hwaddr->hwaddr_)));
}

HWAddrPtr
GenericHostDataSourceTest::DuidToHWAddr(const DuidPtr& duid) {
    if (!duid) {
        return (HWAddrPtr());
    }

    return (HWAddrPtr(new HWAddr(duid->getDuid(), HTYPE_ETHER)));
}


void
GenericHostDataSourceTest::compareReservations6(IPv6ResrvRange resrv1,
261
                                                IPv6ResrvRange resrv2) {
262 263 264 265

    // Compare number of reservations for both hosts
    if (std::distance(resrv1.first, resrv1.second) !=
            std::distance(resrv2.first, resrv2.second)){
266 267
        ADD_FAILURE()<< "Reservation comparison failed, "
            "hosts got different number of reservations.";
268 269 270
        return;
    }

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    // Iterate over the range of reservations to find a match in the
    // reference range.
    for (IPv6ResrvIterator r1 = resrv1.first; r1 != resrv1.second; ++r1) {
        IPv6ResrvIterator r2 = resrv2.first;
        for (; r2 != resrv2.second; ++r2) {
            // IPv6Resrv object implements equality operator.
            if (r1->second == r2->second) {
                break;
            }
        }
        // If r2 iterator reached the end of the range it means that there
        // is no match.
        if (r2 == resrv2.second) {
            ADD_FAILURE() << "No match found for reservation: "
                          << resrv1.first->second.getPrefix().toText();
        }
    }

289
    if (std::distance(resrv1.first, resrv1.second) > 0) {
290 291 292 293 294 295 296 297 298
        for (; resrv1.first != resrv1.second; resrv1.first++) {
            IPv6ResrvIterator iter = resrv2.first;
            while (iter != resrv2.second) {
                if((resrv1.first->second.getType() == iter->second.getType()) &&
                        (resrv1.first->second.getPrefixLen() == iter->second.getPrefixLen()) &&
                        (resrv1.first->second.getPrefix() == iter->second.getPrefix())) {
                    break;
                }
                iter++;
299
                if (iter == resrv2.second) {
300 301 302 303
                    ADD_FAILURE()<< "Reservation comparison failed, "
                    "no match for reservation: "
                    << resrv1.first->second.getPrefix().toText();
                }
304
            }
305 306 307 308 309 310 311 312 313 314 315
        }
    }
}

void
GenericHostDataSourceTest::compareClientClasses(const ClientClasses& /*classes1*/,
                                                const ClientClasses& /*classes2*/) {
    /// @todo: Implement client classes comparison.
    ///        This is part of the work for #4213.
}

316
void GenericHostDataSourceTest::testBasic4(const Host::IdentifierType& id) {
317 318 319 320
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host reservation.
321
    HostPtr host = initializeHost4("192.0.2.1", id);
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    ASSERT_TRUE(host); // Make sure the host is generate properly.
    SubnetID subnet = host->getIPv4SubnetID();

    // Try to add it to the host data source.
    ASSERT_NO_THROW(hdsptr_->add(host));

    // This should not return anything
    ConstHostPtr from_hds = hdsptr_->get4(subnet, IOAddress("10.10.10.10"));
    ASSERT_FALSE(from_hds);

    // This time it should return a host
    from_hds = hdsptr_->get4(subnet, IOAddress("192.0.2.1"));
    ASSERT_TRUE(from_hds);

    // Finally, let's check if what we got makes any sense.
    compareHosts(host, from_hds);
}


341
void GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) {
342 343 344 345
    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Let's create a couple of hosts...
346 347 348 349
    HostPtr host1 = initializeHost4("192.0.2.1", id);
    HostPtr host2 = initializeHost4("192.0.2.2", id);
    HostPtr host3 = initializeHost4("192.0.2.3", id);
    HostPtr host4 = initializeHost4("192.0.2.4", id);
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384

    // ... and add them to the data source.
    ASSERT_NO_THROW(hdsptr_->add(host1));
    ASSERT_NO_THROW(hdsptr_->add(host2));
    ASSERT_NO_THROW(hdsptr_->add(host3));
    ASSERT_NO_THROW(hdsptr_->add(host4));

    SubnetID subnet1 = host1->getIPv4SubnetID();
    SubnetID subnet2 = host2->getIPv4SubnetID();
    SubnetID subnet3 = host3->getIPv4SubnetID();
    SubnetID subnet4 = host4->getIPv4SubnetID();

    // And then try to retrieve them back.
    ConstHostPtr from_hds1 = hdsptr_->get4(subnet1, IOAddress("192.0.2.1"));
    ConstHostPtr from_hds2 = hdsptr_->get4(subnet2, IOAddress("192.0.2.2"));
    ConstHostPtr from_hds3 = hdsptr_->get4(subnet3, IOAddress("192.0.2.3"));
    ConstHostPtr from_hds4 = hdsptr_->get4(subnet4, IOAddress("192.0.2.4"));

    // Make sure we got something back.
    ASSERT_TRUE(from_hds1);
    ASSERT_TRUE(from_hds2);
    ASSERT_TRUE(from_hds3);
    ASSERT_TRUE(from_hds4);

    // Then let's check that what we got seems correct.
    compareHosts(host1, from_hds1);
    compareHosts(host2, from_hds2);
    compareHosts(host3, from_hds3);
    compareHosts(host4, from_hds4);

    // Ok, finally let's check that getting by a different address
    // will not work.
    EXPECT_FALSE(hdsptr_->get4(subnet1, IOAddress("192.0.1.5")));
}

385 386
void
GenericHostDataSourceTest::testGet4ByIdentifier(const Host::IdentifierType& identifier_type) {
387 388 389
    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

390 391
    HostPtr host1 = initializeHost4("192.0.2.1", identifier_type);
    HostPtr host2 = initializeHost4("192.0.2.2", identifier_type);
392

393 394
    // Sanity check: make sure the hosts have different identifiers..
    ASSERT_FALSE(host1->getIdentifier() == host2->getIdentifier());
395 396 397 398 399 400 401 402

    // Try to add both of them to the host data source.
    ASSERT_NO_THROW(hdsptr_->add(host1));
    ASSERT_NO_THROW(hdsptr_->add(host2));

    SubnetID subnet1 = host1->getIPv4SubnetID();
    SubnetID subnet2 = host2->getIPv4SubnetID();

403
    ConstHostPtr from_hds1 = hdsptr_->get4(subnet1,
404
                                           identifier_type,
405 406 407 408
                                           &host1->getIdentifier()[0],
                                           host1->getIdentifier().size());

    ConstHostPtr from_hds2 = hdsptr_->get4(subnet2,
409
                                           identifier_type,
410 411
                                           &host2->getIdentifier()[0],
                                           host2->getIdentifier().size());
412 413 414 415 416 417 418 419 420 421 422 423 424

    // Now let's check if we got what we expected.
    ASSERT_TRUE(from_hds1);
    ASSERT_TRUE(from_hds2);
    compareHosts(host1, from_hds1);
    compareHosts(host2, from_hds2);
}

void GenericHostDataSourceTest::testHWAddrNotClientId() {
    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host with HW address
425
    HostPtr host = initializeHost4("192.0.2.1", Host::IDENT_HWADDR);
426 427 428 429 430 431 432 433 434 435 436
    ASSERT_TRUE(host->getHWAddress());
    ASSERT_FALSE(host->getDuid());

    // Try to add it to the host data source.
    ASSERT_NO_THROW(hdsptr_->add(host));

    SubnetID subnet = host->getIPv4SubnetID();

    DuidPtr duid = HWAddrToDuid(host->getHWAddress());

    // Get the host by HW address (should succeed)
437 438 439
    ConstHostPtr by_hwaddr = hdsptr_->get4(subnet, Host::IDENT_HWADDR,
                                           &host->getIdentifier()[0],
                                           host->getIdentifier().size());
440 441

    // Get the host by DUID (should fail)
442 443 444
    ConstHostPtr by_duid   = hdsptr_->get4(subnet, Host::IDENT_DUID,
                                           &host->getIdentifier()[0],
                                           host->getIdentifier().size());
445 446 447 448 449 450 451 452 453 454 455

    // Now let's check if we got what we expected.
    EXPECT_TRUE(by_hwaddr);
    EXPECT_FALSE(by_duid);
}

void GenericHostDataSourceTest::testClientIdNotHWAddr() {
    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host with client-id
456
    HostPtr host = initializeHost4("192.0.2.1", Host::IDENT_DUID);
457 458 459 460 461 462 463 464 465 466 467
    ASSERT_FALSE(host->getHWAddress());
    ASSERT_TRUE(host->getDuid());

    // Try to add it to the host data source.
    ASSERT_NO_THROW(hdsptr_->add(host));

    SubnetID subnet = host->getIPv4SubnetID();

    HWAddrPtr hwaddr = DuidToHWAddr(host->getDuid());

    // Get the host by DUID (should succeed)
468 469 470 471
    ConstHostPtr by_duid   = hdsptr_->get4(subnet, Host::IDENT_DUID,
                                           &host->getIdentifier()[0],
                                           host->getIdentifier().size());

472 473

    // Get the host by HW address (should fail)
474 475 476
    ConstHostPtr by_hwaddr = hdsptr_->get4(subnet, Host::IDENT_HWADDR,
                                           &host->getIdentifier()[0],
                                           host->getIdentifier().size());
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499

    // Now let's check if we got what we expected.
    EXPECT_TRUE(by_duid);
    EXPECT_FALSE(by_hwaddr);
}

void
GenericHostDataSourceTest::testHostname(std::string name, int num) {

    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Initialize the address to 192.0.2.0 (this will be bumped
    // up to 192.0.2.1 in the first iteration)
    IOAddress addr("192.0.2.0");

    vector<HostPtr> hosts;

    // Prepare a vector of hosts with unique hostnames
    for (int i = 0; i < num; ++i) {

        addr = IOAddress::increase(addr);

500
        HostPtr host = initializeHost4(addr.toText(), Host::IDENT_DUID);
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535

        stringstream hostname;
        hostname.str("");
        if (num > 1) {
            hostname << i;
        }
        hostname << name;
        host->setHostname(hostname.str());

        hosts.push_back(host);
    }

    // Now add them all to the host data source.
    for (vector<HostPtr>::const_iterator it = hosts.begin();
         it != hosts.end(); ++it) {
        // Try to add both of the to the host data source.
        ASSERT_NO_THROW(hdsptr_->add(*it));
    }

    // And finally retrieve them one by one and check
    // if the hostname was preserved.
    for (vector<HostPtr>::const_iterator it = hosts.begin();
         it != hosts.end(); ++it) {

        ConstHostPtr from_hds;
        ASSERT_NO_THROW(from_hds = hdsptr_->get4(
                            (*it)->getIPv4SubnetID(),
                            (*it)->getIPv4Reservation()));
        ASSERT_TRUE(from_hds);

        EXPECT_EQ((*it)->getHostname(), from_hds->getHostname());
    }
}

void
536 537
GenericHostDataSourceTest::testMultipleSubnets(int subnets,
                                               const Host::IdentifierType& id) {
538 539 540 541

    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

542
    HostPtr host = initializeHost4("192.0.2.1", id);
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562

    for (int i = 0; i < subnets; ++i) {
        host->setIPv4SubnetID(i + 1000);
        host->setIPv6SubnetID(i + 1000);

        // Check that the same host can have reservations in multiple subnets.
        EXPECT_NO_THROW(hdsptr_->add(host));
    }

    // Now check that the reservations can be retrieved by IPv4 address from
    // each subnet separately.
    for (int i = 0; i < subnets; ++i) {

        // Try to retrieve the host by IPv4 address.
        ConstHostPtr from_hds = hdsptr_->get4(i + 1000, host->getIPv4Reservation());

        ASSERT_TRUE(from_hds);
        EXPECT_EQ(i + 1000, from_hds->getIPv4SubnetID());

        // Try to retrieve the host by either HW address of client-id
563
        from_hds = hdsptr_->get4(i + 1000,
564
                                 id, &host->getIdentifier()[0],
565
                                 host->getIdentifier().size());
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
        ASSERT_TRUE(from_hds);
        EXPECT_EQ(i + 1000, from_hds->getIPv4SubnetID());
    }

    // Now check that they can be retrieved all at once, by IPv4 address.
    ConstHostCollection all_by_addr = hdsptr_->getAll4(IOAddress("192.0.2.1"));
    ASSERT_EQ(subnets, all_by_addr.size());

    // Verify that the values returned are proper.
    int i = 0;
    for (ConstHostCollection::const_iterator it = all_by_addr.begin();
         it != all_by_addr.end(); ++it) {
        EXPECT_EQ(IOAddress("192.0.2.1"), (*it)->getIPv4Reservation());
        EXPECT_EQ(1000 + i++, (*it)->getIPv4SubnetID());
    }

    // Finally, check that the hosts can be retrived by HW address or DUID
583
    ConstHostCollection all_by_id =
584
        hdsptr_->getAll(id, &host->getIdentifier()[0],
585
                        host->getIdentifier().size());
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
    ASSERT_EQ(subnets, all_by_id.size());

    // Check that the returned values are as expected.
    i = 0;
    for (ConstHostCollection::const_iterator it = all_by_id.begin();
         it != all_by_id.end(); ++it) {
        EXPECT_EQ(IOAddress("192.0.2.1"), (*it)->getIPv4Reservation());
        EXPECT_EQ(1000 + i++, (*it)->getIPv4SubnetID());
    }
}

void GenericHostDataSourceTest::testGet6ByHWAddr() {
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host reservations.
602 603
    HostPtr host1 = initializeHost6("2001:db8::1", Host::IDENT_HWADDR, "hw-address");
    HostPtr host2 = initializeHost6("2001:db8::2", Host::IDENT_HWADDR, "hw-address");
604 605 606 607 608 609 610 611 612 613 614 615 616 617

    // Sanity check: make sure the hosts have different HW addresses.
    ASSERT_TRUE(host1->getHWAddress());
    ASSERT_TRUE(host2->getHWAddress());

    compareHwaddrs(host1, host2, false);

    // Try to add both of them to the host data source.
    ASSERT_NO_THROW(hdsptr_->add(host1));
    ASSERT_NO_THROW(hdsptr_->add(host2));

    SubnetID subnet1 = host1->getIPv6SubnetID();
    SubnetID subnet2 = host2->getIPv6SubnetID();

618 619 620 621 622 623 624
    ConstHostPtr from_hds1 = hdsptr_->get6(subnet1, Host::IDENT_HWADDR,
                                           &host1->getIdentifier()[0],
                                           host1->getIdentifier().size());

    ConstHostPtr from_hds2 = hdsptr_->get6(subnet2, Host::IDENT_HWADDR,
                                           &host2->getIdentifier()[0],
                                           host2->getIdentifier().size());
625 626 627 628 629 630 631 632 633 634 635 636 637

    // Now let's check if we got what we expected.
    ASSERT_TRUE(from_hds1);
    ASSERT_TRUE(from_hds2);
    compareHosts(host1, from_hds1);
    compareHosts(host2, from_hds2);
}

void GenericHostDataSourceTest::testGet6ByClientId() {
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host reservations.
638 639
    HostPtr host1 = initializeHost6("2001:db8::1", Host::IDENT_DUID, "hw-address");
    HostPtr host2 = initializeHost6("2001:db8::2", Host::IDENT_DUID, "hw-address");
640 641 642 643 644 645 646 647 648 649 650 651 652 653

    // Sanity check: make sure the hosts have different HW addresses.
    ASSERT_TRUE(host1->getDuid());
    ASSERT_TRUE(host2->getDuid());

    compareDuids(host1, host2, false);

    // Try to add both of them to the host data source.
    ASSERT_NO_THROW(hdsptr_->add(host1));
    ASSERT_NO_THROW(hdsptr_->add(host2));

    SubnetID subnet1 = host1->getIPv6SubnetID();
    SubnetID subnet2 = host2->getIPv6SubnetID();

654 655 656 657 658 659 660
    ConstHostPtr from_hds1 = hdsptr_->get6(subnet1, Host::IDENT_DUID,
                                           &host1->getIdentifier()[0],
                                           host1->getIdentifier().size());

    ConstHostPtr from_hds2 = hdsptr_->get6(subnet2, Host::IDENT_DUID,
                                           &host2->getIdentifier()[0],
                                           host2->getIdentifier().size());
661 662 663 664 665 666 667 668 669

    // Now let's check if we got what we expected.
    ASSERT_TRUE(from_hds1);
    ASSERT_TRUE(from_hds2);
    compareHosts(host1, from_hds1);
    compareHosts(host2, from_hds2);
}

void
670
GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) {
671 672 673 674

    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

675 676
    HostPtr host;
    IOAddress current_address("2001:db8::0");
677
    for (int i = 0; i < subnets; ++i) {
678 679 680 681
        // Last boolean value set to false indicates that the same identifier
        // must be used for each generated host.
        host = initializeHost6(current_address.toText(), id, true, false);

682 683 684 685 686
        host->setIPv4SubnetID(i + 1000);
        host->setIPv6SubnetID(i + 1000);

        // Check that the same host can have reservations in multiple subnets.
        EXPECT_NO_THROW(hdsptr_->add(host));
687 688 689 690

        // Increase address to make sure we don't assign the same address
        // in different subnets.
        current_address = IOAddress::increase(current_address);
691 692 693 694 695 696
    }

    // Check that the reservations can be retrieved from each subnet separately.
    for (int i = 0; i < subnets; ++i) {

        // Try to retrieve the host
697 698
        ConstHostPtr from_hds = hdsptr_->get6(i + 1000, id, &host->getIdentifier()[0],
                                              host->getIdentifier().size());
699

700
        ASSERT_TRUE(from_hds) << "failed for i=" << i;
701 702 703 704
        EXPECT_EQ(i + 1000, from_hds->getIPv6SubnetID());
    }

    // Check that the hosts can all be retrived by HW address or DUID
705 706
    ConstHostCollection all_by_id = hdsptr_->getAll(id, &host->getIdentifier()[0],
                                                    host->getIdentifier().size());
707 708 709 710 711 712 713 714 715 716 717
    ASSERT_EQ(subnets, all_by_id.size());

    // Check that the returned values are as expected.
    int i = 0;
    for (ConstHostCollection::const_iterator it = all_by_id.begin();
         it != all_by_id.end(); ++it) {
        EXPECT_EQ(IOAddress("0.0.0.0"), (*it)->getIPv4Reservation());
        EXPECT_EQ(1000 + i++, (*it)->getIPv6SubnetID());
    }
}

718
void GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id,
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
                                              bool prefix) {
    // Make sure we have a pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Let's create a couple of hosts...
    HostPtr host1 = initializeHost6("2001:db8::1", id, prefix);
    HostPtr host2 = initializeHost6("2001:db8::2", id, prefix);
    HostPtr host3 = initializeHost6("2001:db8::3", id, prefix);
    HostPtr host4 = initializeHost6("2001:db8::4", id, prefix);

    // ... and add them to the data source.
    ASSERT_NO_THROW(hdsptr_->add(host1));
    ASSERT_NO_THROW(hdsptr_->add(host2));
    ASSERT_NO_THROW(hdsptr_->add(host3));
    ASSERT_NO_THROW(hdsptr_->add(host4));

    // Are we talking about addresses or prefixes?
    uint8_t len = prefix ? 64 : 128;

    // And then try to retrieve them back.
    ConstHostPtr from_hds1 = hdsptr_->get6(IOAddress("2001:db8::1"), len);
    ConstHostPtr from_hds2 = hdsptr_->get6(IOAddress("2001:db8::2"), len);
    ConstHostPtr from_hds3 = hdsptr_->get6(IOAddress("2001:db8::3"), len);
    ConstHostPtr from_hds4 = hdsptr_->get6(IOAddress("2001:db8::4"), len);

    // Make sure we got something back.
    ASSERT_TRUE(from_hds1);
    ASSERT_TRUE(from_hds2);
    ASSERT_TRUE(from_hds3);
    ASSERT_TRUE(from_hds4);

    // Then let's check that what we got seems correct.
    compareHosts(host1, from_hds1);
    compareHosts(host2, from_hds2);
    compareHosts(host3, from_hds3);
    compareHosts(host4, from_hds4);

    // Ok, finally let's check that getting by a different address
    // will not work.
    EXPECT_FALSE(hdsptr_->get6(IOAddress("2001:db8::5"), len));
}

761
void GenericHostDataSourceTest::testAddDuplicate6WithSameDUID() {
762 763 764 765
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host reservations.
766
    HostPtr host = initializeHost6("2001:db8::1", Host::IDENT_DUID, true);
767 768 769 770 771 772

    // Add this reservation once.
    ASSERT_NO_THROW(hdsptr_->add(host));

    // Then try to add it again, it should throw an exception.
    ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
773 774 775
}

void GenericHostDataSourceTest::testAddDuplicate6WithSameHWAddr() {
776 777 778 779
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host reservations.
780
    HostPtr host = initializeHost6("2001:db8::1", Host::IDENT_HWADDR, true);
781 782 783 784 785 786

    // Add this reservation once.
    ASSERT_NO_THROW(hdsptr_->add(host));

    // Then try to add it again, it should throw an exception.
    ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
787 788 789 790 791 792 793
}

void GenericHostDataSourceTest::testAddDuplicate4() {
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host reservations.
794
    HostPtr host = initializeHost4("192.0.2.1", Host::IDENT_DUID);
795 796 797 798 799 800

    // Add this reservation once.
    ASSERT_NO_THROW(hdsptr_->add(host));

    // Then try to add it again, it should throw an exception.
    ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);
801 802 803 804 805 806 807 808 809 810 811

    // This time use a different host identifier and try again.
    // This update should be rejected because of duplicated
    // address.
    ASSERT_NO_THROW(host->setIdentifier("01:02:03:04:05:06", "hw-address"));
    ASSERT_THROW(hdsptr_->add(host), DuplicateEntry);

    // Modify address to avoid its duplication and make sure
    // we can now add the host.
    ASSERT_NO_THROW(host->setIPv4Reservation(IOAddress("192.0.2.3")));
    EXPECT_NO_THROW(hdsptr_->add(host));
812 813
}

814 815 816 817 818
void GenericHostDataSourceTest::testAddr6AndPrefix(){
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);

    // Create a host reservations with prefix reservation (prefix = true)
819
    HostPtr host = initializeHost6("2001:db8::1", Host::IDENT_DUID, true);
820 821 822 823 824 825 826 827 828

    // Create IPv6 reservation (for an address) and add it to the host
    IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::2"), 128);
    host->addReservation(resv);

    // Add this reservation
    ASSERT_NO_THROW(hdsptr_->add(host));

    // Get this host by DUID
829 830 831 832
    ConstHostPtr from_hds = hdsptr_->get6(host->getIPv6SubnetID(),
                                          Host::IDENT_DUID,
                                          &host->getIdentifier()[0],
                                          host->getIdentifier().size());
833 834 835 836 837

    // Make sure we got something back
    ASSERT_TRUE(from_hds);

    // Check if reservations are the same
838 839
    compareReservations6(host->getIPv6Reservations(),
                         from_hds->getIPv6Reservations());
840 841
}

842
void GenericHostDataSourceTest::testMultipleReservations(){
843 844 845 846
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);
    uint8_t len = 128;

847
    HostPtr host = initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
848 849 850 851 852

    // Add some reservations
    IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), len);
    IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), len);
    IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), len);
853
    IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), len);
854 855 856 857

    host->addReservation(resv1);
    host->addReservation(resv2);
    host->addReservation(resv3);
858
    host->addReservation(resv4);
859 860 861 862 863 864 865 866 867 868 869

    ASSERT_NO_THROW(hdsptr_->add(host));


    ConstHostPtr from_hds = hdsptr_->get6(IOAddress("2001:db8::1"), len);

    // Make sure we got something back
    ASSERT_TRUE(from_hds);

    // Check if hosts are the same
    compareHosts(host, from_hds);
870 871
}

872
void GenericHostDataSourceTest::testMultipleReservationsDifferentOrder(){
873 874 875 876
    // Make sure we have the pointer to the host data source.
    ASSERT_TRUE(hdsptr_);
    uint8_t len = 128;

877 878
    HostPtr host1 = initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
    HostPtr host2 = initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896

    // Add some reservations
    IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), len);
    IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), len);
    IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), len);
    IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), len);

    host1->addReservation(resv1);
    host1->addReservation(resv2);
    host1->addReservation(resv3);
    host1->addReservation(resv4);

    host2->addReservation(resv4);
    host2->addReservation(resv3);
    host2->addReservation(resv2);
    host2->addReservation(resv1);

    // Check if reservations are the same
897
    compareReservations6(host1->getIPv6Reservations(), host2->getIPv6Reservations());
898 899 900 901 902 903

}

}; // namespace test
}; // namespace dhcp
}; // namespace isc