nc_add_unittests.cc 74.6 KB
Newer Older
1
// Copyright (C) 2013-2015  Internet Systems Consortium, Inc. ("ISC")
2 3 4 5 6 7 8 9 10 11 12 13 14
//
// 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.

15 16
#include <config.h>

17
#include <asiolink/io_service.h>
18 19
#include <d2/d2_cfg_mgr.h>
#include <d2/d2_cfg_mgr.h>
20
#include <d2/nc_add.h>
21 22
#include <dns/messagerenderer.h>
#include <nc_test_utils.h>
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <gtest/gtest.h>

using namespace std;
using namespace isc;
using namespace isc::d2;

namespace {

/// @brief Test class derived from NameAddTransaction to provide visiblity
// to protected methods.
class NameAddStub : public NameAddTransaction {
public:
38
    NameAddStub(asiolink::IOServicePtr& io_service,
39 40
                dhcp_ddns::NameChangeRequestPtr& ncr,
                DdnsDomainPtr& forward_domain,
41 42 43 44
                DdnsDomainPtr& reverse_domain,
                D2CfgMgrPtr& cfg_mgr)
        : NameAddTransaction(io_service, ncr, forward_domain, reverse_domain,
                             cfg_mgr),
45 46
          simulate_send_exception_(false),
          simulate_build_request_exception_(false) {
47 48 49 50
    }

    virtual ~NameAddStub() {
    }
51

52
    /// @brief Simulates sending update requests to the DNS server
53 54 55 56 57 58 59 60 61
    ///
    /// This method simulates the initiation of an asynchronous send of
    /// a DNS update request. It overrides the actual sendUpdate method in
    /// the base class, thus avoiding an actual send, yet still increments
    /// the update attempt count and posts a next event of NOP_EVT.
    ///
    /// It will also simulate an exception-based failure of sendUpdate, if
    /// the simulate_send_exception_ flag is true.
    ///
62
    /// @param comment Parameter is unused, but present in base class method.
63
    ///
64
    virtual void sendUpdate(const std::string& /*comment*/) {
65 66 67 68 69 70 71 72 73
        if (simulate_send_exception_) {
            // Make the flag a one-shot by resetting it.
            simulate_send_exception_ = false;
            // Transition to failed.
            transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
            return;
        }

        // Update send attempt count and post a NOP_EVT.
74 75 76 77
        setUpdateAttempts(getUpdateAttempts() + 1);
        postNextEvent(StateModel::NOP_EVT);
    }

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    /// @brief Prepares the initial D2UpdateMessage
    ///
    /// This method overrides the NameChangeTransactio implementation to
    /// provide the ability to simulate an exception throw in the build
    /// request logic.
    /// If the one-shot flag, simulate_build_request_exception_ is true,
    /// this method will throw an exception, otherwise it will invoke the
    /// base class method, providing normal functionality.
    ///
    /// For parameter description see the NameChangeTransaction implementation.
    virtual D2UpdateMessagePtr prepNewRequest(DdnsDomainPtr domain) {
        if (simulate_build_request_exception_) {
            simulate_build_request_exception_ = false;
            isc_throw (NameAddTransactionError,
                       "Simulated build requests exception");
        }

        return (NameChangeTransaction::prepNewRequest(domain));
    }

98 99 100 101
    /// @brief Simulates receiving a response
    ///
    /// This method simulates the completion of a DNSClient send.  This allows
    /// the state handler logic devoted to dealing with IO completion to be
102
    /// fully exercised without requiring any actual IO.  The two primary
103 104 105 106 107 108 109 110 111 112 113
    /// pieces of information gleaned from IO completion are the DNSClient
    /// status which indicates whether or not the IO exchange was successful
    /// and the rcode, which indicates the server's reaction to the request.
    ///
    /// This method updates the transaction's DNS status value to that of the
    /// given parameter, and then constructs and DNS update response message
    /// with the given rcode value.  To complete the simulation it then posts
    /// a next event of IO_COMPLETED_EVT.
    ///
    /// @param status simulated DNSClient status
    /// @param rcode  simulated server response code
114
    void fakeResponse(const DNSClient::Status& status,
115
                      const dns::Rcode& rcode) {
116 117
        // Set the DNS update status.  This is normally set in
        // DNSClient IO completion handler.
118
        setDnsUpdateStatus(status);
119 120 121

        // Construct an empty message with the given Rcode.
        D2UpdateMessagePtr msg(new D2UpdateMessage(D2UpdateMessage::OUTBOUND));
122
        msg->setRcode(rcode);
123 124

        // Set the update response to the message.
125
        setDnsUpdateResponse(msg);
126 127

        // Post the IO completion event.
128 129 130
        postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);
    }

131 132 133 134
    /// @brief Selects the first forward server.
    /// Some state handlers require a server to have been selected.
    /// This selects a server without going through the state
    /// transition(s) to do so.
135 136 137 138 139 140 141 142 143 144
    bool selectFwdServer() {
        if (getForwardDomain()) {
            initServerSelection(getForwardDomain());
            selectNextServer();
            return (getCurrentServer());
        }

        return (false);
    }

145 146 147 148
    /// @brief Selects the first reverse server.
    /// Some state handlers require a server to have been selected.
    /// This selects a server without going through the state
    /// transition(s) to do so.
149 150 151 152 153 154 155 156 157 158
    bool selectRevServer() {
        if (getReverseDomain()) {
            initServerSelection(getReverseDomain());
            selectNextServer();
            return (getCurrentServer());
        }

        return (false);
    }

159 160
    /// @brief One-shot flag which will simulate sendUpdate failure if true.
    bool simulate_send_exception_;
161

162 163 164 165
    /// @brief One-shot flag which will simulate an exception when sendUpdate
    /// failure if true.
    bool simulate_build_request_exception_;

166 167 168
    using StateModel::postNextEvent;
    using StateModel::setState;
    using StateModel::initDictionaries;
169 170 171 172
    using NameAddTransaction::defineEvents;
    using NameAddTransaction::verifyEvents;
    using NameAddTransaction::defineStates;
    using NameAddTransaction::verifyStates;
173 174 175 176 177 178 179 180 181 182
    using NameAddTransaction::readyHandler;
    using NameAddTransaction::selectingFwdServerHandler;
    using NameAddTransaction::getCurrentServer;
    using NameAddTransaction::addingFwdAddrsHandler;
    using NameAddTransaction::setDnsUpdateStatus;
    using NameAddTransaction::replacingFwdAddrsHandler;
    using NameAddTransaction::selectingRevServerHandler;
    using NameAddTransaction::replacingRevPtrsHandler;
    using NameAddTransaction::processAddOkHandler;
    using NameAddTransaction::processAddFailedHandler;
183 184 185
    using NameAddTransaction::buildAddFwdAddressRequest;
    using NameAddTransaction::buildReplaceFwdAddressRequest;
    using NameAddTransaction::buildReplaceRevPtrsRequest;
186 187 188 189 190 191 192 193
};

