dhcp4_test_utils.cc 21.9 KB
Newer Older
1
// Copyright (C) 2013-2014  Internet Systems Consortium, Inc. ("ISC")
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#include <config.h>

#include <asiolink/io_address.h>
18
#include <cc/data.h>
19
#include <config/command_interpreter.h>
20
#include <dhcp4/json_config_parser.h>
21 22
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcp/option4_addrlst.h>
23
#include <dhcp/option_int.h>
24 25 26
#include <dhcp/option_int_array.h>
#include <dhcp/option_custom.h>
#include <dhcp/iface_mgr.h>
27
#include <dhcp/tests/iface_mgr_test_config.h>
28
#include <dhcpsrv/cfgmgr.h>
29
#include <dhcpsrv/lease.h>
30 31 32 33 34
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>

using namespace std;
using namespace isc::asiolink;
35
using namespace isc::data;
36 37 38 39 40 41

namespace isc {
namespace dhcp {
namespace test {

Dhcpv4SrvTest::Dhcpv4SrvTest()
42
:rcode_(-1), srv_(0) {
43 44 45 46 47 48 49 50
    subnet_ = Subnet4Ptr(new Subnet4(IOAddress("192.0.2.0"), 24, 1000,
                                     2000, 3000));
    pool_ = Pool4Ptr(new Pool4(IOAddress("192.0.2.100"), IOAddress("192.0.2.110")));
    subnet_->addPool(pool_);

    // Add Router option.
    Option4AddrLstPtr opt_routers(new Option4AddrLst(DHO_ROUTERS));
    opt_routers->setAddress(IOAddress("192.0.2.2"));
51
    subnet_->getCfgOption()->add(opt_routers, false, "dhcp4");
52 53 54 55

    CfgMgr::instance().clear();
    CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->add(subnet_);
    CfgMgr::instance().commit();
56 57
}

58 59 60
Dhcpv4SrvTest::~Dhcpv4SrvTest() {

    // Make sure that we revert to default value
61
    CfgMgr::instance().clear();
62 63 64
    CfgMgr::instance().echoClientId(true);
}

65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
void Dhcpv4SrvTest::addPrlOption(Pkt4Ptr& pkt) {

    OptionUint8ArrayPtr option_prl =
        OptionUint8ArrayPtr(new OptionUint8Array(Option::V4,
                                                 DHO_DHCP_PARAMETER_REQUEST_LIST));

    // Let's request options that have been configured for the subnet.
    option_prl->addValue(DHO_DOMAIN_NAME_SERVERS);
    option_prl->addValue(DHO_DOMAIN_NAME);
    option_prl->addValue(DHO_LOG_SERVERS);
    option_prl->addValue(DHO_COOKIE_SERVERS);
    // Let's also request the option that hasn't been configured. In such
    // case server should ignore request for this particular option.
    option_prl->addValue(DHO_LPR_SERVERS);
    // And add 'Parameter Request List' option into the DISCOVER packet.
    pkt->addOption(option_prl);
}

void Dhcpv4SrvTest::configureRequestedOptions() {
    // dns-servers
    Option4AddrLstPtr
        option_dns_servers(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS));
    option_dns_servers->addAddress(IOAddress("192.0.2.1"));
    option_dns_servers->addAddress(IOAddress("192.0.2.100"));
89
    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_dns_servers, false, "dhcp4"));
90 91 92 93 94

    // domain-name
    OptionDefinition def("domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE);
    OptionCustomPtr option_domain_name(new OptionCustom(def, Option::V4));
    option_domain_name->writeFqdn("example.com");
95
    subnet_->getCfgOption()->add(option_domain_name, false, "dhcp4");
96 97 98 99 100

    // log-servers
    Option4AddrLstPtr option_log_servers(new Option4AddrLst(DHO_LOG_SERVERS));
    option_log_servers->addAddress(IOAddress("192.0.2.2"));
    option_log_servers->addAddress(IOAddress("192.0.2.10"));
101
    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_log_servers, false, "dhcp4"));
