diff --git a/src/bin/d2/Makefile.am b/src/bin/d2/Makefile.am index 43f3e39130..1da489c53d 100644 --- a/src/bin/d2/Makefile.am +++ b/src/bin/d2/Makefile.am @@ -65,6 +65,7 @@ b10_dhcp_ddns_SOURCES += d2_zone.cc d2_zone.h b10_dhcp_ddns_SOURCES += dns_client.cc dns_client.h b10_dhcp_ddns_SOURCES += labeled_value.cc labeled_value.h b10_dhcp_ddns_SOURCES += nc_add.cc nc_add.h +b10_dhcp_ddns_SOURCES += nc_remove.cc nc_remove.h b10_dhcp_ddns_SOURCES += nc_trans.cc nc_trans.h b10_dhcp_ddns_SOURCES += state_model.cc state_model.h diff --git a/src/bin/d2/d2_messages.mes b/src/bin/d2/d2_messages.mes index c0370ea45e..d4ab054e0a 100644 --- a/src/bin/d2/d2_messages.mes +++ b/src/bin/d2/d2_messages.mes @@ -325,19 +325,19 @@ message but the attempt to send it suffered a unexpected error. This is most likely a programmatic error, rather than a communications issue. Some or all of the DNS updates requested as part of this request did not succeed. -% DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE A DNS update message to add a forward DNS entry could not be constructed for this request: %1, reason: %2 +% DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE DNS udpate message to add a forward DNS entry could not be constructed for this request: %1, reason: %2 This is an error message issued when an error occurs attempting to construct the server bound packet requesting a forward address addition. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue. -% DHCP_DDNS_FORWARD_REPLACE_BUILD_FAILURE A DNS update message to replace a forward DNS entry could not be constructed from this request: %1, reason: %2 +% DHCP_DDNS_FORWARD_REPLACE_BUILD_FAILURE DNS update message to replace a forward DNS entry could not be constructed from this request: %1, reason: %2 This is an error message issued when an error occurs attempting to construct the server bound packet requesting a forward address replacement. This is due to invalid data contained in the NameChangeRequest. The request will be aborted. This is most likely a configuration issue. -% DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE A DNS update message to replace a reverse DNS entry could not be constructed from this request: %1, reason: %2 +% DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE DNS update message to replace a reverse DNS entry could not be constructed from this request: %1, reason: %2 This is an error message issued when an error occurs attempting to construct the server bound packet requesting a reverse PTR replacement. This is due to invalid data contained in the NameChangeRequest. The request will be @@ -347,7 +347,94 @@ aborted. This is most likely a configuration issue. This is a debug message issued after DHCP_DDNS has submitted DNS mapping additions which were received and accepted by an appropriate DNS server. -% DHCP_DDNS_ADD_FAILED DHCP_DDNS failed attempting to make DNS mapping additions for this request: %1 +% DHCP_DDNS_ADD_FAILED DHCP_DDNS failed attempting to make DNS mapping additions for this request: %1, event: %2 This is an error message issued after DHCP_DDNS attempts to submit DNS mapping entry additions have failed. The precise reason for the failure should be documented in preceding log entries. + +% DHCP_DDNS_FORWARD_REMOVE_ADDRS_BUILD_FAILURE DNS udpate message to remove a forward DNS Address entry could not be constructed for this request: %1, reason: %2 +This is an error message issued when an error occurs attempting to construct +the server bound packet requesting a forward address (A or AAAA) removal. This +is due to invalid data contained in the NameChangeRequest. The request will be +aborted. This is most likely a configuration issue. + +% DHCP_DDNS_FORWARD_REMOVE_ADDRS_REJECTED DNS Server, %1, rejected a DNS update request to remove the forward address mapping for FQDN, %2, with an RCODE: %3 +This is an error message issued when an update was rejected by the DNS server +it was sent to for the reason given by the RCODE. The rcode values are defined +in RFC 2136. + +% DHCP_DDNS_FORWARD_REMOVE_ADDRS_IO_ERROR DHCP_DDNS encountered an IO error sending a forward mapping address removal for FQDN %1 to DNS server %2 +This is an error message issued when a communication error occurs while +DHCP_DDNS is carrying out a forward address remove. The application will retry +against the same server or others as appropriate. + +% DHCP_DDNS_FORWARD_REMOVE_ADDRS_RESP_CORRUPT DHCP_DDNS received a corrupt response from the DNS server, %1, while removing forward address mapping for FQDN, %2 +This is an error message issued when the response received by DHCP_DDNS, to a +update request to remove a forward address mapping, is mangled or malformed. +The application will retry against the same server or others as appropriate. + +% DHCP_DDNS_FORWARD_REMOVE_ADDRS_BAD_DNSCLIENT_STATUS DHCP_DDNS received an unknown DNSClient status: %1, while removing a forward address mapping for FQDN %2 to DNS server %3 +This is an error message issued when DNSClient returns an unrecognized status +while DHCP_DDNS was removing a forward address mapping. The request will be +aborted. This is most likely a programmatic issue and should be reported. + +% DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE DNS udpate message to remove forward DNS RR entries could not be constructed for this request: %1, reason: %2 +This is an error message issued when an error occurs attempting to construct +the server bound packet requesting forward RR (DHCID RR) removal. This is due +to invalid data contained in the NameChangeRequest. The request will be aborted.This is most likely a configuration issue. + +% DHCP_DDNS_FORWARD_REMOVE_RRS_REJECTED DNS Server, %1, rejected a DNS update request to remove forward RR entries for FQDN, %2, with an RCODE: %3 +This is an error message issued when an update was rejected by the DNS server +it was sent to for the reason given by the RCODE. The rcode values are defined +in RFC 2136. + +% DHCP_DDNS_FORWARD_REMOVE_RRS_IO_ERROR DHCP_DDNS encountered an IO error sending a forward RR removal for FQDN %1 to DNS server %2 +This is an error message issued when a communication error occurs while +DHCP_DDNS is carrying out a forward RR remove. The application will retry +against the same server. + +% DHCP_DDNS_FORWARD_REMOVE_RRS_RESP_CORRUPT DHCP_DDNS received a corrupt response from the DNS server, %1, while removing forward RRs for FQDN, %2 +This is an error message issued when the response received by DHCP_DDNS, to a +update request to remove forward RRs mapping, is mangled or malformed. +The application will retry against the same server or others as appropriate. + +% DHCP_DDNS_FORWARD_REMOVE_RRS_BAD_DNSCLIENT_STATUS DHCP_DDNS received an unknown DNSClient status: %1, while removing forward RRs for FQDN %2 to DNS server %3 +This is an error message issued when DNSClient returns an unrecognized status +while DHCP_DDNS was removing forward RRs. The request will be aborted. This is +most likely a programmatic issue and should be reported. + +% DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE DNS update message to remove a reverse DNS entry could not be constructed from this request: %1, reason: %2 +This is an error message issued when an error occurs attempting to construct +the server bound packet requesting a reverse PTR removal. This is +due to invalid data contained in the NameChangeRequest. The request will be +aborted. This is most likely a configuration issue. + +% DHCP_DDNS_REVERSE_REMOVE_REJECTED DNS Server, %1, rejected a DNS update request to remove the reverse mapping for FQDN, %2, with an RCODE: %3 +This is an error message issued when an update was rejected by the DNS server +it was sent to for the reason given by the RCODE. The rcode values are defined +in RFC 2136. + +% DHCP_DDNS_REVERSE_REMOVE_IO_ERROR DHCP_DDNS encountered an IO error sending a reverse mapping remove for FQDN %1 to DNS server %2 +This is an error message issued when a communication error occurs while +DHCP_DDNS is carrying out a reverse address update. The application will +retry against the same server or others as appropriate. + +% DHCP_DDNS_REVERSE_REMOVE_RESP_CORRUPT DHCP_DDNS received a corrupt response from the DNS server, %1, while removing reverse address mapping for FQDN, %2 +This is an error message issued when the response received by DHCP_DDNS, to a +update request to remove a reverse address, is mangled or malformed. +The application will retry against the same server or others as appropriate. + +% DHCP_DDNS_REVERSE_REMOVE_BAD_DNSCLIENT_STATUS DHCP_DDNS received an unknown DNSClient status: %1, while removing reverse address mapping for FQDN %2 to DNS server %3 +This is an error message issued when DNSClient returns an unrecognized status +while DHCP_DDNS was removing a reverse address mapping. The request will be +aborted. This is most likely a programmatic issue and should be reported. + +% DHCP_DDNS_REMOVE_SUCCEEDED DHCP_DDNS successfully removed the DNS mapping addition for this request: %1 +This is a debug message issued after DHCP_DDNS has submitted DNS mapping +removals which were received and accepted by an appropriate DNS server. + +% DHCP_DDNS_REMOVE_FAILED DHCP_DDNS failed attempting to make DNS mapping removals for this request: %1, event: %2 +This is an error message issued after DHCP_DDNS attempts to submit DNS mapping +entry removals have failed. The precise reason for the failure should be +documented in preceding log entries. + diff --git a/src/bin/d2/nc_add.cc b/src/bin/d2/nc_add.cc index b92ec564e6..da20763ace 100644 --- a/src/bin/d2/nc_add.cc +++ b/src/bin/d2/nc_add.cc @@ -54,17 +54,25 @@ NameAddTransaction::defineEvents() { // Call superclass impl first. NameChangeTransaction::defineEvents(); - // Define NCT events. + // Define NameAddTransaction events. defineEvent(FQDN_IN_USE_EVT, "FQDN_IN_USE_EVT"); defineEvent(FQDN_NOT_IN_USE_EVT, "FQDN_NOT_IN_USE_EVT"); } void NameAddTransaction::verifyEvents() { - // Call superclass impl first. + // Call superclass implementation first to verify its events. These are + // events common to all transactions, and they must be defined. + // SELECT_SERVER_EVT + // SERVER_SELECTED_EVT + // SERVER_IO_ERROR_EVT + // NO_MORE_SERVERS_EVT + // IO_COMPLETED_EVT + // UPDATE_OK_EVT + // UPDATE_FAILED_EVT NameChangeTransaction::verifyEvents(); - // Verify NCT events. + // Verify NameAddTransaction events by attempting to fetch them. getEvent(FQDN_IN_USE_EVT); getEvent(FQDN_NOT_IN_USE_EVT); } @@ -74,7 +82,7 @@ NameAddTransaction::defineStates() { // Call superclass impl first. NameChangeTransaction::defineStates(); - // Define the states. + // Define NameAddTransaction states. defineState(READY_ST, "READY_ST", boost::bind(&NameAddTransaction::readyHandler, this)); @@ -102,10 +110,16 @@ NameAddTransaction::defineStates() { } void NameAddTransaction::verifyStates() { - // Call superclass impl first. + // Call superclass implementation first to verify its states. These are + // states common to all transactions, and they must be defined. + // READY_ST + // SELECTING_FWD_SERVER_ST + // SELECTING_REV_SERVER_ST + // PROCESS_TRANS_OK_ST + // PROCESS_TRANS_FAILED_ST NameChangeTransaction::verifyStates(); - // Verify NCT states. This ensures that derivations provide the handlers. + // Verify NameAddTransaction states by attempting to fetch them. getState(ADDING_FWD_ADDRS_ST); getState(REPLACING_FWD_ADDRS_ST); getState(REPLACING_REV_PTRS_ST); @@ -541,7 +555,9 @@ void NameAddTransaction::processAddFailedHandler() { switch(getNextEvent()) { case UPDATE_FAILED_EVT: - LOG_ERROR(dctl_logger, DHCP_DDNS_ADD_FAILED).arg(getNcr()->toText()); + case NO_MORE_SERVERS_EVT: + LOG_ERROR(dctl_logger, DHCP_DDNS_ADD_FAILED).arg(getNcr()->toText()) + .arg(getContextStr()); setNcrStatus(dhcp_ddns::ST_FAILED); endModel(); break; @@ -560,27 +576,28 @@ NameAddTransaction::buildAddFwdAddressRequest() { // Construct dns::Name from NCR fqdn. dns::Name fqdn(dns::Name(getNcr()->getFqdn())); + // Content on this request is based on RFC 4703, section 5.3.1 // First build the Prerequisite Section. - // Create 'FQDN Is Not In Use' prerequisite (RFC 2136, section 2.4.5) - // Add the RR to prerequisite section. + // Create 'FQDN Is Not In Use' prerequisite and add it to the + // prerequisite section. + // Based on RFC 2136, section 2.4.5 dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::NONE(), dns::RRType::ANY(), dns::RRTTL(0))); request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq); // Next build the Update Section. - // Create the FQDN/IP 'add' RR (RFC 2136, section 2.5.1) - // Set the message RData to lease address. - // Add the RR to update section. + // Create the FQDN/IP 'add' RR and add it to the to update section. + // Based on RFC 2136, section 2.5.1 dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::IN(), getAddressRRType(), dns::RRTTL(0))); addLeaseAddressRdata(update); request->addRRset(D2UpdateMessage::SECTION_UPDATE, update); - // Now create the FQDN/DHCID 'add' RR per RFC 4701) - // Set the message RData to DHCID. - // Add the RR to update section. + + // Now create the FQDN/DHCID 'add' RR and add it to update section. + // Based on RFC 2136, section 2.5.1 update.reset(new dns::RRset(fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), dns::RRTTL(0))); addDhcidRdata(update); @@ -598,17 +615,19 @@ NameAddTransaction::buildReplaceFwdAddressRequest() { // Construct dns::Name from NCR fqdn. dns::Name fqdn(dns::Name(getNcr()->getFqdn())); + // Content on this request is based on RFC 4703, section 5.3.2 // First build the Prerequisite Section. - // Create an 'FQDN Is In Use' prerequisite (RFC 2136, section 2.4.4) - // Add it to the pre-requisite section. + // Create an 'FQDN Is In Use' prerequisite and add it to the + // pre-requisite section. + // Based on RFC 2136, section 2.4.4 dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::ANY(), dns::RRType::ANY(), dns::RRTTL(0))); request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq); - // Now create an DHCID matches prerequisite RR. - // Set the RR's RData to DHCID. - // Add it to the pre-requisite section. + // Create an DHCID matches prerequisite RR and add it to the + // pre-requisite section. + // Based on RFC 2136, section 2.4.2. prereq.reset(new dns::RRset(fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), dns::RRTTL(0))); addDhcidRdata(prereq); @@ -616,16 +635,14 @@ NameAddTransaction::buildReplaceFwdAddressRequest() { // Next build the Update Section. - // Create the FQDN/IP 'delete' RR (RFC 2136, section 2.5.1) - // Set the message RData to lease address. - // Add the RR to update section. + // Create the FQDN/IP 'delete' RR and add it to the update section. + // Based on RFC 2136, section 2.5.2 dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::ANY(), getAddressRRType(), dns::RRTTL(0))); request->addRRset(D2UpdateMessage::SECTION_UPDATE, update); - // Create the FQDN/IP 'add' RR (RFC 2136, section 2.5.1) - // Set the message RData to lease address. - // Add the RR to update section. + // Create the FQDN/IP 'add' RR and add it to the update section. + // Based on RFC 2136, section 2.5.1 update.reset(new dns::RRset(fqdn, dns::RRClass::IN(), getAddressRRType(), dns::RRTTL(0))); addLeaseAddressRdata(update); @@ -644,6 +661,7 @@ NameAddTransaction::buildReplaceRevPtrsRequest() { std::string rev_addr = D2CfgMgr::reverseIpAddress(getNcr()->getIpAddress()); dns::Name rev_ip(rev_addr); + // Content on this request is based on RFC 4703, section 5.4 // Reverse replacement has no prerequisites so straight on to // building the Update section. diff --git a/src/bin/d2/nc_add.h b/src/bin/d2/nc_add.h index b5776b45f3..1fe167b99e 100644 --- a/src/bin/d2/nc_add.h +++ b/src/bin/d2/nc_add.h @@ -34,9 +34,10 @@ public: /// @brief Embodies the "life-cycle" required to carry out a DDNS Add update. /// /// NameAddTransaction implements a state machine for adding (or replacing) a -/// forward DNS mapping. This state machine is based upon the processing logic -/// described in RFC 4703, Sections 5.3 and 5.4. That logic may be paraphrased -/// as follows: +/// forward and/or reverse DNS mapping. This state machine is based upon the +/// processing logic described in RFC 4703, Sections 5.3 and 5.4. That logic +/// may be paraphrased as follows: +/// /// @code /// /// If the request includes a forward change: @@ -109,7 +110,8 @@ protected: /// @brief Validates the contents of the set of events. /// /// Invokes NameChangeTransaction's implementation and then verifies the - /// Add transaction's events. + /// Add transaction's. This tests that the needed events are in the event + /// dictionary. /// /// @throw StateModelError if an event value is undefined. virtual void verifyEvents(); @@ -125,7 +127,8 @@ protected: /// @brief Validates the contents of the set of states. /// /// Invokes NameChangeTransaction's implementation and then verifies the - /// Add transaction's states. + /// Add transaction's states. This tests that the needed states are in the + /// state dictionary. /// /// @throw StateModelError if an event value is undefined. virtual void verifyStates(); @@ -166,7 +169,7 @@ protected: /// handler simply attempts to select the next server. /// /// Transitions to: - /// - ADDING_REV_PTRS_ST with next event of SERVER_SELECTED upon successful + /// - ADDING_FWD_ADDRS_ST with next event of SERVER_SELECTED upon successful /// server selection /// /// - PROCESS_TRANS_FAILED with next event of NO_MORE_SERVERS_EVT upon @@ -329,7 +332,7 @@ protected: /// - PROCESS_TRANS_OK_ST with a next event of UPDATE_OK_EVT upon /// successful replacement. /// - /// - PROCESS_TRANS_FAILED_ST with a next event of UPDATE_OK_EVT If the + /// - PROCESS_TRANS_FAILED_ST with a next event of UPDATE_FAILED_EVT If the /// DNS server rejected the update for any reason or the IO completed /// with an unrecognized status. /// @@ -365,8 +368,10 @@ protected: /// @brief State handler for PROCESS_TRANS_FAILED_ST. /// /// Entered from: + /// - SELECTING_FWD_SERVER_ST with a next event of NO_MORE_SERVERS /// - ADDING_FWD_ADDRS_ST with a next event of UPDATE_FAILED_EVT /// - REPLACING_FWD_ADDRS_ST with a next event of UPDATE_FAILED_EVT + /// - SELECTING_REV_SERVER_ST with a next event of NO_MORE_SERVERS /// - REPLACING_REV_PTRS_ST with a next event of UPDATE_FAILED_EVT /// /// Sets the transaction status to indicate failure and ends @@ -438,7 +443,7 @@ protected: void buildReplaceRevPtrsRequest(); }; -/// @brief Defines a pointer to a NameChangeTransaction. +/// @brief Defines a pointer to a NameAddTransaction. typedef boost::shared_ptr NameAddTransactionPtr; } // namespace isc::d2 diff --git a/src/bin/d2/nc_remove.cc b/src/bin/d2/nc_remove.cc new file mode 100644 index 0000000000..d7135bdd9f --- /dev/null +++ b/src/bin/d2/nc_remove.cc @@ -0,0 +1,695 @@ +// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") +// +// 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 +#include +#include + +#include +#include + +namespace isc { +namespace d2 { + + +// NameRemoveTransaction states +const int NameRemoveTransaction::REMOVING_FWD_ADDRS_ST; +const int NameRemoveTransaction::REMOVING_FWD_RRS_ST; +const int NameRemoveTransaction::REMOVING_REV_PTRS_ST; + +// NameRemoveTransaction events +// Currently NameRemoveTransaction does not define any events. + +NameRemoveTransaction:: +NameRemoveTransaction(IOServicePtr& io_service, + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain) + : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain) { + if (ncr->getChangeType() != isc::dhcp_ddns::CHG_REMOVE) { + isc_throw (NameRemoveTransactionError, + "NameRemoveTransaction, request type must be CHG_REMOVE"); + } +} + +NameRemoveTransaction::~NameRemoveTransaction(){ +} + +void +NameRemoveTransaction::defineEvents() { + // Call superclass impl first. + NameChangeTransaction::defineEvents(); + + // Define NameRemoveTransaction events. + // Currently NameRemoveTransaction does not define any events. + // defineEvent(TBD_EVENT, "TBD_EVT"); +} + +void +NameRemoveTransaction::verifyEvents() { + // Call superclass implementation first to verify its events. These are + // events common to all transactions, and they must be defined. + // SELECT_SERVER_EVT + // SERVER_SELECTED_EVT + // SERVER_IO_ERROR_EVT + // NO_MORE_SERVERS_EVT + // IO_COMPLETED_EVT + // UPDATE_OK_EVT + // UPDATE_FAILED_EVT + NameChangeTransaction::verifyEvents(); + + // Verify NameRemoveTransaction events by attempting to fetch them. + // Currently NameRemoveTransaction does not define any events. + // getEvent(TBD_EVENT); +} + +void +NameRemoveTransaction::defineStates() { + // Call superclass impl first. + NameChangeTransaction::defineStates(); + + // Define NameRemoveTransaction states. + defineState(READY_ST, "READY_ST", + boost::bind(&NameRemoveTransaction::readyHandler, this)); + + defineState(SELECTING_FWD_SERVER_ST, "SELECTING_FWD_SERVER_ST", + boost::bind(&NameRemoveTransaction::selectingFwdServerHandler, + this)); + + defineState(SELECTING_REV_SERVER_ST, "SELECTING_REV_SERVER_ST", + boost::bind(&NameRemoveTransaction::selectingRevServerHandler, + this)); + + defineState(REMOVING_FWD_ADDRS_ST, "REMOVING_FWD_ADDRS_ST", + boost::bind(&NameRemoveTransaction::removingFwdAddrsHandler, + this)); + + defineState(REMOVING_FWD_RRS_ST, "REMOVING_FWD_RRS_ST", + boost::bind(&NameRemoveTransaction::removingFwdRRsHandler, + this)); + + defineState(REMOVING_REV_PTRS_ST, "REMOVING_REV_PTRS_ST", + boost::bind(&NameRemoveTransaction::removingRevPtrsHandler, + this)); + + defineState(PROCESS_TRANS_OK_ST, "PROCESS_TRANS_OK_ST", + boost::bind(&NameRemoveTransaction::processRemoveOkHandler, + this)); + + defineState(PROCESS_TRANS_FAILED_ST, "PROCESS_TRANS_FAILED_ST", + boost::bind(&NameRemoveTransaction::processRemoveFailedHandler, + this)); +} + +void +NameRemoveTransaction::verifyStates() { + // Call superclass implementation first to verify its states. These are + // states common to all transactions, and they must be defined. + // READY_ST + // SELECTING_FWD_SERVER_ST + // SELECTING_REV_SERVER_ST + // PROCESS_TRANS_OK_ST + // PROCESS_TRANS_FAILED_ST + NameChangeTransaction::verifyStates(); + + // Verify NameRemoveTransaction states by attempting to fetch them. + getState(REMOVING_FWD_ADDRS_ST); + getState(REMOVING_FWD_RRS_ST); + getState(REMOVING_REV_PTRS_ST); +} + +void +NameRemoveTransaction::readyHandler() { + switch(getNextEvent()) { + case START_EVT: + if (getForwardDomain()) { + // Request includes a forward change, do that first. + transition(SELECTING_FWD_SERVER_ST, SELECT_SERVER_EVT); + } else { + // Reverse change only, transition accordingly. + transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT); + } + + break; + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } +} + +void +NameRemoveTransaction::selectingFwdServerHandler() { + switch(getNextEvent()) { + case SELECT_SERVER_EVT: + // First time through for this transaction, so initialize server + // selection. + initServerSelection(getForwardDomain()); + break; + case SERVER_IO_ERROR_EVT: + // We failed to communicate with current server. Attempt to select + // another one below. + break; + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } + + // Select the next server from the list of forward servers. + if (selectNextServer()) { + // We have a server to try. + transition(REMOVING_FWD_ADDRS_ST, SERVER_SELECTED_EVT); + } + else { + // Server list is exhausted, so fail the transaction. + transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT); + } +} + +void +NameRemoveTransaction::removingFwdAddrsHandler() { + if (doOnEntry()) { + // Clear the request on initial transition. This allows us to reuse + // the request on retries if necessary. + clearDnsUpdateRequest(); + } + + switch(getNextEvent()) { + case SERVER_SELECTED_EVT: + if (!getDnsUpdateRequest()) { + // Request hasn't been constructed yet, so build it. + try { + buildRemoveFwdAddressRequest(); + } catch (const std::exception& ex) { + // While unlikely, the build might fail if we have invalid + // data. Should that be the case, we need to fail the + // transaction. + LOG_ERROR(dctl_logger, + DHCP_DDNS_FORWARD_REMOVE_ADDRS_BUILD_FAILURE) + .arg(getNcr()->toText()) + .arg(ex.what()); + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + break; + } + } + + // Call sendUpdate() to initiate the async send. Note it also sets + // next event to NOP_EVT. + sendUpdate(); + break; + + case IO_COMPLETED_EVT: { + switch (getDnsUpdateStatus()) { + case DNSClient::SUCCESS: { + // We successfully received a response packet from the server. + const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode(); + if ((rcode == dns::Rcode::NOERROR()) || + (rcode == dns::Rcode::NXDOMAIN())) { + // We were able to remove it or it wasn't there, now we + // need to remove any other RRs for this FQDN. + transition(REMOVING_FWD_RRS_ST, UPDATE_OK_EVT); + } else { + // Per RFC4703 any other value means cease. + // If we get not authorized should we try the next server in + // the list? @todo This needs some discussion perhaps. + LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_REJECTED) + .arg(getCurrentServer()->getIpAddress()) + .arg(getNcr()->getFqdn()) + .arg(rcode.getCode()); + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + } + + break; + } + + case DNSClient::TIMEOUT: + case DNSClient::OTHER: + // We couldn't send to the current server, log it and set up + // to select the next server for a retry. + // @note For now we treat OTHER as an IO error like TIMEOUT. It + // is not entirely clear if this is accurate. + LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_IO_ERROR) + .arg(getNcr()->getFqdn()) + .arg(getCurrentServer()->getIpAddress()); + + retryTransition(SELECTING_FWD_SERVER_ST); + break; + + case DNSClient::INVALID_RESPONSE: + // A response was received but was corrupt. Retry it like an IO + // error. + LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_ADDRS_RESP_CORRUPT) + .arg(getCurrentServer()->getIpAddress()) + .arg(getNcr()->getFqdn()); + + retryTransition(SELECTING_FWD_SERVER_ST); + break; + + default: + // Any other value and we will fail this transaction, something + // bigger is wrong. + LOG_ERROR(dctl_logger, + DHCP_DDNS_FORWARD_REMOVE_ADDRS_BAD_DNSCLIENT_STATUS) + .arg(getDnsUpdateStatus()) + .arg(getNcr()->getFqdn()) + .arg(getCurrentServer()->getIpAddress()); + + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + break; + } // end switch on dns_status + + break; + } // end case IO_COMPLETE_EVT + + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } +} + + +void +NameRemoveTransaction::removingFwdRRsHandler() { + if (doOnEntry()) { + // Clear the request on initial transition. This allows us to reuse + // the request on retries if necessary. + clearDnsUpdateRequest(); + } + + switch(getNextEvent()) { + case UPDATE_OK_EVT: + case SERVER_SELECTED_EVT: + if (!getDnsUpdateRequest()) { + // Request hasn't been constructed yet, so build it. + try { + buildRemoveFwdRRsRequest(); + } catch (const std::exception& ex) { + // While unlikely, the build might fail if we have invalid + // data. Should that be the case, we need to fail the + // transaction. + LOG_ERROR(dctl_logger, + DHCP_DDNS_FORWARD_REMOVE_RRS_BUILD_FAILURE) + .arg(getNcr()->toText()) + .arg(ex.what()); + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + break; + } + } + + // Call sendUpdate() to initiate the async send. Note it also sets + // next event to NOP_EVT. + sendUpdate(); + break; + + case IO_COMPLETED_EVT: { + switch (getDnsUpdateStatus()) { + case DNSClient::SUCCESS: { + // We successfully received a response packet from the server. + const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode(); + // @todo Not sure if NXDOMAIN is ok here, but I think so. + // A Rcode of NXDOMAIN would mean there are no RRs for the FQDN, + // which is fine. We were asked to delete them, they are not there + // so all is well. + if ((rcode == dns::Rcode::NOERROR()) || + (rcode == dns::Rcode::NXDOMAIN())) { + // We were able to remove the forward mapping. Mark it as done. + setForwardChangeCompleted(true); + + // If request calls for reverse update then do that next, + // otherwise we can process ok. + if (getReverseDomain()) { + transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT); + } else { + transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT); + } + } else { + // Per RFC4703 any other value means cease. + // If we get not authorized should try the next server in + // the list? @todo This needs some discussion perhaps. + LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_REJECTED) + .arg(getCurrentServer()->getIpAddress()) + .arg(getNcr()->getFqdn()) + .arg(rcode.getCode()); + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + } + + break; + } + + case DNSClient::TIMEOUT: + case DNSClient::OTHER: + // We couldn't send to the current server, log it and set up + // to select the next server for a retry. + // @note For now we treat OTHER as an IO error like TIMEOUT. It + // is not entirely clear if this is accurate. + LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_IO_ERROR) + .arg(getNcr()->getFqdn()) + .arg(getCurrentServer()->getIpAddress()); + + // @note If we exhaust the IO retries for the current server + // due to IO failures, we will abort the remaining updates. + // The rational is that we are only in this state, if the remove + // of the forward address RR succeeded (removingFwdAddrsHandler) + // on the current server. Therefore we should not attempt another + // removal on a different server. This is perhaps a point + // for discussion. + // @todo Should we go ahead with the reverse remove? + retryTransition(PROCESS_TRANS_FAILED_ST); + break; + + case DNSClient::INVALID_RESPONSE: + // A response was received but was corrupt. Retry it like an IO + // error. + LOG_ERROR(dctl_logger, DHCP_DDNS_FORWARD_REMOVE_RRS_RESP_CORRUPT) + .arg(getCurrentServer()->getIpAddress()) + .arg(getNcr()->getFqdn()); + + // If we are out of retries on this server abandon the transaction. + // (Same logic as the case for TIMEOUT above). + retryTransition(PROCESS_TRANS_FAILED_ST); + break; + + default: + // Any other value and we will fail this transaction, something + // bigger is wrong. + LOG_ERROR(dctl_logger, + DHCP_DDNS_FORWARD_REMOVE_RRS_BAD_DNSCLIENT_STATUS) + .arg(getDnsUpdateStatus()) + .arg(getNcr()->getFqdn()) + .arg(getCurrentServer()->getIpAddress()); + + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + break; + } // end switch on dns_status + + break; + } // end case IO_COMPLETE_EVT + + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } +} + + +void +NameRemoveTransaction::selectingRevServerHandler() { + switch(getNextEvent()) { + case SELECT_SERVER_EVT: + // First time through for this transaction, so initialize server + // selection. + initServerSelection(getReverseDomain()); + break; + case SERVER_IO_ERROR_EVT: + // We failed to communicate with current server. Attempt to select + // another one below. + break; + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } + + // Select the next server from the list of forward servers. + if (selectNextServer()) { + // We have a server to try. + transition(REMOVING_REV_PTRS_ST, SERVER_SELECTED_EVT); + } + else { + // Server list is exhausted, so fail the transaction. + transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT); + } +} + + +void +NameRemoveTransaction::removingRevPtrsHandler() { + if (doOnEntry()) { + // Clear the request on initial transition. This allows us to reuse + // the request on retries if necessary. + clearDnsUpdateRequest(); + } + + switch(getNextEvent()) { + case SERVER_SELECTED_EVT: + if (!getDnsUpdateRequest()) { + // Request hasn't been constructed yet, so build it. + try { + buildRemoveRevPtrsRequest(); + } catch (const std::exception& ex) { + // While unlikely, the build might fail if we have invalid + // data. Should that be the case, we need to fail the + // transaction. + LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_BUILD_FAILURE) + .arg(getNcr()->toText()) + .arg(ex.what()); + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + break; + } + } + + // Call sendUpdate() to initiate the async send. Note it also sets + // next event to NOP_EVT. + sendUpdate(); + break; + + case IO_COMPLETED_EVT: { + switch (getDnsUpdateStatus()) { + case DNSClient::SUCCESS: { + // We successfully received a response packet from the server. + const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode(); + if ((rcode == dns::Rcode::NOERROR()) || + (rcode == dns::Rcode::NXDOMAIN())) { + // We were able to update the reverse mapping. Mark it as done. + // @todo For now we are also treating NXDOMAIN as success. + setReverseChangeCompleted(true); + transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT); + } else { + // Per RFC4703 any other value means cease. + // If we get not authorized should try the next server in + // the list? @todo This needs some discussion perhaps. + LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_REJECTED) + .arg(getCurrentServer()->getIpAddress()) + .arg(getNcr()->getFqdn()) + .arg(rcode.getCode()); + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + } + + break; + } + + case DNSClient::TIMEOUT: + case DNSClient::OTHER: + // We couldn't send to the current server, log it and set up + // to select the next server for a retry. + // @note For now we treat OTHER as an IO error like TIMEOUT. It + // is not entirely clear if this is accurate. + LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_IO_ERROR) + .arg(getNcr()->getFqdn()) + .arg(getCurrentServer()->getIpAddress()); + + // If we are out of retries on this server, we go back and start + // all over on a new server. + retryTransition(SELECTING_REV_SERVER_ST); + break; + + case DNSClient::INVALID_RESPONSE: + // A response was received but was corrupt. Retry it like an IO + // error. + LOG_ERROR(dctl_logger, DHCP_DDNS_REVERSE_REMOVE_RESP_CORRUPT) + .arg(getCurrentServer()->getIpAddress()) + .arg(getNcr()->getFqdn()); + + // If we are out of retries on this server, we go back and start + // all over on a new server. + retryTransition(SELECTING_REV_SERVER_ST); + break; + + default: + // Any other value and we will fail this transaction, something + // bigger is wrong. + LOG_ERROR(dctl_logger, + DHCP_DDNS_REVERSE_REMOVE_BAD_DNSCLIENT_STATUS) + .arg(getDnsUpdateStatus()) + .arg(getNcr()->getFqdn()) + .arg(getCurrentServer()->getIpAddress()); + + transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT); + break; + } // end switch on dns_status + + break; + } // end case IO_COMPLETE_EVT + + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } +} + + +void +NameRemoveTransaction::processRemoveOkHandler() { + switch(getNextEvent()) { + case UPDATE_OK_EVT: + LOG_DEBUG(dctl_logger, DBGLVL_TRACE_DETAIL, DHCP_DDNS_REMOVE_SUCCEEDED) + .arg(getNcr()->toText()); + setNcrStatus(dhcp_ddns::ST_COMPLETED); + endModel(); + break; + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } +} + +void +NameRemoveTransaction::processRemoveFailedHandler() { + switch(getNextEvent()) { + case UPDATE_FAILED_EVT: + case NO_MORE_SERVERS_EVT: + case SERVER_IO_ERROR_EVT: + LOG_ERROR(dctl_logger, DHCP_DDNS_REMOVE_FAILED).arg(getNcr()->toText()) + .arg(getEventLabel(getNextEvent())); + setNcrStatus(dhcp_ddns::ST_FAILED); + endModel(); + break; + default: + // Event is invalid. + isc_throw(NameRemoveTransactionError, + "Wrong event for context: " << getContextStr()); + } +} + +void +NameRemoveTransaction::buildRemoveFwdAddressRequest() { + // Construct an empty request. + D2UpdateMessagePtr request = prepNewRequest(getForwardDomain()); + + // Content on this request is based on RFC 4703, section 5.5, paragraph 4. + // Construct dns::Name from NCR fqdn. + dns::Name fqdn(dns::Name(getNcr()->getFqdn())); + // First build the Prerequisite Section + + // Create an DHCID matches prerequisite RR and add it to the + // pre-requisite section + // Based on RFC 2136, section 2.4.2. + dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::IN(), + dns::RRType::DHCID(), dns::RRTTL(0))); + addDhcidRdata(prereq); + request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq); + + // Next build the Update Section + + // Create the FQDN/IP 'delete' RR and add it to the update section. + // Add the RR to update section. + // Based on 2136 section 2.5.4 + dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::NONE(), + getAddressRRType(), dns::RRTTL(0))); + addLeaseAddressRdata(update); + request->addRRset(D2UpdateMessage::SECTION_UPDATE, update); + + // Set the transaction's update request to the new request. + setDnsUpdateRequest(request); +} + +void +NameRemoveTransaction::buildRemoveFwdRRsRequest() { + // Construct an empty request. + D2UpdateMessagePtr request = prepNewRequest(getForwardDomain()); + + // Construct dns::Name from NCR fqdn. + dns::Name fqdn(dns::Name(getNcr()->getFqdn())); + + // Content on this request is based on RFC 4703, section 5.5, paragraph 5. + // First build the Prerequisite Section. + + // Now create an DHCID matches prerequisite RR. + // Set the RR's RData to DHCID. + // Add it to the pre-requisite section. + // Based on RFC 2136, section 2.4.2. + dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::IN(), + dns::RRType::DHCID(), dns::RRTTL(0))); + addDhcidRdata(prereq); + request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq); + + // Create an assertion that there are no A RRs for the FQDN. + // Add it to the pre-reqs. + // Based on RFC 2136, section 2.4.3. + prereq.reset(new dns::RRset(fqdn, dns::RRClass::NONE(), + dns::RRType::A(), dns::RRTTL(0))); + request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq); + + // Create an assertion that there are no A RRs for the FQDN. + // Add it to the pre-reqs. + // Based on RFC 2136, section 2.4.3. + prereq.reset(new dns::RRset(fqdn, dns::RRClass::NONE(), + dns::RRType::AAAA(), dns::RRTTL(0))); + request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq); + + // Next build the Update Section. + + // Create the 'delete' of all RRs for FQDN. + // Set the message RData to lease address. + // Add the RR to update section. + // Based on RFC 2136, section 2.5.3. + dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::ANY(), + dns::RRType::ANY(), dns::RRTTL(0))); + request->addRRset(D2UpdateMessage::SECTION_UPDATE, update); + + // Set the transaction's update request to the new request. + setDnsUpdateRequest(request); +} + +void +NameRemoveTransaction::buildRemoveRevPtrsRequest() { + // Construct an empty request. + D2UpdateMessagePtr request = prepNewRequest(getReverseDomain()); + + // Create the reverse IP address "FQDN". + std::string rev_addr = D2CfgMgr::reverseIpAddress(getNcr()->getIpAddress()); + dns::Name rev_ip(rev_addr); + + // Content on this request is based on RFC 4703, section 5.5, paragraph 2. + // First build the Prerequisite Section. + // (Note that per RFC 4703, section 5.4, there is no need to validate + // DHCID RR for PTR entries.) + + // Create an assertion that the PTRDNAME in the PTR record matches the + // client's FQDN for the address that was released. + // Based on RFC 2136, section 3.2.3 + dns::RRsetPtr prereq(new dns::RRset(rev_ip, dns::RRClass::IN(), + dns::RRType::PTR(), dns::RRTTL(0))); + addPtrRdata(prereq); + request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq); + + // Now, build the Update section. + + // Create a delete of any RRs for the FQDN and add it to update section. + // Based on RFC 2136, section 3.4.2.3 + dns::RRsetPtr update(new dns::RRset(rev_ip, dns::RRClass::ANY(), + dns::RRType::ANY(), dns::RRTTL(0))); + request->addRRset(D2UpdateMessage::SECTION_UPDATE, update); + + // Set the transaction's update request to the new request. + setDnsUpdateRequest(request); +} + +} // namespace isc::d2 +} // namespace isc diff --git a/src/bin/d2/nc_remove.h b/src/bin/d2/nc_remove.h new file mode 100644 index 0000000000..f7b0dcc081 --- /dev/null +++ b/src/bin/d2/nc_remove.h @@ -0,0 +1,435 @@ +// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") +// +// 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. + +#ifndef NC_REMOVE_H +#define NC_REMOVE_H + +/// @file nc_remove.h This file defines the class NameRemoveTransaction. + +#include + +namespace isc { +namespace d2 { + +/// @brief Thrown if the NameRemoveTransaction encounters a general error. +class NameRemoveTransactionError : public isc::Exception { +public: + NameRemoveTransactionError(const char* file, size_t line, + const char* what) : + isc::Exception(file, line, what) { }; +}; + +/// @brief Embodies the "life-cycle" required to carry out a DDNS Remove update. +/// +/// NameRemoveTransaction implements a state machine for removing a forward +/// and/or reverse DNS mappings. This state machine is based upon the processing +/// logic described in RFC 4703, Section 5.5. That logic may be paraphrased as +/// follows: +/// +/// @code +/// +/// If the request includes a forward change: +/// Select a forward server +/// Send the server a request to remove client's specific forward address RR +/// If it succeeds or the server responds with name no longer in use +/// Send a server a request to delete any other RRs for that FQDN, such +/// as the DHCID RR. +/// otherwise +/// abandon the update +/// +/// If the request includes a reverse change: +/// Select a reverse server +/// Send a server a request to delete reverse entry (PTR RR) +/// +/// @endcode +/// +/// This class derives from NameChangeTransaction from which it inherits +/// states, events, and methods common to NameChangeRequest processing. +class NameRemoveTransaction : public NameChangeTransaction { +public: + + //@{ Additional states needed for NameRemove state model. + /// @brief State that attempts to remove specific forward address record. + static const int REMOVING_FWD_ADDRS_ST = NCT_DERIVED_STATE_MIN + 1; + + /// @brief State that attempts to remove any other forward RRs for the DHCID + static const int REMOVING_FWD_RRS_ST = NCT_DERIVED_STATE_MIN + 2; + + /// @brief State that attempts to remove reverse PTR records + static const int REMOVING_REV_PTRS_ST = NCT_DERIVED_STATE_MIN + 3; + //@} + + //@{ Additional events needed for NameRemove state model. + /// @brief Event sent when replace attempt to fails with address not in use. + /// @todo Currently none have been identified. + //@} + + /// @brief Constructor + /// + /// Instantiates an Remove transaction that is ready to be started. + /// + /// @param io_service IO service to be used for IO processing + /// @param ncr is the NameChangeRequest to fulfill + /// @param forward_domain is the domain to use for forward DNS updates + /// @param reverse_domain is the domain to use for reverse DNS updates + /// + /// @throw NameRemoveTransaction error if given request is not a CHG_REMOVE, + /// NameChangeTransaction error for base class construction errors. + NameRemoveTransaction(IOServicePtr& io_service, + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain); + + /// @brief Destructor + virtual ~NameRemoveTransaction(); + +protected: + /// @brief Adds events defined by NameRemoveTransaction to the event set. + /// + /// Invokes NameChangeTransaction's implementation and then defines the + /// events unique to NCR Remove transaction processing. + /// + /// @throw StateModelError if an event definition is invalid or a duplicate. + virtual void defineEvents(); + + /// @brief Validates the contents of the set of events. + /// + /// Invokes NameChangeTransaction's implementation and then verifies the + /// Remove transaction's events. This tests that the needed events are in + /// the event dictionary. + /// + /// @throw StateModelError if an event value is undefined. + virtual void verifyEvents(); + + /// @brief Adds states defined by NameRemoveTransaction to the state set. + /// + /// Invokes NameChangeTransaction's implementation and then defines the + /// states unique to NCR Remove transaction processing. + /// + /// @throw StateModelError if an state definition is invalid or a duplicate. + virtual void defineStates(); + + /// @brief Validates the contents of the set of states. + /// + /// Invokes NameChangeTransaction's implementation and then verifies the + /// Remove transaction's states. This tests that the needed states are in + /// the state dictionary. + /// + /// @throw StateModelError if an event value is undefined. + virtual void verifyStates(); + + /// @brief State handler for READY_ST. + /// + /// Entered from: + /// - INIT_ST with next event of START_EVT + /// + /// The READY_ST is the state the model transitions into when the inherited + /// method, startTransaction() is invoked. This handler, therefore, is the + /// entry point into the state model execution. Its primary task is to + /// determine whether to start with a forward DNS change or a reverse DNS + /// change. + /// + /// Transitions to: + /// - SELECTING_FWD_SERVER_ST with next event of SERVER_SELECT_ST if request + /// includes a forward change. + /// + /// - SELECTING_REV_SERVER_ST with next event of SERVER_SELECT_ST if request + /// includes only a reverse change. + /// + /// @throw NameRemoveTransactionError if upon entry next event is not + /// START_EVT. + void readyHandler(); + + /// @brief State handler for SELECTING_FWD_SERVER_ST. + /// + /// Entered from: + /// - READY_ST with next event of SELECT_SERVER_EVT + /// - REMOVING_FWD_ADDRS_ST with next event of SERVER_IO_ERROR_EVT + /// + /// Selects the server to be used from the forward domain for the forward + /// DNS update. If next event is SELECT_SERVER_EVT the handler initializes + /// the forward domain's server selection mechanism and then attempts to + /// select the next server. If next event is SERVER_IO_ERROR_EVT then the + /// handler simply attempts to select the next server. + /// + /// Transitions to: + /// - REMOVING_FWD_ADDRS_ST with next event of SERVER_SELECTED upon + /// successful server selection + /// + /// - PROCESS_TRANS_FAILED with next event of NO_MORE_SERVERS_EVT upon + /// failure to select a server + /// + /// @throw NameRemoveTransactionError if upon entry next event is not + /// SELECT_SERVER_EVT or SERVER_IO_ERROR_EVT. + void selectingFwdServerHandler(); + + /// @brief State handler for SELECTING_REV_SERVER_ST. + /// + /// Entered from: + /// - READY_ST with next event of SELECT_SERVER_EVT + /// - REMOVING_FWD_RRS_ST with next event of SELECT_SERVER_EVT + /// - REMOVING_REV_PTRS_ST with next event of SERVER_IO_ERROR_EVT + /// + /// Selects the server to be used from the reverse domain for the reverse + /// DNS update. If next event is SELECT_SERVER_EVT the handler initializes + /// the reverse domain's server selection mechanism and then attempts to + /// select the next server. If next event is SERVER_IO_ERROR_EVT then the + /// handler simply attempts to select the next server. + /// + /// Transitions to: + /// - REMOVING_REV_PTRS_ST with next event of SERVER_SELECTED upon + /// successful server selection + /// + /// - PROCESS_TRANS_FAILED with next event of NO_MORE_SERVERS_EVT upon + /// failure to select a server + /// + /// @throw NameRemoveTransactionError if upon entry next event is not + /// SELECT_SERVER_EVT or SERVER_IO_ERROR_EVT. + void selectingRevServerHandler(); + + /// @brief State handler for REMOVING_FWD_ADDRS_ST. + /// + /// Entered from: + /// - SELECTING_FWD_SERVER with next event of SERVER_SELECTED_EVT + /// + /// Attempts to remove the forward DNS entry for a given FQDN, provided + /// a DHCID RR exists which matches the requesting DHCID. If this is + /// first invocation of the handler after transitioning into this state, + /// any previous update request context is deleted. If next event + /// is SERVER_SELECTED_EVT, the handler builds the forward remove request, + /// schedules an asynchronous send via sendUpdate(), and returns. Note + /// that sendUpdate will post NOP_EVT as next event. + /// + /// Posting the NOP_EVT will cause runModel() to suspend execution of + /// the state model thus affecting a "wait" for the update IO to complete. + /// Update completion occurs via the DNSClient callback operator() method + /// inherited from NameChangeTransaction. When invoked this callback will + /// post a next event of IO_COMPLETED_EVT and then invoke runModel which + /// resumes execution of the state model. + /// + /// When the handler is invoked with a next event of IO_COMPELTED_EVT, + /// the DNS update status is checked and acted upon accordingly: + /// + /// Transitions to: + /// - REMOVING_FWD_RRS_ST with next event of UPDATE_OK_EVT upon successful + /// removal or RCODE of indication FQDN is no longer in use (NXDOMAIN). + /// + /// - PROCESS_TRANS_FAILED_ST with next event of UPDATE_FAILED_EVT if the + /// DNS server rejected the update for any reason or the IO completed + /// with an unrecognized status. + /// + /// - RE-ENTER this state with next event of SERVER_SELECTED_EVT if + /// there was an IO error communicating with the server and the number of + /// per server retries has not been exhausted. + /// + /// - SELECTING_FWD_SERVER_ST with next event of SERVER_IO_ERROR_EVT if + /// there was an IO error communicating with the server and the number of + /// per server retries has been exhausted. + /// + /// @throw NameRemoveTransactionError if upon entry next event is not + /// SERVER_SELECTED_EVT or IO_COMPLETE_EVT + void removingFwdAddrsHandler(); + + /// @brief State handler for REMOVING_FWD_RRS_ST. + /// + /// Entered from: + /// - REMOVING_FWD_ADDRS_ST with next event of UPDATE_OK_EVT + /// + /// Attempts to delete any remaining RRs associated with the given FQDN + /// such as the DHCID RR. If this is first invocation of the handler after + /// transitioning into this state, any previous update request context is + /// deleted and the handler builds the forward remove request. It then + /// schedules an asynchronous send via sendUpdate(), + /// and returns. Note that sendUpdate will post NOP_EVT as the next event. + /// + /// Posting the NOP_EVT will cause runModel() to suspend execution of + /// the state model thus affecting a "wait" for the update IO to complete. + /// Update completion occurs via the DNSClient callback operator() method + /// inherited from NameChangeTransaction. When invoked this callback will + /// post a next event of IO_COMPLETED_EVT and then invoke runModel which + /// resumes execution of the state model. + /// + /// When the handler is invoked with a next event of IO_COMPELTED_EVT, + /// the DNS update status is checked and acted upon accordingly: + /// + /// Transitions to: + /// - SELECTING_REV_SERVER_ST with a next event of SELECT_SERVER_EVT upon + /// successful completion and the request includes a reverse DNS update. + /// + /// - PROCESS_TRANS_OK_ST with next event of UPDATE_OK_EVT upon successful + /// completion and the request does not include a reverse DNS update. + /// + /// - PROCESS_TRANS_FAILED_ST with a next event of UPDATE_FAILED_EVT if the + /// DNS server rejected the update for any other reason or the IO completed + /// with an unrecognized status. + /// + /// - RE-ENTER this state with a next event of SERVER_SELECTED_EVT if + /// there was an IO error communicating with the server and the number of + /// per server retries has not been exhausted. + /// + /// - PROCESS_TRANS_FAILED_ST with a next event of SERVER_IO_ERROR_EVT if + /// there we have reached maximum number of retries without success on the + /// current server. + /// + /// @note If we exhaust the IO retries for the current server due to IO + /// failures, we will abort the remaining updates. The rational is that + /// we are only in this state, if the remove of the forward address RR + /// succeeded (removingFwdAddrsHandler) on the current server so we should + /// not attempt another removal on a different server. This is perhaps a + /// point for discussion. @todo Should we go ahead with the reverse remove? + /// + /// @throw NameRemoveTransactionError if upon entry next event is not: + /// UPDATE_OK_EVT or IO_COMPLETE_EVT + void removingFwdRRsHandler(); + + /// @brief State handler for REMOVING_REV_PTRS_ST. + /// + /// Entered from: + /// - SELECTING_REV_SERVER_ST with a next event of SERVER_SELECTED_EVT + /// + /// Attempts to delete a reverse DNS entry for a given FQDN. If this is + /// first invocation of the handler after transitioning into this state, + /// any previous update request context is deleted. If next event is + /// SERVER_SELECTED_EVT, the handler builds the reverse remove request, + /// schedules an asynchronous send via sendUpdate(), and then returns. + /// Note that sendUpdate will post NOP_EVT as next event. + /// + /// Posting the NOP_EVT will cause runModel() to suspend execution of + /// the state model thus affecting a "wait" for the update IO to complete. + /// Update completion occurs via the DNSClient callback operator() method + /// inherited from NameChangeTransaction. When invoked this callback will + /// post a next event of IO_COMPLETED_EVT and then invoke runModel which + /// resumes execution of the state model. + /// + /// When the handler is invoked with a next event of IO_COMPELTED_EVT, + /// the DNS update status is checked and acted upon accordingly: + /// + /// Transitions to: + /// - PROCESS_TRANS_OK_ST with a next event of UPDATE_OK_EVT upon + /// successful completion. + /// + /// - PROCESS_TRANS_FAILED_ST with a next event of UPDATE_FAILED_EVT If the + /// DNS server rejected the update for any reason or the IO completed + /// with an unrecognized status. + /// + /// - RE-ENTER this state with a next event of SERVER_SELECTED_EVT if + /// there was an IO error communicating with the server and the number of + /// per server retries has not been exhausted. + /// + /// - SELECTING_REV_SERVER_ST with next event of SERVER_IO_ERROR_EVT if + /// there was an IO error communicating with the server and the number of + /// per server retries has been exhausted. + /// + /// @throw NameRemoveTransactionError if upon entry next event is not: + /// SERVER_SELECTED_EVT or IO_COMPLETED_EVT + void removingRevPtrsHandler(); + + /// @brief State handler for PROCESS_TRANS_OK_ST. + /// + /// Entered from: + /// - REMOVING_FWD_RRS_ST with a next event of UPDATE_OK_EVT + /// - REMOVING_REV_PTRS_ST with a next event of UPDATE_OK_EVT + /// + /// Sets the transaction action status to indicate success and ends + /// model execution. + /// + /// Transitions to: + /// - END_ST with a next event of END_EVT. + /// + /// @throw NameRemoveTransactionError if upon entry next event is not: + /// UPDATE_OK_EVT + void processRemoveOkHandler(); + + /// @brief State handler for PROCESS_TRANS_FAILED_ST. + /// + /// Entered from: + /// - SELECTING_FWD_SERVER_ST with a next event of NO_MORE_SERVERS + /// - REMOVING_FWD_ADDRS_ST with a next event of UPDATE_FAILED_EVT + /// - REMOVING_FWD_RRS_ST with a next event of UPDATE_FAILED_EVT + /// - REMOVING_FWD_RRS_ST with a next event of SERVER_IO_ERROR_EVT + /// - SELECTING_REV_SERVER_ST with a next event of NO_MORE_SERVERS + /// - REMOVING_REV_PTRS_ST with a next event of UPDATE_FAILED_EVT + /// + /// Sets the transaction status to indicate failure and ends + /// model execution. + /// + /// Transitions to: + /// - END_ST with a next event of FAIL_EVT. + /// + /// @throw NameRemoveTransactionError if upon entry next event is not: + /// UPDATE_FAILED_EVT + void processRemoveFailedHandler(); + + /// @brief Builds a DNS request to remove a forward DNS address for a FQDN. + /// + /// Constructs a DNS update request, based upon the NCR, for removing a + /// forward DNS address mapping. Once constructed, the request is stored as + /// the transaction's DNS update request. + /// + /// The request content is adherent to RFC 4703 section 5.5, paragraph 4. + /// + /// Prerequisite RRsets: + /// 1. An assertion that a matching DHCID RR exists + /// + /// Updates RRsets: + /// 1. A delete of the FQDN/IP RR (type A for IPv4, AAAA for IPv6) + /// + /// @throw This method does not throw but underlying methods may. + void buildRemoveFwdAddressRequest(); + + /// @brief Builds a DNS request to remove all forward DNS RRs for a FQDN. + /// + /// Constructs a DNS update request, based upon the NCR, for removing any + /// remaining forward DNS RRs, once all A or AAAA entries for the FQDN + /// have been removed. Once constructed, the request is stored as the + /// transaction's DNS update request. + /// + /// The request content is adherent to RFC 4703 section 5.5, paragraph 5. + /// + /// Prerequisite RRsets: + /// 1. An assertion that a matching DHCID RR exists + /// 2. An assertion that no A RRs for the FQDN exist + /// 3. An assertion that no AAAA RRs for the FQDN exist + /// + /// Updates RRsets: + /// 1. A delete of all RRs for the FQDN + /// + /// @throw This method does not throw but underlying methods may. + void buildRemoveFwdRRsRequest(); + + /// @brief Builds a DNS request to remove a reverse DNS entry for a FQDN + /// + /// Constructs a DNS update request, based upon the NCR, for removing a + /// reverse DNS mapping. Once constructed, the request is stored as + /// the transaction's DNS update request. + /// + /// The request content is adherent to RFC 4703 section 5.5, paragraph 2: + /// + /// Prerequisite RRsets: + /// 1. An assertion that a PTR record matching the client's FQDN exists. + /// + /// Updates RRsets: + /// 1. A delete of all RRs for the FQDN + /// + /// @throw This method does not throw but underlying methods may. + void buildRemoveRevPtrsRequest(); +}; + +/// @brief Defines a pointer to a NameRemoveTransaction. +typedef boost::shared_ptr NameRemoveTransactionPtr; + + +} // namespace isc::d2 +} // namespace isc +#endif diff --git a/src/bin/d2/nc_trans.cc b/src/bin/d2/nc_trans.cc index 3c604d24e1..1ad9b9371f 100644 --- a/src/bin/d2/nc_trans.cc +++ b/src/bin/d2/nc_trans.cc @@ -14,6 +14,7 @@ #include #include +#include namespace isc { namespace d2 { @@ -181,14 +182,14 @@ NameChangeTransaction::onModelFailure(const std::string& explanation) { } void -NameChangeTransaction::retryTransition(const int server_sel_state) { +NameChangeTransaction::retryTransition(const int fail_to_state) { if (update_attempts_ < MAX_UPDATE_TRIES_PER_SERVER) { // Re-enter the current state with same server selected. transition(getCurrState(), SERVER_SELECTED_EVT); } else { - // Transition to given server selection state if we are out + // Transition to given fail_to_state state if we are out // of retries. - transition(server_sel_state, SERVER_IO_ERROR_EVT); + transition(fail_to_state, SERVER_IO_ERROR_EVT); } } @@ -262,13 +263,13 @@ NameChangeTransaction::addLeaseAddressRdata(dns::RRsetPtr& rrset) { try { // Manufacture an RData from the lease address then add it to the RR. + dns::rdata::ConstRdataPtr rdata; if (ncr_->isV4()) { - dns::rdata::in::A a_rdata(ncr_->getIpAddress()); - rrset->addRdata(a_rdata); + rdata.reset(new dns::rdata::in::A(ncr_->getIpAddress())); } else { - dns::rdata::in::AAAA rdata(ncr_->getIpAddress()); - rrset->addRdata(rdata); + rdata.reset(new dns::rdata::in::AAAA(ncr_->getIpAddress())); } + rrset->addRdata(rdata); } catch (const std::exception& ex) { isc_throw(NameChangeTransactionError, "Cannot add address rdata: " << ex.what()); @@ -285,12 +286,14 @@ NameChangeTransaction::addDhcidRdata(dns::RRsetPtr& rrset) { try { const std::vector& ncr_dhcid = ncr_->getDhcid().getBytes(); util::InputBuffer buffer(ncr_dhcid.data(), ncr_dhcid.size()); - dns::rdata::in::DHCID rdata(buffer, ncr_dhcid.size()); + dns::rdata::ConstRdataPtr rdata (new dns::rdata::in:: + DHCID(buffer, ncr_dhcid.size())); rrset->addRdata(rdata); } catch (const std::exception& ex) { isc_throw(NameChangeTransactionError, "Cannot add DCHID rdata: " << ex.what()); } + } void @@ -301,7 +304,8 @@ NameChangeTransaction::addPtrRdata(dns::RRsetPtr& rrset) { } try { - dns::rdata::generic::PTR rdata(getNcr()->getFqdn()); + dns::rdata::ConstRdataPtr rdata(new dns::rdata::generic:: + PTR(getNcr()->getFqdn())); rrset->addRdata(rdata); } catch (const std::exception& ex) { isc_throw(NameChangeTransactionError, "Cannot add PTR rdata: " @@ -412,7 +416,7 @@ NameChangeTransaction::getUpdateAttempts() const { const dns::RRType& NameChangeTransaction::getAddressRRType() const { - return (ncr_->isV4() ? dns::RRType::A(): dns::RRType::AAAA()); + return (ncr_->isV4() ? dns::RRType::A() : dns::RRType::AAAA()); } } // namespace isc::d2 diff --git a/src/bin/d2/nc_trans.h b/src/bin/d2/nc_trans.h index b0f7c4a747..86a89d7198 100644 --- a/src/bin/d2/nc_trans.h +++ b/src/bin/d2/nc_trans.h @@ -277,10 +277,10 @@ protected: /// If the maximum number of attempts has been reached, it will transition /// to the given state with a next event of SERVER_IO_ERROR_EVT. /// - /// @param server_sel_state State to transition to if maximum attempts + /// @param fail_to_state State to transition to if maximum attempts /// have been tried. /// - void retryTransition(const int server_sel_state); + void retryTransition(const int fail_to_state); /// @brief Sets the update request packet to the given packet. /// @@ -435,13 +435,13 @@ public: /// @brief Fetches the forward DdnsDomain. /// - /// @return A pointer reference to the forward DdnsDomain. If + /// @return A pointer reference to the forward DdnsDomain. If /// the request does not include a forward change, the pointer will empty. DdnsDomainPtr& getForwardDomain(); /// @brief Fetches the reverse DdnsDomain. /// - /// @return A pointer reference to the reverse DdnsDomain. If + /// @return A pointer reference to the reverse DdnsDomain. If /// the request does not include a reverse change, the pointer will empty. DdnsDomainPtr& getReverseDomain(); diff --git a/src/bin/d2/tests/Makefile.am b/src/bin/d2/tests/Makefile.am index d860ccc785..8b5e3519cc 100644 --- a/src/bin/d2/tests/Makefile.am +++ b/src/bin/d2/tests/Makefile.am @@ -67,6 +67,7 @@ d2_unittests_SOURCES += ../d2_zone.cc ../d2_zone.h d2_unittests_SOURCES += ../dns_client.cc ../dns_client.h d2_unittests_SOURCES += ../labeled_value.cc ../labeled_value.h d2_unittests_SOURCES += ../nc_add.cc ../nc_add.h +d2_unittests_SOURCES += ../nc_remove.cc ../nc_remove.h d2_unittests_SOURCES += ../nc_trans.cc ../nc_trans.h d2_unittests_SOURCES += ../state_model.cc ../state_model.h d2_unittests_SOURCES += d_test_stubs.cc d_test_stubs.h @@ -83,6 +84,7 @@ d2_unittests_SOURCES += d2_zone_unittests.cc d2_unittests_SOURCES += dns_client_unittests.cc d2_unittests_SOURCES += labeled_value_unittests.cc d2_unittests_SOURCES += nc_add_unittests.cc +d2_unittests_SOURCES += nc_remove_unittests.cc d2_unittests_SOURCES += nc_test_utils.cc nc_test_utils.h d2_unittests_SOURCES += nc_trans_unittests.cc d2_unittests_SOURCES += state_model_unittests.cc diff --git a/src/bin/d2/tests/nc_add_unittests.cc b/src/bin/d2/tests/nc_add_unittests.cc index c291a54944..9aecda40fe 100644 --- a/src/bin/d2/tests/nc_add_unittests.cc +++ b/src/bin/d2/tests/nc_add_unittests.cc @@ -407,14 +407,14 @@ TEST_F(NameAddTransactionTest, buildForwardAdd) { NameAddStubPtr name_add; ASSERT_NO_THROW(name_add = makeTransaction4()); ASSERT_NO_THROW(name_add->buildAddFwdAddressRequest()); - checkForwardAddRequest(*name_add); + checkAddFwdAddressRequest(*name_add); // 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()); - checkForwardAddRequest(*name_add); + checkAddFwdAddressRequest(*name_add); } /// @brief Tests construction of a DNS update request for replacing a forward @@ -426,14 +426,14 @@ TEST_F(NameAddTransactionTest, buildReplaceFwdAddressRequest) { NameAddStubPtr name_add; ASSERT_NO_THROW(name_add = makeTransaction4()); ASSERT_NO_THROW(name_add->buildReplaceFwdAddressRequest()); - checkForwardReplaceRequest(*name_add); + checkReplaceFwdAddressRequest(*name_add); // 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()); - checkForwardReplaceRequest(*name_add); + checkReplaceFwdAddressRequest(*name_add); } /// @brief Tests the construction of a DNS update request for replacing a @@ -445,14 +445,14 @@ TEST_F(NameAddTransactionTest, buildReplaceRevPtrsRequest) { NameAddStubPtr name_add; ASSERT_NO_THROW(name_add = makeTransaction4()); ASSERT_NO_THROW(name_add->buildReplaceRevPtrsRequest()); - checkReverseReplaceRequest(*name_add); + checkReplaceRevPtrsRequest(*name_add); // 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()); - checkReverseReplaceRequest(*name_add); + checkReplaceRevPtrsRequest(*name_add); } // Tests the readyHandler functionality. @@ -632,7 +632,7 @@ TEST_F(NameAddTransactionTest, addingFwdAddrsHandler_FwdOnlyAddOK) { EXPECT_NO_THROW(name_add->addingFwdAddrsHandler()); // Verify that an update message was constructed properly. - checkForwardAddRequest(*name_add); + checkAddFwdAddressRequest(*name_add); // 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. @@ -943,7 +943,7 @@ TEST_F(NameAddTransactionTest, replacingFwdAddrsHandler_FwdOnlyAddOK) { EXPECT_NO_THROW(name_add->replacingFwdAddrsHandler()); // Verify that an update message was constructed properly. - checkForwardReplaceRequest(*name_add); + checkReplaceFwdAddressRequest(*name_add); // 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. @@ -1366,7 +1366,7 @@ TEST_F(NameAddTransactionTest, replacingRevPtrsHandler_FwdOnlyAddOK) { EXPECT_NO_THROW(name_add->replacingRevPtrsHandler()); // Verify that an update message was constructed properly. - checkReverseReplaceRequest(*name_add); + checkReplaceRevPtrsRequest(*name_add); // 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. @@ -1419,8 +1419,7 @@ TEST_F(NameAddTransactionTest, replacingRevPtrsHandler_OtherRcode) { name_add->fakeResponse(DNSClient::SUCCESS, dns::Rcode::REFUSED()); // Run replacingRevPtrsHandler again to process the response. - //EXPECT_NO_THROW(name_add->replacingRevPtrsHandler()); - (name_add->replacingRevPtrsHandler()); + EXPECT_NO_THROW(name_add->replacingRevPtrsHandler()); // Completion flags should still be false. EXPECT_FALSE(name_add->getForwardChangeCompleted()); @@ -1634,6 +1633,29 @@ TEST_F(NameAddTransactionTest, processAddFailedHandler) { EXPECT_THROW(name_add->processAddFailedHandler(), NameAddTransactionError); } +// Tests the processAddFailedHandler functionality. +// It verifies behavior for posted event of NO_MORE_SERVERS_EVT. +TEST_F(NameAddTransactionTest, processAddFailedHandler_NoMoreServers) { + NameAddStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + PROCESS_TRANS_FAILED_ST, + NameChangeTransaction:: + NO_MORE_SERVERS_EVT)); + + // Run processAddFailedHandler. + EXPECT_NO_THROW(name_remove->processAddFailedHandler()); + + // Verify that a server was selected. + EXPECT_EQ(dhcp_ddns::ST_FAILED, name_remove->getNcrStatus()); + + // Verify that the model has ended. (Remember, the transaction failed NOT + // the model. The model should have ended normally.) + EXPECT_EQ(StateModel::END_ST, name_remove->getCurrState()); + EXPECT_EQ(StateModel::END_EVT, name_remove->getNextEvent()); +} + // Tests addingFwdAddrsHandler with the following scenario: // // The request includes only a forward change. diff --git a/src/bin/d2/tests/nc_remove_unittests.cc b/src/bin/d2/tests/nc_remove_unittests.cc new file mode 100644 index 0000000000..37efad6ac2 --- /dev/null +++ b/src/bin/d2/tests/nc_remove_unittests.cc @@ -0,0 +1,1872 @@ +// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") +// +// 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 +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace isc; +using namespace isc::d2; + +namespace { + +/// @brief Test class derived from NameRemoveTransaction to provide visiblity +// to protected methods. +class NameRemoveStub : public NameRemoveTransaction { +public: + NameRemoveStub(IOServicePtr& io_service, + dhcp_ddns::NameChangeRequestPtr& ncr, + DdnsDomainPtr& forward_domain, + DdnsDomainPtr& reverse_domain) + : NameRemoveTransaction(io_service, ncr, forward_domain, + reverse_domain), + simulate_send_exception_(false), + simulate_build_request_exception_(false) { + } + + virtual ~NameRemoveStub() { + } + + /// @brief Simulates sending update requests to the DNS server + /// + /// 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. + /// + /// @param use_tsig_ Parameter is unused, but present in the base class + /// method. + /// + virtual void sendUpdate(bool /* use_tsig_ = false */) { + 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. + setUpdateAttempts(getUpdateAttempts() + 1); + postNextEvent(StateModel::NOP_EVT); + } + + /// @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 (NameRemoveTransactionError, + "Simulated build requests exception"); + } + + return (NameChangeTransaction::prepNewRequest(domain)); + } + + /// @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 + /// fully exercised without requiring any actual IO. The two primary + /// 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 + void fakeResponse(const DNSClient::Status& status, + const dns::Rcode& rcode) { + // Set the DNS update status. This is normally set in + // DNSClient IO completion handler. + setDnsUpdateStatus(status); + + // Construct an empty message with the given Rcode. + D2UpdateMessagePtr msg(new D2UpdateMessage(D2UpdateMessage::OUTBOUND)); + msg->setRcode(rcode); + + // Set the update response to the message. + setDnsUpdateResponse(msg); + + // Post the IO completion event. + postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT); + } + + /// @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. + bool selectFwdServer() { + if (getForwardDomain()) { + initServerSelection(getForwardDomain()); + selectNextServer(); + return (getCurrentServer()); + } + + return (false); + } + + /// @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. + bool selectRevServer() { + if (getReverseDomain()) { + initServerSelection(getReverseDomain()); + selectNextServer(); + return (getCurrentServer()); + } + + return (false); + } + + /// @brief One-shot flag which will simulate sendUpdate failure if true. + bool simulate_send_exception_; + + /// @brief One-shot flag which will simulate an exception when sendUpdate + /// failure if true. + bool simulate_build_request_exception_; + + using StateModel::postNextEvent; + using StateModel::setState; + using StateModel::initDictionaries; + using NameRemoveTransaction::defineEvents; + using NameRemoveTransaction::verifyEvents; + using NameRemoveTransaction::defineStates; + using NameRemoveTransaction::verifyStates; + using NameRemoveTransaction::readyHandler; + using NameRemoveTransaction::selectingFwdServerHandler; + using NameRemoveTransaction::getCurrentServer; + using NameRemoveTransaction::removingFwdAddrsHandler; + using NameRemoveTransaction::setDnsUpdateStatus; + using NameRemoveTransaction::removingFwdRRsHandler; + using NameRemoveTransaction::selectingRevServerHandler; + using NameRemoveTransaction::removingRevPtrsHandler; + using NameRemoveTransaction::processRemoveOkHandler; + using NameRemoveTransaction::processRemoveFailedHandler; + using NameRemoveTransaction::buildRemoveFwdAddressRequest; + using NameRemoveTransaction::buildRemoveFwdRRsRequest; + using NameRemoveTransaction::buildRemoveRevPtrsRequest; +}; + +typedef boost::shared_ptr NameRemoveStubPtr; + +/// @brief Test fixture for testing NameRemoveTransaction +/// +/// Note this class uses NameRemoveStub class to exercise non-public +/// aspects of NameRemoveTransaction. +class NameRemoveTransactionTest : public TransactionTest { +public: + NameRemoveTransactionTest() { + } + + virtual ~NameRemoveTransactionTest() { + } + + /// @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 + /// 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 + NameRemoveStubPtr makeTransaction4(int change_mask) { + // Creates IPv4 remove request, forward, and reverse domains. + setupForIPv4Transaction(dhcp_ddns::CHG_REMOVE, change_mask); + + // Now create the test transaction as would occur in update manager. + return (NameRemoveStubPtr(new NameRemoveStub(io_service_, ncr_, + forward_domain_, + reverse_domain_))); + } + + /// @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 + NameRemoveStubPtr makeTransaction6(int change_mask) { + // Creates IPv6 remove request, forward, and reverse domains. + setupForIPv6Transaction(dhcp_ddns::CHG_REMOVE, change_mask); + + // Now create the test transaction as would occur in update manager. + return (NameRemoveStubPtr(new NameRemoveStub(io_service_, ncr_, + forward_domain_, + reverse_domain_))); + } + + /// @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 + /// through prerequisite states. It also provides the ability to set + /// 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 + /// @param family selects between an IPv4 (AF_INET) and IPv6 (AF_INET6) + /// transaction. + NameRemoveStubPtr prepHandlerTest(unsigned int state, unsigned int event, + unsigned int change_mask + = FWD_AND_REV_CHG, + short family = AF_INET) { + NameRemoveStubPtr name_remove = (family == AF_INET ? + makeTransaction4(change_mask) : + makeTransaction6(change_mask)); + name_remove->initDictionaries(); + name_remove->postNextEvent(event); + name_remove->setState(state); + return (name_remove); + } + +}; + +/// @brief Tests NameRemoveTransaction construction. +/// This test verifies that: +/// 1. Construction with invalid type of request +/// 2. Valid construction functions properly +TEST(NameRemoveTransaction, construction) { + IOServicePtr io_service(new isc::asiolink::IOService()); + + const char* msg_str = + "{" + " \"change_type\" : 0 , " + " \"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)); + ASSERT_NO_THROW(forward_domain.reset(new DdnsDomain("*", "", servers))); + ASSERT_NO_THROW(reverse_domain.reset(new DdnsDomain("*", "", servers))); + + // Verify that construction with wrong change type fails. + EXPECT_THROW(NameRemoveTransaction(io_service, ncr, + forward_domain, reverse_domain), + NameRemoveTransactionError); + + // Verify that a valid construction attempt works. + ncr->setChangeType(isc::dhcp_ddns::CHG_REMOVE); + EXPECT_NO_THROW(NameRemoveTransaction(io_service, ncr, + forward_domain, reverse_domain)); +} + +/// @brief Tests event and state dictionary construction and verification. +TEST_F(NameRemoveTransactionTest, dictionaryCheck) { + NameRemoveStubPtr name_remove; + ASSERT_NO_THROW(name_remove = makeTransaction4(FWD_AND_REV_CHG)); + // Verify that the event and state dictionary validation fails prior + // dictionary construction. + ASSERT_THROW(name_remove->verifyEvents(), StateModelError); + ASSERT_THROW(name_remove->verifyStates(), StateModelError); + + // Construct both dictionaries. + ASSERT_NO_THROW(name_remove->defineEvents()); + ASSERT_NO_THROW(name_remove->defineStates()); + + // Verify both event and state dictionaries now pass validation. + ASSERT_NO_THROW(name_remove->verifyEvents()); + ASSERT_NO_THROW(name_remove->verifyStates()); +} + + +/// @brief Tests construction of a DNS update request for removing forward +/// DNS address RRs. +TEST_F(NameRemoveTransactionTest, buildRemoveFwdAddressRequest) { + // Create a IPv4 forward add transaction. + // Verify the request builds without error. + // and then verify the request contents. + NameRemoveStubPtr name_remove; + ASSERT_NO_THROW(name_remove = makeTransaction4(FORWARD_CHG)); + ASSERT_NO_THROW(name_remove->buildRemoveFwdAddressRequest()); + checkRemoveFwdAddressRequest(*name_remove); + + // Create a IPv6 forward add transaction. + // Verify the request builds without error. + // and then verify the request contents. + ASSERT_NO_THROW(name_remove = makeTransaction6(FORWARD_CHG)); + ASSERT_NO_THROW(name_remove->buildRemoveFwdAddressRequest()); + checkRemoveFwdAddressRequest(*name_remove); +} + +/// @brief Tests construction of a DNS update request for removing forward +/// dns RR entries. +TEST_F(NameRemoveTransactionTest, buildRemoveFwdRRsRequest) { + // Create a IPv4 forward replace transaction. + // Verify the request builds without error. + // and then verify the request contents. + NameRemoveStubPtr name_remove; + ASSERT_NO_THROW(name_remove = makeTransaction4(FORWARD_CHG)); + ASSERT_NO_THROW(name_remove->buildRemoveFwdRRsRequest()); + checkRemoveFwdRRsRequest(*name_remove); + + // Create a IPv6 forward replace transaction. + // Verify the request builds without error. + // and then verify the request contents. + ASSERT_NO_THROW(name_remove = makeTransaction6(FORWARD_CHG)); + ASSERT_NO_THROW(name_remove->buildRemoveFwdRRsRequest()); + checkRemoveFwdRRsRequest(*name_remove); +} + +/// @brief Tests the construction of a DNS update request for removing a +/// reverse dns entry. +TEST_F(NameRemoveTransactionTest, buildRemoveRevPtrsRequest) { + // Create a IPv4 reverse replace transaction. + // Verify the request builds without error. + // and then verify the request contents. + NameRemoveStubPtr name_remove; + ASSERT_NO_THROW(name_remove = makeTransaction4(REVERSE_CHG)); + ASSERT_NO_THROW(name_remove->buildRemoveRevPtrsRequest()); + checkRemoveRevPtrsRequest(*name_remove); + + // Create a IPv6 reverse replace transaction. + // Verify the request builds without error. + // and then verify the request contents. + ASSERT_NO_THROW(name_remove = makeTransaction6(REVERSE_CHG)); + ASSERT_NO_THROW(name_remove->buildRemoveRevPtrsRequest()); + checkRemoveRevPtrsRequest(*name_remove); +} + +// Tests the readyHandler functionality. +// It verifies behavior for the following scenarios: +// +// 1. Posted event is START_EVT and request includes only a forward change +// 2. Posted event is START_EVT and request includes both a forward and a +// reverse change +// 3. Posted event is START_EVT and request includes only a reverse change +// 4. Posted event is invalid +// +TEST_F(NameRemoveTransactionTest, readyHandler) { + NameRemoveStubPtr name_remove; + + // Create a transaction which includes only a forward change. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction::READY_ST, + StateModel::START_EVT, FORWARD_CHG)); + // Run readyHandler. + EXPECT_NO_THROW(name_remove->readyHandler()); + + // Verify that a request requiring only a forward change, transitions to + // selecting a forward server. + EXPECT_EQ(NameChangeTransaction::SELECTING_FWD_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT, + name_remove->getNextEvent()); + + // Create a transaction which includes both a forward and a reverse change. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction::READY_ST, + StateModel::START_EVT, FWD_AND_REV_CHG)); + // Run readyHandler. + EXPECT_NO_THROW(name_remove->readyHandler()); + + // Verify that a request requiring both forward and reverse, starts with + // the forward change by transitioning to selecting a forward server. + EXPECT_EQ(NameChangeTransaction::SELECTING_FWD_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT, + name_remove->getNextEvent()); + + // Create and prep a reverse only transaction. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction::READY_ST, + StateModel::START_EVT, REVERSE_CHG)); + // Run readyHandler. + EXPECT_NO_THROW(name_remove->readyHandler()); + + // Verify that a request requiring only a reverse change, transitions to + // selecting a reverse server. + EXPECT_EQ(NameChangeTransaction::SELECTING_REV_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT, + name_remove->getNextEvent()); + + // Create and prep transaction, poised to run the handler but with an + // invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction::READY_ST, + StateModel::NOP_EVT)); + + // Running the readyHandler should throw. + EXPECT_THROW(name_remove->readyHandler(), NameRemoveTransactionError); +} + + +// Tests the selectingFwdServerHandler functionality. +// It verifies behavior for the following scenarios: +// +// 1. Posted event is SELECT_SERVER_EVT +// 2. Posted event is SERVER_IO_ERROR_EVT +// 3. Posted event is invalid +// +TEST_F(NameRemoveTransactionTest, selectingFwdServerHandler) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + SELECTING_FWD_SERVER_ST, + NameChangeTransaction::SELECT_SERVER_EVT)); + + // 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_remove->getForwardDomain()->getServers()->size(); + for (int i = 0; i < num_servers; ++i) { + // Run selectingFwdServerHandler. + ASSERT_NO_THROW(name_remove->selectingFwdServerHandler()) + << " num_servers: " << num_servers + << " selections: " << i; + + // Verify that a server was selected. + ASSERT_TRUE(name_remove->getCurrentServer()) + << " num_servers: " << num_servers << " selections: " << i; + + // Verify that we transitioned correctly. + ASSERT_EQ(NameRemoveTransaction::REMOVING_FWD_ADDRS_ST, + name_remove->getCurrState()) + << " num_servers: " << num_servers << " selections: " << i; + ASSERT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()) + << " num_servers: " << num_servers << " selections: " << i; + + // Post a server IO error event. This simulates an IO error occuring + // and a need to select the new server. + ASSERT_NO_THROW(name_remove->postNextEvent(NameChangeTransaction:: + SERVER_IO_ERROR_EVT)) + << " num_servers: " << num_servers + << " selections: " << i; + } + + // We should have exhausted the list of servers. Processing another + // SERVER_IO_ERROR_EVT should transition us to failure. + EXPECT_NO_THROW(name_remove->selectingFwdServerHandler()); + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::NO_MORE_SERVERS_EVT, + name_remove->getNextEvent()); + + // Create and prep transaction, poised to run the handler but with an + // invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + SELECTING_FWD_SERVER_ST, + StateModel::NOP_EVT)); + + // Running the handler should throw. + EXPECT_THROW(name_remove->selectingFwdServerHandler(), + NameRemoveTransactionError); +} + +// ************************ addingFwdAddrHandler Tests ***************** + +// Tests that removingFwdAddrsHandler rejects invalid events. +TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_InvalidEvent) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler but with + // an invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + StateModel::NOP_EVT)); + + // Running the handler should throw. + EXPECT_THROW(name_remove->removingFwdAddrsHandler(), + NameRemoveTransactionError); +} + + +// Tests addingFwdAddrsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent without error. +// A server response is received which indicates successful update +// +TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_FwdOnlyOK) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + // Should not be an update message yet. + D2UpdateMessagePtr update_msg = name_remove->getDnsUpdateRequest(); + ASSERT_FALSE(update_msg); + + // At this point completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Run removingFwdAddrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Verify that an update message was constructed properly. + checkRemoveFwdAddressRequest(*name_remove); + + // 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. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_ADDRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::NOP_EVT, + name_remove->getNextEvent()); + + // Simulate receiving a successful update response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR()); + + // Run removingFwdAddrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Completion flags should both still be false, as we are only partly + // done with forward updates. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since we succeeded, we should now attempt to remove any remaining + // forward RRs. + // Verify that we transitioned correctly. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_RRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameRemoveTransaction::UPDATE_OK_EVT, + name_remove->getNextEvent()); +} + +// Tests addingFwdAddrsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent without error. +// A server response is received which indicates FQDN is not in use. +// +TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_FqdnNotInUse) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + // Run removingFwdAddrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Simulate receiving a FQDN not in use response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NXDOMAIN()); + + // Run removingFwdAddrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Completion flags should both still be false, as we are only partly + // done with forward updates. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // There was no address RR to remove, but we will still make sure there + // are no other RRs for this FQDN. + // Verify that we transitioned correctly. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_RRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameRemoveTransaction::UPDATE_OK_EVT, + name_remove->getNextEvent()); +} + + +// Tests removingFwdAddrsHandler with the following scenario: +// +// The request includes a forward and reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent without error. +// A server response is received which indicates the update was rejected. +// +TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_OtherRcode) { + NameRemoveStubPtr name_remove; + + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectFwdServer()); + + // Run removingFwdAddrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Simulate receiving server rejection response. Per RFC, anything other + // than no error or FQDN not in use is failure. Arbitrarily choosing + // refused. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::REFUSED()); + + // Run removingFwdAddrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Completion flags should still be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // We should have failed the transaction. Verify that we transitioned + // correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + + +// Tests removingFwdAddrsHandler with the following scenario: +// +// The request includes a forward and reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request send times out MAX_UPDATE_TRIES_PER_SERVER times. +// +TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_Timeout) { + NameRemoveStubPtr name_remove; + + // Create and prep a transaction, poised to run the handler. + // The log message issued when this test succeeds, displays the + // selected server, so we need to select a server before running this + // test. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectFwdServer()); + + // Verify that we can make maximum number of update attempts permitted + // and then transition to selecting a new server. + int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER; + for (int i = 1; i <= max_tries; ++i) { + const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest(); + + // Run removingFwdAddrsHandler to send the request. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest(); + if (i == 1) { + // First time around we should build the message. + EXPECT_FALSE(prev_msg); + EXPECT_TRUE(curr_msg); + } else { + // 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. + EXPECT_TRUE(prev_msg == curr_msg); + } + + // Simulate a server IO timeout. + name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT); + name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT); + + // Run removingFwdAddrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + if (i < max_tries) { + // We should be ready to try again. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_ADDRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()); + } else { + // Server retries should be exhausted, time for a new server. + EXPECT_EQ(NameRemoveTransaction::SELECTING_FWD_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT, + name_remove->getNextEvent()); + } + } +} + +// Tests removingFwdAddrsHandler with the following scenario: +// +// The request includes a forward and reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent but a corrupt response is received, this occurs +// MAX_UPDATE_TRIES_PER_SERVER times. +// +TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_InvalidResponse) { + NameRemoveStubPtr name_remove; + + // Create and prep a transaction, poised to run the handler. + // The log message issued when this test succeeds, displays the + // selected server, so we need to select a server before running this + // test. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectFwdServer()); + + // Verify that we can make maximum number of update attempts permitted + // and then transition to selecting a new server. + int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER; + for (int i = 1; i <= max_tries; ++i) { + // Run removingFwdAddrsHandler to construct send the request. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Simulate a corrupt server response. + name_remove->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE); + name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT); + + // Run removingFwdAddrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + if (i < max_tries) { + // We should be ready to try again. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_ADDRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()); + } else { + // Server retries should be exhausted, time for a new server. + EXPECT_EQ(NameRemoveTransaction::SELECTING_FWD_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT, + name_remove->getNextEvent()); + } + } + +} + +// ************************ removingFwdRRsHandler Tests ***************** + +// Tests that removingFwdRRsHandler rejects invalid events. +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_InvalidEvent) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler but with + // an invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_RRS_ST, + StateModel::NOP_EVT)); + + // Running the handler should throw. + EXPECT_THROW(name_remove->removingFwdRRsHandler(), + NameRemoveTransactionError); +} + +// Tests removingFwdRRsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is UPDATE_OK_EVT. +// The update request is sent without error. +// A server response is received which indicates successful update. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_FwdOnlyOK) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + UPDATE_OK_EVT, FORWARD_CHG)); + + // Should not be an update message yet. + D2UpdateMessagePtr update_msg = name_remove->getDnsUpdateRequest(); + ASSERT_FALSE(update_msg); + + // At this point completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Run removingFwdRRsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Verify that an update message was constructed properly. + checkRemoveFwdRRsRequest(*name_remove); + + // 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. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_ADDRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::NOP_EVT, + name_remove->getNextEvent()); + + // Simulate receiving a successful update response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR()); + + // Run removingFwdRRsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Forward completion should be true, reverse should be false. + EXPECT_TRUE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since it is a forward only change, we should be done. + // Verify that we transitioned correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT, + name_remove->getNextEvent()); +} + +// Tests removingFwdRRsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent without error. +// A server response is received which indicates successful update. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_FwdOnlyOK2) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + // Run removingFwdRRsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Simulate receiving a successful update response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR()); + + // Run removingFwdRRsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Forward completion should be true, reverse should be false. + EXPECT_TRUE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since it is a forward only change, we should be done. + // Verify that we transitioned correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT, + name_remove->getNextEvent()); +} + + +// Tests removingFwdRRsHandler with the following scenario: +// +// The request includes a forward and reverse change. +// Initial posted event is UPDATE_OK_EVT. +// The update request is sent without error. +// A server response is received which indicates successful update. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_FwdAndRevOK) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + UPDATE_OK_EVT, FWD_AND_REV_CHG)); + + // Run removingFwdRRsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Simulate receiving a successful update response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR()); + + // Run removingFwdRRsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Forward change completion should be true, reverse flag should be false. + EXPECT_TRUE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since the request also includes a reverse change we should + // be poised to start it. Verify that we transitioned correctly. + EXPECT_EQ(NameChangeTransaction::SELECTING_REV_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SELECT_SERVER_EVT, + name_remove->getNextEvent()); +} + +// Tests removingFwdAddrsHandler with the following scenario: +// +// The request includes a forward and reverse change. +// Initial posted event is UPDATE_OK_EVT. +// The update request is sent without error. +// A server response is received which indicates the FQDN is NOT in use. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_FqdnNotInUse) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + UPDATE_OK_EVT, FORWARD_CHG)); + + // Run removingFwdRRsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Simulate receiving a FQDN not in use response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NXDOMAIN()); + + // Run removingFwdRRsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Forwad completion flag should be true, reverse should still be false. + EXPECT_TRUE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // The FQDN is no longer in use, RFC is unclear about this, + // but we will treat this as success. + // Since it is a forward only change, we should be done. + // Verify that we transitioned correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT, + name_remove->getNextEvent()); +} + +// Tests removingFwdRRsHandler with the following scenario: +// +// 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. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_OtherRcode) { + NameRemoveStubPtr name_remove; + // Create the transaction. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + UPDATE_OK_EVT, FWD_AND_REV_CHG)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectFwdServer()); + + // Run removingFwdRRsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Simulate receiving server rejection response. Per RFC, anything other + // than no error is failure (we are also treating FQDN not in use is + // success). Arbitrarily choosing refused. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::REFUSED()); + + // Run removingFwdRRsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Completion flags should still be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // We should have failed the transaction. Verifiy that we transitioned + // correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + +// Tests removingFwdRRsHandler with the following scenario: +// +// The request includes a forward and reverse change. +// Initial posted event is UPDATE_OK_EVT. +// The update request send times out MAX_UPDATE_TRIES_PER_SERVER times. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_Timeout) { + NameRemoveStubPtr name_remove; + + // Create the transaction. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_RRS_ST, + NameChangeTransaction:: + UPDATE_OK_EVT, FWD_AND_REV_CHG)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectFwdServer()); + + // Verify that we can make maximum number of update attempts permitted + // and then transition to selecting a new server. + int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER; + for (int i = 1; i <= max_tries; ++i) { + const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest(); + + // Run removingFwdRRsHandler to send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest(); + if (i == 1) { + // First time around we should build the message. + EXPECT_FALSE(prev_msg); + EXPECT_TRUE(curr_msg); + } else { + // 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. + EXPECT_TRUE(prev_msg == curr_msg); + } + + // Simulate a server IO timeout. + name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT); + name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT); + + // Run removingFwdRRsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + if (i < max_tries) { + // We should be ready to try again. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_RRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()); + } else { + // Server retries should be exhausted. + // We should abandon the transaction. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT, + name_remove->getNextEvent()); + } + } +} + +// Tests removingFwdRRsHandler with the following scenario: +// +// The request includes a forward and reverse change. +// Initial posted event is UPDATE_OK_EVT. +// The update request is sent but a corrupt response is received, this occurs +// MAX_UPDATE_TRIES_PER_SERVER times. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_InvalidResponse) { + NameRemoveStubPtr name_remove; + + // Create the transaction. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_RRS_ST, + NameChangeTransaction:: + UPDATE_OK_EVT, FWD_AND_REV_CHG)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectFwdServer()); + + // Verify that we can make maximum number of update attempts permitted + // and then transition to selecting a new server. + int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER; + for (int i = 1; i <= max_tries; ++i) { + const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest(); + + // Run removingFwdRRsHandler to send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest(); + if (i == 1) { + // First time around we should build the message. + EXPECT_FALSE(prev_msg); + EXPECT_TRUE(curr_msg); + } else { + // 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. + EXPECT_TRUE(prev_msg == curr_msg); + } + + // Simulate a corrupt server response. + name_remove->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE); + name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT); + + // Run removingFwdRRsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + if (i < max_tries) { + // We should be ready to try again. + EXPECT_EQ(NameRemoveTransaction::REMOVING_FWD_RRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()); + } else { + // Server retries should be exhausted. + // We should abandon the transaction. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT, + name_remove->getNextEvent()); + } + } +} + + +// Tests the selectingRevServerHandler functionality. +// It verifies behavior for the following scenarios: +// +// 1. Posted event is SELECT_SERVER_EVT +// 2. Posted event is SERVER_IO_ERROR_EVT +// 3. Posted event is invalid +// +TEST_F(NameRemoveTransactionTest, selectingRevServerHandler) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + SELECTING_REV_SERVER_ST, + NameChangeTransaction::SELECT_SERVER_EVT)); + + // Call selectingRevServerHandler 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_remove->getReverseDomain()->getServers()->size(); + for (int i = 0; i < num_servers; ++i) { + // Run selectingRevServerHandler. + ASSERT_NO_THROW(name_remove->selectingRevServerHandler()) + << " num_servers: " << num_servers + << " selections: " << i; + + // Verify that a server was selected. + ASSERT_TRUE(name_remove->getCurrentServer()) + << " num_servers: " << num_servers + << " selections: " << i; + + // Verify that we transitioned correctly. + ASSERT_EQ(NameRemoveTransaction::REMOVING_REV_PTRS_ST, + name_remove->getCurrState()) + << " num_servers: " << num_servers << " selections: " << i; + ASSERT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()) + << " num_servers: " << num_servers << " selections: " << i; + + // Post a server IO error event. This simulates an IO error occuring + // and a need to select the new server. + ASSERT_NO_THROW(name_remove->postNextEvent(NameChangeTransaction:: + SERVER_IO_ERROR_EVT)) + << " num_servers: " << num_servers + << " selections: " << i; + } + + // We should have exhausted the list of servers. Processing another + // SERVER_IO_ERROR_EVT should transition us to failure. + EXPECT_NO_THROW(name_remove->selectingRevServerHandler()); + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::NO_MORE_SERVERS_EVT, + name_remove->getNextEvent()); + + // Create and prep transaction, poised to run the handler but with an + // invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + SELECTING_REV_SERVER_ST, + StateModel::NOP_EVT)); + + // Running the handler should throw. + EXPECT_THROW(name_remove->selectingRevServerHandler(), + NameRemoveTransactionError); +} + +//************************** removingRevPtrsHandler tests ***************** + +// Tests that removingRevPtrsHandler rejects invalid events. +TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_InvalidEvent) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler but with + // an invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + StateModel::NOP_EVT)); + + // Running the handler should throw. + EXPECT_THROW(name_remove->removingRevPtrsHandler(), + NameRemoveTransactionError); +} + +// Tests removingRevPtrsHandler with the following scenario: +// +// The request includes only a reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent without error. +// A server response is received which indicates successful update. +// +TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_RevOnlyOK) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, REVERSE_CHG)); + + // Should not be an update message yet. + D2UpdateMessagePtr update_msg = name_remove->getDnsUpdateRequest(); + ASSERT_FALSE(update_msg); + + // At this point completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Run removingRevPtrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Verify that an update message was constructed properly. + checkRemoveRevPtrsRequest(*name_remove); + + // 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. + EXPECT_EQ(NameRemoveTransaction::REMOVING_REV_PTRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(StateModel::NOP_EVT, + name_remove->getNextEvent()); + + // Simulate receiving a successful update response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NOERROR()); + + // Run removingRevPtrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Forward completion should be false, reverse should be true. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_TRUE(name_remove->getReverseChangeCompleted()); + + // Since it is a reverse change, we should be done. + // Verify that we transitioned correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT, + name_remove->getNextEvent()); +} + +// Tests removingRevPtrsHandler with the following scenario: +// +// The request includes only a reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent without error. +// A server response is received which indicates FQDN is NOT in use. +// +TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_FqdnNotInUse) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, REVERSE_CHG)); + + // Should not be an update message yet. + D2UpdateMessagePtr update_msg = name_remove->getDnsUpdateRequest(); + ASSERT_FALSE(update_msg); + + // At this point completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Run removingRevPtrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Verify that an update message was constructed properly. + checkRemoveRevPtrsRequest(*name_remove); + + // 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. + EXPECT_EQ(NameRemoveTransaction::REMOVING_REV_PTRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(StateModel::NOP_EVT, + name_remove->getNextEvent()); + + // Simulate receiving a FQDN not in use response. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::NXDOMAIN()); + + // Run removingRevPtrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Forward completion should be false, reverse should be true. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_TRUE(name_remove->getReverseChangeCompleted()); + + // Since it is a reverse change, we should be done. + // Verify that we transitioned correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT, + name_remove->getNextEvent()); +} + +// Tests removingRevPtrsHandler with the following scenario: +// +// The request includes only a reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent without error. +// A server response is received which indicates the update was rejected. +// +TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_OtherRcode) { + NameRemoveStubPtr name_remove; + // Create the transaction. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, REVERSE_CHG)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectRevServer()); + + // Run removingRevPtrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Simulate receiving server rejection response. Per RFC, anything other + // than no error is failure. Arbitrarily choosing refused. + name_remove->fakeResponse(DNSClient::SUCCESS, dns::Rcode::REFUSED()); + + // Run removingRevPtrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Completion flags should still be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // We should have failed the transaction. Verify that we transitioned + // correctly. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + +// Tests removingRevPtrsHandler with the following scenario: +// +// The request includes only a reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request send times out MAX_UPDATE_TRIES_PER_SERVER times. +// +TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_Timeout) { + NameRemoveStubPtr name_remove; + // Create the transaction. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, REVERSE_CHG)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectRevServer()); + + // Verify that we can make maximum number of update attempts permitted + // and then transition to selecting a new server. + int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER; + for (int i = 1; i <= max_tries; ++i) { + const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest(); + + // Run removingRevPtrsHandler to send the request. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest(); + if (i == 1) { + // First time around we should build the message. + EXPECT_FALSE(prev_msg); + EXPECT_TRUE(curr_msg); + } else { + // 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. + EXPECT_TRUE(prev_msg == curr_msg); + } + + // Simulate a server IO timeout. + name_remove->setDnsUpdateStatus(DNSClient::TIMEOUT); + name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT); + + // Run removingRevPtrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + if (i < max_tries) { + // We should be ready to try again. + EXPECT_EQ(NameRemoveTransaction::REMOVING_REV_PTRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()); + } else { + // Server retries should be exhausted, time for a new server. + EXPECT_EQ(NameChangeTransaction::SELECTING_REV_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT, + name_remove->getNextEvent()); + } + } +} + + +// Tests removingRevPtrsHandler with the following scenario: +// +// The request includes only a reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The update request is sent but a corrupt response is received, this occurs +// MAX_UPDATE_TRIES_PER_SERVER times. +// +TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_CorruptResponse) { + NameRemoveStubPtr name_remove; + // Create the transaction. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, REVERSE_CHG)); + + // Select a server to satisfy log statements. + ASSERT_TRUE(name_remove->selectRevServer()); + + // Verify that we can make maximum number of update attempts permitted + // and then transition to selecting a new server. + int max_tries = NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER; + for (int i = 1; i <= max_tries; ++i) { + const D2UpdateMessagePtr prev_msg = name_remove->getDnsUpdateRequest(); + + // Run removingRevPtrsHandler to send the request. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + const D2UpdateMessagePtr curr_msg = name_remove->getDnsUpdateRequest(); + if (i == 1) { + // First time around we should build the message. + EXPECT_FALSE(prev_msg); + EXPECT_TRUE(curr_msg); + } else { + // 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. + EXPECT_TRUE(prev_msg == curr_msg); + } + + // Simulate a server corrupt response. + name_remove->setDnsUpdateStatus(DNSClient::INVALID_RESPONSE); + name_remove->postNextEvent(NameChangeTransaction::IO_COMPLETED_EVT); + + // Run removingRevPtrsHandler again to process the response. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + if (i < max_tries) { + // We should be ready to try again. + EXPECT_EQ(NameRemoveTransaction::REMOVING_REV_PTRS_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT, + name_remove->getNextEvent()); + } else { + // Server retries should be exhausted, time for a new server. + EXPECT_EQ(NameChangeTransaction::SELECTING_REV_SERVER_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT, + name_remove->getNextEvent()); + } + } +} + +// Tests the processRemoveOkHandler functionality. +// It verifies behavior for the following scenarios: +// +// 1. Posted event is UPDATE_OK_EVT +// 2. Posted event is invalid +// +TEST_F(NameRemoveTransactionTest, processRemoveOkHandler) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction::PROCESS_TRANS_OK_ST, + NameChangeTransaction::UPDATE_OK_EVT)); + // Run processRemoveOkHandler. + EXPECT_NO_THROW(name_remove->processRemoveOkHandler()); + + // Verify that a server was selected. + EXPECT_EQ(dhcp_ddns::ST_COMPLETED, name_remove->getNcrStatus()); + + // Verify that the model has ended. + EXPECT_EQ(StateModel::END_ST, name_remove->getCurrState()); + EXPECT_EQ(StateModel::END_EVT, name_remove->getNextEvent()); + + + // Create and prep transaction, poised to run the handler but with an + // invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction::PROCESS_TRANS_OK_ST, + StateModel::NOP_EVT)); + // Running the handler should throw. + EXPECT_THROW(name_remove->processRemoveOkHandler(), + NameRemoveTransactionError); +} + +// Tests the processRemoveFailedHandler functionality. +// It verifies behavior for the following scenarios: +// +// 1. Posted event is UPDATE_FAILED_EVT +// 2. Posted event is invalid +// +TEST_F(NameRemoveTransactionTest, processRemoveFailedHandler) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + PROCESS_TRANS_FAILED_ST, + NameChangeTransaction::UPDATE_FAILED_EVT)); + // Run processRemoveFailedHandler. + EXPECT_NO_THROW(name_remove->processRemoveFailedHandler()); + + // Verify that a server was selected. + EXPECT_EQ(dhcp_ddns::ST_FAILED, name_remove->getNcrStatus()); + + // Verify that the model has ended. (Remember, the transaction failed NOT + // the model. The model should have ended normally.) + EXPECT_EQ(StateModel::END_ST, name_remove->getCurrState()); + EXPECT_EQ(StateModel::END_EVT, name_remove->getNextEvent()); + + + // Create and prep transaction, poised to run the handler but with an + // invalid event. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + PROCESS_TRANS_FAILED_ST, + StateModel::NOP_EVT)); + // Running the handler should throw. + EXPECT_THROW(name_remove->processRemoveFailedHandler(), + NameRemoveTransactionError); +} + +// Tests the processRemoveFailedHandler functionality. +// It verifies behavior for posted event of NO_MORE_SERVERS_EVT. +TEST_F(NameRemoveTransactionTest, processRemoveFailedHandler_NoMoreServers) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + PROCESS_TRANS_FAILED_ST, + NameChangeTransaction:: + NO_MORE_SERVERS_EVT)); + + // Run processRemoveFailedHandler. + EXPECT_NO_THROW(name_remove->processRemoveFailedHandler()); + + // Verify that a server was selected. + EXPECT_EQ(dhcp_ddns::ST_FAILED, name_remove->getNcrStatus()); + + // Verify that the model has ended. (Remember, the transaction failed NOT + // the model. The model should have ended normally.) + EXPECT_EQ(StateModel::END_ST, name_remove->getCurrState()); + EXPECT_EQ(StateModel::END_EVT, name_remove->getNextEvent()); +} + +// Tests the processRemoveFailedHandler functionality. +// It verifies behavior for posted event of SERVER_IO_ERROR_EVT. +TEST_F(NameRemoveTransactionTest, processRemoveFailedHandler_ServerIOError) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameChangeTransaction:: + PROCESS_TRANS_FAILED_ST, + NameChangeTransaction:: + SERVER_IO_ERROR_EVT)); + + // Run processRemoveFailedHandler. + EXPECT_NO_THROW(name_remove->processRemoveFailedHandler()); + + // Verify that a server was selected. + EXPECT_EQ(dhcp_ddns::ST_FAILED, name_remove->getNcrStatus()); + + // Verify that the model has ended. (Remember, the transaction failed NOT + // the model. The model should have ended normally.) + EXPECT_EQ(StateModel::END_ST, name_remove->getCurrState()); + EXPECT_EQ(StateModel::END_EVT, name_remove->getNextEvent()); +} + +// Tests removingFwdAddrsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The send update request fails due to an unexpected exception. +// +TEST_F(NameRemoveTransactionTest, removingFwdAddrsHandler_sendUpdateException) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + name_remove->simulate_send_exception_ = true; + + // Run removingFwdAddrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since IO exceptions should be gracefully handled, any that occur + // are unanticipated, and deemed unrecoverable, so the transaction should + // be transitioned to failure. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + + +// Tests removingFwdRRsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The send update request fails due to an unexpected exception. +// +TEST_F(NameRemoveTransactionTest, removingFwdRRsHandler_SendUpdateException) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_RRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + name_remove->simulate_send_exception_ = true; + + // Run removingFwdRRsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since IO exceptions should be gracefully handled, any that occur + // are unanticipated, and deemed unrecoverable, so the transaction should + // be transitioned to failure. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + +// Tests removingRevPtrHandler with the following scenario: +// +// The request includes only a reverse change. +// Initial posted event is SERVER_SELECTED_EVT. +// The send update request fails due to an unexpected exception. +// +TEST_F(NameRemoveTransactionTest, removingRevPtrsHandler_SendUpdateException) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, REVERSE_CHG)); + + name_remove->simulate_send_exception_ = true; + + // Run removingRevPtrsHandler to construct and send the request. + EXPECT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since IO exceptions should be gracefully handled, any that occur + // are unanticipated, and deemed unrecoverable, so the transaction should + // be transitioned to failure. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + +// Tests removingFwdAddrsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The request build fails due to an unexpected exception. +// +TEST_F(NameRemoveTransactionTest, + removingFwdAddrsHandler_BuildRequestException) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_ADDRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + // Set the one-shot exception simulation flag. + name_remove->simulate_build_request_exception_ = true; + + // Run removingFwdAddrsHandler to construct and send the request. + // This should fail with a build request throw which should be caught + // in the state handler. + ASSERT_NO_THROW(name_remove->removingFwdAddrsHandler()); + + // Verify we did not attempt to send anything. + EXPECT_EQ(0, name_remove->getUpdateAttempts()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since IO exceptions should be gracefully handled, any that occur + // are unanticipated, and deemed unrecoverable, so the transaction should + // be transitioned to failure. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + +// Tests removingFwdRRsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The request build fails due to an unexpected exception. +// +TEST_F(NameRemoveTransactionTest, + removingFwdRRsHandler_BuildRequestException) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_FWD_RRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + // Set the one-shot exception simulation flag. + name_remove->simulate_build_request_exception_ = true; + + // Run removingFwdRRsHandler to construct and send the request. + // This should fail with a build request throw which should be caught + // in the state handler. + ASSERT_NO_THROW(name_remove->removingFwdRRsHandler()); + + // Verify we did not attempt to send anything. + EXPECT_EQ(0, name_remove->getUpdateAttempts()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since IO exceptions should be gracefully handled, any that occur + // are unanticipated, and deemed unrecoverable, so the transaction should + // be transitioned to failure. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + +// Tests removingRevPTRsHandler with the following scenario: +// +// The request includes only a forward change. +// Initial posted event is SERVER_SELECTED_EVT. +// The request build fails due to an unexpected exception. +// +TEST_F(NameRemoveTransactionTest, + removingRevPTRsHandler_BuildRequestException) { + NameRemoveStubPtr name_remove; + // Create and prep a transaction, poised to run the handler. + ASSERT_NO_THROW(name_remove = + prepHandlerTest(NameRemoveTransaction:: + REMOVING_REV_PTRS_ST, + NameChangeTransaction:: + SERVER_SELECTED_EVT, FORWARD_CHG)); + + // Set the one-shot exception simulation flag. + name_remove->simulate_build_request_exception_ = true; + + // Run removingRevPtrsHandler to construct and send the request. + // This should fail with a build request throw which should be caught + // in the state handler. + ASSERT_NO_THROW(name_remove->removingRevPtrsHandler()); + + // Verify we did not attempt to send anything. + EXPECT_EQ(0, name_remove->getUpdateAttempts()); + + // Completion flags should be false. + EXPECT_FALSE(name_remove->getForwardChangeCompleted()); + EXPECT_FALSE(name_remove->getReverseChangeCompleted()); + + // Since IO exceptions should be gracefully handled, any that occur + // are unanticipated, and deemed unrecoverable, so the transaction should + // be transitioned to failure. + EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST, + name_remove->getCurrState()); + EXPECT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT, + name_remove->getNextEvent()); +} + +} diff --git a/src/bin/d2/tests/nc_test_utils.cc b/src/bin/d2/tests/nc_test_utils.cc index 2df18e9a79..bebc06c034 100644 --- a/src/bin/d2/tests/nc_test_utils.cc +++ b/src/bin/d2/tests/nc_test_utils.cc @@ -29,6 +29,11 @@ namespace d2 { const char* TEST_DNS_SERVER_IP = "127.0.0.1"; size_t TEST_DNS_SERVER_PORT = 5301; +const bool HAS_RDATA = true; +const bool NO_RDATA = false; + +//*************************** FauxServer class *********************** + FauxServer::FauxServer(asiolink::IOService& io_service, asiolink::IOAddress& address, size_t port) :io_service_(io_service), address_(address), port_(port), @@ -136,6 +141,135 @@ FauxServer::requestHandler(const asio::error_code& error, } } +//********************** TransactionTest class *********************** + +const unsigned int TransactionTest::FORWARD_CHG = 0x01; +const unsigned int TransactionTest::REVERSE_CHG = 0x02; +const unsigned int TransactionTest::FWD_AND_REV_CHG = REVERSE_CHG | FORWARD_CHG; + +TransactionTest::TransactionTest() + : io_service_(new isc::asiolink::IOService()), ncr_(), + timer_(*io_service_), run_time_(0) { +} + +TransactionTest::~TransactionTest() { +} + +void +TransactionTest::runTimedIO(int run_time) { + run_time_ = run_time; + timer_.setup(boost::bind(&TransactionTest::timesUp, this), run_time_); + io_service_->run(); +} + +void +TransactionTest::timesUp() { + io_service_->stop(); + FAIL() << "Test Time: " << run_time_ << " expired"; +} + +void +TransactionTest::setupForIPv4Transaction(dhcp_ddns::NameChangeType chg_type, + int change_mask) { + const char* msg_str = + "{" + " \"change_type\" : 0 , " + " \"forward_change\" : true , " + " \"reverse_change\" : true , " + " \"fqdn\" : \"my.forward.example.com.\" , " + " \"ip_address\" : \"192.168.2.1\" , " + " \"dhcid\" : \"0102030405060708\" , " + " \"lease_expires_on\" : \"20130121132405\" , " + " \"lease_length\" : 1300 " + "}"; + + // Create NameChangeRequest from JSON string. + ncr_ = dhcp_ddns::NameChangeRequest::fromJSON(msg_str); + + // Set the change type. + ncr_->setChangeType(chg_type); + + // If the change mask does not include a forward change clear the + // forward domain; otherwise create the domain and its servers. + if (!(change_mask & FORWARD_CHG)) { + ncr_->setForwardChange(false); + forward_domain_.reset(); + } else { + // Create the forward domain and then its servers. + forward_domain_ = makeDomain("example.com."); + addDomainServer(forward_domain_, "forward.example.com", + "127.0.0.1", 5301); + addDomainServer(forward_domain_, "forward2.example.com", + "127.0.0.1", 5302); + } + + // If the change mask does not include a reverse change clear the + // reverse domain; otherwise create the domain and its servers. + if (!(change_mask & REVERSE_CHG)) { + ncr_->setReverseChange(false); + reverse_domain_.reset(); + } else { + // Create the reverse domain and its server. + reverse_domain_ = makeDomain("2.168.192.in.addr.arpa."); + addDomainServer(reverse_domain_, "reverse.example.com", + "127.0.0.1", 5301); + addDomainServer(reverse_domain_, "reverse2.example.com", + "127.0.0.1", 5302); + } +} + +void +TransactionTest::setupForIPv6Transaction(dhcp_ddns::NameChangeType chg_type, + int change_mask) { + const char* msg_str = + "{" + " \"change_type\" : 0 , " + " \"forward_change\" : true , " + " \"reverse_change\" : true , " + " \"fqdn\" : \"my6.forward.example.com.\" , " + " \"ip_address\" : \"2001:1::100\" , " + " \"dhcid\" : \"0102030405060708\" , " + " \"lease_expires_on\" : \"20130121132405\" , " + " \"lease_length\" : 1300 " + "}"; + + // Create NameChangeRequest from JSON string. + ncr_ = makeNcrFromString(msg_str); + + // Set the change type. + ncr_->setChangeType(chg_type); + + // If the change mask does not include a forward change clear the + // forward domain; otherwise create the domain and its servers. + if (!(change_mask & FORWARD_CHG)) { + ncr_->setForwardChange(false); + forward_domain_.reset(); + } else { + // Create the forward domain and then its servers. + forward_domain_ = makeDomain("example.com."); + addDomainServer(forward_domain_, "fwd6-server.example.com", + "::1", 5301); + addDomainServer(forward_domain_, "fwd6-server2.example.com", + "::1", 5302); + } + + // If the change mask does not include a reverse change clear the + // reverse domain; otherwise create the domain and its servers. + if (!(change_mask & REVERSE_CHG)) { + ncr_->setReverseChange(false); + reverse_domain_.reset(); + } else { + // Create the reverse domain and its server. + reverse_domain_ = makeDomain("1.2001.ip6.arpa."); + addDomainServer(reverse_domain_, "rev6-server.example.com", + "::1", 5301); + addDomainServer(reverse_domain_, "rev6-server2.example.com", + "::1", 5302); + } +} + + +//********************** Functions **************************** void checkRRCount(const D2UpdateMessagePtr& request, @@ -158,13 +292,15 @@ checkZone(const D2UpdateMessagePtr& request, const std::string& exp_zone_name) { void checkRR(dns::RRsetPtr rrset, const std::string& exp_name, const dns::RRClass& exp_class, const dns::RRType& exp_type, - unsigned int exp_ttl, dhcp_ddns::NameChangeRequestPtr ncr) { + unsigned int exp_ttl, dhcp_ddns::NameChangeRequestPtr ncr, + bool has_rdata) { // Verify the FQDN/DHCID RR fields. EXPECT_EQ(exp_name, rrset->getName().toText()); EXPECT_EQ(exp_class.getCode(), rrset->getClass().getCode()); EXPECT_EQ(exp_type.getCode(), rrset->getType().getCode()); EXPECT_EQ(exp_ttl, rrset->getTTL().getValue()); - if (exp_type == dns::RRType::ANY() || exp_class == dns::RRClass::ANY()) { + if ((!has_rdata) || + (exp_type == dns::RRType::ANY() || exp_class == dns::RRClass::ANY())) { // ANY types do not have RData ASSERT_EQ(0, rrset->getRdataCount()); return; @@ -229,7 +365,7 @@ void addDomainServer(DdnsDomainPtr& domain, const std::string& name, // Verifies that the contents of the given transaction's DNS update request // is correct for adding a forward DNS entry -void checkForwardAddRequest(NameChangeTransaction& tran) { +void checkAddFwdAddressRequest(NameChangeTransaction& tran) { const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest(); ASSERT_TRUE(request); @@ -276,7 +412,7 @@ void checkForwardAddRequest(NameChangeTransaction& tran) { // Verifies that the contents of the given transaction's DNS update request // is correct for replacing a forward DNS entry -void checkForwardReplaceRequest(NameChangeTransaction& tran) { +void checkReplaceFwdAddressRequest(NameChangeTransaction& tran) { const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest(); ASSERT_TRUE(request); @@ -332,7 +468,7 @@ void checkForwardReplaceRequest(NameChangeTransaction& tran) { // Verifies that the contents of the given transaction's DNS update request // is correct for replacing a reverse DNS entry -void checkReverseReplaceRequest(NameChangeTransaction& tran) { +void checkReplaceRevPtrsRequest(NameChangeTransaction& tran) { const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest(); ASSERT_TRUE(request); @@ -390,5 +526,133 @@ void checkReverseReplaceRequest(NameChangeTransaction& tran) { ASSERT_NO_THROW(request->toWire(renderer)); } +void checkRemoveFwdAddressRequest(NameChangeTransaction& tran) { + const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest(); + ASSERT_TRUE(request); + + // Safety check. + dhcp_ddns::NameChangeRequestPtr ncr = tran.getNcr(); + ASSERT_TRUE(ncr); + + std::string exp_zone_name = tran.getForwardDomain()->getName(); + std::string exp_fqdn = ncr->getFqdn(); + + // Verify the zone section. + checkZone(request, exp_zone_name); + + // Verify there is 1 RR in the PREREQUISITE Section. + checkRRCount(request, D2UpdateMessage::SECTION_PREREQUISITE, 1); + + // Verify the DHCID matching assertion RR. + dns::RRsetPtr rrset; + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_PREREQUISITE, 0)); + checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), + 0, ncr); + + // Verify there is 1 RR in the UPDATE Section. + checkRRCount(request, D2UpdateMessage::SECTION_UPDATE, 1); + + // Verify the FQDN/IP delete RR. + const dns::RRType& exp_ip_rr_type = tran.getAddressRRType(); + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_UPDATE, 0)); + checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), exp_ip_rr_type, + 0, ncr); + + // Verify that it will render toWire without throwing. + dns::MessageRenderer renderer; + ASSERT_NO_THROW(request->toWire(renderer)); +} + +void checkRemoveFwdRRsRequest(NameChangeTransaction& tran) { + const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest(); + ASSERT_TRUE(request); + + // Safety check. + dhcp_ddns::NameChangeRequestPtr ncr = tran.getNcr(); + ASSERT_TRUE(ncr); + + std::string exp_zone_name = tran.getForwardDomain()->getName(); + std::string exp_fqdn = ncr->getFqdn(); + + // Verify the zone section. + checkZone(request, exp_zone_name); + + // Verify there is 1 RR in the PREREQUISITE Section. + checkRRCount(request, D2UpdateMessage::SECTION_PREREQUISITE, 3); + + // Verify the DHCID matches assertion. + dns::RRsetPtr rrset; + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_PREREQUISITE, 0)); + checkRR(rrset, exp_fqdn, dns::RRClass::IN(), dns::RRType::DHCID(), + 0, ncr); + + // Verify the NO A RRs assertion. + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_PREREQUISITE, 1)); + checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), dns::RRType::A(), + 0, ncr, NO_RDATA); + + // Verify the NO AAAA RRs assertion. + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_PREREQUISITE, 2)); + checkRR(rrset, exp_fqdn, dns::RRClass::NONE(), dns::RRType::AAAA(), + 0, ncr, NO_RDATA); + + // Verify there is 1 RR in the UPDATE Section. + checkRRCount(request, D2UpdateMessage::SECTION_UPDATE, 1); + + // Verify the delete all for the FQDN RR. + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_UPDATE, 0)); + checkRR(rrset, exp_fqdn, dns::RRClass::ANY(), dns::RRType::ANY(), + 0, ncr); + + // Verify that it will render toWire without throwing. + dns::MessageRenderer renderer; + ASSERT_NO_THROW(request->toWire(renderer)); +} + +void checkRemoveRevPtrsRequest(NameChangeTransaction& tran) { + const D2UpdateMessagePtr& request = tran.getDnsUpdateRequest(); + ASSERT_TRUE(request); + + // Safety check. + dhcp_ddns::NameChangeRequestPtr ncr = tran.getNcr(); + ASSERT_TRUE(ncr); + + std::string exp_zone_name = tran.getReverseDomain()->getName(); + std::string exp_rev_addr = D2CfgMgr::reverseIpAddress(ncr->getIpAddress()); + + // Verify the zone section. + checkZone(request, exp_zone_name); + + // Verify there is 1 RR in the PREREQUISITE Section. + checkRRCount(request, D2UpdateMessage::SECTION_PREREQUISITE, 1); + + // Verify the FQDN-PTRNAME assertion RR. + dns::RRsetPtr rrset; + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_PREREQUISITE, 0)); + checkRR(rrset, exp_rev_addr, dns::RRClass::IN(), dns::RRType::PTR(), + 0, ncr); + + // Verify there is 1 RR in the UPDATE Section. + checkRRCount(request, D2UpdateMessage::SECTION_UPDATE, 1); + + // Verify the delete all for the FQDN RR. + ASSERT_TRUE(rrset = getRRFromSection(request, D2UpdateMessage:: + SECTION_UPDATE, 0)); + checkRR(rrset, exp_rev_addr, dns::RRClass::ANY(), dns::RRType::ANY(), + 0, ncr); + + // Verify that it will render toWire without throwing. + dns::MessageRenderer renderer; + ASSERT_NO_THROW(request->toWire(renderer)); +} + + }; // namespace isc::d2 }; // namespace isc diff --git a/src/bin/d2/tests/nc_test_utils.h b/src/bin/d2/tests/nc_test_utils.h index 7cffd05963..9b96b2ebdc 100644 --- a/src/bin/d2/tests/nc_test_utils.h +++ b/src/bin/d2/tests/nc_test_utils.h @@ -21,6 +21,7 @@ #include #include +#include namespace isc { namespace d2 { @@ -94,6 +95,68 @@ public: const dns::Rcode& response_rcode); }; +/// @brief Base class Test fixture for testing transactions. +class TransactionTest : public ::testing::Test { +public: + IOServicePtr io_service_; + dhcp_ddns::NameChangeRequestPtr ncr_; + DdnsDomainPtr forward_domain_; + DdnsDomainPtr reverse_domain_; + asiolink::IntervalTimer timer_; + int run_time_; + + /// #brief constants used to specify change directions for a transaction. + static const unsigned int FORWARD_CHG; // Only forward change. + static const unsigned int REVERSE_CHG; // Only reverse change. + static const unsigned int FWD_AND_REV_CHG; // Both forward and reverse. + + TransactionTest(); + virtual ~TransactionTest(); + + /// @brief Run the IO service for no more than a given amount of time. + /// + /// Uses an IntervalTimer to interrupt the invocation of IOService run(), + /// after the given number of milliseconds elapse. The timer executes + /// the timesUp() method if it expires. + /// + /// @param run_time amount of time in milliseconds to allow run to execute. + void runTimedIO(int run_time); + + /// @brief IO Timer expiration handler + /// + /// Stops the IOSerivce and fails the current test. + virtual void timesUp(); + + /// @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 + /// changes requested. Based upon the change mask, the transaction + /// will have either the forward, reverse, or both domains populated. + /// + /// @param change_type selects the type of change requested, CHG_ADD or + /// CHG_REMOVE. + /// @param change_mask determines which change directions are requested + /// FORWARD_CHG, REVERSE_CHG, or FWD_AND_REV_CHG. + void setupForIPv4Transaction(dhcp_ddns::NameChangeType change_type, + int change_mask); + + /// @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_type selects the type of change requested, CHG_ADD or + /// CHG_REMOVE. + /// @param change_mask determines which change directions are requested + /// FORWARD_CHG, REVERSE_CHG, or FWD_AND_REV_CHG. + void setupForIPv6Transaction(dhcp_ddns::NameChangeType change_type, + int change_mask); +}; + + /// @brief Tests the number of RRs in a request section against a given count. /// /// This function actually returns the number of RRsetPtrs in a section. Since @@ -124,9 +187,14 @@ extern void checkZone(const D2UpdateMessagePtr& request, /// @param exp_typ expected RRType value of RRset /// @param exp_ttl expected TTL value of RRset /// @param ncr NameChangeRequest on which the RRset is based +/// @param has_rdata if true, RRset's rdata will be checked based on it's +/// RRType. Set this to false if the RRset's type supports Rdata but it does +/// not contain it. For instance, prerequisites of type NONE have no Rdata +/// where udpates of type NONE may. extern void checkRR(dns::RRsetPtr rrset, const std::string& exp_name, const dns::RRClass& exp_class, const dns::RRType& exp_type, - unsigned int exp_ttl, dhcp_ddns::NameChangeRequestPtr ncr); + unsigned int exp_ttl, dhcp_ddns::NameChangeRequestPtr ncr, + bool has_rdata=true); /// @brief Fetches an RR(set) from a given section of a request /// @@ -163,7 +231,7 @@ extern dns::RRsetPtr getRRFromSection(const D2UpdateMessagePtr& request, /// adding a forward DNS mapping. /// /// @param tran Transaction containing the request to be verified. -extern void checkForwardAddRequest(NameChangeTransaction& tran); +extern void checkAddFwdAddressRequest(NameChangeTransaction& tran); /// @brief Verifies a forward mapping replacement DNS update request /// @@ -171,7 +239,7 @@ extern void checkForwardAddRequest(NameChangeTransaction& tran); /// replacing a forward DNS mapping. /// /// @param tran Transaction containing the request to be verified. -extern void checkForwardReplaceRequest(NameChangeTransaction& tran); +extern void checkReplaceFwdAddressRequest(NameChangeTransaction& tran); /// @brief Verifies a reverse mapping replacement DNS update request /// @@ -179,7 +247,32 @@ extern void checkForwardReplaceRequest(NameChangeTransaction& tran); /// replacing a reverse DNS mapping. /// /// @param tran Transaction containing the request to be verified. -extern void checkReverseReplaceRequest(NameChangeTransaction& tran); +extern void checkReplaceRevPtrsRequest(NameChangeTransaction& tran); + +/// @brief Verifies a forward address removal DNS update request +/// +/// Tests that the DNS Update request for a given transaction, is correct for +/// removing the forward address DNS entry. +/// +/// @param tran Transaction containing the request to be verified. +extern void checkRemoveFwdAddressRequest(NameChangeTransaction& tran); + +/// @brief Verifies a forward RR removal DNS update request +/// +/// Tests that the DNS Update request for a given transaction, is correct for +/// removing forward RR DNS entries. +/// +/// @param tran Transaction containing the request to be verified. +extern void checkRemoveFwdRRsRequest(NameChangeTransaction& tran); + +/// @brief Verifies a reverse mapping removal DNS update request +/// +/// Tests that the DNS Update request for a given transaction, is correct for +/// removing a reverse DNS mapping. +/// +/// @param tran Transaction containing the request to be verified. +extern void checkRemoveRevPtrsRequest(NameChangeTransaction& tran); + /// @brief Creates a NameChangeRequest from JSON string. /// diff --git a/src/bin/d2/tests/nc_trans_unittests.cc b/src/bin/d2/tests/nc_trans_unittests.cc index 6e1c3fc69a..b235ef1ab7 100644 --- a/src/bin/d2/tests/nc_trans_unittests.cc +++ b/src/bin/d2/tests/nc_trans_unittests.cc @@ -997,19 +997,10 @@ TEST_F(NameChangeTransactionTest, addLeaseAddressRData) { ASSERT_NO_THROW(name_change = makeCannedTransaction()); dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr(); - // Test a lease rdata add failure. - // As you cannot stuff an invalid address into an NCR, the only failure - // that can be induced is a mismatch between the RData and the RRset. - // Attempt to add a lease address Rdata, this should fail. - // Create an Any class/Any type RRset, they are not allowed to contain - // rdata. - dns::RRsetPtr rrset(new dns::RRset(dns::Name("bs"), dns::RRClass::ANY(), - dns::RRType::ANY(), dns::RRTTL(0))); - ASSERT_THROW(name_change->addLeaseAddressRdata(rrset), std::exception); - // Verify we can add a lease RData to an valid RRset. - rrset.reset(new dns::RRset(dns::Name("bs"), dns::RRClass::IN(), - name_change->getAddressRRType(), dns::RRTTL(0))); + dns::RRsetPtr rrset(new dns::RRset(dns::Name("bs"), dns::RRClass::IN(), + name_change->getAddressRRType(), + dns::RRTTL(0))); ASSERT_NO_THROW(name_change->addLeaseAddressRdata(rrset)); // Verify the Rdata was added and the value is correct. @@ -1026,14 +1017,9 @@ TEST_F(NameChangeTransactionTest, addDhcidRdata) { ASSERT_NO_THROW(name_change = makeCannedTransaction()); dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr(); - // Test a DHCID rdata add failure. - dns::RRsetPtr rrset(new dns::RRset(dns::Name("bs"), dns::RRClass::ANY(), - dns::RRType::ANY(), dns::RRTTL(0))); - ASSERT_THROW(name_change->addDhcidRdata(rrset), std::exception); - // Verify we can add a lease RData to an valid RRset. - rrset.reset(new dns::RRset(dns::Name("bs"), dns::RRClass::IN(), - dns::RRType::DHCID(), dns::RRTTL(0))); + dns::RRsetPtr rrset(new dns::RRset(dns::Name("bs"), dns::RRClass::IN(), + dns::RRType::DHCID(), dns::RRTTL(0))); ASSERT_NO_THROW(name_change->addDhcidRdata(rrset)); // Verify the Rdata was added and the value is correct. @@ -1053,14 +1039,9 @@ TEST_F(NameChangeTransactionTest, addPtrRdata) { ASSERT_NO_THROW(name_change = makeCannedTransaction()); dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr(); - // Test a PTR rdata add failure. - dns::RRsetPtr rrset(new dns::RRset(dns::Name("bs"), dns::RRClass::ANY(), - dns::RRType::ANY(), dns::RRTTL(0))); - ASSERT_THROW(name_change->addPtrRdata(rrset), std::exception); - // Verify we can add a PTR RData to an valid RRset. - rrset.reset(new dns::RRset(dns::Name("bs"), dns::RRClass::IN(), - dns::RRType::PTR(), dns::RRTTL(0))); + dns::RRsetPtr rrset (new dns::RRset(dns::Name("bs"), dns::RRClass::IN(), + dns::RRType::PTR(), dns::RRTTL(0))); ASSERT_NO_THROW(name_change->addPtrRdata(rrset)); // Verify the Rdata was added and the value is correct.