typedef boost::shared_ptr<NameAddStub> NameAddStubPtr;

/// @brief Test fixture for testing NameAddTransaction
///
/// Note this class uses NameAddStub class to exercise non-public
/// aspects of NameAddTransaction.
194
class NameAddTransactionTest : public TransactionTest {
195 196
public:

197
    NameAddTransactionTest() {
198 199 200 201 202
    }

    virtual ~NameAddTransactionTest() {
    }

203 204 205 206
    /// @brief Creates a transaction which requests an IPv4 DNS update.
    ///
    /// The transaction is constructed around a predefined (i.e. "canned")
    /// IPv4 NameChangeRequest. The request has both forward and reverse DNS
207 208 209 210
    /// changes requested.  Based upon the change mask, the transaction
    /// will have either the forward, reverse, or both domains populated.
    ///
    /// @param change_mask determines which change directions are requested
211 212 213
    NameAddStubPtr makeTransaction4(int change_mask = FWD_AND_REV_CHG) {
        // Creates IPv4 remove request, forward, and reverse domains.
        setupForIPv4Transaction(dhcp_ddns::CHG_ADD, change_mask);
214

215
        // Now create the test transaction as would occur in update manager.
216
        return (NameAddStubPtr(new NameAddStub(io_service_, ncr_,
217
                                               forward_domain_,
218
                                               reverse_domain_, cfg_mgr_)));
219
    }
220

221 222 223 224 225 226 227 228
    /// @brief Creates a transaction which requests an IPv6 DNS update.
    ///
    /// The transaction is constructed around a predefined (i.e. "canned")
    /// IPv6 NameChangeRequest. The request has both forward and reverse DNS
    /// changes requested.  Based upon the change mask, the transaction
    /// will have either the forward, reverse, or both domains populated.
    ///
    /// @param change_mask determines which change directions are requested
229 230 231
    NameAddStubPtr makeTransaction6(int change_mask = FWD_AND_REV_CHG) {
        // Creates IPv6 remove request, forward, and reverse domains.
        setupForIPv6Transaction(dhcp_ddns::CHG_ADD, change_mask);
232 233

        // Now create the test transaction as would occur in update manager.
234
        return (NameAddStubPtr(new NameAddStub(io_service_, ncr_,
235
                                               forward_domain_,
236 237
                                               reverse_domain_,
                                               cfg_mgr_)));
238 239
    }

240 241 242 243 244
    /// @brief Create a test transaction at a known point in the state model.
    ///
    /// Method prepares a new test transaction and sets its state and next
    /// event values to those given.  This makes the transaction appear to
    /// be at that point in the state model without having to transition it
245
    /// through prerequisite states.   It also provides the ability to set
246 247 248 249 250 251
    /// which change directions are requested: forward change only, reverse
    /// change only, or both.
    ///
    /// @param state value to set as the current state
    /// @param event value to post as the next event
    /// @param change_mask determines which change directions are requested
252 253
    /// @param family selects between an IPv4 (AF_INET) and IPv6 (AF_INET6)
    /// transaction.
254
    NameAddStubPtr prepHandlerTest(unsigned int state, unsigned int event,
255 256 257 258 259
                                   unsigned int change_mask = FWD_AND_REV_CHG,
                                   short family = AF_INET) {
        NameAddStubPtr name_add =  (family == AF_INET ?
                                    makeTransaction4(change_mask) :
                                    makeTransaction4(change_mask));
260 261 262 263
        name_add->initDictionaries();
        name_add->postNextEvent(event);
        name_add->setState(state);
        return (name_add);
264 265 266 267 268 269 270 271
    }
};