102 103 104 105

    // cookie-servers
    Option4AddrLstPtr option_cookie_servers(new Option4AddrLst(DHO_COOKIE_SERVERS));
    option_cookie_servers->addAddress(IOAddress("192.0.2.1"));
106
    ASSERT_NO_THROW(subnet_->getCfgOption()->add(option_cookie_servers, false, "dhcp4"));
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
}

void Dhcpv4SrvTest::messageCheck(const Pkt4Ptr& q, const Pkt4Ptr& a) {
    ASSERT_TRUE(q);
    ASSERT_TRUE(a);

    EXPECT_EQ(q->getHops(),   a->getHops());
    EXPECT_EQ(q->getIface(),  a->getIface());
    EXPECT_EQ(q->getIndex(),  a->getIndex());
    EXPECT_EQ(q->getGiaddr(), a->getGiaddr());
    // When processing an incoming packet the remote address
    // is copied as a src address, and the source address is
    // copied as a remote address to the response.
    EXPECT_TRUE(q->getLocalHWAddr() == a->getLocalHWAddr());
    EXPECT_TRUE(q->getRemoteHWAddr() == a->getRemoteHWAddr());

123 124
    // Check that the server identifier is present in the response.
    // Presence (or absence) of other options is checked elsewhere.
125 126 127
    EXPECT_TRUE(a->getOption(DHO_DHCP_SERVER_IDENTIFIER));

    // Check that something is offered
128
    EXPECT_NE("0.0.0.0", a->getYiaddr().toText());
129 130
}

131 132 133 134 135
::testing::AssertionResult
Dhcpv4SrvTest::basicOptionsPresent(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option missing in the response";
    if (!pkt->getOption(DHO_DOMAIN_NAME)) {
136 137
        return (::testing::AssertionFailure(::testing::Message()
                                            << "domain-name " << errmsg));
138 139

    } else if (!pkt->getOption(DHO_DOMAIN_NAME_SERVERS)) {
140 141
        return (::testing::AssertionFailure(::testing::Message()
                                            << "dns-servers " << errmsg));
142 143

    } else if (!pkt->getOption(DHO_SUBNET_MASK)) {
144 145
        return (::testing::AssertionFailure(::testing::Message()
                                            << "subnet-mask " << errmsg));
146 147

    } else if (!pkt->getOption(DHO_ROUTERS)) {
148 149
        return (::testing::AssertionFailure(::testing::Message() << "routers "
                                            << errmsg));
150 151

    } else if (!pkt->getOption(DHO_DHCP_LEASE_TIME)) {
152 153
        return (::testing::AssertionFailure(::testing::Message() <<
                                            "dhcp-lease-time " << errmsg));
154 155 156 157

    }
    return (::testing::AssertionSuccess());

158 159
}

160 161 162 163 164
::testing::AssertionResult
Dhcpv4SrvTest::noBasicOptions(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option present in the response";
    if (pkt->getOption(DHO_DOMAIN_NAME)) {
165 166
        return (::testing::AssertionFailure(::testing::Message()
                                            << "domain-name " << errmsg));
167 168

    } else if (pkt->getOption(DHO_DOMAIN_NAME_SERVERS)) {
169 170
        return (::testing::AssertionFailure(::testing::Message()
                                            << "dns-servers " << errmsg));
171 172

    } else if (pkt->getOption(DHO_SUBNET_MASK)) {
173 174
        return (::testing::AssertionFailure(::testing::Message()
                                            << "subnet-mask " << errmsg));
175 176

    } else if (pkt->getOption(DHO_ROUTERS)) {
177 178
        return (::testing::AssertionFailure(::testing::Message() << "routers "
                                            << errmsg));
179 180

    } else if (pkt->getOption(DHO_DHCP_LEASE_TIME)) {
181 182
        return (::testing::AssertionFailure(::testing::Message()
                                            << "dhcp-lease-time " << errmsg));
183 184 185 186 187 188 189 190 191 192

    }
    return (::testing::AssertionSuccess());
}

