subnet_unittest.cc 48.7 KB
Newer Older
1
// Copyright (C) 2012-2017 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 <asiolink/io_address.h>
10
#include <dhcp/option.h>
11
#include <dhcp/dhcp6.h>
12
#include <dhcp/option_space.h>
13
#include <dhcpsrv/subnet.h>
14
#include <exceptions/exceptions.h>
15

16 17
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
18
#include <limits>
19 20 21 22 23 24 25 26 27 28

// don't import the entire boost namespace.  It will unexpectedly hide uint8_t
// for some systems.
using boost::scoped_ptr;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::asiolink;

namespace {

29 30
TEST(Subnet4Test, constructor) {
    EXPECT_NO_THROW(Subnet4 subnet1(IOAddress("192.0.2.2"), 16,
31
                                    1, 2, 3, 10));
32 33 34 35 36 37 38

    EXPECT_THROW(Subnet4 subnet2(IOAddress("192.0.2.0"), 33, 1, 2, 3),
                BadValue); // invalid prefix length
    EXPECT_THROW(Subnet4 subnet3(IOAddress("2001:db8::1"), 24, 1, 2, 3),
                BadValue); // IPv6 addresses are not allowed in Subnet4
}

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
// Checks that the subnet id can be either autogenerated or set to an
// arbitrary value through the constructor.
TEST(Subnet4Test, subnetID) {
    // Create subnet and don't specify id, so as it is autogenerated.
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1000, 2000,
                                  3000));
    SubnetID id0 = subnet->getID();

    // Create another subnet and let id be autogenerated.
    subnet.reset(new Subnet4(IOAddress("192.0.3.0"), 24, 1000, 2000,
                             3000));
    SubnetID id1 = subnet->getID();

    // The autogenerated ids must not be equal.
    EXPECT_NE(id0, id1);

    // Create third subnet but this time select an arbitrary id. The id
56
    // we use the one of the second subnet. That way we ensure that the
57 58 59 60 61 62 63 64 65
    // subnet id we provide via constructor is used and it is not
    // autogenerated - if it was autogenerated we would get id other
    // than id1 because id1 has already been used.
    subnet.reset(new Subnet4(IOAddress("192.0.4.0"), 24, 1000, 2000,
                             3000, id1));
    EXPECT_EQ(id1, subnet->getID());
}

TEST(Subnet4Test, inRange) {
66 67 68 69 70 71
    Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);

    EXPECT_EQ(1000, subnet.getT1());
    EXPECT_EQ(2000, subnet.getT2());
    EXPECT_EQ(3000, subnet.getValid());

72
    EXPECT_EQ("0.0.0.0", subnet.getRelayInfo().addr_.toText());
73

74 75 76 77 78 79 80 81 82
    EXPECT_FALSE(subnet.inRange(IOAddress("192.0.0.0")));
    EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.0")));
    EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.1")));
    EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.255")));
    EXPECT_FALSE(subnet.inRange(IOAddress("192.0.3.0")));
    EXPECT_FALSE(subnet.inRange(IOAddress("0.0.0.0")));
    EXPECT_FALSE(subnet.inRange(IOAddress("255.255.255.255")));
}

83 84 85 86 87
// Checks whether the relay field has sane default and if it can
// be changed, stored and retrieved
TEST(Subnet4Test, relay) {
    Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);

88
    EXPECT_EQ("0.0.0.0", subnet.getRelayInfo().addr_.toText());
89

90 91
    subnet.setRelayInfo(IOAddress("192.0.123.45"));
    EXPECT_EQ("192.0.123.45", subnet.getRelayInfo().addr_.toText());
92 93
}

Tomek Mrugalski's avatar
Tomek Mrugalski committed
94
// Checks whether siaddr field can be set and retrieved correctly.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
TEST(Subnet4Test, siaddr) {
    Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);

    // Check if the default is 0.0.0.0
    EXPECT_EQ("0.0.0.0", subnet.getSiaddr().toText());

    // Check that we can set it up
    EXPECT_NO_THROW(subnet.setSiaddr(IOAddress("1.2.3.4")));

    // Check that we can get it back
    EXPECT_EQ("1.2.3.4", subnet.getSiaddr().toText());

    // Check that only v4 addresses are supported
    EXPECT_THROW(subnet.setSiaddr(IOAddress("2001:db8::1")),
        BadValue);
}

112 113
// Checks if the match-client-id flag can be set and retrieved.
TEST(Subnet4Test, matchClientId) {
114 115
    Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);

116
    // By default the flag should be set to true.
117
    EXPECT_TRUE(subnet.getMatchClientId());
118 119

    // Modify it and retrieve.
120 121
    subnet.setMatchClientId(false);
    EXPECT_FALSE(subnet.getMatchClientId());
122 123

    // Modify again.
124 125
    subnet.setMatchClientId(true);
    EXPECT_TRUE(subnet.getMatchClientId());
126 127
}

128 129
// Checks that it is possible to add and retrieve multiple pools.
TEST(Subnet4Test, pool4InSubnet4) {
130 131 132

    Subnet4Ptr subnet(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3));

133 134 135
    PoolPtr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
    PoolPtr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
    PoolPtr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
136

137 138 139
    // Add pools in reverse order to make sure that they get ordered by
    // first address.
    EXPECT_NO_THROW(subnet->addPool(pool3));
140 141

    // If there's only one pool, get that pool
142
    PoolPtr mypool = subnet->getAnyPool(Lease::TYPE_V4);
143
    EXPECT_EQ(mypool, pool3);
144

Tomek Mrugalski's avatar
Tomek Mrugalski committed
145
    EXPECT_NO_THROW(subnet->addPool(pool2));
146
    EXPECT_NO_THROW(subnet->addPool(pool1));
147 148 149

    // If there are more than one pool and we didn't provide hint, we
    // should get the first pool
150
    EXPECT_NO_THROW(mypool = subnet->getAnyPool(Lease::TYPE_V4));
151 152 153 154

    EXPECT_EQ(mypool, pool1);

    // If we provide a hint, we should get a pool that this hint belongs to
155
    ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
Tomek Mrugalski's avatar
Tomek Mrugalski committed
156
                                             IOAddress("192.1.2.195")));
157 158
    EXPECT_EQ(mypool, pool3);

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
                                             IOAddress("192.1.2.129")));
    EXPECT_EQ(mypool, pool2);

    ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
                                             IOAddress("192.1.2.64")));
    EXPECT_EQ(mypool, pool1);

    // Specify addresses which don't belong to any existing pools. The
    // third parameter prevents it from returning "any" available
    // pool if a good match is not found.
    ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
                                             IOAddress("192.1.2.200"),
                                             false));
    EXPECT_FALSE(mypool);

    ASSERT_NO_THROW(mypool = subnet->getPool(Lease::TYPE_V4,
                                             IOAddress("192.1.1.254"),
                                             false));
    EXPECT_FALSE(mypool);
179 180
}

181 182
// Check if it's possible to get specified number of possible leases for
// an IPv4 subnet.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
183
TEST(Subnet4Test, getCapacity) {
184 185 186 187 188

    // There's one /24 pool.
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3));

    // There are no pools defined, so the total number of available addrs is 0.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
189
    EXPECT_EQ(0, subnet->getPoolCapacity(Lease::TYPE_V4));
190 191 192 193

    // Let's add a /25 pool. That's 128 addresses.
    PoolPtr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
    subnet->addPool(pool1);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
194
    EXPECT_EQ(128, subnet->getPoolCapacity(Lease::TYPE_V4));
195 196 197 198

    // Let's add another /26 pool. That's extra 64 addresses.
    PoolPtr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
    subnet->addPool(pool2);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
199
    EXPECT_EQ(192, subnet->getPoolCapacity(Lease::TYPE_V4));
200 201 202 203

    // Let's add a third pool /30. This one has 4 addresses.
    PoolPtr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
    subnet->addPool(pool3);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
204
    EXPECT_EQ(196, subnet->getPoolCapacity(Lease::TYPE_V4));
205 206
}

207 208
// Checks that it is not allowed to add invalid pools.
TEST(Subnet4Test, pool4Checks) {
209 210 211 212

    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));

    // this one is in subnet
213
    Pool4Ptr pool1(new Pool4(IOAddress("192.254.0.0"), 16));
214
    subnet->addPool(pool1);
215 216 217 218

    // this one is larger than the subnet!
    Pool4Ptr pool2(new Pool4(IOAddress("193.0.0.0"), 24));

219
    ASSERT_THROW(subnet->addPool(pool2), BadValue);
220 221 222

    // this one is totally out of blue
    Pool4Ptr pool3(new Pool4(IOAddress("1.2.3.4"), 16));
223 224 225 226 227 228 229 230 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 261 262 263 264 265 266 267 268 269
    ASSERT_THROW(subnet->addPool(pool3), BadValue);

    // This pool should be added just fine.
    Pool4Ptr pool4(new Pool4(IOAddress("192.0.2.10"),
                             IOAddress("192.0.2.20")));
    ASSERT_NO_THROW(subnet->addPool(pool4));

    // This one overlaps with the previous pool.
    Pool4Ptr pool5(new Pool4(IOAddress("192.0.2.1"),
                             IOAddress("192.0.2.15")));
    ASSERT_THROW(subnet->addPool(pool5), BadValue);

    // This one also overlaps.
    Pool4Ptr pool6(new Pool4(IOAddress("192.0.2.20"),
                             IOAddress("192.0.2.30")));
    ASSERT_THROW(subnet->addPool(pool6), BadValue);

    // This one "surrounds" the other pool.
    Pool4Ptr pool7(new Pool4(IOAddress("192.0.2.8"),
                             IOAddress("192.0.2.23")));
    ASSERT_THROW(subnet->addPool(pool7), BadValue);

    // This one does not overlap.
    Pool4Ptr pool8(new Pool4(IOAddress("192.0.2.30"),
                             IOAddress("192.0.2.40")));
    ASSERT_NO_THROW(subnet->addPool(pool8));

    // This one has a lower bound in the pool of 192.0.2.10-20.
    Pool4Ptr pool9(new Pool4(IOAddress("192.0.2.18"),
                             IOAddress("192.0.2.30")));
    ASSERT_THROW(subnet->addPool(pool9), BadValue);

    // This one has an upper bound in the pool of 192.0.2.30-40.
    Pool4Ptr pool10(new Pool4(IOAddress("192.0.2.25"),
                              IOAddress("192.0.2.32")));
    ASSERT_THROW(subnet->addPool(pool10), BadValue);

    // Add a pool with a single address.
    Pool4Ptr pool11(new Pool4(IOAddress("192.255.0.50"),
                              IOAddress("192.255.0.50")));
    ASSERT_NO_THROW(subnet->addPool(pool11));

    // Now we're going to add the same pool again. This is an interesting
    // case because we're checking if the code is properly using upper_bound
    // function, which returns a pool that has an address greater than the
    // specified one.
    ASSERT_THROW(subnet->addPool(pool11), BadValue);
270 271
}