/// @brief Tests NameAddTransaction construction.
/// This test verifies that:
/// 1. Construction with invalid type of request
/// 2. Valid construction functions properly
TEST(NameAddTransaction, construction) {
272
    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
273
    D2CfgMgrPtr cfg_mgr(new D2CfgMgr());
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293

    const char* msg_str =
        "{"
        " \"change_type\" : 1 , "
        " \"forward_change\" : true , "
        " \"reverse_change\" : true , "
        " \"fqdn\" : \"example.com.\" , "
        " \"ip_address\" : \"192.168.2.1\" , "
        " \"dhcid\" : \"0102030405060708\" , "
        " \"lease_expires_on\" : \"20130121132405\" , "
        " \"lease_length\" : 1300 "
        "}";

    dhcp_ddns::NameChangeRequestPtr ncr;
    DnsServerInfoStoragePtr servers;
    DdnsDomainPtr forward_domain;
    DdnsDomainPtr reverse_domain;
    DdnsDomainPtr empty_domain;

    ASSERT_NO_THROW(ncr = dhcp_ddns::NameChangeRequest::fromJSON(msg_str));
294 295
    ASSERT_NO_THROW(forward_domain.reset(new DdnsDomain("*", servers)));
    ASSERT_NO_THROW(reverse_domain.reset(new DdnsDomain("*", servers)));
296 297 298

    // Verify that construction with wrong change type fails.
    EXPECT_THROW(NameAddTransaction(io_service, ncr,
299
                                    forward_domain, reverse_domain, cfg_mgr),
300 301 302 303 304
                                    NameAddTransactionError);

    // Verify that a valid construction attempt works.
    ncr->setChangeType(isc::dhcp_ddns::CHG_ADD);
    EXPECT_NO_THROW(NameAddTransaction(io_service, ncr,
305 306
                                       forward_domain, reverse_domain,
                                       cfg_mgr));
307 308 309 310 311
}

/// @brief Tests event and state dictionary construction and verification.
TEST_F(NameAddTransactionTest, dictionaryCheck) {
    NameAddStubPtr name_add;
312
    ASSERT_NO_THROW(name_add = makeTransaction4());
313 314 315 316 317 318 319 320 321 322 323 324 325 326
    // Verify that the event and state dictionary validation fails prior
    // dictionary construction.
    ASSERT_THROW(name_add->verifyEvents(), StateModelError);
    ASSERT_THROW(name_add->verifyStates(), StateModelError);

    // Construct both dictionaries.
    ASSERT_NO_THROW(name_add->defineEvents());
    ASSERT_NO_THROW(name_add->defineStates());

    // Verify both event and state dictionaries now pass validation.
    ASSERT_NO_THROW(name_add->verifyEvents());
    ASSERT_NO_THROW(name_add->verifyStates());
}

327 328 329 330 331 332 333 334 335
/// @brief Tests construction of a DNS update request for adding a forward
/// dns entry.
TEST_F(NameAddTransactionTest, buildForwardAdd) {
    // Create a IPv4 forward add transaction.
    // Verify the request builds without error.
    // and then verify the request contents.
    NameAddStubPtr name_add;
    ASSERT_NO_THROW(name_add = makeTransaction4());
    ASSERT_NO_THROW(name_add->buildAddFwdAddressRequest());
336
    checkAddFwdAddressRequest(*name_add);
337 338 339 340 341 342

    // Create a IPv6 forward add transaction.
    // Verify the request builds without error.
    // and then verify the request contents.
    ASSERT_NO_THROW(name_add = makeTransaction6());
    ASSERT_NO_THROW(name_add->buildAddFwdAddressRequest());
343
    checkAddFwdAddressRequest(*name_add);
344 345 346 347 348 349 350 351 352 353 354
}

/// @brief Tests construction of a DNS update request for replacing a forward
/// dns entry.
TEST_F(NameAddTransactionTest, buildReplaceFwdAddressRequest) {
    // Create a IPv4 forward replace transaction.
    // Verify the request builds without error.
    // and then verify the request contents.
    NameAddStubPtr name_add;
    ASSERT_NO_THROW(name_add = makeTransaction4());
    ASSERT_NO_THROW(name_add->buildReplaceFwdAddressRequest());
355
    checkReplaceFwdAddressRequest(*name_add);
356 357 358 359 360 361

    // Create a IPv6 forward replace transaction.
    // Verify the request builds without error.
    // and then verify the request contents.
    ASSERT_NO_THROW(name_add = makeTransaction6());
    ASSERT_NO_THROW(name_add->buildReplaceFwdAddressRequest());
362
    checkReplaceFwdAddressRequest(*name_add);
363 364 365 366 367 368 369 370 371 372 373
}

