dhcp6_test_utils.h 25.6 KB
Newer Older
1
// Copyright (C) 2013-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

/// @file   dhcp6_test_utils.h
///
/// @brief  This file contains utility classes used for DHCPv6 server testing

11 12 13
#ifndef DHCP6_TEST_UTILS_H
#define DHCP6_TEST_UTILS_H

14 15 16 17 18
#include <gtest/gtest.h>

#include <dhcp/pkt6.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
19
#include <dhcp/option6_iaprefix.h>
20
#include <dhcp/option6_status_code.h>
21
#include <dhcp/option_int_array.h>
22
#include <dhcp/option_custom.h>
23
#include <dhcp/option.h>
24 25 26 27 28
#include <dhcp/iface_mgr.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcp6/dhcp6_srv.h>
29
#include <dhcp6/parser_context.h>
30
#include <hooks/hooks_manager.h>
31 32 33 34

#include <list>

namespace isc {
35
namespace dhcp {
36 37
namespace test {

38 39 40
/// @brief Generic wrapper to provide strongly typed values.
///
/// In many cases, the test fixture class methods require providing many
41
/// parameters, of which some are optional. Some of the parameters may also
42 43 44 45 46 47
/// be implicitly converted to other types. Non-careful test implementer
/// may often "shift by one" or swap two values on the arguments list, which
/// will be accepted by the compiler but will result in troubles running the
/// function. Sometimes it takes non trivial amount of debugging to find out
/// why the particular function fails until we find that the arguments were
/// swapped or shifted. In addition, the use of classes wrapping simple types
48
/// results in better readability of the test code.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
///
/// @tparam ValueType Type of the wrapped value.
template<typename ValueType>
struct SpecializedTypeWrapper {

    /// @brief Constructor
    ///
    /// @param value Wrapped value
    explicit SpecializedTypeWrapper(const ValueType& value)
        : value_(value) { }

    /// @brief Operator returning a wrapped value.
    operator ValueType () const {
        return (value_);
    }

    /// @brief Wrapped value.
    ValueType value_;
};


/// @brief Class representing strongly typed IAID.
struct IAID : public SpecializedTypeWrapper<uint32_t> {
    /// @brief Constructor
    ///
    /// @param iaid IAID.
    explicit IAID(const uint32_t iaid)
76
        : SpecializedTypeWrapper<uint32_t>(iaid) { }
77 78 79 80 81 82 83 84 85 86 87 88 89
};

/// @brief Class representing strongly typed value for strict IAID checks.
///
/// Strict IAID checks are used to verify that  the particular address has been
/// assign to a specific IA. In many cases we don't check that because it may
/// not be possible to predict to which IA the specific lease will be assigned.
struct StrictIAIDChecking : public SpecializedTypeWrapper<bool> {
    /// @brief Constructor.
    ///
    /// @param strict_check Boolean value indicating if strict checking should
    /// be performed.
    explicit StrictIAIDChecking(const bool strict_check)
90
        : SpecializedTypeWrapper<bool>(strict_check) { }
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

    /// @brief Convenience function returning an object indicating that strict
    /// checks should be performed.
    static const StrictIAIDChecking YES() {
        static StrictIAIDChecking strict_check(true);
        return (strict_check);
    }

    /// @brief Convenience function returning an object indicating that strict
    /// checks should not be performed.
    static StrictIAIDChecking NO() {
        static StrictIAIDChecking strict_check(false);
        return (strict_check);
    }
};


108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/// @brief Base class for DHCPv6 server testing.
///
/// Currently it configures the test data path directory in
/// the @c CfgMgr. When the object is destroyed, the original
/// path is reverted.
class BaseServerTest : public ::testing::Test {
public:

    /// @brief Location of a test DUID file
    static const char* DUID_FILE;

    /// @brief Constructor.
    BaseServerTest();

    /// @brief Destructor.
    virtual ~BaseServerTest();

private:

