nc_trans_unittests.cc 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. // Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <asiolink/interval_timer.h>
  15. #include <d2/nc_trans.h>
  16. #include <dns/opcode.h>
  17. #include <dns/messagerenderer.h>
  18. #include <log/logger_support.h>
  19. #include <log/macros.h>
  20. #include <util/buffer.h>
  21. #include <nc_test_utils.h>
  22. #include <asio/ip/udp.hpp>
  23. #include <asio/socket_base.hpp>
  24. #include <asio.hpp>
  25. #include <asio/error_code.hpp>
  26. #include <boost/function.hpp>
  27. #include <boost/bind.hpp>
  28. #include <gtest/gtest.h>
  29. using namespace std;
  30. using namespace isc;
  31. using namespace isc::d2;
  32. namespace {
  33. /// @brief Test derivation of NameChangeTransaction for exercising state
  34. /// model mechanics.
  35. ///
  36. /// This class facilitates testing by making non-public methods accessible so
  37. /// they can be invoked directly in test routines. It implements a very
  38. /// rudimentary state model, sufficient to test the state model mechanics
  39. /// supplied by the base class.
  40. class NameChangeStub : public NameChangeTransaction {
  41. public:
  42. // NameChangeStub states
  43. static const int DOING_UPDATE_ST = NCT_DERIVED_STATE_MIN + 1;
  44. // NameChangeStub events
  45. static const int SEND_UPDATE_EVT = NCT_DERIVED_EVENT_MIN + 2;
  46. bool use_stub_callback_;
  47. /// @brief Constructor
  48. ///
  49. /// Parameters match those needed by NameChangeTransaction.
  50. NameChangeStub(IOServicePtr& io_service,
  51. dhcp_ddns::NameChangeRequestPtr& ncr,
  52. DdnsDomainPtr forward_domain,
  53. DdnsDomainPtr reverse_domain)
  54. : NameChangeTransaction(io_service, ncr, forward_domain,
  55. reverse_domain),
  56. use_stub_callback_(false) {
  57. }
  58. /// @brief Destructor
  59. virtual ~NameChangeStub() {
  60. }
  61. /// @brief DNSClient callback
  62. /// Overrides the callback in NameChangeTranscation to allow testing
  63. /// sendUpdate without incorporating exectution of the state model
  64. /// into the test.
  65. /// It sets the DNS status update and posts IO_COMPLETED_EVT as does
  66. /// the normal callback, but rather than invoking runModel it stops
  67. /// the IO service. This allows tests to be constructed that consisted
  68. /// of generating a DNS request and invoking sendUpdate to post it and
  69. /// wait for response.
  70. virtual void operator()(DNSClient::Status status) {
  71. if (use_stub_callback_) {
  72. setDnsUpdateStatus(status);
  73. postNextEvent(IO_COMPLETED_EVT);
  74. getIOService()->stop();
  75. } else {
  76. // For tests which need to use the real callback.
  77. NameChangeTransaction::operator()(status);
  78. }
  79. }
  80. /// @brief Some tests require a server to be selected. This method
  81. /// selects the first server in the forward domain without involving
  82. /// state model execution to do so.
  83. bool selectFwdServer() {
  84. if (getForwardDomain()) {
  85. initServerSelection(getForwardDomain());
  86. selectNextServer();
  87. return (getCurrentServer());
  88. }
  89. return (false);
  90. }
  91. /// @brief Empty handler used to satisfy map verification.
  92. void dummyHandler() {
  93. isc_throw(NameChangeTransactionError,
  94. "dummyHandler - invalid event: " << getContextStr());
  95. }
  96. /// @brief State handler for the READY_ST.
  97. ///
  98. /// Serves as the starting state handler, it consumes the
  99. /// START_EVT "transitioning" to the state, DOING_UPDATE_ST and
  100. /// sets the next event to SEND_UPDATE_EVT.
  101. void readyHandler() {
  102. switch(getNextEvent()) {
  103. case START_EVT:
  104. transition(DOING_UPDATE_ST, SEND_UPDATE_EVT);
  105. break;
  106. default:
  107. // its bogus
  108. isc_throw(NameChangeTransactionError,
  109. "readyHandler - invalid event: " << getContextStr());
  110. }
  111. }
  112. /// @brief State handler for the DOING_UPDATE_ST.
  113. ///
  114. /// Simulates a state that starts some form of asynchronous work.
  115. /// When next event is SEND_UPDATE_EVT it sets the status to pending
  116. /// and signals the state model must "wait" for an event by setting
  117. /// next event to NOP_EVT.
  118. ///
  119. /// When next event is IO_COMPLETED_EVT, it transitions to the state,
  120. /// PROCESS_TRANS_OK_ST, and sets the next event to UPDATE_OK_EVT.
  121. void doingUpdateHandler() {
  122. switch(getNextEvent()) {
  123. case SEND_UPDATE_EVT:
  124. setNcrStatus(dhcp_ddns::ST_PENDING);
  125. postNextEvent(NOP_EVT);
  126. break;
  127. case IO_COMPLETED_EVT:
  128. if (getDnsUpdateStatus() == DNSClient::SUCCESS) {
  129. setForwardChangeCompleted(true);
  130. transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
  131. } else {
  132. transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
  133. }
  134. break;
  135. default:
  136. // its bogus
  137. isc_throw(NameChangeTransactionError,
  138. "doingUpdateHandler - invalid event: "
  139. << getContextStr());
  140. }
  141. }
  142. /// @brief State handler for the PROCESS_TRANS_OK_ST.
  143. ///
  144. /// This is the last state in the model. Note that it sets the
  145. /// status to completed and next event to NOP_EVT.
  146. void processTransDoneHandler() {
  147. switch(getNextEvent()) {
  148. case UPDATE_OK_EVT:
  149. setNcrStatus(dhcp_ddns::ST_COMPLETED);
  150. endModel();
  151. break;
  152. case UPDATE_FAILED_EVT:
  153. setNcrStatus(dhcp_ddns::ST_FAILED);
  154. endModel();
  155. break;
  156. default:
  157. // its bogus
  158. isc_throw(NameChangeTransactionError,
  159. "processTransDoneHandler - invalid event: "
  160. << getContextStr());
  161. }
  162. }
  163. /// @brief Construct the event dictionary.
  164. virtual void defineEvents() {
  165. // Invoke the base call implementation first.
  166. NameChangeTransaction::defineEvents();
  167. // Define our events.
  168. defineEvent(SEND_UPDATE_EVT, "SEND_UPDATE_EVT");
  169. }
  170. /// @brief Verify the event dictionary.
  171. virtual void verifyEvents() {
  172. // Invoke the base call implementation first.
  173. NameChangeTransaction::verifyEvents();
  174. // Define our events.
  175. getEvent(SEND_UPDATE_EVT);
  176. }
  177. /// @brief Construct the state dictionary.
  178. virtual void defineStates() {
  179. // Invoke the base call implementation first.
  180. NameChangeTransaction::defineStates();
  181. // Define our states.
  182. defineState(READY_ST, "READY_ST",
  183. boost::bind(&NameChangeStub::readyHandler, this));
  184. defineState(SELECTING_FWD_SERVER_ST, "SELECTING_FWD_SERVER_ST",
  185. boost::bind(&NameChangeStub::dummyHandler, this));
  186. defineState(SELECTING_REV_SERVER_ST, "SELECTING_REV_SERVER_ST",
  187. boost::bind(&NameChangeStub::dummyHandler, this));
  188. defineState(DOING_UPDATE_ST, "DOING_UPDATE_ST",
  189. boost::bind(&NameChangeStub::doingUpdateHandler,
  190. this));
  191. defineState(PROCESS_TRANS_OK_ST, "PROCESS_TRANS_OK_ST",
  192. boost::bind(&NameChangeStub::
  193. processTransDoneHandler, this));
  194. defineState(PROCESS_TRANS_FAILED_ST, "PROCESS_TRANS_FAILED_ST",
  195. boost::bind(&NameChangeStub::
  196. processTransDoneHandler, this));
  197. }
  198. /// @brief Verify the event dictionary.
  199. virtual void verifyStates() {
  200. // Invoke the base call implementation first.
  201. NameChangeTransaction::verifyStates();
  202. // Check our states.
  203. getState(DOING_UPDATE_ST);
  204. }
  205. // Expose the protected methods to be tested.
  206. using StateModel::runModel;
  207. using StateModel::postNextEvent;
  208. using StateModel::setState;
  209. using StateModel::initDictionaries;
  210. using NameChangeTransaction::initServerSelection;
  211. using NameChangeTransaction::selectNextServer;
  212. using NameChangeTransaction::getCurrentServer;
  213. using NameChangeTransaction::getDNSClient;
  214. using NameChangeTransaction::setNcrStatus;
  215. using NameChangeTransaction::setDnsUpdateRequest;
  216. using NameChangeTransaction::clearDnsUpdateRequest;
  217. using NameChangeTransaction::setDnsUpdateStatus;
  218. using NameChangeTransaction::getDnsUpdateResponse;
  219. using NameChangeTransaction::setDnsUpdateResponse;
  220. using NameChangeTransaction::clearDnsUpdateResponse;
  221. using NameChangeTransaction::getForwardChangeCompleted;
  222. using NameChangeTransaction::getReverseChangeCompleted;
  223. using NameChangeTransaction::setForwardChangeCompleted;
  224. using NameChangeTransaction::setReverseChangeCompleted;
  225. using NameChangeTransaction::setUpdateAttempts;
  226. using NameChangeTransaction::transition;
  227. using NameChangeTransaction::retryTransition;
  228. using NameChangeTransaction::sendUpdate;
  229. using NameChangeTransaction::prepNewRequest;
  230. using NameChangeTransaction::addLeaseAddressRdata;
  231. using NameChangeTransaction::addDhcidRdata;
  232. using NameChangeTransaction::addPtrRdata;
  233. };
  234. // Declare them so Gtest can see them.
  235. const int NameChangeStub::DOING_UPDATE_ST;
  236. const int NameChangeStub::SEND_UPDATE_EVT;
  237. /// @brief Defines a pointer to a NameChangeStubPtr instance.
  238. typedef boost::shared_ptr<NameChangeStub> NameChangeStubPtr;
  239. /// @brief Test fixture for testing NameChangeTransaction
  240. ///
  241. /// Note this class uses NameChangeStub class to exercise non-public
  242. /// aspects of NameChangeTransaction.
  243. class NameChangeTransactionTest : public TransactionTest {
  244. public:
  245. NameChangeTransactionTest() {
  246. }
  247. virtual ~NameChangeTransactionTest() {
  248. }
  249. /// @brief Instantiates a NameChangeStub test transaction
  250. /// The transaction is constructed around a predefined (i.e "canned")
  251. /// NameChangeRequest. The request has both forward and reverse DNS
  252. /// changes requested, and both forward and reverse domains are populated.
  253. NameChangeStubPtr makeCannedTransaction() {
  254. // Creates IPv4 remove request, forward, and reverse domains.
  255. setupForIPv4Transaction(dhcp_ddns::CHG_ADD, FWD_AND_REV_CHG);
  256. // Now create the test transaction as would occur in update manager.
  257. // Instantiate the transaction as would be done by update manager.
  258. return (NameChangeStubPtr(new NameChangeStub(io_service_, ncr_,
  259. forward_domain_, reverse_domain_)));
  260. }
  261. /// @brief Builds and then sends an update request
  262. ///
  263. /// This method is used to build and send and update request. It is used
  264. /// in conjuction with FauxServer to test various message response
  265. /// scenarios.
  266. /// @param name_change Transaction under test
  267. /// @param run_time Maximum time to permit IO processing to run before
  268. /// timing out (in milliseconds)
  269. void doOneExchange(NameChangeStubPtr name_change,
  270. unsigned int run_time = 500) {
  271. // Create a valid request for the transaction.
  272. D2UpdateMessagePtr req;
  273. ASSERT_NO_THROW(req.reset(new D2UpdateMessage(D2UpdateMessage::
  274. OUTBOUND)));
  275. ASSERT_NO_THROW(name_change->setDnsUpdateRequest(req));
  276. req->setZone(dns::Name("request.example.com"), dns::RRClass::ANY());
  277. req->setRcode(dns::Rcode(dns::Rcode::NOERROR_CODE));
  278. // Set the flag to use the NameChangeStub's DNSClient callback.
  279. name_change->use_stub_callback_ = true;
  280. // Invoke sendUpdate.
  281. ASSERT_NO_THROW(name_change->sendUpdate());
  282. // Update attempt count should be 1, next event should be NOP_EVT.
  283. ASSERT_EQ(1, name_change->getUpdateAttempts());
  284. ASSERT_EQ(NameChangeTransaction::NOP_EVT,
  285. name_change->getNextEvent());
  286. while (name_change->getNextEvent() == NameChangeTransaction::NOP_EVT) {
  287. int cnt = 0;
  288. ASSERT_NO_THROW(cnt = runTimedIO(run_time));
  289. if (cnt == 0) {
  290. FAIL() << "IO Service stopped unexpectedly";
  291. }
  292. }
  293. }
  294. };
  295. /// @brief Tests NameChangeTransaction construction.
  296. /// This test verifies that:
  297. /// 1. Construction with null NameChangeRequest
  298. /// 2. Construction with null forward domain is not allowed when the request
  299. /// requires forward change.
  300. /// 3. Construction with null reverse domain is not allowed when the request
  301. /// requires reverse change.
  302. /// 4. Valid construction functions properly
  303. TEST(NameChangeTransaction, construction) {
  304. IOServicePtr io_service(new isc::asiolink::IOService());
  305. const char* msg_str =
  306. "{"
  307. " \"change_type\" : 0 , "
  308. " \"forward_change\" : true , "
  309. " \"reverse_change\" : true , "
  310. " \"fqdn\" : \"example.com.\" , "
  311. " \"ip_address\" : \"192.168.2.1\" , "
  312. " \"dhcid\" : \"0102030405060708\" , "
  313. " \"lease_expires_on\" : \"20130121132405\" , "
  314. " \"lease_length\" : 1300 "
  315. "}";
  316. dhcp_ddns::NameChangeRequestPtr ncr;
  317. dhcp_ddns::NameChangeRequestPtr empty_ncr;
  318. DnsServerInfoStoragePtr servers;
  319. DdnsDomainPtr forward_domain;
  320. DdnsDomainPtr reverse_domain;
  321. DdnsDomainPtr empty_domain;
  322. ASSERT_NO_THROW(ncr = dhcp_ddns::NameChangeRequest::fromJSON(msg_str));
  323. ASSERT_NO_THROW(forward_domain.reset(new DdnsDomain("*", "", servers)));
  324. ASSERT_NO_THROW(reverse_domain.reset(new DdnsDomain("*", "", servers)));
  325. // Verify that construction with a null IOServicePtr fails.
  326. // @todo Subject to change if multi-threading is implemented.
  327. IOServicePtr empty;
  328. EXPECT_THROW(NameChangeTransaction(empty, ncr,
  329. forward_domain, reverse_domain),
  330. NameChangeTransactionError);
  331. // Verify that construction with an empty NameChangeRequest throws.
  332. EXPECT_THROW(NameChangeTransaction(io_service, empty_ncr,
  333. forward_domain, reverse_domain),
  334. NameChangeTransactionError);
  335. // Verify that construction with an empty forward domain when the
  336. // NameChangeRequest calls for a forward change throws.
  337. EXPECT_THROW(NameChangeTransaction(io_service, ncr,
  338. empty_domain, reverse_domain),
  339. NameChangeTransactionError);
  340. // Verify that construction with an empty reverse domain when the
  341. // NameChangeRequest calls for a reverse change throws.
  342. EXPECT_THROW(NameChangeTransaction(io_service, ncr,
  343. forward_domain, empty_domain),
  344. NameChangeTransactionError);
  345. // Verify that a valid construction attempt works.
  346. EXPECT_NO_THROW(NameChangeTransaction(io_service, ncr,
  347. forward_domain, reverse_domain));
  348. // Verify that an empty forward domain is allowed when the requests does
  349. // not include a forward change.
  350. ncr->setForwardChange(false);
  351. ncr->setReverseChange(true);
  352. EXPECT_NO_THROW(NameChangeTransaction(io_service, ncr,
  353. empty_domain, reverse_domain));
  354. // Verify that an empty reverse domain is allowed when the requests does
  355. // not include a reverse change.
  356. ncr->setForwardChange(true);
  357. ncr->setReverseChange(false);
  358. EXPECT_NO_THROW(NameChangeTransaction(io_service, ncr,
  359. forward_domain, empty_domain));
  360. }
  361. /// @brief General testing of member accessors.
  362. /// Most if not all of these are also tested as a byproduct off larger tests.
  363. TEST_F(NameChangeTransactionTest, accessors) {
  364. NameChangeStubPtr name_change;
  365. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  366. // Verify that fetching the NameChangeRequest works.
  367. dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr();
  368. ASSERT_TRUE(ncr);
  369. // Verify that getTransactionKey works.
  370. EXPECT_EQ(ncr->getDhcid(), name_change->getTransactionKey());
  371. // Verify that NcrStatus can be set and retrieved.
  372. EXPECT_NO_THROW(name_change->setNcrStatus(dhcp_ddns::ST_FAILED));
  373. EXPECT_EQ(dhcp_ddns::ST_FAILED, ncr->getStatus());
  374. // Verify that the forward domain can be retrieved.
  375. ASSERT_TRUE(name_change->getForwardDomain());
  376. EXPECT_EQ(forward_domain_, name_change->getForwardDomain());
  377. // Verify that the reverse domain can be retrieved.
  378. ASSERT_TRUE(name_change->getReverseDomain());
  379. EXPECT_EQ(reverse_domain_, name_change->getReverseDomain());
  380. // Neither of these have direct setters, but are tested under server
  381. // selection.
  382. EXPECT_FALSE(name_change->getDNSClient());
  383. EXPECT_FALSE(name_change->getCurrentServer());
  384. // Verify that DNS update status can be set and retrieved.
  385. EXPECT_NO_THROW(name_change->setDnsUpdateStatus(DNSClient::TIMEOUT));
  386. EXPECT_EQ(DNSClient::TIMEOUT, name_change->getDnsUpdateStatus());
  387. // Verify that the forward change complete flag can be set and fetched.
  388. EXPECT_NO_THROW(name_change->setForwardChangeCompleted(true));
  389. EXPECT_TRUE(name_change->getForwardChangeCompleted());
  390. // Verify that the reverse change complete flag can be set and fetched.
  391. EXPECT_NO_THROW(name_change->setReverseChangeCompleted(true));
  392. EXPECT_TRUE(name_change->getReverseChangeCompleted());
  393. }
  394. /// @brief Tests DNS update request accessor methods.
  395. TEST_F(NameChangeTransactionTest, dnsUpdateRequestAccessors) {
  396. // Create a transaction.
  397. NameChangeStubPtr name_change;
  398. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  399. // Post transaction construction, there should not be an update request.
  400. EXPECT_FALSE(name_change->getDnsUpdateRequest());
  401. // Create a request.
  402. D2UpdateMessagePtr req;
  403. ASSERT_NO_THROW(req.reset(new D2UpdateMessage(D2UpdateMessage::OUTBOUND)));
  404. // Use the setter and then verify we can fetch the request.
  405. ASSERT_NO_THROW(name_change->setDnsUpdateRequest(req));
  406. // Post set, we should be able to fetch it.
  407. ASSERT_TRUE(name_change->getDnsUpdateRequest());
  408. // Should be able to clear it.
  409. ASSERT_NO_THROW(name_change->clearDnsUpdateRequest());
  410. // Should be empty again.
  411. EXPECT_FALSE(name_change->getDnsUpdateRequest());
  412. }
  413. /// @brief Tests DNS update request accessor methods.
  414. TEST_F(NameChangeTransactionTest, dnsUpdateResponseAccessors) {
  415. // Create a transaction.
  416. NameChangeStubPtr name_change;
  417. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  418. // Post transaction construction, there should not be an update response.
  419. EXPECT_FALSE(name_change->getDnsUpdateResponse());
  420. // Create a response.
  421. D2UpdateMessagePtr resp;
  422. ASSERT_NO_THROW(resp.reset(new D2UpdateMessage(D2UpdateMessage::INBOUND)));
  423. // Use the setter and then verify we can fetch the response.
  424. ASSERT_NO_THROW(name_change->setDnsUpdateResponse(resp));
  425. // Post set, we should be able to fetch it.
  426. EXPECT_TRUE(name_change->getDnsUpdateResponse());
  427. // Should be able to clear it.
  428. ASSERT_NO_THROW(name_change->clearDnsUpdateResponse());
  429. // Should be empty again.
  430. EXPECT_FALSE(name_change->getDnsUpdateResponse());
  431. }
  432. /// @brief Tests event and state dictionary construction and verification.
  433. TEST_F(NameChangeTransactionTest, dictionaryCheck) {
  434. NameChangeStubPtr name_change;
  435. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  436. // Verify that the event and state dictionary validation fails prior
  437. // dictionary construction.
  438. ASSERT_THROW(name_change->verifyEvents(), StateModelError);
  439. ASSERT_THROW(name_change->verifyStates(), StateModelError);
  440. // Construct both dictionaries.
  441. ASSERT_NO_THROW(name_change->defineEvents());
  442. ASSERT_NO_THROW(name_change->defineStates());
  443. // Verify both event and state dictionaries now pass validation.
  444. ASSERT_NO_THROW(name_change->verifyEvents());
  445. ASSERT_NO_THROW(name_change->verifyStates());
  446. }
  447. /// @brief Tests server selection methods.
  448. /// Each transaction has a list of one or more servers for each DNS direction
  449. /// it is required to update. The transaction must be able to start at the
  450. /// beginning of a server list and cycle through them one at time, as needed,
  451. /// when a DNS exchange fails due to an IO error. This test verifies the
  452. /// ability to iteratively select a server from the list as the current server.
  453. TEST_F(NameChangeTransactionTest, serverSelectionTest) {
  454. NameChangeStubPtr name_change;
  455. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  456. // Verify that the forward domain and its list of servers can be retrieved.
  457. DdnsDomainPtr& domain = name_change->getForwardDomain();
  458. ASSERT_TRUE(domain);
  459. DnsServerInfoStoragePtr servers = domain->getServers();
  460. ASSERT_TRUE(servers);
  461. // Get the number of entries in the server list.
  462. int num_servers = servers->size();
  463. ASSERT_TRUE(num_servers > 0);
  464. // Verify that we can initialize server selection. This "resets" the
  465. // selection process to start over using the list of servers in the
  466. // given domain.
  467. ASSERT_NO_THROW(name_change->initServerSelection(domain));
  468. // The server selection process determines the current server,
  469. // instantiates a new DNSClient, and a DNS response message buffer.
  470. // We need to save the values before each selection, so we can verify
  471. // they are correct after each selection.
  472. DnsServerInfoPtr prev_server = name_change->getCurrentServer();
  473. DNSClientPtr prev_client = name_change->getDNSClient();
  474. // Verify response pointer is empty.
  475. EXPECT_FALSE(name_change->getDnsUpdateResponse());
  476. // Create dummy response so we can verify it is cleared at each
  477. // new server select.
  478. D2UpdateMessagePtr dummyResp;
  479. dummyResp.reset(new D2UpdateMessage(D2UpdateMessage::INBOUND));
  480. ASSERT_NO_THROW(name_change->setDnsUpdateResponse(dummyResp));
  481. ASSERT_TRUE(name_change->getDnsUpdateResponse());
  482. // Iteratively select through the list of servers.
  483. int passes = 0;
  484. while (name_change->selectNextServer()) {
  485. // Get the new values after the selection has been made.
  486. DnsServerInfoPtr server = name_change->getCurrentServer();
  487. DNSClientPtr client = name_change->getDNSClient();
  488. D2UpdateMessagePtr response = name_change->getDnsUpdateResponse();
  489. // Verify that the new values are not empty.
  490. EXPECT_TRUE(server);
  491. EXPECT_TRUE(client);
  492. // Verify response pointer is now empty.
  493. EXPECT_FALSE(name_change->getDnsUpdateResponse());
  494. // Verify that the new values are indeed new.
  495. EXPECT_NE(server, prev_server);
  496. EXPECT_NE(client, prev_client);
  497. // Remember the selected values for the next pass.
  498. prev_server = server;
  499. prev_client = client;
  500. // Create new dummy response.
  501. dummyResp.reset(new D2UpdateMessage(D2UpdateMessage::INBOUND));
  502. ASSERT_NO_THROW(name_change->setDnsUpdateResponse(dummyResp));
  503. ASSERT_TRUE(name_change->getDnsUpdateResponse());
  504. ++passes;
  505. }
  506. // Verify that the number of passes made equal the number of servers.
  507. EXPECT_EQ (passes, num_servers);
  508. // Repeat the same test using the reverse domain.
  509. // Verify that the reverse domain and its list of servers can be retrieved.
  510. domain = name_change->getReverseDomain();
  511. ASSERT_TRUE(domain);
  512. servers = domain->getServers();
  513. ASSERT_TRUE(servers);
  514. // Get the number of entries in the server list.
  515. num_servers = servers->size();
  516. ASSERT_TRUE(num_servers > 0);
  517. // Verify that we can initialize server selection. This "resets" the
  518. // selection process to start over using the list of servers in the
  519. // given domain.
  520. ASSERT_NO_THROW(name_change->initServerSelection(domain));
  521. // The server selection process determines the current server,
  522. // instantiates a new DNSClient, and resets the DNS response message buffer.
  523. // We need to save the values before each selection, so we can verify
  524. // they are correct after each selection.
  525. prev_server = name_change->getCurrentServer();
  526. prev_client = name_change->getDNSClient();
  527. // Iteratively select through the list of servers.
  528. passes = 0;
  529. while (name_change->selectNextServer()) {
  530. // Get the new values after the selection has been made.
  531. DnsServerInfoPtr server = name_change->getCurrentServer();
  532. DNSClientPtr client = name_change->getDNSClient();
  533. D2UpdateMessagePtr response = name_change->getDnsUpdateResponse();
  534. // Verify that the new values are not empty.
  535. EXPECT_TRUE(server);
  536. EXPECT_TRUE(client);
  537. // Verify response pointer is now empty.
  538. EXPECT_FALSE(name_change->getDnsUpdateResponse());
  539. // Verify that the new values are indeed new.
  540. EXPECT_NE(server, prev_server);
  541. EXPECT_NE(client, prev_client);
  542. // Remember the selected values for the next pass.
  543. prev_server = server;
  544. prev_client = client;
  545. // Create new dummy response.
  546. dummyResp.reset(new D2UpdateMessage(D2UpdateMessage::INBOUND));
  547. ASSERT_NO_THROW(name_change->setDnsUpdateResponse(dummyResp));
  548. ASSERT_TRUE(name_change->getDnsUpdateResponse());
  549. ++passes;
  550. }
  551. // Verify that the number of passes made equal the number of servers.
  552. EXPECT_EQ (passes, num_servers);
  553. }
  554. /// @brief Tests that the transaction will be "failed" upon model errors.
  555. TEST_F(NameChangeTransactionTest, modelFailure) {
  556. NameChangeStubPtr name_change;
  557. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  558. // Now call runModel() with an undefined event which should not throw,
  559. // but should result in a failed model and failed transaction.
  560. EXPECT_NO_THROW(name_change->runModel(9999));
  561. // Verify that the model reports are done but failed.
  562. EXPECT_TRUE(name_change->isModelDone());
  563. EXPECT_TRUE(name_change->didModelFail());
  564. // Verify that the transaction has failed.
  565. EXPECT_EQ(dhcp_ddns::ST_FAILED, name_change->getNcrStatus());
  566. }
  567. /// @brief Tests the ability to use startTransaction to initiate the state
  568. /// model execution, and DNSClient callback, operator(), to resume the
  569. /// model with a update successful outcome.
  570. TEST_F(NameChangeTransactionTest, successfulUpdateTest) {
  571. NameChangeStubPtr name_change;
  572. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  573. ASSERT_TRUE(name_change->selectFwdServer());
  574. EXPECT_TRUE(name_change->isModelNew());
  575. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  576. // Launch the transaction by calling startTransaction. The state model
  577. // should run up until the "IO" operation is initiated in DOING_UPDATE_ST.
  578. ASSERT_NO_THROW(name_change->startTransaction());
  579. // Verify that the model is running but waiting, and that forward change
  580. // completion is still false.
  581. EXPECT_TRUE(name_change->isModelRunning());
  582. EXPECT_TRUE(name_change->isModelWaiting());
  583. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  584. // Simulate completion of DNSClient exchange by invoking the callback, as
  585. // DNSClient would. This should cause the state model to progress through
  586. // completion.
  587. EXPECT_NO_THROW((*name_change)(DNSClient::SUCCESS));
  588. // The model should have worked through to completion.
  589. // Verify that the model is done and not failed.
  590. EXPECT_TRUE(name_change->isModelDone());
  591. EXPECT_FALSE(name_change->didModelFail());
  592. // Verify that NCR status is completed, and that the forward change
  593. // was completed.
  594. EXPECT_EQ(dhcp_ddns::ST_COMPLETED, name_change->getNcrStatus());
  595. EXPECT_TRUE(name_change->getForwardChangeCompleted());
  596. }
  597. /// @brief Tests the ability to use startTransaction to initate the state
  598. /// model execution, and DNSClient callback, operator(), to resume the
  599. /// model with a update failure outcome.
  600. TEST_F(NameChangeTransactionTest, failedUpdateTest) {
  601. NameChangeStubPtr name_change;
  602. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  603. ASSERT_TRUE(name_change->selectFwdServer());
  604. // Launch the transaction by calling startTransaction. The state model
  605. // should run up until the "IO" operation is initiated in DOING_UPDATE_ST.
  606. ASSERT_NO_THROW(name_change->startTransaction());
  607. // Vefity that the model is running but waiting, and that the forward
  608. // change has not been completed.
  609. EXPECT_TRUE(name_change->isModelRunning());
  610. EXPECT_TRUE(name_change->isModelWaiting());
  611. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  612. // Simulate completion of DNSClient exchange by invoking the callback, as
  613. // DNSClient would. This should cause the state model to progress through
  614. // to completion.
  615. EXPECT_NO_THROW((*name_change)(DNSClient::TIMEOUT));
  616. // The model should have worked through to completion.
  617. // Verify that the model is done and not failed.
  618. EXPECT_TRUE(name_change->isModelDone());
  619. EXPECT_FALSE(name_change->didModelFail());
  620. // Verify that the NCR status is failed and that the forward change
  621. // was not completed.
  622. EXPECT_EQ(dhcp_ddns::ST_FAILED, name_change->getNcrStatus());
  623. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  624. }
  625. /// @brief Tests update attempt accessors.
  626. TEST_F(NameChangeTransactionTest, updateAttempts) {
  627. NameChangeStubPtr name_change;
  628. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  629. // Post transaction construction, update attempts should be 0.
  630. EXPECT_EQ(0, name_change->getUpdateAttempts());
  631. // Set it to a known value.
  632. name_change->setUpdateAttempts(5);
  633. // Verify that the value is as expected.
  634. EXPECT_EQ(5, name_change->getUpdateAttempts());
  635. }
  636. /// @brief Tests retryTransition method
  637. ///
  638. /// Verifies that while the maximum number of update attempts has not
  639. /// been exceeded, the method will leave the state unchanged but post a
  640. /// SERVER_SELECTED_EVT. Once the maximum is exceeded, the method should
  641. /// transition to the state given with a next event of SERVER_IO_ERROR_EVT.
  642. TEST_F(NameChangeTransactionTest, retryTransition) {
  643. // Create the transaction.
  644. NameChangeStubPtr name_change;
  645. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  646. // Define dictionaries.
  647. ASSERT_NO_THROW(name_change->initDictionaries());
  648. // Transition to a known spot.
  649. ASSERT_NO_THROW(name_change->transition(
  650. NameChangeStub::DOING_UPDATE_ST,
  651. NameChangeStub::SEND_UPDATE_EVT));
  652. // Verify we are at the known spot.
  653. ASSERT_EQ(NameChangeStub::DOING_UPDATE_ST,
  654. name_change->getCurrState());
  655. ASSERT_EQ(NameChangeStub::SEND_UPDATE_EVT,
  656. name_change->getNextEvent());
  657. // Verify that we have not exceeded maximum number of attempts.
  658. ASSERT_LT(name_change->getUpdateAttempts(),
  659. NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER);
  660. // Call retryTransition.
  661. ASSERT_NO_THROW(name_change->retryTransition(
  662. NameChangeTransaction::PROCESS_TRANS_FAILED_ST));
  663. // Since the number of update attempts is less than the maximum allowed
  664. // we should remain in our current state but with next event of
  665. // SERVER_SELECTED_EVT posted.
  666. ASSERT_EQ(NameChangeStub::DOING_UPDATE_ST,
  667. name_change->getCurrState());
  668. ASSERT_EQ(NameChangeTransaction::SERVER_SELECTED_EVT,
  669. name_change->getNextEvent());
  670. // Now set the number of attempts to the maximum.
  671. name_change->setUpdateAttempts(NameChangeTransaction::
  672. MAX_UPDATE_TRIES_PER_SERVER);
  673. // Call retryTransition.
  674. ASSERT_NO_THROW(name_change->retryTransition(
  675. NameChangeTransaction::PROCESS_TRANS_FAILED_ST));
  676. // Since we have exceeded maximum attempts, we should transition to
  677. // PROCESS_UPDATE_FAILED_ST with a next event of SERVER_IO_ERROR_EVT.
  678. ASSERT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST,
  679. name_change->getCurrState());
  680. ASSERT_EQ(NameChangeTransaction::SERVER_IO_ERROR_EVT,
  681. name_change->getNextEvent());
  682. }
  683. /// @brief Tests sendUpdate method when underlying doUpdate throws.
  684. ///
  685. /// DNSClient::doUpdate can throw for a variety of reasons. This tests
  686. /// sendUpdate handling of such a throw by passing doUpdate a request
  687. /// that will not render.
  688. TEST_F(NameChangeTransactionTest, sendUpdateDoUpdateFailure) {
  689. NameChangeStubPtr name_change;
  690. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  691. ASSERT_NO_THROW(name_change->initDictionaries());
  692. ASSERT_TRUE(name_change->selectFwdServer());
  693. // Set the transaction's request to an empty DNS update.
  694. D2UpdateMessagePtr req;
  695. ASSERT_NO_THROW(req.reset(new D2UpdateMessage(D2UpdateMessage::OUTBOUND)));
  696. ASSERT_NO_THROW(name_change->setDnsUpdateRequest(req));
  697. // Verify that sendUpdate does not throw, but it should fail because
  698. // the request won't render.
  699. ASSERT_NO_THROW(name_change->sendUpdate());
  700. // Verify that we transition to failed state and event.
  701. ASSERT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST,
  702. name_change->getCurrState());
  703. ASSERT_EQ(NameChangeTransaction::UPDATE_FAILED_EVT,
  704. name_change->getNextEvent());
  705. }
  706. /// @brief Tests sendUpdate method when underlying doUpdate times out.
  707. TEST_F(NameChangeTransactionTest, sendUpdateTimeout) {
  708. NameChangeStubPtr name_change;
  709. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  710. ASSERT_NO_THROW(name_change->initDictionaries());
  711. ASSERT_TRUE(name_change->selectFwdServer());
  712. // Build a valid request, call sendUpdate and process the response.
  713. // Note we have to wait for DNSClient timeout plus a bit more to allow
  714. // DNSClient to timeout.
  715. // The method, doOneExchange, can suffer fatal assertions which invalidate
  716. // not only it but the invoking test as well. In other words, if the
  717. // doOneExchange blows up the rest of test is pointless. I use
  718. // ASSERT_NO_FATAL_FAILURE to abort the test immediately.
  719. ASSERT_NO_FATAL_FAILURE(doOneExchange(name_change,
  720. NameChangeTransaction::
  721. DNS_UPDATE_DEFAULT_TIMEOUT + 100));
  722. // Verify that next event is IO_COMPLETED_EVT and DNS status is TIMEOUT.
  723. ASSERT_EQ(NameChangeTransaction::IO_COMPLETED_EVT,
  724. name_change->getNextEvent());
  725. ASSERT_EQ(DNSClient::TIMEOUT, name_change->getDnsUpdateStatus());
  726. }
  727. /// @brief Tests sendUpdate method when it receives a corrupt response from
  728. /// the server.
  729. TEST_F(NameChangeTransactionTest, sendUpdateCorruptResponse) {
  730. NameChangeStubPtr name_change;
  731. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  732. ASSERT_NO_THROW(name_change->initDictionaries());
  733. ASSERT_TRUE(name_change->selectFwdServer());
  734. // Create a server and start it listening.
  735. FauxServer server(*io_service_, *(name_change->getCurrentServer()));
  736. server.receive(FauxServer::CORRUPT_RESP);
  737. // Build a valid request, call sendUpdate and process the response.
  738. ASSERT_NO_FATAL_FAILURE(doOneExchange(name_change));
  739. // Verify that next event is IO_COMPLETED_EVT and DNS status is INVALID.
  740. ASSERT_EQ(NameChangeTransaction::IO_COMPLETED_EVT,
  741. name_change->getNextEvent());
  742. ASSERT_EQ(DNSClient::INVALID_RESPONSE, name_change->getDnsUpdateStatus());
  743. }
  744. /// @brief Tests sendUpdate method when the exchange succeeds.
  745. TEST_F(NameChangeTransactionTest, sendUpdate) {
  746. NameChangeStubPtr name_change;
  747. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  748. ASSERT_NO_THROW(name_change->initDictionaries());
  749. ASSERT_TRUE(name_change->selectFwdServer());
  750. // Create a server and start it listening.
  751. FauxServer server(*io_service_, *(name_change->getCurrentServer()));
  752. server.receive (FauxServer::USE_RCODE, dns::Rcode::NOERROR());
  753. // Build a valid request, call sendUpdate and process the response.
  754. ASSERT_NO_FATAL_FAILURE(doOneExchange(name_change));
  755. // Verify that next event is IO_COMPLETED_EVT and DNS status is SUCCESS.
  756. ASSERT_EQ(NameChangeTransaction::IO_COMPLETED_EVT,
  757. name_change->getNextEvent());
  758. ASSERT_EQ(DNSClient::SUCCESS, name_change->getDnsUpdateStatus());
  759. // Verify that we have a response and it's Rcode is NOERROR,
  760. // and the zone is as expected.
  761. D2UpdateMessagePtr response = name_change->getDnsUpdateResponse();
  762. ASSERT_TRUE(response);
  763. ASSERT_EQ(dns::Rcode::NOERROR().getCode(), response->getRcode().getCode());
  764. D2ZonePtr zone = response->getZone();
  765. EXPECT_TRUE(zone);
  766. EXPECT_EQ("response.example.com.", zone->getName().toText());
  767. }
  768. /// @brief Tests the prepNewRequest method
  769. TEST_F(NameChangeTransactionTest, prepNewRequest) {
  770. NameChangeStubPtr name_change;
  771. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  772. D2UpdateMessagePtr request;
  773. // prepNewRequest should fail on empty domain.
  774. ASSERT_THROW(request = name_change->prepNewRequest(DdnsDomainPtr()),
  775. NameChangeTransactionError);
  776. // Verify that prepNewRequest fails on invalid zone name.
  777. // @todo This test becomes obsolete if/when DdnsDomain enforces valid
  778. // names as is done in dns::Name.
  779. DdnsDomainPtr bsDomain = makeDomain(".badname","");
  780. ASSERT_THROW(request = name_change->prepNewRequest(bsDomain),
  781. NameChangeTransactionError);
  782. // Verify that prepNewRequest properly constructs a message given
  783. // valid input.
  784. ASSERT_NO_THROW(request = name_change->prepNewRequest(forward_domain_));
  785. checkZone(request, forward_domain_->getName());
  786. }
  787. /// @brief Tests the addLeaseAddressRData method
  788. TEST_F(NameChangeTransactionTest, addLeaseAddressRData) {
  789. NameChangeStubPtr name_change;
  790. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  791. dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr();
  792. // Verify we can add a lease RData to an valid RRset.
  793. dns::RRsetPtr rrset(new dns::RRset(dns::Name("bs"), dns::RRClass::IN(),
  794. name_change->getAddressRRType(),
  795. dns::RRTTL(0)));
  796. ASSERT_NO_THROW(name_change->addLeaseAddressRdata(rrset));
  797. // Verify the Rdata was added and the value is correct.
  798. ASSERT_EQ(1, rrset->getRdataCount());
  799. dns::RdataIteratorPtr rdata_it = rrset->getRdataIterator();
  800. ASSERT_TRUE(rdata_it);
  801. EXPECT_EQ(ncr->getIpAddress(), rdata_it->getCurrent().toText());
  802. }
  803. /// @brief Tests the addDhcidRData method
  804. TEST_F(NameChangeTransactionTest, addDhcidRdata) {
  805. NameChangeStubPtr name_change;
  806. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  807. dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr();
  808. // Verify we can add a lease RData to an valid RRset.
  809. dns::RRsetPtr rrset(new dns::RRset(dns::Name("bs"), dns::RRClass::IN(),
  810. dns::RRType::DHCID(), dns::RRTTL(0)));
  811. ASSERT_NO_THROW(name_change->addDhcidRdata(rrset));
  812. // Verify the Rdata was added and the value is correct.
  813. ASSERT_EQ(1, rrset->getRdataCount());
  814. dns::RdataIteratorPtr rdata_it = rrset->getRdataIterator();
  815. ASSERT_TRUE(rdata_it);
  816. const std::vector<uint8_t>& ncr_dhcid = ncr->getDhcid().getBytes();
  817. util::InputBuffer buffer(ncr_dhcid.data(), ncr_dhcid.size());
  818. dns::rdata::in::DHCID rdata_ref(buffer, ncr_dhcid.size());
  819. EXPECT_EQ(0, rdata_ref.compare(rdata_it->getCurrent()));
  820. }
  821. /// @brief Tests the addPtrData method
  822. TEST_F(NameChangeTransactionTest, addPtrRdata) {
  823. NameChangeStubPtr name_change;
  824. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  825. dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr();
  826. // Verify we can add a PTR RData to an valid RRset.
  827. dns::RRsetPtr rrset (new dns::RRset(dns::Name("bs"), dns::RRClass::IN(),
  828. dns::RRType::PTR(), dns::RRTTL(0)));
  829. ASSERT_NO_THROW(name_change->addPtrRdata(rrset));
  830. // Verify the Rdata was added and the value is correct.
  831. ASSERT_EQ(1, rrset->getRdataCount());
  832. dns::RdataIteratorPtr rdata_it = rrset->getRdataIterator();
  833. ASSERT_TRUE(rdata_it);
  834. EXPECT_EQ(ncr->getFqdn(), rdata_it->getCurrent().toText());
  835. }
  836. }; // anonymous namespace