/// @brief Tests the construction of a DNS update request for replacing a
/// reverse dns entry.
TEST_F(NameAddTransactionTest, buildReplaceRevPtrsRequest) {
    // Create a IPv4 reverse replace transaction.
    // Verify the request builds without error.
    // and then verify the request contents.
    NameAddStubPtr name_add;
    ASSERT_NO_THROW(name_add = makeTransaction4());
    ASSERT_NO_THROW(name_add->buildReplaceRevPtrsRequest());
374
    checkReplaceRevPtrsRequest(*name_add);
375 376 377 378 379 380

    // Create a IPv6 reverse replace transaction.
    // Verify the request builds without error.
    // and then verify the request contents.
    ASSERT_NO_THROW(name_add = makeTransaction6());
    ASSERT_NO_THROW(name_add->buildReplaceRevPtrsRequest());
381
    checkReplaceRevPtrsRequest(*name_add);
382 383
}

384 385 386 387
// Tests the readyHandler functionality.
// It verifies behavior for the following scenarios:
//
// 1. Posted event is START_EVT and request includes only a forward change
388
// 2. Posted event is START_EVT and request includes both a forward and a
389
// reverse change
390
// 3. Posted event is START_EVT and request includes only a reverse change
391
// 4. Posted event is invalid
392 393 394 395 396
//
TEST_F(NameAddTransactionTest, readyHandler) {
    NameAddStubPtr name_add;

    // Create a transaction which includes only a forward change.
397 398
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameChangeTransaction::READY_ST,
399
                                    StateModel::START_EVT, FORWARD_CHG));
400
    // Run readyHandler.
401 402
    EXPECT_NO_THROW(name_add->readyHandler());

403
    // Verify that a request requiring only a forward change, transitions to
404
    // selecting a forward server.
405
    EXPECT_EQ(NameChangeTransaction::SELECTING_FWD_SERVER_ST,
406
              name_add->getCurrState());
407
    EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT,
408 409 410 411
              name_add->getNextEvent());


    // Create a transaction which includes both a forward and a reverse change.
412 413 414 415
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameChangeTransaction::READY_ST,
                                    StateModel::START_EVT, FWD_AND_REV_CHG));
    // Run readyHandler.
416 417 418 419
    EXPECT_NO_THROW(name_add->readyHandler());

    // Verify that a request requiring both forward and reverse, starts with
    // the forward change by transitioning to selecting a forward server.
420
    EXPECT_EQ(NameChangeTransaction::SELECTING_FWD_SERVER_ST,
421
              name_add->getCurrState());
422
    EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT,
423 424 425 426
              name_add->getNextEvent());


    // Create and prep a reverse only transaction.
427 428
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameChangeTransaction::READY_ST,
429
                                    StateModel::START_EVT, REVERSE_CHG));
430
    // Run readyHandler.
431 432
    EXPECT_NO_THROW(name_add->readyHandler());

433
    // Verify that a request requiring only a reverse change, transitions to
434
    // selecting a reverse server.
435
    EXPECT_EQ(NameChangeTransaction::SELECTING_REV_SERVER_ST,
436
              name_add->getCurrState());
437
    EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT,
438 439 440 441 442
              name_add->getNextEvent());


    // Create and prep transaction, poised to run the handler but with an
    // invalid event.
443 444
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameChangeTransaction::READY_ST,
445 446
                                    StateModel::NOP_EVT));

447
    // Running the readyHandler should throw.
448 449 450 451 452 453
    EXPECT_THROW(name_add->readyHandler(), NameAddTransactionError);
}