    /// @brief Holds the original data directory.
    std::string original_datadir_;

};

132 133 134
/// @brief "naked" Dhcpv6Srv class that exposes internal members
class NakedDhcpv6Srv: public isc::dhcp::Dhcpv6Srv {
public:
135
    NakedDhcpv6Srv(uint16_t port) : isc::dhcp::Dhcpv6Srv(port) {
136
        // Open the "memfile" database for leases
137
        std::string memfile = "type=memfile universe=6 persist=false";
138
        isc::dhcp::LeaseMgrFactory::create(memfile);
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    }

    /// @brief fakes packet reception
    /// @param timeout ignored
    ///
    /// The method receives all packets queued in receive
    /// queue, one after another. Once the queue is empty,
    /// it initiates the shutdown procedure.
    ///
    /// See fake_received_ field for description
    virtual isc::dhcp::Pkt6Ptr receivePacket(int /*timeout*/) {

        // If there is anything prepared as fake incoming
        // traffic, use it
        if (!fake_received_.empty()) {
154
            isc::dhcp::Pkt6Ptr pkt = fake_received_.front();
155 156 157 158 159 160 161
            fake_received_.pop_front();
            return (pkt);
        }

        // If not, just trigger shutdown and
        // return immediately
        shutdown();
162
        return (isc::dhcp::Pkt6Ptr());
163 164 165 166 167 168 169
    }

    /// @brief fake packet sending
    ///
    /// Pretend to send a packet, but instead just store
    /// it in fake_send_ list where test can later inspect
    /// server's response.
170
    virtual void sendPacket(const isc::dhcp::Pkt6Ptr& pkt) {
171 172 173 174 175 176
        fake_sent_.push_back(pkt);
    }

    /// @brief adds a packet to fake receive queue
    ///
    /// See fake_received_ field for description
177
    void fakeReceive(const isc::dhcp::Pkt6Ptr& pkt) {
178 179 180 181 182
        fake_received_.push_back(pkt);
    }

    virtual ~NakedDhcpv6Srv() {
        // Close the lease database
183
        isc::dhcp::LeaseMgrFactory::destroy();
184 185 186 187 188
    }

    using Dhcpv6Srv::processSolicit;
    using Dhcpv6Srv::processRequest;
    using Dhcpv6Srv::processRenew;
189 190
    using Dhcpv6Srv::processRebind;
    using Dhcpv6Srv::processConfirm;
191
    using Dhcpv6Srv::processRelease;
192 193
    using Dhcpv6Srv::processDecline;
    using Dhcpv6Srv::processInfRequest;
194 195
    using Dhcpv6Srv::processClientFqdn;
    using Dhcpv6Srv::createNameChangeRequests;
196
    using Dhcpv6Srv::selectSubnet;
197
    using Dhcpv6Srv::testServerID;
198
    using Dhcpv6Srv::testUnicast;
199
    using Dhcpv6Srv::sanityCheck;
200
    using Dhcpv6Srv::classifyPacket;
201
    using Dhcpv6Srv::shutdown_;
202
    using Dhcpv6Srv::name_change_reqs_;
203
    using Dhcpv6Srv::VENDOR_CLASS_PREFIX;
204
    using Dhcpv6Srv::initContext;
205 206 207

    /// @brief packets we pretend to receive
    ///
208 209 210 211 212 213 214 215
    /// Instead of setting up sockets on interfaces that change between
    /// OSes, it is much easier to fake packet reception. This is a list
    /// of packets that we pretend to have received. You can schedule
    /// new packets to be received using fakeReceive() and
    /// NakedDhcpv6Srv::receivePacket() methods.
    std::list<isc::dhcp::Pkt6Ptr> fake_received_;

    std::list<isc::dhcp::Pkt6Ptr> fake_sent_;
216 217
};

218 219
/// @brief Test fixture for any tests requiring blank/empty configuration
///        serves as base class for additional tests
220
class NakedDhcpv6SrvTest : public BaseServerTest {
221 222
public:

223 224
    /// @brief Constructor
    NakedDhcpv6SrvTest();
225

226
    // Generate IA_NA or IA_PD option with specified parameters
227 228
    boost::shared_ptr<isc::dhcp::Option6IA> generateIA
        (uint16_t type, uint32_t iaid, uint32_t t1, uint32_t t2);
229 230 231 232 233 234