::testing::AssertionResult
Dhcpv4SrvTest::requestedOptionsPresent(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option missing in the response";
    if (!pkt->getOption(DHO_LOG_SERVERS)) {
193 194
        return (::testing::AssertionFailure(::testing::Message()
                                            << "log-servers " << errmsg));
195 196

    } else if (!pkt->getOption(DHO_COOKIE_SERVERS)) {
197 198
        return (::testing::AssertionFailure(::testing::Message()
                                            << "cookie-servers " << errmsg));
199 200 201 202 203 204 205 206 207 208

    }
    return (::testing::AssertionSuccess());
}

::testing::AssertionResult
Dhcpv4SrvTest::noRequestedOptions(const Pkt4Ptr& pkt) {
    std::ostringstream errmsg;
    errmsg << "option present in the response";
    if (pkt->getOption(DHO_LOG_SERVERS)) {
209 210
        return (::testing::AssertionFailure(::testing::Message()
                                            << "log-servers " << errmsg));
211 212

    } else if (pkt->getOption(DHO_COOKIE_SERVERS)) {
213 214
        return (::testing::AssertionFailure(::testing::Message()
                                            << "cookie-servers " << errmsg));
215 216 217

    }
    return (::testing::AssertionSuccess());
218 219
}

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
OptionPtr Dhcpv4SrvTest::generateClientId(size_t size /*= 4*/) {

    OptionBuffer clnt_id(size);
    for (int i = 0; i < size; i++) {
        clnt_id[i] = 100 + i;
    }

    client_id_ = ClientIdPtr(new ClientId(clnt_id));

    return (OptionPtr(new Option(Option::V4, DHO_DHCP_CLIENT_IDENTIFIER,
                                 clnt_id.begin(),
                                 clnt_id.begin() + size)));
}

HWAddrPtr Dhcpv4SrvTest::generateHWAddr(size_t size /*= 6*/) {
    const uint8_t hw_type = 123; // Just a fake number (typically 6=HTYPE_ETHER, see dhcp4.h)
    OptionBuffer mac(size);
    for (int i = 0; i < size; ++i) {
        mac[i] = 50 + i;
    }
    return (HWAddrPtr(new HWAddr(mac, hw_type)));
}

243 244 245
void Dhcpv4SrvTest::checkAddressParams(const Pkt4Ptr& rsp,
                                       const SubnetPtr subnet,
                                       bool t1_present,
246
                                       bool t2_present) {
247 248 249 250 251 252 253

    // Technically inPool implies inRange, but let's be on the safe
    // side and check both.
    EXPECT_TRUE(subnet->inRange(rsp->getYiaddr()));
    EXPECT_TRUE(subnet->inPool(Lease::TYPE_V4, rsp->getYiaddr()));

    // Check lease time
254 255
    OptionUint32Ptr opt = boost::dynamic_pointer_cast<
        OptionUint32>(rsp->getOption(DHO_DHCP_LEASE_TIME));
256
    if (!opt) {
257 258
        ADD_FAILURE() << "Lease time option missing in response or the"
            " option has unexpected type";
259
    } else {
260
        EXPECT_EQ(opt->getValue(), subnet->getValid());
261 262 263
    }

    // Check T1 timer
264 265 266
    opt = boost::dynamic_pointer_cast<
        OptionUint32>(rsp->getOption(DHO_DHCP_RENEWAL_TIME));
    if (t1_present) {
267 268
        ASSERT_TRUE(opt) << "Required T1 option missing or it has"
            " an unexpected type";
269
        EXPECT_EQ(opt->getValue(), subnet->getT1());
270
    } else {
271
        EXPECT_FALSE(opt);
272 273 274
    }

    // Check T2 timer
275 276 277
    opt = boost::dynamic_pointer_cast<
        OptionUint32>(rsp->getOption(DHO_DHCP_REBINDING_TIME));
    if (t2_present) {
278 279
        ASSERT_TRUE(opt) << "Required T2 option missing or it has"
            " an unexpected type";
280
        EXPECT_EQ(opt->getValue(), subnet->getT2());
281
    } else {
282
        EXPECT_FALSE(opt);
283 284 285
    }
}