// Tests the selectingFwdServerHandler functionality.
// It verifies behavior for the following scenarios:
//
454 455
// 1. Posted event is SELECT_SERVER_EVT
// 2. Posted event is SERVER_IO_ERROR_EVT
456 457 458 459 460
// 3. Posted event is invalid
//
TEST_F(NameAddTransactionTest, selectingFwdServerHandler) {
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
461
    ASSERT_NO_THROW(name_add =
462
                    prepHandlerTest(NameChangeTransaction::
463
                                    SELECTING_FWD_SERVER_ST,
464 465
                                    NameChangeTransaction::SELECT_SERVER_EVT));

466 467 468 469 470
    // Call selectingFwdServerHandler enough times to select all of the
    // servers in it's current domain.  The first time, it will be with
    // next event of SELECT_SERVER_EVT.  Thereafter it will be with a next
    // event of SERVER_IO_ERROR_EVT.
    int num_servers = name_add->getForwardDomain()->getServers()->size();
471
    for (int i = 0; i < num_servers; ++i) {
472
        // Run selectingFwdServerHandler.
473
        ASSERT_NO_THROW(name_add->selectingFwdServerHandler())
474 475
                        << " num_servers: " << num_servers
                        << " selections: " << i;
476

477
        // Verify that a server was selected.
478 479
        ASSERT_TRUE(name_add->getCurrentServer())
                    << " num_servers: " << num_servers << " selections: " << i;
480 481

        // Verify that we transitioned correctly.
482
        ASSERT_EQ(NameAddTransaction::ADDING_FWD_ADDRS_ST,
483 484
                  name_add->getCurrState())
                  << " num_servers: " << num_servers << " selections: " << i;
485
        ASSERT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT,
486 487
                  name_add->getNextEvent())
                  << " num_servers: " << num_servers << " selections: " << i;
488

489 490 491
        // Post a server IO error event.  This simulates an IO error occuring
        // and a need to select the new server.
        ASSERT_NO_THROW(name_add->postNextEvent(NameChangeTransaction::
492 493 494
                                                SERVER_IO_ERROR_EVT))
                        << " num_servers: " << num_servers
                        << " selections: " << i;
495
    }
496

497 498
    // We should have exhausted the list of servers. Processing another
    // SERVER_IO_ERROR_EVT should transition us to failure.
499
    EXPECT_NO_THROW(name_add->selectingFwdServerHandler());
500
    EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST,
501
              name_add->getCurrState());
502
    EXPECT_EQ(NameChangeTransaction::NO_MORE_SERVERS_EVT,
503 504 505 506
              name_add->getNextEvent());

    // Create and prep transaction, poised to run the handler but with an
    // invalid event.
507
    ASSERT_NO_THROW(name_add =
508
                    prepHandlerTest(NameChangeTransaction::
509
                                    SELECTING_FWD_SERVER_ST,
510 511
                                    StateModel::NOP_EVT));

512 513
    // Running the handler should throw.
    EXPECT_THROW(name_add->selectingFwdServerHandler(),
514 515 516 517 518 519
                 NameAddTransactionError);
}

// ************************ addingFwdAddrHandler Tests *****************

// Tests that addingFwdAddrsHandler rejects invalid events.
520
TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_InvalidEvent) {
521 522 523
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler but with
    // an invalid event.
524 525
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::ADDING_FWD_ADDRS_ST,
526 527 528
                                    NameChangeTransaction::
                                    StateModel::NOP_EVT));

529 530
    // Running the handler should throw.
    EXPECT_THROW(name_add->addingFwdAddrsHandler(),
531 532 533
                 NameAddTransactionError);
}

534
// Tests addingFwdAddrsHandler with the following scenario:
535 536
//
//  The request includes only a forward change.
537
//  Initial posted event is SERVER_SELECTED_EVT.
538
//  The update request is sent without error.
539
//  A server response is received which indicates successful update
540
//
541
TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_FwdOnlyAddOK) {
542 543
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
544 545
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::ADDING_FWD_ADDRS_ST,
546 547
                                    NameChangeTransaction::
                                    SERVER_SELECTED_EVT, FORWARD_CHG));
548 549

    // Should not be an update message yet.
550
    D2UpdateMessagePtr update_msg = name_add->getDnsUpdateRequest();
551
    ASSERT_FALSE(update_msg);
552 553 554 555 556

    // At this point completion flags should be false.
    EXPECT_FALSE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

557
    // Run addingFwdAddrsHandler to construct and send the request.
558 559
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

560
    // Verify that an update message was constructed properly.
561
    checkAddFwdAddressRequest(*name_add);
562 563 564

    // Verify that we are still in this state and next event is NOP_EVT.
    // This indicates we "sent" the message and are waiting for IO completion.
565
    EXPECT_EQ(NameAddTransaction::ADDING_FWD_ADDRS_ST,
566
              name_add->getCurrState());
567
    EXPECT_EQ(NameChangeTransaction::NOP_EVT,
568 569
              name_add->getNextEvent());

570
    // Simulate receiving a successful update response.
571 572 573 574 575 576 577 578 579 580 581
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR());

    // Run addingFwdAddrsHandler again to process the response.
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

    // Forward completion should be true, reverse should be false.
    EXPECT_TRUE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

    // Since it is a forward only change, we should be done.
    // Verify that we transitioned correctly.
582
    EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST,
583
              name_add->getCurrState());
584
    EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT,
585 586 587
              name_add->getNextEvent());
}

588
// Tests addingFwdAddrsHandler with the following scenario:
589 590
//
//  The request includes a forward and reverse change.
591
//  Initial posted event is SERVER_SELECTED_EVT.
592 593 594
//  The update request is sent without error.
//  A server response is received which indicates successful update.
//
595
TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_fwdAndRevAddOK) {
596 597
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
598 599
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::ADDING_FWD_ADDRS_ST,
600 601
                                    NameChangeTransaction::
                                    SERVER_SELECTED_EVT, FWD_AND_REV_CHG));