    /// @brief generates interface-id option, based on text
    ///
    /// @param iface_id textual representation of the interface-id content
    ///
    /// @return pointer to the option object
235 236 237 238 239
    isc::dhcp::OptionPtr generateInterfaceId(const std::string& iface_id) {
        isc::dhcp::OptionBuffer tmp(iface_id.begin(), iface_id.end());
        return (isc::dhcp::OptionPtr
                (new isc::dhcp::Option(isc::dhcp::Option::V6,
                                       D6O_INTERFACE_ID, tmp)));
240 241 242
    }

    // Generate client-id option
243
    isc::dhcp::OptionPtr generateClientId(size_t duid_size = 32) {
244

245
        isc::dhcp::OptionBuffer clnt_duid(duid_size);
246
        for (size_t i = 0; i < duid_size; i++) {
247 248 249
            clnt_duid[i] = 100 + i;
        }

250
        duid_ = isc::dhcp::DuidPtr(new isc::dhcp::DUID(clnt_duid));
251

252 253 254 255
        return (isc::dhcp::OptionPtr
                (new isc::dhcp::Option(isc::dhcp::Option::V6, D6O_CLIENTID,
                                       clnt_duid.begin(),
                                       clnt_duid.begin() + duid_size)));
256 257
    }

258 259 260 261 262
    // Checks if server response (ADVERTISE or REPLY) includes proper
    // server-id.
    void checkServerId(const isc::dhcp::Pkt6Ptr& rsp,
                       const isc::dhcp::OptionPtr& expected_srvid)
    {
263
        // check that server included its server-id
264
        isc::dhcp::OptionPtr tmp = rsp->getOption(D6O_SERVERID);
265 266 267 268 269
        EXPECT_EQ(tmp->getType(), expected_srvid->getType() );
        ASSERT_EQ(tmp->len(), expected_srvid->len() );
        EXPECT_TRUE(tmp->getData() == expected_srvid->getData());
    }

270 271 272 273 274
    // Checks if server response (ADVERTISE or REPLY) includes proper
    // client-id.
    void checkClientId(const isc::dhcp::Pkt6Ptr& rsp,
                       const isc::dhcp::OptionPtr& expected_clientid)
    {
275
        // check that server included our own client-id
276
        isc::dhcp::OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
277 278 279 280 281 282 283 284 285
        ASSERT_TRUE(tmp);
        EXPECT_EQ(expected_clientid->getType(), tmp->getType());
        ASSERT_EQ(expected_clientid->len(), tmp->len());

        // check that returned client-id is valid
        EXPECT_TRUE(expected_clientid->getData() == tmp->getData());
    }

    // Checks if server response is a NAK
286 287
    void checkNakResponse(const isc::dhcp::Pkt6Ptr& rsp,
                          uint8_t expected_message_type,
288
                          uint32_t expected_transid,
289 290
                          uint16_t expected_status_code,
                          uint32_t expected_t1, uint32_t expected_t2)
291
    {
292 293 294 295
        // Check if we get response at all
        checkResponse(rsp, expected_message_type, expected_transid);

        // Check that IA_NA was returned
296
        isc::dhcp::OptionPtr option_ia_na = rsp->getOption(D6O_IA_NA);
297 298 299
        ASSERT_TRUE(option_ia_na);

        // check that the status is no address available
300 301
        boost::shared_ptr<isc::dhcp::Option6IA> ia =
            boost::dynamic_pointer_cast<isc::dhcp::Option6IA>(option_ia_na);
302 303
        ASSERT_TRUE(ia);

304 305
        checkIA_NAStatusCode(ia, expected_status_code, expected_t1,
                             expected_t2);
306 307
    }

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
    /// @brief Checks that the server inserted expected status code in IA_NA
    ///
    /// Check that the server used status code as expected, i.e. that it has
    /// no addresses (if status code is non-zero) and that expected status
    /// code really appears there. In some limited cases (reply to RELEASE)
    /// it may be used to verify positive case, where IA_NA response is
    /// expected to not include address.
    ///
    /// Status code indicates type of error encountered (in theory it can also
    /// indicate success, but servers typically don't send success status
    /// as this is the default result and it saves bandwidth)
    /// @param ia IA_NA container to be checked
    /// @param expected_status_code expected value in status-code option
    /// @param expected_t1 expected T1 in IA_NA option
    /// @param expected_t2 expected T2 in IA_NA option
    /// @param check_addr whether to check for address with 0 lifetimes
324 325
    void checkIA_NAStatusCode
        (const boost::shared_ptr<isc::dhcp::Option6IA>& ia,
326
         uint16_t expected_status_code, uint32_t expected_t1,
327
         uint32_t expected_t2, bool check_addr = true);
328

329 330 331
    void checkMsgStatusCode(const isc::dhcp::Pkt6Ptr& msg,
                            uint16_t expected_status)
    {
332 333
        isc::dhcp::Option6StatusCodePtr status =
            boost::dynamic_pointer_cast<isc::dhcp::Option6StatusCode>
334
                (msg->getOption(D6O_STATUS_CODE));
335

336 337
        // It is ok to not include status success as this is the default
        // behavior
338 339 340 341 342 343
        if (expected_status == STATUS_Success && !status) {
            return;
        }

        EXPECT_TRUE(status);
        if (status) {
344 345 346 347
            // We don't have dedicated class for status code, so let's
            // just interpret first 2 bytes as status. Remainder of the
            // status code option content is just a text explanation
            // what went wrong.
348
            EXPECT_EQ(static_cast<uint16_t>(expected_status),
349
                      status->getStatusCode());
350 351 352 353
        }
    }