286
void Dhcpv4SrvTest::checkResponse(const Pkt4Ptr& rsp, int expected_message_type,
287 288
                                  uint32_t expected_transid) {
    ASSERT_TRUE(rsp);
289 290
    EXPECT_EQ(expected_message_type,
              static_cast<int>(rsp->getType()));
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
    EXPECT_EQ(expected_transid, rsp->getTransid());
}

Lease4Ptr Dhcpv4SrvTest::checkLease(const Pkt4Ptr& rsp,
                                    const OptionPtr& client_id,
                                    const HWAddrPtr&,
                                    const IOAddress& expected_addr) {

    ClientIdPtr id;
    if (client_id) {
        OptionBuffer data = client_id->getData();
        id.reset(new ClientId(data));
    }

    Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(expected_addr);
    if (!lease) {
307
        cout << "Lease for " << expected_addr
308 309 310 311
             << " not found in the database backend.";
        return (Lease4Ptr());
    }

312
    EXPECT_EQ(rsp->getYiaddr(), expected_addr);
313

314
    EXPECT_EQ(expected_addr, lease->addr_);
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
    if (client_id) {
        EXPECT_TRUE(*lease->client_id_ == *id);
    }
    EXPECT_EQ(subnet_->getID(), lease->subnet_id_);

    return (lease);
}

void Dhcpv4SrvTest::checkServerId(const Pkt4Ptr& rsp, const OptionPtr& expected_srvid) {
    // Check that server included its server-id
    OptionPtr opt = rsp->getOption(DHO_DHCP_SERVER_IDENTIFIER);
    ASSERT_TRUE(opt);
    EXPECT_EQ(opt->getType(), expected_srvid->getType() );
    EXPECT_EQ(opt->len(), expected_srvid->len() );
    EXPECT_TRUE(opt->getData() == expected_srvid->getData());
}

void Dhcpv4SrvTest::checkClientId(const Pkt4Ptr& rsp, const OptionPtr& expected_clientid) {
333 334 335

    bool include_clientid = CfgMgr::instance().echoClientId();

336 337
    // check that server included our own client-id
    OptionPtr opt = rsp->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
338 339 340 341 342 343 344 345 346 347
    if (include_clientid) {
        // Normal mode: echo back (see RFC6842)
        ASSERT_TRUE(opt);
        EXPECT_EQ(expected_clientid->getType(), opt->getType());
        EXPECT_EQ(expected_clientid->len(), opt->len());
        EXPECT_TRUE(expected_clientid->getData() == opt->getData());
    } else {
        // Backward compatibility mode for pre-RFC6842 devices
        ASSERT_FALSE(opt);
    }
348 349
}

350 351 352 353 354 355 356 357 358
::testing::AssertionResult
Dhcpv4SrvTest::createPacketFromBuffer(const Pkt4Ptr& src_pkt,
                                      Pkt4Ptr& dst_pkt) {
    // Create on-wire format of the packet. If pack() has been called
    // on this instance of the packet already, the next call to pack()
    // should remove all contents of the output buffer.
    try {
        src_pkt->pack();
    } catch (const Exception& ex) {
359 360 361
        return (::testing::AssertionFailure(::testing::Message()
                                            << "Failed to parse source packet: "
                                            << ex.what()));
362 363 364 365 366 367 368 369 370
    }
    // Get the output buffer from the source packet.
    const util::OutputBuffer& buf = src_pkt->getBuffer();
    // Create a copy of the packet using the output buffer from the source
    // packet.
    try {
        dst_pkt.reset(new Pkt4(static_cast<const uint8_t*>(buf.getData()),
                               buf.getLength()));
    } catch (const Exception& ex) {
371 372 373 374 375
        return (::testing::AssertionFailure(::testing::Message()
                                            << "Failed to create a"
                                            " destination packet from"
                                            " the buffer: "
                                            << ex.what()));
376 377 378 379 380 381
    }

    try {
        // Parse the new packet and return to the caller.
        dst_pkt->unpack();
    } catch (const Exception& ex) {
382 383 384 385
        return (::testing::AssertionFailure(::testing::Message()
                                            << "Failed to parse a"
                                            << " destination packet: "
                                            << ex.what()));
386 387 388 389 390
    }

    return (::testing::AssertionSuccess());
}