272
// Tests whether Subnet4 object is able to store and process properly
273
// information about allowed client class (a single class).
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
TEST(Subnet4Test, clientClasses) {
    // Create the V4 subnet.
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));

    // This client does not belong to any class.
    isc::dhcp::ClientClasses no_class;

    // This client belongs to foo only.
    isc::dhcp::ClientClasses foo_class;
    foo_class.insert("foo");

    // This client belongs to bar only. I like that client.
    isc::dhcp::ClientClasses bar_class;
    bar_class.insert("bar");

    // This client belongs to foo, bar and baz classes.
    isc::dhcp::ClientClasses three_classes;
    three_classes.insert("foo");
    three_classes.insert("bar");
    three_classes.insert("baz");

    // No class restrictions defined, any client should be supported
296
    EXPECT_EQ(0, subnet->getClientClasses().size());
297 298 299 300 301
    EXPECT_TRUE(subnet->clientSupported(no_class));
    EXPECT_TRUE(subnet->clientSupported(foo_class));
    EXPECT_TRUE(subnet->clientSupported(bar_class));
    EXPECT_TRUE(subnet->clientSupported(three_classes));

Andrei Pavel's avatar
Andrei Pavel committed
302
    // Let's allow only clients belonging to "bar" class.
303
    subnet->allowClientClass("bar");
304
    EXPECT_EQ(1, subnet->getClientClasses().size());
305 306 307 308 309 310 311

    EXPECT_FALSE(subnet->clientSupported(no_class));
    EXPECT_FALSE(subnet->clientSupported(foo_class));
    EXPECT_TRUE(subnet->clientSupported(bar_class));
    EXPECT_TRUE(subnet->clientSupported(three_classes));
}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
// Tests whether Subnet4 object is able to store and process properly
// information about allowed client classes (multiple classes allowed).
TEST(Subnet4Test, clientClassesMultiple) {
    // Create the V4 subnet.
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));

    // This client does not belong to any class.
    isc::dhcp::ClientClasses no_class;

    // This client belongs to foo only.
    isc::dhcp::ClientClasses foo_class;
    foo_class.insert("foo");

    // This client belongs to bar only. I like that client.
    isc::dhcp::ClientClasses bar_class;
    bar_class.insert("bar");

    // No class restrictions defined, any client should be supported
330
    EXPECT_EQ(0, subnet->getClientClasses().size());
331 332 333 334
    EXPECT_TRUE(subnet->clientSupported(no_class));
    EXPECT_TRUE(subnet->clientSupported(foo_class));
    EXPECT_TRUE(subnet->clientSupported(bar_class));

Andrei Pavel's avatar
Andrei Pavel committed
335
    // Let's allow clients belonging to "bar" or "foo" class.
336 337
    subnet->allowClientClass("bar");
    subnet->allowClientClass("foo");
338
    EXPECT_EQ(2, subnet->getClientClasses().size());
339 340 341 342 343 344 345 346 347 348 349

    // Class-less clients are to be rejected.
    EXPECT_FALSE(subnet->clientSupported(no_class));

    // Clients in foo class should be accepted.
    EXPECT_TRUE(subnet->clientSupported(foo_class));

    // Clients in bar class should be accepted as well.
    EXPECT_TRUE(subnet->clientSupported(bar_class));
}

350 351 352 353 354 355 356 357
TEST(Subnet4Test, addInvalidOption) {
    // Create the V4 subnet.
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));

    // Create NULL pointer option. Attempt to add NULL option
    // should result in exception.
    OptionPtr option2;
    ASSERT_FALSE(option2);
358
    EXPECT_THROW(subnet->getCfgOption()->add(option2, false, DHCP4_OPTION_SPACE),
359
                 isc::BadValue);
360 361
}

362 363 364 365 366 367
// This test verifies that inRange() and inPool() methods work properly.
TEST(Subnet4Test, inRangeinPool) {
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.0.0"), 8, 1, 2, 3));

    // this one is in subnet
    Pool4Ptr pool1(new Pool4(IOAddress("192.2.0.0"), 16));
368
    subnet->addPool(pool1);
369 370 371 372 373

    // 192.1.1.1 belongs to the subnet...
    EXPECT_TRUE(subnet->inRange(IOAddress("192.1.1.1")));

    // ... but it does not belong to any pool within
374
    EXPECT_FALSE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.1.1.1")));
375 376 377

    // the last address that is in range, but out of pool
    EXPECT_TRUE(subnet->inRange(IOAddress("192.1.255.255")));
378
    EXPECT_FALSE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.1.255.255")));
379 380 381

    // the first address that is in range, in pool
    EXPECT_TRUE(subnet->inRange(IOAddress("192.2.0.0")));
382
    EXPECT_TRUE (subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.0.0")));
383 384 385

    // let's try something in the middle as well
    EXPECT_TRUE(subnet->inRange(IOAddress("192.2.3.4")));
386
    EXPECT_TRUE (subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.3.4")));
387 388 389

    // the last address that is in range, in pool
    EXPECT_TRUE(subnet->inRange(IOAddress("192.2.255.255")));
390
    EXPECT_TRUE (subnet->inPool(Lease::TYPE_V4, IOAddress("192.2.255.255")));
391 392 393

    // the first address that is in range, but out of pool
    EXPECT_TRUE(subnet->inRange(IOAddress("192.3.0.0")));
394
    EXPECT_FALSE(subnet->inPool(Lease::TYPE_V4, IOAddress("192.3.0.0")));
395 396
}

397 398 399 400 401 402 403 404 405 406 407 408 409
// This test checks if the toText() method returns text representation
TEST(Subnet4Test, toText) {
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
    EXPECT_EQ("192.0.2.0/24", subnet->toText());
}

// This test checks if the get() method returns proper parameters
TEST(Subnet4Test, get) {
    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 28, 1, 2, 3));
    EXPECT_EQ("192.0.2.0", subnet->get().first.toText());
    EXPECT_EQ(28, subnet->get().second);
}

410 411 412 413 414 415 416 417 418 419

// Checks if last allocated address/prefix is stored/retrieved properly
TEST(Subnet4Test, lastAllocated) {
    IOAddress addr("192.0.2.17");

    IOAddress last("192.0.2.255");

    Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));

    // Check initial conditions (all should be set to the last address in range)
420
    EXPECT_EQ(last.toText(), subnet->getLastAllocated(Lease::TYPE_V4).toText());
421 422

    // Now set last allocated for IA
423 424
    EXPECT_NO_THROW(subnet->setLastAllocated(Lease::TYPE_V4, addr));
    EXPECT_EQ(addr.toText(), subnet->getLastAllocated(Lease::TYPE_V4).toText());
425 426

    // No, you can't set the last allocated IPv6 address in IPv4 subnet
427 428 429
    EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_TA, addr), BadValue);
    EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_TA, addr), BadValue);
    EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_PD, addr), BadValue);
430 431
}

432 433 434 435 436 437 438 439
// Checks if the V4 is the only allowed type for Pool4 and if getPool()
// is working properly.
TEST(Subnet4Test, PoolType) {

    Subnet4Ptr subnet(new Subnet4(IOAddress("192.2.0.0"), 16, 1, 2, 3));

    PoolPtr pool1(new Pool4(IOAddress("192.2.1.0"), 24));
    PoolPtr pool2(new Pool4(IOAddress("192.2.2.0"), 24));
440 441 442
    PoolPtr pool3(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:3::"), 64));
    PoolPtr pool4(new Pool6(Lease::TYPE_TA, IOAddress("2001:db8:1:4::"), 64));
    PoolPtr pool5(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1:1::"), 64));
443 444

    // There should be no pools of any type by default
445
    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Lease::TYPE_V4));
446 447

    // It should not be possible to ask for V6 pools in Subnet4
448 449 450
    EXPECT_THROW(subnet->getAnyPool(Lease::TYPE_NA), BadValue);
    EXPECT_THROW(subnet->getAnyPool(Lease::TYPE_TA), BadValue);
    EXPECT_THROW(subnet->getAnyPool(Lease::TYPE_PD), BadValue);
451 452

    // Let's add a single V4 pool and check that it can be retrieved
Tomek Mrugalski's avatar
Tomek Mrugalski committed
453
    EXPECT_NO_THROW(subnet->addPool(pool1));
454 455

    // If there's only one IA pool, get that pool (without and with hint)
456 457
    EXPECT_EQ(pool1, subnet->getAnyPool(Lease::TYPE_V4));
    EXPECT_EQ(pool1, subnet->getPool(Lease::TYPE_V4, IOAddress("192.0.1.167")));
458 459

    // Let's add additional V4 pool
Tomek Mrugalski's avatar
Tomek Mrugalski committed
460
    EXPECT_NO_THROW(subnet->addPool(pool2));
461 462

    // Try without hints
463
    EXPECT_EQ(pool1, subnet->getAnyPool(Lease::TYPE_V4));
464 465

    // Try with valid hints
466 467
    EXPECT_EQ(pool1, subnet->getPool(Lease::TYPE_V4, IOAddress("192.2.1.5")));
    EXPECT_EQ(pool2, subnet->getPool(Lease::TYPE_V4, IOAddress("192.2.2.254")));
468

Andrei Pavel's avatar
Andrei Pavel committed
469
    // Try with bogus hints (hints should be ignored)
470
    EXPECT_EQ(pool1, subnet->getPool(Lease::TYPE_V4, IOAddress("10.1.1.1")));
471 472 473 474 475 476 477

    // Trying to add Pool6 to Subnet4 is a big no,no!
    EXPECT_THROW(subnet->addPool(pool3), BadValue);
    EXPECT_THROW(subnet->addPool(pool4), BadValue);
    EXPECT_THROW(subnet->addPool(pool5), BadValue);
}

478 479
// Tests for Subnet6

480 481 482 483 484 485 486 487 488 489 490
TEST(Subnet6Test, constructor) {

    EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
                                    1, 2, 3, 4));

    EXPECT_THROW(Subnet6 subnet2(IOAddress("2001:db8:1::"), 129, 1, 2, 3, 4),
                BadValue); // invalid prefix length
    EXPECT_THROW(Subnet6 subnet3(IOAddress("192.168.0.0"), 32, 1, 2, 3, 4),
                BadValue); // IPv4 addresses are not allowed in Subnet6
}

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
// Checks that the subnet id can be either autogenerated or set to an
// arbitrary value through the constructor.
TEST(Subnet6Test, subnetID) {
    // Create subnet and don't specify id, so as it is autogenerated.
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64, 1000, 2000,
                                  3000, 4000));
    SubnetID id0 = subnet->getID();

    // Create another subnet and let id be autogenerated.
    subnet.reset(new Subnet6(IOAddress("2001:db8:2::"), 64, 1000, 2000,
                             3000, 4000));
    SubnetID id1 = subnet->getID();

    // The autogenerated ids must not be equal.
    EXPECT_NE(id0, id1);

    // Create third subnet but this time select an arbitrary id. The id
    // we use us the one of second subnet. That way we ensure that the
    // subnet id we provide via constructor is used and it is not
    // autogenerated - if it was autogenerated we would get id other
    // than id1 because id1 has already been used.
    subnet.reset(new Subnet6(IOAddress("2001:db8:3::"), 64, 1000, 2000,
                             3000, 4000, id1));
    EXPECT_EQ(id1, subnet->getID());
}

TEST(Subnet6Test, inRange) {
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
    Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);

    EXPECT_EQ(1000, subnet.getT1());
    EXPECT_EQ(2000, subnet.getT2());
    EXPECT_EQ(3000, subnet.getPreferred());
    EXPECT_EQ(4000, subnet.getValid());

    EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
    EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
    EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
    EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
    EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
    EXPECT_FALSE(subnet.inRange(IOAddress("::")));
}

533 534 535 536 537
// Checks whether the relay field has sane default and if it can
// be changed, stored and retrieved
TEST(Subnet6Test, relay) {
    Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);

538
    EXPECT_EQ("::", subnet.getRelayInfo().addr_.toText());
539

540
    subnet.setRelayInfo(IOAddress("2001:ffff::1"));
541

542
    EXPECT_EQ("2001:ffff::1", subnet.getRelayInfo().addr_.toText());
543 544
}

545 546
// Test checks whether the number of addresses available in the pools are
// calculated properly.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
547
TEST(Subnet6Test, Pool6getCapacity) {
548 549 550 551 552 553 554 555 556 557

    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // There's 2^16 = 65536 addresses in this one.
    PoolPtr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 112));

    // There's 2^32 = 4294967296 addresses in each of those.
    PoolPtr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::"), 96));
    PoolPtr pool3(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:3::"), 96));

Tomek Mrugalski's avatar
Tomek Mrugalski committed
558 559 560
    EXPECT_EQ(0, subnet->getPoolCapacity(Lease::TYPE_NA));
    EXPECT_EQ(0, subnet->getPoolCapacity(Lease::TYPE_TA));
    EXPECT_EQ(0, subnet->getPoolCapacity(Lease::TYPE_PD));
561 562

    subnet->addPool(pool1);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
563
    EXPECT_EQ(65536, subnet->getPoolCapacity(Lease::TYPE_NA));
564 565

    subnet->addPool(pool2);
566
    EXPECT_EQ(uint64_t(4294967296ull + 65536), subnet->getPoolCapacity(Lease::TYPE_NA));
567 568

    subnet->addPool(pool3);
569
    EXPECT_EQ(uint64_t(4294967296ull + 4294967296ull + 65536),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
570
              subnet->getPoolCapacity(Lease::TYPE_NA));
571 572 573 574 575

    // This is 2^64 prefixes. We're overflown uint64_t.
    PoolPtr pool4(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:4::"), 64));
    subnet->addPool(pool4);
    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
576
              subnet->getPoolCapacity(Lease::TYPE_NA));
577 578 579 580

    PoolPtr pool5(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:5::"), 64));
    subnet->addPool(pool5);
    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
581
              subnet->getPoolCapacity(Lease::TYPE_NA));
582 583 584 585
}

// Test checks whether the number of prefixes available in the pools are
// calculated properly.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
586
TEST(Subnet6Test, Pool6PdgetPoolCapacity) {
587 588 589 590 591 592 593 594 595 596

    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));

    // There's 2^16 = 65536 addresses in this one.
    PoolPtr pool1(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 48, 64));

    // There's 2^32 = 4294967296 addresses in each of those.
    PoolPtr pool2(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:2::"), 48, 80));
    PoolPtr pool3(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:3::"), 48, 80));

Tomek Mrugalski's avatar
Tomek Mrugalski committed
597 598 599
    EXPECT_EQ(0, subnet->getPoolCapacity(Lease::TYPE_NA));
    EXPECT_EQ(0, subnet->getPoolCapacity(Lease::TYPE_TA));
    EXPECT_EQ(0, subnet->getPoolCapacity(Lease::TYPE_PD));
600 601

    subnet->addPool(pool1);
Tomek Mrugalski's avatar
Tomek Mrugalski committed
602
    EXPECT_EQ(65536, subnet->getPoolCapacity(Lease::TYPE_PD));
603 604

    subnet->addPool(pool2);
605
    EXPECT_EQ(uint64_t(4294967296ull + 65536), subnet->getPoolCapacity(Lease::TYPE_PD));
606 607

    subnet->addPool(pool3);
608
    EXPECT_EQ(uint64_t(4294967296ull + 4294967296ull + 65536),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
609
              subnet->getPoolCapacity(Lease::TYPE_PD));
610 611 612 613 614

    // This is 2^64.
    PoolPtr pool4(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:4::"), 48, 112));
    subnet->addPool(pool4);
    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
615
              subnet->getPoolCapacity(Lease::TYPE_PD));
616 617 618 619

    PoolPtr pool5(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:5::"), 48, 112));
    subnet->addPool(pool5);
    EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
Tomek Mrugalski's avatar
Tomek Mrugalski committed
620
              subnet->getPoolCapacity(Lease::TYPE_PD));
621 622
}

623 624 625 626
TEST(Subnet6Test, Pool6InSubnet6) {

    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

627 628 629
    PoolPtr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
    PoolPtr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::"), 64));
    PoolPtr pool3(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:3::"), 64));
630

631
    subnet->addPool(pool1);
632 633

    // If there's only one pool, get that pool
634
    PoolPtr mypool = subnet->getAnyPool(Lease::TYPE_NA);
635 636
    EXPECT_EQ(mypool, pool1);

637 638
    subnet->addPool(pool2);
    subnet->addPool(pool3);
639 640 641

    // If there are more than one pool and we didn't provide hint, we
    // should get the first pool
642
    mypool = subnet->getAnyPool(Lease::TYPE_NA);
643 644 645 646

    EXPECT_EQ(mypool, pool1);

    // If we provide a hint, we should get a pool that this hint belongs to
647
    mypool = subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8:1:3::dead:beef"));
648 649 650 651

    EXPECT_EQ(mypool, pool3);
}

652
// Check if Subnet6 supports different types of pools properly.
653
TEST(Subnet6Test, poolTypes) {
654 655 656

    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

657 658 659
    PoolPtr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
    PoolPtr pool2(new Pool6(Lease::TYPE_TA, IOAddress("2001:db8:1:2::"), 64));
    PoolPtr pool3(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1:3::"), 64));
660
    PoolPtr pool4(new Pool6(Lease::TYPE_PD, IOAddress("3000:1::"), 64));
661 662 663 664

    PoolPtr pool5(new Pool4(IOAddress("192.0.2.0"), 24));

    // There should be no pools of any type by default
665 666 667
    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Lease::TYPE_NA));
    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Lease::TYPE_TA));
    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Lease::TYPE_PD));
668 669

    // Trying to get IPv4 pool from Subnet6 is not allowed
670
    EXPECT_THROW(subnet->getAnyPool(Lease::TYPE_V4), BadValue);
671 672

    // Let's add a single IA pool and check that it can be retrieved
Tomek Mrugalski's avatar
Tomek Mrugalski committed
673
    EXPECT_NO_THROW(subnet->addPool(pool1));
674 675

    // If there's only one IA pool, get that pool
676 677
    EXPECT_EQ(pool1, subnet->getAnyPool(Lease::TYPE_NA));
    EXPECT_EQ(pool1, subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8:1:1::1")));
678 679

    // Check if pools of different type are not returned
680 681
    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Lease::TYPE_TA));
    EXPECT_EQ(PoolPtr(), subnet->getAnyPool(Lease::TYPE_PD));
682 683

    // We ask with good hints, but wrong types, should return nothing
684 685
    EXPECT_EQ(PoolPtr(), subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8:1:2::1")));
    EXPECT_EQ(PoolPtr(), subnet->getPool(Lease::TYPE_TA, IOAddress("2001:db8:1:3::1")));
686 687

    // Let's add TA and PD pools
Tomek Mrugalski's avatar
Tomek Mrugalski committed
688 689
    EXPECT_NO_THROW(subnet->addPool(pool2));
    EXPECT_NO_THROW(subnet->addPool(pool3));
690 691

    // Try without hints
692 693 694
    EXPECT_EQ(pool1, subnet->getAnyPool(Lease::TYPE_NA));
    EXPECT_EQ(pool2, subnet->getAnyPool(Lease::TYPE_TA));
    EXPECT_EQ(pool3, subnet->getAnyPool(Lease::TYPE_PD));
695 696

    // Try with valid hints
697 698 699
    EXPECT_EQ(pool1, subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8:1:1::1")));
    EXPECT_EQ(pool2, subnet->getPool(Lease::TYPE_TA, IOAddress("2001:db8:1:2::1")));
    EXPECT_EQ(pool3, subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8:1:3::1")));
700

Andrei Pavel's avatar
Andrei Pavel committed
701
    // Try with bogus hints (hints should be ignored)
702 703 704
    EXPECT_EQ(pool1, subnet->getPool(Lease::TYPE_NA, IOAddress("2001:db8:1:7::1")));
    EXPECT_EQ(pool2, subnet->getPool(Lease::TYPE_TA, IOAddress("2001:db8:1:7::1")));
    EXPECT_EQ(pool3, subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8:1:7::1")));
705 706

    // Let's add a second PD pool
Tomek Mrugalski's avatar
Tomek Mrugalski committed
707
    EXPECT_NO_THROW(subnet->addPool(pool4));
708 709

    // Without hints, it should return the first pool
710
    EXPECT_EQ(pool3, subnet->getAnyPool(Lease::TYPE_PD));
711 712

    // With valid hint, it should return that hint
713
    EXPECT_EQ(pool3, subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8:1:3::1")));
714
    EXPECT_EQ(pool4, subnet->getPool(Lease::TYPE_PD, IOAddress("3000:1::")));
715 716

    // With invalid hint, it should return the first pool
717
    EXPECT_EQ(pool3, subnet->getPool(Lease::TYPE_PD, IOAddress("2001:db8::123")));
718 719 720 721 722

    // Adding Pool4 to Subnet6 is a big no, no!
    EXPECT_THROW(subnet->addPool(pool5), BadValue);
}

723
// Tests whether Subnet6 object is able to store and process properly
724
// information about allowed client class (a single class).
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
TEST(Subnet6Test, clientClasses) {
    // Create the V6 subnet.
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // This client does not belong to any class.
    isc::dhcp::ClientClasses no_class;

    // This client belongs to foo only.
    isc::dhcp::ClientClasses foo_class;
    foo_class.insert("foo");

    // This client belongs to bar only. I like that client.
    isc::dhcp::ClientClasses bar_class;
    bar_class.insert("bar");

    // This client belongs to foo, bar and baz classes.
    isc::dhcp::ClientClasses three_classes;
    three_classes.insert("foo");
    three_classes.insert("bar");
    three_classes.insert("baz");

    // No class restrictions defined, any client should be supported
747
    EXPECT_EQ(0, subnet->getClientClasses().size());
748 749 750 751 752
    EXPECT_TRUE(subnet->clientSupported(no_class));
    EXPECT_TRUE(subnet->clientSupported(foo_class));
    EXPECT_TRUE(subnet->clientSupported(bar_class));
    EXPECT_TRUE(subnet->clientSupported(three_classes));

Andrei Pavel's avatar
Andrei Pavel committed
753
    // Let's allow only clients belonging to "bar" class.
754
    subnet->allowClientClass("bar");
755
    EXPECT_EQ(1, subnet->getClientClasses().size());
756 757 758 759 760 761 762

    EXPECT_FALSE(subnet->clientSupported(no_class));
    EXPECT_FALSE(subnet->clientSupported(foo_class));
    EXPECT_TRUE(subnet->clientSupported(bar_class));
    EXPECT_TRUE(subnet->clientSupported(three_classes));
}

763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
// Tests whether Subnet6 object is able to store and process properly
// information about allowed client class (multiple classes allowed).
TEST(Subnet6Test, clientClassesMultiple) {
    // Create the V6 subnet.
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // This client does not belong to any class.
    isc::dhcp::ClientClasses no_class;

    // This client belongs to foo only.
    isc::dhcp::ClientClasses foo_class;
    foo_class.insert("foo");

    // This client belongs to bar only. I like that client.
    isc::dhcp::ClientClasses bar_class;
    bar_class.insert("bar");

    // No class restrictions defined, any client should be supported
781
    EXPECT_EQ(0, subnet->getClientClasses().size());
782 783 784 785
    EXPECT_TRUE(subnet->clientSupported(no_class));
    EXPECT_TRUE(subnet->clientSupported(foo_class));
    EXPECT_TRUE(subnet->clientSupported(bar_class));

Andrei Pavel's avatar
Andrei Pavel committed
786
    // Let's allow only clients belonging to "foo" or "bar" class.
787 788
    subnet->allowClientClass("foo");
    subnet->allowClientClass("bar");
789
    EXPECT_EQ(2, subnet->getClientClasses().size());
790 791 792 793 794 795 796 797 798 799 800

    // Class-less clients are to be rejected.
    EXPECT_FALSE(subnet->clientSupported(no_class));

    // Clients in foo class should be accepted.
    EXPECT_TRUE(subnet->clientSupported(foo_class));

    // Clients in bar class should be accepted as well.
    EXPECT_TRUE(subnet->clientSupported(bar_class));
}

801 802
// Checks that it is not allowed to add invalid pools.
TEST(Subnet6Test, pool6Checks) {
803 804 805 806

    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // this one is in subnet
807
    Pool6Ptr pool1(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
808
    ASSERT_NO_THROW(subnet->addPool(pool1));
809 810

    // this one is larger than the subnet!
811
    Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8::"), 48));
812

813
    ASSERT_THROW(subnet->addPool(pool2), BadValue);
814 815

    // this one is totally out of blue
816
    Pool6Ptr pool3(new Pool6(Lease::TYPE_NA, IOAddress("3000::"), 16));
817
    ASSERT_THROW(subnet->addPool(pool3), BadValue);
818

819
    Pool6Ptr pool4(new Pool6(Lease::TYPE_NA, IOAddress("4001:db8:1::"), 80));
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
    ASSERT_THROW(subnet->addPool(pool4), BadValue);

    // This pool should be added just fine.
    Pool6Ptr pool5(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::100"),
                             IOAddress("2001:db8:1:2::200")));
    ASSERT_NO_THROW(subnet->addPool(pool5));

    // This pool overlaps with a previously added pool.
    Pool6Ptr pool6(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::1"),
                             IOAddress("2001:db8:1:2::150")));
    ASSERT_THROW(subnet->addPool(pool6), BadValue);

    // This pool also overlaps
    Pool6Ptr pool7(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::150"),
                             IOAddress("2001:db8:1:2::300")));
    ASSERT_THROW(subnet->addPool(pool7), BadValue);

    // This one "surrounds" the other pool.
    Pool6Ptr pool8(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::50"),
                             IOAddress("2001:db8:1:2::250")));
    ASSERT_THROW(subnet->addPool(pool8), BadValue);

    // This one does not overlap.
    Pool6Ptr pool9(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::300"),
                             IOAddress("2001:db8:1:2::400")));
    ASSERT_NO_THROW(subnet->addPool(pool9));

    // This one has a lower bound in the pool of 2001:db8:1::100-200.
    Pool6Ptr pool10(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::200"),
                              IOAddress("2001:db8:1:2::225")));
    ASSERT_THROW(subnet->addPool(pool10), BadValue);

    // This one has an upper bound in the pool of 2001:db8:1::300-400.
    Pool6Ptr pool11(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:2::250"),
                              IOAddress("2001:db8:1:2::300")));
    ASSERT_THROW(subnet->addPool(pool11), BadValue);

    // Add a pool with a single address.
    Pool6Ptr pool12(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:3::250"),
                              IOAddress("2001:db8:1:3::250")));
    ASSERT_NO_THROW(subnet->addPool(pool12));

    // Now we're going to add the same pool again. This is an interesting
    // case because we're checking if the code is properly using upper_bound
    // function, which returns a pool that has an address greater than the
    // specified one.
    ASSERT_THROW(subnet->addPool(pool12), BadValue);

    // Prefix pool overlaps with the pool1. We can't hand out addresses and
    // prefixes from the same range.
    Pool6Ptr pool13(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8:1:1:2::"),
                              80, 96));
    ASSERT_THROW(subnet->addPool(pool13), BadValue);
873
}
874

875 876 877 878 879 880 881
TEST(Subnet6Test, addOptions) {
    // Create as subnet to add options to it.
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // Differentiate options by their codes (100-109)
    for (uint16_t code = 100; code < 110; ++code) {
        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
882
        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, DHCP6_OPTION_SPACE));
883 884 885 886 887 888
    }

    // Add 7 options to another option space. The option codes partially overlap
    // with option codes that we have added to dhcp6 option space.
    for (uint16_t code = 105; code < 112; ++code) {
        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
889
        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, "isc"));
890 891 892
    }

    // Get options from the Subnet and check if all 10 are there.
893
    OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE);
894 895
    ASSERT_TRUE(options);
    ASSERT_EQ(10, options->size());
896

897
    // Validate codes of options added to dhcp6 option space.
898
    uint16_t expected_code = 100;
899
    for (OptionContainer::const_iterator option_desc = options->begin();
900
         option_desc != options->end(); ++option_desc) {
901 902
        ASSERT_TRUE(option_desc->option_);
        EXPECT_EQ(expected_code, option_desc->option_->getType());
903 904 905
        ++expected_code;
    }

906
    options = subnet->getCfgOption()->getAll("isc");
907 908
    ASSERT_TRUE(options);
    ASSERT_EQ(7, options->size());