    // Basic checks for generated response (message type and transaction-id).
354 355
    void checkResponse(const isc::dhcp::Pkt6Ptr& rsp,
                       uint8_t expected_message_type,
356 357 358 359 360 361
                       uint32_t expected_transid) {
        ASSERT_TRUE(rsp);
        EXPECT_EQ(expected_message_type, rsp->getType());
        EXPECT_EQ(expected_transid, rsp->getTransid());
    }

362
    virtual ~NakedDhcpv6SrvTest();
363 364

    // A DUID used in most tests (typically as client-id)
365
    isc::dhcp::DuidPtr duid_;
366 367

    int rcode_;
368
    isc::data::ConstElementPtr comment_;
369 370 371 372 373

    // Name of a valid network interface
    std::string valid_iface_;
};

374 375 376 377 378
// We need to pass one reference to the Dhcp6Client, which is defined in
// dhcp6_client.h. That header includes this file. To avoid circular
// dependencies, we use forward declaration here.
class Dhcp6Client;

379 380 381 382
// Provides suport for tests against a preconfigured subnet6
// extends upon NakedDhcp6SrvTest
class Dhcpv6SrvTest : public NakedDhcpv6SrvTest {
public:
383 384 385 386 387 388 389 390 391 392 393 394 395
    /// @brief Specifies expected outcome
    enum ExpectedResult {
        SHOULD_PASS, // pass = accept decline, move lease to declined state.
        SHOULD_FAIL  // fail = reject the decline
    };

    /// @brief Specifies what address should the client include in its Decline
    enum AddressInclusion {
        VALID_ADDR, // Client will include its own, valid address
        BOGUS_ADDR, // Client will include an address it doesn't own
        NO_ADDR,    // Client will send empty IA_NA (without address)
        NO_IA       // Client will not send IA_NA at all
    };
396

Francis Dupont's avatar
Francis Dupont committed
397
    /// @brief Constructor that initializes a simple default configuration
Tomek Mrugalski's avatar
Tomek Mrugalski committed
398 399 400
    ///
    /// Sets up a single subnet6 with one pool for addresses and second
    /// pool for prefixes.
401
    Dhcpv6SrvTest();
402

Tomek Mrugalski's avatar
Tomek Mrugalski committed
403 404 405 406
    /// @brief destructor
    ///
    /// Removes existing configuration.
    ~Dhcpv6SrvTest() {
407
        isc::dhcp::CfgMgr::instance().clear();
Tomek Mrugalski's avatar
Tomek Mrugalski committed
408 409
    };

410 411 412
    /// @brief Runs DHCPv6 configuration from the JSON string.
    ///
    /// @param config String holding server configuration in JSON format.
413 414 415 416 417 418 419
    void configure(const std::string& config);