391 392 393
void
// cppcheck-suppress unusedFunction
Dhcpv4SrvTest::TearDown() {
394

395
    CfgMgr::instance().clear();
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420

    // Close all open sockets.
    IfaceMgr::instance().closeSockets();

    // Some unit tests override the default packet filtering class, used
    // by the IfaceMgr. The dummy class, called PktFilterTest, reports the
    // capability to directly respond to the clients without IP address
    // assigned. This capability is not supported by the default packet
    // filtering class: PktFilterInet. Therefore setting the dummy class
    // allows to test scenarios, when server responds to the broadcast address
    // on client's request, despite having support for direct response.
    // The following call restores the use of original packet filtering class
    // after the test.
    try {
        IfaceMgr::instance().setPacketFilter(PktFilterPtr(new PktFilterInet()));

    } catch (const Exception& ex) {
        FAIL() << "Failed to restore the default (PktFilterInet) packet filtering"
               << " class after the test. Exception has been caught: "
               << ex.what();
    }

}

void
421 422 423
Dhcpv4SrvTest::testDiscoverRequest(const uint8_t msg_type) {
    IfaceMgrTestConfig test_config(true);
    IfaceMgr::instance().openSockets4();
424

425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
    // Create an instance of the tested class.
    boost::scoped_ptr<NakedDhcpv4Srv> srv(new NakedDhcpv4Srv(0));

    // Initialize the source HW address.
    vector<uint8_t> mac(6);
    for (int i = 0; i < 6; ++i) {
        mac[i] = i * 10;
    }
    // Initialized the destination HW address.
    vector<uint8_t> dst_mac(6);
    for (int i = 0; i < 6; ++i) {
        dst_mac[i] = i * 20;
    }
    // Create a DHCP message. It will be used to simulate the
    // incoming message.
    boost::shared_ptr<Pkt4> req(new Pkt4(msg_type, 1234));
Francis Dupont's avatar
Francis Dupont committed
441
    // Create a response message. It will hold a response packet.
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
    // Initially, set it to NULL.
    boost::shared_ptr<Pkt4> rsp;
    // Set the name of the interface on which packet is received.
    req->setIface("eth0");
    // Set the interface index. It is just a dummy value and will
    // not be interpreted.
    req->setIndex(17);
    // Set the target HW address. This value is normally used to
    // construct the data link layer header.
    req->setRemoteHWAddr(1, 6, dst_mac);
    // Set the HW address. This value is set on DHCP level (in chaddr).
    req->setHWAddr(1, 6, mac);
    // Set local HW address. It is used to construct the data link layer
    // header.
    req->setLocalHWAddr(1, 6, mac);
    // Set target IP address.
    req->setRemoteAddr(IOAddress("192.0.2.55"));
459
    // Set relay address and hops.
460
    req->setGiaddr(IOAddress("192.0.2.10"));
461
    req->setHops(1);
462 463 464 465 466 467 468

    // We are going to test that certain options are returned
    // in the response message when requested using 'Parameter
    // Request List' option. Let's configure those options that
    // are returned when requested.
    configureRequestedOptions();

469 470 471 472 473
    // Create a copy of the original packet by parsing its wire format.
    // This simulates the real life scenario when we process the packet
    // which was parsed from its wire format.
    Pkt4Ptr received;
    ASSERT_TRUE(createPacketFromBuffer(req, received));
474 475
    // Set interface. It is required for the server to generate server id.
    received->setIface("eth0");
476 477
    if (msg_type == DHCPDISCOVER) {
        ASSERT_NO_THROW(
478
            rsp = srv->processDiscover(received);
479
        );
480 481 482 483 484 485

        // Should return OFFER
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPOFFER, rsp->getType());

    } else {
486
        ASSERT_NO_THROW(rsp = srv->processRequest(received));
487 488 489 490 491 492 493

        // Should return ACK
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPACK, rsp->getType());

    }

494
    messageCheck(received, rsp);
495

496 497
    // Basic options should be present when we got the lease.
    EXPECT_TRUE(basicOptionsPresent(rsp));