602 603

    // Run addingFwdAddrsHandler to construct and send the request.
604 605
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

606
    // Simulate receiving a successful update response.
607 608 609 610 611 612 613 614 615
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR());

    // Run addingFwdAddrsHandler again  to process the response.
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

    // Forward change completion should be true, reverse flag should be false.
    EXPECT_TRUE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

616
    // Since the request also includes a reverse change we should
617
    // be poised to start it. Verify that we transitioned correctly.
618
    EXPECT_EQ(NameChangeTransaction::SELECTING_REV_SERVER_ST,
619
              name_add->getCurrState());
620
    EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT,
621 622 623
              name_add->getNextEvent());
}

624
// Tests addingFwdAddrsHandler with the following scenario:
625 626
//
//  The request includes a forward and reverse change.
627
//  Initial posted event is SERVER_SELECTED_EVT.
628 629 630
//  The update request is sent without error.
//  A server response is received which indicates the FQDN is in use.
//
631
TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_FqdnInUse) {
632 633
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
634 635
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::ADDING_FWD_ADDRS_ST,
636 637
                                    NameChangeTransaction::
                                    SERVER_SELECTED_EVT));
638 639

    // Run addingFwdAddrsHandler to construct and send the request.
640 641 642 643 644
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

    // Simulate receiving a FQDN in use response.
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::YXDOMAIN());

645
    // Run addingFwdAddrsHandler again to process the response.
646 647 648 649 650 651 652 653
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

    // Completion flags should still be false.
    EXPECT_FALSE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

    // Since the FQDN is in use, per the RFC we must attempt to replace it.
    // Verify that we transitioned correctly.
654
    EXPECT_EQ(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
655
              name_add->getCurrState());
656
    EXPECT_EQ(NameAddTransaction::FQDN_IN_USE_EVT,
657 658 659
              name_add->getNextEvent());
}

660
// Tests addingFwdAddrsHandler with the following scenario:
661 662
//
//  The request includes a forward and reverse change.
663
//  Initial posted event is SERVER_SELECTED_EVT.
664 665 666
//  The update request is sent without error.
//  A server response is received which indicates the update was rejected.
//
667
TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_OtherRcode) {
668 669 670
    NameAddStubPtr name_add;

    // Create and prep a transaction, poised to run the handler.
671 672
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::ADDING_FWD_ADDRS_ST,
673 674 675 676 677 678
                                    NameChangeTransaction::
                                    SERVER_SELECTED_EVT));

    // Select a server to satisfy log statements.
    ASSERT_TRUE(name_add->selectFwdServer());

679
    // Run addingFwdAddrsHandler to construct and send the request.
680 681 682 683 684 685
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

    // Simulate receiving server rejection response. Per RFC, anything other
    // than no error or FQDN in use is failure.  Arbitrarily choosing refused.
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::REFUSED());

686
    // Run addingFwdAddrsHandler again to process the response.
687 688 689 690 691 692
    EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

    // Completion flags should still be false.
    EXPECT_FALSE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

693
    // We should have failed the transaction. Verify that we transitioned
694
    // correctly.
695
    EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST,
696
              name_add->getCurrState());
697
    EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT,
698 699 700
              name_add->getNextEvent());
}

701
// Tests addingFwdAddrsHandler with the following scenario:
702 703
//
//  The request includes a forward and reverse change.
704
//  Initial posted event is SERVER_SELECTED_EVT.
705 706
//  The update request send times out MAX_UPDATE_TRIES_PER_SERVER times.
//
707
TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_Timeout) {
708 709 710
    NameAddStubPtr name_add;

    // Create and prep a transaction, poised to run the handler.
711
    // The log message issued when this test succeeds, displays the
712 713
    // selected server, so we need to select a server before running this
    // test.
714 715
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::ADDING_FWD_ADDRS_ST,
716 717 718 719 720 721 722 723
                                    NameChangeTransaction::
                                    SERVER_SELECTED_EVT));

    // Select a server to satisfy log statements.
    ASSERT_TRUE(name_add->selectFwdServer());

    // Verify that we can make maximum number of update attempts permitted
    // and then transition to selecting a new server.
724
    int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
725
    for (int i = 1; i <= max_tries; ++i) {
726 727
        const D2UpdateMessagePtr prev_msg = name_add->getDnsUpdateRequest();

728
        // Run addingFwdAddrsHandler to send the request.
729 730 731 732 733 734 735 736
        EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

        const D2UpdateMessagePtr curr_msg = name_add->getDnsUpdateRequest();
        if (i == 1) {
            // First time out we should build the message.
            EXPECT_FALSE(prev_msg);
            EXPECT_TRUE(curr_msg);
        } else {
737 738 739 740
            // Subsequent passes should reuse the request. We are only
            // looking to check that we have not replaced the pointer value
            // with a new pointer.  This tests the on_entry() logic which
            // clears the request ONLY upon initial entry into the state.
741 742 743
            EXPECT_TRUE(prev_msg == curr_msg);
        }

744
        // Simulate a server IO timeout.
745 746 747
        name_add->setDnsUpdateStatus(DNSClient::TIMEOUT);
        name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);