    /// @brief Configure the DHCPv6 server using the JSON string.
    ///
    /// @param config String holding server configuration in JSON format.
    /// @param srv Server to be configured.
    void configure(const std::string& config, NakedDhcpv6Srv& srv);
420

421 422 423 424 425 426 427 428
    /// @brief Checks that server response (ADVERTISE or REPLY) contains proper
    ///        IA_NA option
    ///
    /// @param rsp server's response
    /// @param expected_iaid expected IAID value
    /// @param expected_t1 expected T1 value
    /// @param expected_t2 expected T2 value
    /// @return IAADDR option for easy chaining with checkIAAddr method
429 430
    boost::shared_ptr<isc::dhcp::Option6IAAddr>
        checkIA_NA(const isc::dhcp::Pkt6Ptr& rsp, uint32_t expected_iaid,
431 432 433 434 435 436 437 438 439 440
                   uint32_t expected_t1, uint32_t expected_t2);

    /// @brief Checks that server response (ADVERTISE or REPLY) contains proper
    ///        IA_PD option
    ///
    /// @param rsp server's response
    /// @param expected_iaid expected IAID value
    /// @param expected_t1 expected T1 value
    /// @param expected_t2 expected T2 value
    /// @return IAPREFIX option for easy chaining with checkIAAddr method
441 442
    boost::shared_ptr<isc::dhcp::Option6IAPrefix>
    checkIA_PD(const isc::dhcp::Pkt6Ptr& rsp, uint32_t expected_iaid,
443 444
               uint32_t expected_t1, uint32_t expected_t2);

445 446
    // Check that generated IAADDR option contains expected address
    // and lifetime values match the configured subnet
447 448 449
    void checkIAAddr(const boost::shared_ptr<isc::dhcp::Option6IAAddr>& addr,
                     const isc::asiolink::IOAddress& expected_addr,
                     isc::dhcp::Lease::Type type) {
450 451 452 453 454

        // Check that the assigned address is indeed from the configured pool.
        // Note that when comparing addresses, we compare the textual
        // representation. IOAddress does not support being streamed to
        // an ostream, which means it can't be used in EXPECT_EQ.
455
        EXPECT_TRUE(subnet_->inPool(type, addr->getAddress()));
456
        EXPECT_EQ(expected_addr.toText(), addr->getAddress().toText());
457 458
        EXPECT_EQ(subnet_->getPreferred(), addr->getPreferred());
        EXPECT_EQ(subnet_->getValid(), addr->getValid());
459 460 461
    }

    // Checks if the lease sent to client is present in the database
462
    // and is valid when checked against the configured subnet
463 464 465
    isc::dhcp::Lease6Ptr checkLease
        (const isc::dhcp::DuidPtr& duid, const isc::dhcp::OptionPtr& ia_na,
         boost::shared_ptr<isc::dhcp::Option6IAAddr> addr);
466

467 468 469 470 471 472
    /// @brief Check if the specified lease is present in the data base.
    ///
    /// @param lease Lease to be searched in the database.
    /// @return Pointer to the lease in the database.
    isc::dhcp::Lease6Ptr checkLease(const isc::dhcp::Lease6& lease);

473 474
    /// @brief Verifies received IAPrefix option
    ///
475 476 477
    /// Verifies if the received IAPrefix option matches the lease in the
    /// database.
    ///
478 479 480 481
    /// @param duid client's DUID
    /// @param ia_pd IA_PD option that contains the IAPRefix option
    /// @param prefix pointer to the IAPREFIX option
    /// @return corresponding IPv6 lease (if found)
482 483 484
    isc::dhcp::Lease6Ptr checkPdLease
      (const isc::dhcp::DuidPtr& duid, const isc::dhcp::OptionPtr& ia_pd,
       boost::shared_ptr<isc::dhcp::Option6IAPrefix> prefix);
485

486 487
    /// @brief Creates a message with specified IA
    ///
488 489
    /// A utility function that creates a message of the specified type with
    /// a specified container (IA_NA or IA_PD) and an address or prefix
490 491 492 493 494 495 496 497
    /// inside it.
    ///
    /// @param message_type type of the message (e.g. DHCPV6_SOLICIT)
    /// @param lease_type type of a lease (TYPE_NA or TYPE_PD)
    /// @param addr address or prefix to use in IADDRESS or IAPREFIX options
    /// @param prefix_len length of the prefix (used for prefixes only)
    /// @param iaid IA identifier (used in IA_XX option)
    /// @return created message
498 499 500
    isc::dhcp::Pkt6Ptr
    createMessage(uint8_t message_type, isc::dhcp::Lease::Type lease_type,
                  const isc::asiolink::IOAddress& addr,
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
                  const uint8_t prefix_len, const uint32_t iaid);

    /// @brief Creates instance of IA option holding single address or prefix.
    ///
    /// Utility function that creates an IA option instance with a single
    /// IPv6 address or prefix. This function is internally called by the
    /// @c createMessage function. It may be also used to add additional
    /// IA options to the message generated by @c createMessage (which adds
    /// a single IA option by itself.).
    ///
    /// @param lease_type type of the lease (TYPE_NA or TYPE_PD).
    /// @param addr address or prefix to use in IADDRESS or IAPREFIX options.
    /// @param prefix_len length of the prefix (used for PD, ignored for NA).
    /// @param iaid IA identifier.
    ///
    /// @return Created instance of the IA option.
    isc::dhcp::Option6IAPtr
    createIA(isc::dhcp::Lease::Type lease_type,
             const isc::asiolink::IOAddress& addr,
             const uint8_t prefix_len, const uint32_t iaid);
521

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
    /// @brief Compare options
    ///
    /// This method compares whether options content is identical. It writes
    /// both options to a buffer and then compares the buffers. Comparing
    /// two different instances of an option that has identical content
    /// will return true.
    ///
    /// It is safe to pass NULL pointers. Two NULL pointers are equal.
    /// NULL pointer and non-NULL pointers are obviously non-equal.
    ///
    /// @param option1 pointer to the first option
    /// @param option2
    /// @return true, if content is identical
    bool compareOptions(const isc::dhcp::OptionPtr& option1,
                        const isc::dhcp::OptionPtr& option2);

538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
    /// @brief Tests if the acquired lease is or is not declined.
    ///
    /// @param client Dhcp6Client instance
    /// @param duid1 DUID used during lease acquisition
    /// @param iaid1 IAID used during lease acquisition
    /// @param duid2 DUID used during Decline exchange
    /// @param iaid2 IAID used during Decline exchange
    /// @param addr_type specify what sort of address the client should
    ///        include (its own, a bogus one or no address at all)
    /// @param expected_result SHOULD_PASS if the lease is expected to
    /// be successfully declined, or SHOULD_FAIL if the lease is expected
    /// to not be declined.
    void acquireAndDecline(Dhcp6Client& client,
                           const std::string& duid1,
                           const uint32_t iaid1,
                           const std::string& duid2,
                           const uint32_t iaid2,
                           AddressInclusion addr_type,
                           ExpectedResult expected_result);

558
    /// @brief Performs basic (positive) RENEW test
559
    ///
560
    /// See renewBasic and pdRenewBasic tests for detailed explanation.
561 562 563 564 565 566 567
    /// In essence the test attempts to perform a successful RENEW scenario.
    ///
    /// This method does not throw, but uses gtest macros to signify failures.
    ///
    /// @param type type (TYPE_NA or TYPE_PD)
    /// @param existing_addr address to be preinserted into the database
    /// @param renew_addr address being sent in RENEW
568
    /// @param prefix_len length of the prefix (128 for addresses)
569 570
    /// @param insert_before_renew should the lease be inserted into the database
    ///        before we try renewal?
571
    void
572 573
    testRenewBasic(isc::dhcp::Lease::Type type,
                   const std::string& existing_addr,
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
                   const std::string& renew_addr, const uint8_t prefix_len,
                   bool insert_before_renew = true);

    /// @brief Checks if RENEW with invalid IAID is processed correctly.
    ///
    /// @param type lease type (currently only IA_NA is supported)
    /// @param addr address to be renewed
    void
    testRenewWrongIAID(isc::dhcp::Lease::Type type,
                       const asiolink::IOAddress& addr);

    /// @brief Checks if client A can renew address used by client B
    ///
    /// @param type lease type (currently only IA_NA is supported)
    /// @param addr address to be renewed
    void
    testRenewSomeoneElsesLease(isc::dhcp::Lease::Type type,
                               const asiolink::IOAddress& addr);
592

593 594 595 596 597 598 599 600 601 602 603
    /// @brief Performs basic (positive) RELEASE test
    ///
    /// See releaseBasic and pdReleaseBasic tests for detailed explanation.
    /// In essence the test attempts to perform a successful RELEASE scenario.
    ///
    /// This method does not throw, but uses gtest macros to signify failures.
    ///
    /// @param type type (TYPE_NA or TYPE_PD)
    /// @param existing address to be preinserted into the database
    /// @param release_addr address being sent in RELEASE
    void
604 605 606
    testReleaseBasic(isc::dhcp::Lease::Type type,
                     const isc::asiolink::IOAddress& existing,
                     const isc::asiolink::IOAddress& release_addr);
607

608 609
    /// @brief Performs negative RELEASE test
    ///
610 611 612
    /// See releaseReject and pdReleaseReject tests for detailed
    /// explanation.  In essence the test attempts to perform couple
    /// failed RELEASE scenarios.
613 614 615 616 617 618
    ///
    /// This method does not throw, but uses gtest macros to signify failures.
    ///
    /// @param type type (TYPE_NA or TYPE_PD)
    /// @param addr address being sent in RELEASE
    void
619 620
    testReleaseReject(isc::dhcp::Lease::Type type,
                      const isc::asiolink::IOAddress& addr);
621

622 623 624 625 626 627
    /// @brief simulates reception of a packet of specified type and checks statistic
    ///
    /// @param pkt_type reception of a packet of this type will be simulated
    /// @param stat_name this statistic is expected to be set to 1
    void testReceiveStats(uint8_t pkt_type, const std::string& stat_name);

628

629
    /// A subnet used in most tests
630
    isc::dhcp::Subnet6Ptr subnet_;
631

632
    /// A normal, non-temporary pool used in most tests
633
    isc::dhcp::Pool6Ptr pool_;
634 635

    /// A prefix pool used in most tests
636
    isc::dhcp::Pool6Ptr pd_pool_;
637 638 639

    /// @brief Server object under test.
    NakedDhcpv6Srv srv_;
640 641
};

642 643 644 645 646
// For parser testing (JSON map, no exception expected)
inline isc::data::ConstElementPtr
parseJSON(const std::string& in)
{
    isc::dhcp::Parser6Context ctx;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
647
    return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_JSON));
648 649 650 651 652 653 654 655 656 657 658
}

// For parser testing (DHCP6)
inline isc::data::ConstElementPtr
parseDHCP6(const std::string& in)
{
    try {
        isc::dhcp::Parser6Context ctx;
        return (ctx.parseString(in, isc::dhcp::Parser6Context::SUBPARSER_DHCP6));
    }
    catch (const std::exception& ex) {
659
#ifdef ENABLE_DEBUG
660
        std::cout << "EXCEPTION: " << ex.what() << std::endl;
661
#endif // ENABLE_DEBUG
662 663 664 665 666 667 668 669 670 671
        throw;
    }
}

// For parser testing (OPTION_DEF)
inline isc::data::ConstElementPtr
parseOPTION_DEF(const std::string& in)
{
    try {
        isc::dhcp::Parser6Context ctx;
Tomek Mrugalski's avatar
Tomek Mrugalski committed
672
        return (ctx.parseString(in, isc::dhcp::Parser6Context::PARSER_OPTION_DEF));
673 674
    }
    catch (const std::exception& ex) {
675
#ifdef ENABLE_DEBUG
676
        std::cout << "EXCEPTION: " << ex.what() << std::endl;
677
#endif // ENABLE_DEBUG
678 679 680 681
        throw;
    }
}

682 683
}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
684
}; // end of isc namespace
685 686

#endif // DHCP6_TEST_UTILS_H