909 910 911

    // Validate codes of options added to isc option space.
    expected_code = 105;
912
    for (OptionContainer::const_iterator option_desc = options->begin();
913
         option_desc != options->end(); ++option_desc) {
914 915
        ASSERT_TRUE(option_desc->option_);
        EXPECT_EQ(expected_code, option_desc->option_->getType());
916 917 918 919
        ++expected_code;
    }

    // Try to get options from a non-existing option space.
920
    options = subnet->getCfgOption()->getAll("abcd");
921 922
    ASSERT_TRUE(options);
    EXPECT_TRUE(options->empty());
923 924 925 926 927 928 929 930 931 932 933
}

TEST(Subnet6Test, addNonUniqueOptions) {
    // Create as subnet to add options to it.
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // Create a set of options with non-unique codes.
    for (int i = 0;  i < 2; ++i) {
        // In the inner loop we create options with unique codes (100-109).
        for (uint16_t code = 100; code < 110; ++code) {
            OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
934
            ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, DHCP6_OPTION_SPACE));
935 936 937 938
        }
    }

    // Sanity check that all options are there.
939
    OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE);
940
    ASSERT_EQ(20, options->size());
941 942

    // Use container index #1 to get the options by their codes.
943
    OptionContainerTypeIndex& idx = options->get<1>();
944 945
    // Look for the codes 100-109.
    for (uint16_t code = 100; code < 110; ++ code) {
946
        // For each code we should get two instances of options->
947
        OptionContainerTypeRange range = idx.equal_range(code);
948
        // Distance between iterators indicates how many options
Andrei Pavel's avatar
Andrei Pavel committed
949
        // have been returned for the particular code.
950 951
        ASSERT_EQ(2, distance(range.first, range.second));
        // Check that returned options actually have the expected option code.
952
        for (OptionContainerTypeIndex::const_iterator option_desc = range.first;
953
             option_desc != range.second; ++option_desc) {
954 955
            ASSERT_TRUE(option_desc->option_);
            EXPECT_EQ(code, option_desc->option_->getType());
956 957 958 959 960
        }
    }

    // Let's try to find some non-exiting option.
    const uint16_t non_existing_code = 150;
961
    OptionContainerTypeRange range = idx.equal_range(non_existing_code);
962 963 964 965 966 967 968 969 970 971 972
    // Empty set is expected.
    EXPECT_EQ(0, distance(range.first, range.second));
}

TEST(Subnet6Test, addPersistentOption) {
    // Create as subnet to add options to it.
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // Add 10 options to the subnet with option codes 100 - 109.
    for (uint16_t code = 100; code < 110; ++code) {
        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
973 974 975 976 977
        // We create 10 options and want some of them to be flagged
        // persistent and some non-persistent. Persistent options are
        // those that server sends to clients regardless if they ask
        // for them or not. We pick 3 out of 10 options and mark them
        // non-persistent and 7 other options persistent.
978
        // Code values: 102, 105 and 108 are divisible by 3
979 980 981
        // and options with these codes will be flagged non-persistent.
        // Options with other codes will be flagged persistent.
        bool persistent = (code % 3) ? true : false;
982
        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, persistent, DHCP6_OPTION_SPACE));
983 984 985
    }

    // Get added options from the subnet.
986
    OptionContainerPtr options = subnet->getCfgOption()->getAll(DHCP6_OPTION_SPACE);
987

988
    // options->get<2> returns reference to container index #2. This
989
    // index is used to access options by the 'persistent' flag.
990
    OptionContainerPersistIndex& idx = options->get<2>();
991

992
    // Get all persistent options->
993 994
    OptionContainerPersistRange range_persistent = idx.equal_range(true);
    // 7 out of 10 options have been flagged persistent.
995
    ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
996

997
    // Get all non-persistent options->
998 999
    OptionContainerPersistRange range_non_persistent = idx.equal_range(false);
    // 3 out of 10 options have been flagged not persistent.
1000
    ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
1001
}
1002

1003
TEST(Subnet6Test, getOptions) {
1004 1005 1006 1007 1008
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 56, 1, 2, 3, 4));

    // Add 10 options to a "dhcp6" option space in the subnet.
    for (uint16_t code = 100; code < 110; ++code) {
        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
1009
        ASSERT_NO_THROW(subnet->getCfgOption()->add(option, false, DHCP6_OPTION_SPACE));
1010 1011 1012 1013 1014 1015 1016
    }

    // Check that we can get each added option descriptor using
    // individually.
    for (uint16_t code = 100; code < 110; ++code) {
        std::ostringstream stream;
        // First, try the invalid option space name.
1017
        OptionDescriptor desc = subnet->getCfgOption()->get("isc", code);
1018
        // Returned descriptor should contain NULL option ptr.
1019
        EXPECT_FALSE(desc.option_);
1020
        // Now, try the valid option space.
1021
        desc = subnet->getCfgOption()->get(DHCP6_OPTION_SPACE, code);
1022
        // Test that the option code matches the expected code.
1023 1024
        ASSERT_TRUE(desc.option_);
        EXPECT_EQ(code, desc.option_->getType());
1025 1026 1027
    }
}

1028

1029
TEST(Subnet6Test, addVendorOption) {
1030 1031 1032 1033 1034 1035 1036

    // Create as subnet to add options to it.
    Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));

    // Differentiate options by their codes (100-109)
    for (uint16_t code = 100; code < 110; ++code) {
        OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));