748
        // Run addingFwdAddrsHandler again to process the response.
749 750 751 752 753 754 755 756
        EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

        // Completion flags should be false.
        EXPECT_FALSE(name_add->getForwardChangeCompleted());
        EXPECT_FALSE(name_add->getReverseChangeCompleted());

        if (i < max_tries) {
            // We should be ready to try again.
757
            EXPECT_EQ(NameAddTransaction::ADDING_FWD_ADDRS_ST,
758
                      name_add->getCurrState());
759
            EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT,
760 761 762
                    name_add->getNextEvent());
        } else {
            // Server retries should be exhausted, time for a new server.
763
            EXPECT_EQ(NameAddTransaction::SELECTING_FWD_SERVER_ST,
764
                      name_add->getCurrState());
765
            EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT,
766 767 768 769 770
                    name_add->getNextEvent());
        }
    }
}

771
// Tests addingFwdAddrsHandler with the following scenario:
772 773
//
//  The request includes a forward and reverse change.
774
//  Initial posted event is SERVER_SELECTED_EVT.
775 776 777
//  The update request is sent but a corrupt response is received, this occurs
//  MAX_UPDATE_TRIES_PER_SERVER times.
//
778
TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_InvalidResponse) {
779 780 781
    NameAddStubPtr name_add;

    // Create and prep a transaction, poised to run the handler.
782
    // The log message issued when this test succeeds, displays the
783 784
    // selected server, so we need to select a server before running this
    // test.
785 786
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::ADDING_FWD_ADDRS_ST,
787 788 789 790 791 792 793 794
                                    NameChangeTransaction::
                                    SERVER_SELECTED_EVT));

    // Select a server to satisfy log statements.
    ASSERT_TRUE(name_add->selectFwdServer());

    // Verify that we can make maximum number of update attempts permitted
    // and then transition to selecting a new server.
795
    int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
796
    for (int i = 1; i <= max_tries; ++i) {
797
        // Run addingFwdAddrsHandler to construct send the request.
798 799
        EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

800
        // Simulate a corrupt server response.
801 802 803
        name_add->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE);
        name_add->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT);

804
        // Run addingFwdAddrsHandler again to process the response.
805 806 807 808 809 810 811 812
        EXPECT_NO_THROW(name_add->addingFwdAddrsHandler());

        // Completion flags should be false.
        EXPECT_FALSE(name_add->getForwardChangeCompleted());
        EXPECT_FALSE(name_add->getReverseChangeCompleted());

        if (i < max_tries) {
            // We should be ready to try again.
813
            EXPECT_EQ(NameAddTransaction::ADDING_FWD_ADDRS_ST,
814
                      name_add->getCurrState());
815
            EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT,
816 817 818
                    name_add->getNextEvent());
        } else {
            // Server retries should be exhausted, time for a new server.
819
            EXPECT_EQ(NameAddTransaction::SELECTING_FWD_SERVER_ST,
820
                      name_add->getCurrState());
821
            EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT,
822 823 824 825 826 827 828 829 830
                    name_add->getNextEvent());
        }
    }

}

// ************************ replacingFwdAddrHandler Tests *****************

// Tests that replacingFwdAddrsHandler rejects invalid events.
831
TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_InvalidEvent) {
832 833 834
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler but with
    // an invalid event.
835 836
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
837 838 839
                                    NameChangeTransaction::
                                    StateModel::NOP_EVT));

840 841
    // Running the handler should throw.
    EXPECT_THROW(name_add->replacingFwdAddrsHandler(),
842 843 844
                 NameAddTransactionError);
}

845
// Tests replacingFwdAddrsHandler with the following scenario:
846 847
//
//  The request includes only a forward change.
848
//  Initial posted event is FQDN_IN_USE_EVT.
849 850 851
//  The update request is sent without error.
//  A server response is received which indicates successful update.
//
852
TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_FwdOnlyAddOK) {
853 854
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
855 856
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
857 858
                                    NameAddTransaction::
                                    FQDN_IN_USE_EVT, FORWARD_CHG));
859 860

    // Should not be an update message yet.
861
    D2UpdateMessagePtr update_msg = name_add->getDnsUpdateRequest();
862
    ASSERT_FALSE(update_msg);
863 864 865 866 867

    // At this point completion flags should be false.
    EXPECT_FALSE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

868
    // Run replacingFwdAddrsHandler to construct and send the request.
869 870
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

871
    // Verify that an update message was constructed properly.
872
    checkReplaceFwdAddressRequest(*name_add);
873 874 875

    // Verify that we are still in this state and next event is NOP_EVT.
    // This indicates we "sent" the message and are waiting for IO completion.
876
    EXPECT_EQ(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
877
              name_add->getCurrState());
878
    EXPECT_EQ(NameChangeTransaction::NOP_EVT,
879 880
              name_add->getNextEvent());

881
    // Simulate receiving a successful update response.
882 883 884 885 886 887 888 889 890 891 892
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR());

    // Run replacingFwdAddrsHandler again to process the response.
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

    // Forward completion should be true, reverse should be false.
    EXPECT_TRUE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

    // Since it is a forward only change, we should be done.
    // Verify that we transitioned correctly.
893
    EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST,
894
              name_add->getCurrState());
895
    EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT,
896 897 898
              name_add->getNextEvent());
}

899
// Tests replacingFwdAddrsHandler with the following scenario:
900 901
//
//  The request includes only a forward change.
902
//  Initial posted event is SERVER_SELECTED_EVT.
903 904 905
//  The update request is sent without error.
//  A server response is received which indicates successful update.
//
906
TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_FwdOnlyAddOK2) {
907 908
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
909 910
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
911 912
                                    NameChangeTransaction::
                                    SERVER_SELECTED_EVT, FORWARD_CHG));
913 914

    // Run replacingFwdAddrsHandler to construct and send the request.
915 916
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

917
    // Simulate receiving a successful update response.
918 919 920 921 922 923 924 925 926 927 928
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR());

    // Run replacingFwdAddrsHandler again to process the response.
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

    // Forward completion should be true, reverse should be false.
    EXPECT_TRUE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

    // Since it is a forward only change, we should be done.
    // Verify that we transitioned correctly.
929
    EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST,
930
              name_add->getCurrState());
931
    EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT,
932 933 934
              name_add->getNextEvent());
}

935
// Tests replacingFwdAddrsHandler with the following scenario:
936 937 938 939 940 941
//
//  The request includes a forward and reverse change.
//  Initial posted event is FQDN_IN_USE_EVT.
//  The update request is sent without error.
//  A server response is received which indicates successful update.
//
942
TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_FwdAndRevAddOK) {
943 944
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
945 946
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
947 948
                                    NameAddTransaction::
                                    FQDN_IN_USE_EVT, FWD_AND_REV_CHG));
949 950

    // Run replacingFwdAddrsHandler to construct and send the request.
951 952
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

953
    // Simulate receiving a successful update response.
954 955 956 957 958 959 960 961 962
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR());

    // Run replacingFwdAddrsHandler again  to process the response.
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

    // Forward change completion should be true, reverse flag should be false.
    EXPECT_TRUE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

963
    // Since the request also includes a reverse change we should
964
    // be poised to start it. Verify that we transitioned correctly.
965
    EXPECT_EQ(NameChangeTransaction::SELECTING_REV_SERVER_ST,
966
              name_add->getCurrState());
967
    EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT,
968 969 970 971
              name_add->getNextEvent());
}


972
// Tests replacingFwdAddrsHandler with the following scenario:
973 974 975 976 977 978
//
//  The request includes a forward and reverse change.
//  Initial posted event is FQDN_IN_USE_EVT.
//  The update request is sent without error.
//  A server response is received which indicates the FQDN is NOT in use.
//
979
TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_FqdnNotInUse) {
980 981
    NameAddStubPtr name_add;
    // Create and prep a transaction, poised to run the handler.
982 983
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
984 985
                                    NameAddTransaction::
                                    FQDN_IN_USE_EVT, FWD_AND_REV_CHG));
986 987

    // Run replacingFwdAddrsHandler to construct and send the request.
988 989 990 991 992
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

    // Simulate receiving a FQDN not in use response.
    name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NXDOMAIN());

993
    // Run replacingFwdAddrsHandler again to process the response.
994 995 996 997 998 999 1000 1001
    EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler());

    // Completion flags should still be false.
    EXPECT_FALSE(name_add->getForwardChangeCompleted());
    EXPECT_FALSE(name_add->getReverseChangeCompleted());

    // Since the FQDN is no longer in use, per the RFC, try to add it.
    // Verify that we transitioned correctly.
1002
    EXPECT_EQ(NameAddTransaction::ADDING_FWD_ADDRS_ST,
1003
              name_add->getCurrState());
1004
    EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT,
1005 1006 1007 1008
              name_add->getNextEvent());
}


1009
// Tests replacingFwdAddrsHandler with the following scenario:
1010 1011 1012 1013 1014
//
//  The request includes a forward and reverse change.
//  The update request is sent without error.
//  A server response is received which indicates the update was rejected.
//
1015
TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_OtherRcode) {
1016 1017
    NameAddStubPtr name_add;
    // Create the transaction.
1018 1019
    ASSERT_NO_THROW(name_add =
                    prepHandlerTest(NameAddTransaction::REPLACING_FWD_ADDRS_ST,
1020 1021 1022 1023 1024 1025
                                    NameAddTransaction::
                                    FQDN_IN_USE_EVT, FWD_AND_REV_CHG));

    // Select a server to satisfy log statements.
    ASSERT_TRUE