498 499
    // We did not request any options so these should not be present
    // in the RSP.
500
    EXPECT_TRUE(noRequestedOptions(rsp));
501 502 503 504 505

    // Repeat the test but request some options.
    // Add 'Parameter Request List' option.
    addPrlOption(req);

506 507 508
    ASSERT_TRUE(createPacketFromBuffer(req, received));
    ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));

509 510 511
    // Set interface. It is required for the server to generate server id.
    received->setIface("eth0");

512
    if (msg_type == DHCPDISCOVER) {
513
        ASSERT_NO_THROW(rsp = srv->processDiscover(received));
514 515 516 517 518 519

        // Should return non-NULL packet.
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPOFFER, rsp->getType());

    } else {
520
        ASSERT_NO_THROW(rsp = srv->processRequest(received));
521 522 523 524 525 526 527

        // Should return non-NULL packet.
        ASSERT_TRUE(rsp);
        EXPECT_EQ(DHCPACK, rsp->getType());
    }

    // Check that the requested options are returned.
528 529
    EXPECT_TRUE(basicOptionsPresent(rsp));
    EXPECT_TRUE(requestedOptionsPresent(rsp));
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544

    // The following part of the test will test that the NAK is sent when
    // there is no address pool configured. In the same time, we expect
    // that the requested options are not included in NAK message, but that
    // they are only included when yiaddr is set to non-zero value.
    ASSERT_NO_THROW(subnet_->delPools(Lease::TYPE_V4));

    // There has been a lease allocated for the particular client. So,
    // even though we deleted the subnet, the client would get the
    // existing lease (not a NAK). Therefore, we have to change the chaddr
    // in the packet so as the existing lease is not returned.
    req->setHWAddr(1, 6, std::vector<uint8_t>(2, 6));
    ASSERT_TRUE(createPacketFromBuffer(req, received));
    ASSERT_TRUE(received->getOption(DHO_DHCP_PARAMETER_REQUEST_LIST));

545 546 547
    // Set interface. It is required for the server to generate server id.
    received->setIface("eth0");

548 549
    if (msg_type == DHCPDISCOVER) {
        ASSERT_NO_THROW(rsp = srv->processDiscover(received));
550 551 552
        // Should return NULL packet.
        ASSERT_FALSE(rsp);

553 554 555 556
    } else {
        ASSERT_NO_THROW(rsp = srv->processRequest(received));
        // Should return non-NULL packet.
        ASSERT_TRUE(rsp);
557 558 559 560 561 562 563 564 565
        // We should get the NAK packet with yiaddr set to 0.
        EXPECT_EQ(DHCPNAK, rsp->getType());
        ASSERT_EQ("0.0.0.0", rsp->getYiaddr().toText());

        // Make sure that none of the requested options is returned in NAK.
        // Also options such as Routers or Subnet Mask should not be there,
        // because lease hasn't been acquired.
        EXPECT_TRUE(noRequestedOptions(rsp));
        EXPECT_TRUE(noBasicOptions(rsp));
566
    }
567 568
}

569
void
570 571
Dhcpv4SrvTest::configure(const std::string& config, const bool commit) {
    configure(config, srv_, commit);
572 573 574
}

void
575 576
Dhcpv4SrvTest::configure(const std::string& config, NakedDhcpv4Srv& srv,
                         const bool commit) {
577 578 579 580
    ElementPtr json = Element::fromJSON(config);
    ConstElementPtr status;

    // Configure the server and make sure the config is accepted
581
    EXPECT_NO_THROW(status = configureDhcp4Server(srv, json));
582 583 584 585
    ASSERT_TRUE(status);
    int rcode;
    ConstElementPtr comment = config::parseAnswer(rcode, status);
    ASSERT_EQ(0, rcode);
586

587 588 589
    if (commit) {
        CfgMgr::instance().commit();
    }
590 591
 }

592
Dhcpv4Exchange
593
Dhcpv4SrvTest::createExchange(const Pkt4Ptr& query) {
594
    return (Dhcpv4Exchange(srv_.alloc_engine_, query, srv_.selectSubnet(query)));
595
}
596 597


598 599 600
}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace