nc_trans_unittests.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. // Copyright (C) 2013 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 <d2/nc_trans.h>
  15. #include <boost/function.hpp>
  16. #include <boost/bind.hpp>
  17. #include <gtest/gtest.h>
  18. using namespace std;
  19. using namespace isc;
  20. using namespace isc::d2;
  21. namespace {
  22. /// @brief Test derivation of NameChangeTransaction for exercising state
  23. /// model mechanics.
  24. ///
  25. /// This class facilitates testing by making non-public methods accessible so
  26. /// they can be invoked directly in test routines. It implements a very
  27. /// rudimentary state model, sufficient to test the state model mechanics
  28. /// supplied by the base class.
  29. class NameChangeStub : public NameChangeTransaction {
  30. public:
  31. // NameChangeStub states
  32. static const int DOING_UPDATE_ST = NCT_STATE_MAX + 1;
  33. // NameChangeStub events
  34. static const int SEND_UPDATE_EVT = NCT_EVENT_MAX + 2;
  35. /// @brief Constructor
  36. ///
  37. /// Parameters match those needed by NameChangeTransaction.
  38. NameChangeStub(isc::asiolink::IOService& io_service,
  39. dhcp_ddns::NameChangeRequestPtr& ncr,
  40. DdnsDomainPtr forward_domain,
  41. DdnsDomainPtr reverse_domain)
  42. : NameChangeTransaction(io_service, ncr, forward_domain,
  43. reverse_domain) {
  44. }
  45. /// @brief Destructor
  46. virtual ~NameChangeStub() {
  47. }
  48. /// @brief Empty handler used to statisfy map verification.
  49. void dummyHandler() {
  50. isc_throw(NameChangeTransactionError,
  51. "dummyHandler - invalid event: " << getContextStr());
  52. }
  53. /// @brief State handler for the READY_ST.
  54. ///
  55. /// Serves as the starting state handler, it consumes the
  56. /// START_EVT "transitioning" to the state, DOING_UPDATE_ST and
  57. /// sets the next event to SEND_UPDATE_EVT.
  58. void readyHandler() {
  59. switch(getNextEvent()) {
  60. case START_EVT:
  61. transition(DOING_UPDATE_ST, SEND_UPDATE_EVT);
  62. break;
  63. default:
  64. // its bogus
  65. isc_throw(NameChangeTransactionError,
  66. "readyHandler - invalid event: " << getContextStr());
  67. }
  68. }
  69. /// @brief State handler for the DOING_UPDATE_ST.
  70. ///
  71. /// Simulates a state that starts some form of asynchronous work.
  72. /// When next event is SEND_UPDATE_EVT it sets the status to pending
  73. /// and signals the state model must "wait" for an event by setting
  74. /// next event to NOP_EVT.
  75. ///
  76. /// When next event is IO_COMPLETED_EVT, it transitions to the state,
  77. /// PROCESS_TRANS_OK_ST, and sets the next event to UPDATE_OK_EVT.
  78. void doingUpdateHandler() {
  79. switch(getNextEvent()) {
  80. case SEND_UPDATE_EVT:
  81. setNcrStatus(dhcp_ddns::ST_PENDING);
  82. postNextEvent(NOP_EVT);
  83. break;
  84. case IO_COMPLETED_EVT:
  85. if (getDnsUpdateStatus() == DNSClient::SUCCESS) {
  86. setForwardChangeCompleted(true);
  87. transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
  88. } else {
  89. transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
  90. }
  91. break;
  92. default:
  93. // its bogus
  94. isc_throw(NameChangeTransactionError,
  95. "doingUpdateHandler - invalid event: "
  96. << getContextStr());
  97. }
  98. }
  99. /// @brief State handler for the PROCESS_TRANS_OK_ST.
  100. ///
  101. /// This is the last state in the model. Note that it sets the
  102. /// status to completed and next event to NOP_EVT.
  103. void processTransDoneHandler() {
  104. switch(getNextEvent()) {
  105. case UPDATE_OK_EVT:
  106. setNcrStatus(dhcp_ddns::ST_COMPLETED);
  107. endModel();
  108. break;
  109. case UPDATE_FAILED_EVT:
  110. setNcrStatus(dhcp_ddns::ST_FAILED);
  111. endModel();
  112. break;
  113. default:
  114. // its bogus
  115. isc_throw(NameChangeTransactionError,
  116. "processTransDoneHandler - invalid event: "
  117. << getContextStr());
  118. }
  119. }
  120. /// @brief Initializes the state handler map.
  121. void initStateHandlerMap() {
  122. addToMap(READY_ST,
  123. boost::bind(&NameChangeStub::readyHandler, this));
  124. addToMap(SELECTING_FWD_SERVER_ST,
  125. boost::bind(&NameChangeStub::dummyHandler, this));
  126. addToMap(SELECTING_REV_SERVER_ST,
  127. boost::bind(&NameChangeStub::dummyHandler, this));
  128. addToMap(DOING_UPDATE_ST,
  129. boost::bind(&NameChangeStub::doingUpdateHandler, this));
  130. addToMap(PROCESS_TRANS_OK_ST,
  131. boost::bind(&NameChangeStub::processTransDoneHandler, this));
  132. addToMap(PROCESS_TRANS_FAILED_ST,
  133. boost::bind(&NameChangeStub::processTransDoneHandler, this));
  134. }
  135. void verifyStateHandlerMap() {
  136. getStateHandler(READY_ST);
  137. getStateHandler(DOING_UPDATE_ST);
  138. // Call base class verification.
  139. NameChangeTransaction::verifyStateHandlerMap();
  140. }
  141. const char* getStateLabel(const int state) const {
  142. const char* str = "Unknown";
  143. switch(state) {
  144. case NameChangeStub::DOING_UPDATE_ST:
  145. str = "NameChangeStub::DOING_UPDATE_ST";
  146. break;
  147. default:
  148. str = NameChangeTransaction::getStateLabel(state);
  149. break;
  150. }
  151. return (str);
  152. }
  153. const char* getEventLabel(const int event) const {
  154. const char* str = "Unknown";
  155. switch(event) {
  156. case NameChangeStub::SEND_UPDATE_EVT:
  157. str = "NameChangeStub::SEND_UPDATE_EVT";
  158. break;
  159. default:
  160. str = NameChangeTransaction::getEventLabel(event);
  161. break;
  162. }
  163. return (str);
  164. }
  165. // Expose the protected methods to be tested.
  166. using StateModel::runModel;
  167. using StateModel::getStateHandler;
  168. using NameChangeTransaction::initServerSelection;
  169. using NameChangeTransaction::selectNextServer;
  170. using NameChangeTransaction::getCurrentServer;
  171. using NameChangeTransaction::getDNSClient;
  172. using NameChangeTransaction::setNcrStatus;
  173. using NameChangeTransaction::setDnsUpdateStatus;
  174. using NameChangeTransaction::getDnsUpdateResponse;
  175. using NameChangeTransaction::getForwardChangeCompleted;
  176. using NameChangeTransaction::getReverseChangeCompleted;
  177. using NameChangeTransaction::setForwardChangeCompleted;
  178. using NameChangeTransaction::setReverseChangeCompleted;
  179. };
  180. /// @brief Defines a pointer to a NameChangeStubPtr instance.
  181. typedef boost::shared_ptr<NameChangeStub> NameChangeStubPtr;
  182. /// @brief Test fixture for testing NameChangeTransaction
  183. ///
  184. /// Note this class uses NameChangeStub class to exercise non-public
  185. /// aspects of NameChangeTransaction.
  186. class NameChangeTransactionTest : public ::testing::Test {
  187. public:
  188. isc::asiolink::IOService io_service_;
  189. DdnsDomainPtr forward_domain_;
  190. DdnsDomainPtr reverse_domain_;
  191. virtual ~NameChangeTransactionTest() {
  192. }
  193. /// @brief Instantiates a NameChangeStub built around a canned
  194. /// NameChangeRequest.
  195. NameChangeStubPtr makeCannedTransaction() {
  196. const char* msg_str =
  197. "{"
  198. " \"change_type\" : 0 , "
  199. " \"forward_change\" : true , "
  200. " \"reverse_change\" : true , "
  201. " \"fqdn\" : \"example.com.\" , "
  202. " \"ip_address\" : \"192.168.2.1\" , "
  203. " \"dhcid\" : \"0102030405060708\" , "
  204. " \"lease_expires_on\" : \"20130121132405\" , "
  205. " \"lease_length\" : 1300 "
  206. "}";
  207. dhcp_ddns::NameChangeRequestPtr ncr;
  208. DnsServerInfoStoragePtr servers(new DnsServerInfoStorage());
  209. DnsServerInfoPtr server;
  210. ncr = dhcp_ddns::NameChangeRequest::fromJSON(msg_str);
  211. // make forward server list
  212. server.reset(new DnsServerInfo("forward.example.com",
  213. isc::asiolink::IOAddress("1.1.1.1")));
  214. servers->push_back(server);
  215. forward_domain_.reset(new DdnsDomain("*", "", servers));
  216. // make reverse server list
  217. servers->clear();
  218. server.reset(new DnsServerInfo("reverse.example.com",
  219. isc::asiolink::IOAddress("2.2.2.2")));
  220. servers->push_back(server);
  221. reverse_domain_.reset(new DdnsDomain("*", "", servers));
  222. return (NameChangeStubPtr(new NameChangeStub(io_service_, ncr,
  223. forward_domain_, reverse_domain_)));
  224. }
  225. };
  226. /// @brief Tests NameChangeTransaction construction.
  227. /// This test verifies that:
  228. /// 1. Construction with null NameChangeRequest
  229. /// 2. Construction with null forward domain is not allowed when the request
  230. /// requires forward change.
  231. /// 3. Construction with null reverse domain is not allowed when the request
  232. /// requires reverse change.
  233. /// 4. Valid construction functions properly
  234. TEST(NameChangeTransaction, construction) {
  235. isc::asiolink::IOService io_service;
  236. const char* msg_str =
  237. "{"
  238. " \"change_type\" : 0 , "
  239. " \"forward_change\" : true , "
  240. " \"reverse_change\" : true , "
  241. " \"fqdn\" : \"example.com.\" , "
  242. " \"ip_address\" : \"192.168.2.1\" , "
  243. " \"dhcid\" : \"0102030405060708\" , "
  244. " \"lease_expires_on\" : \"20130121132405\" , "
  245. " \"lease_length\" : 1300 "
  246. "}";
  247. dhcp_ddns::NameChangeRequestPtr ncr;
  248. dhcp_ddns::NameChangeRequestPtr empty_ncr;
  249. DnsServerInfoStoragePtr servers;
  250. DdnsDomainPtr forward_domain;
  251. DdnsDomainPtr reverse_domain;
  252. DdnsDomainPtr empty_domain;
  253. ASSERT_NO_THROW(ncr = dhcp_ddns::NameChangeRequest::fromJSON(msg_str));
  254. ASSERT_NO_THROW(forward_domain.reset(new DdnsDomain("*", "", servers)));
  255. ASSERT_NO_THROW(reverse_domain.reset(new DdnsDomain("*", "", servers)));
  256. // Verify that construction with an empty NameChangeRequest throws.
  257. EXPECT_THROW(NameChangeTransaction(io_service, empty_ncr,
  258. forward_domain, reverse_domain),
  259. NameChangeTransactionError);
  260. // Verify that construction with an empty forward domain when the
  261. // NameChangeRequest calls for a forward change throws.
  262. EXPECT_THROW(NameChangeTransaction(io_service, ncr,
  263. empty_domain, reverse_domain),
  264. NameChangeTransactionError);
  265. // Verify that construction with an empty reverse domain when the
  266. // NameChangeRequest calls for a reverse change throws.
  267. EXPECT_THROW(NameChangeTransaction(io_service, ncr,
  268. forward_domain, empty_domain),
  269. NameChangeTransactionError);
  270. // Verify that a valid construction attempt works.
  271. EXPECT_NO_THROW(NameChangeTransaction(io_service, ncr,
  272. forward_domain, reverse_domain));
  273. // Verify that an empty forward domain is allowed when the requests does
  274. // not include a forward change.
  275. ncr->setForwardChange(false);
  276. ncr->setReverseChange(true);
  277. EXPECT_NO_THROW(NameChangeTransaction(io_service, ncr,
  278. empty_domain, reverse_domain));
  279. // Verify that an empty reverse domain is allowed when the requests does
  280. // not include a reverse change.
  281. ncr->setForwardChange(true);
  282. ncr->setReverseChange(false);
  283. EXPECT_NO_THROW(NameChangeTransaction(io_service, ncr,
  284. forward_domain, empty_domain));
  285. }
  286. /// @brief General testing of member accessors.
  287. /// Most if not all of these are also tested as a byproduct off larger tests.
  288. TEST_F(NameChangeTransactionTest, accessors) {
  289. NameChangeStubPtr name_change;
  290. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  291. // Verify that fetching the NameChangeRequest works.
  292. dhcp_ddns::NameChangeRequestPtr ncr = name_change->getNcr();
  293. ASSERT_TRUE(ncr);
  294. // Verify that getTransactionKey works.
  295. EXPECT_EQ(ncr->getDhcid(), name_change->getTransactionKey());
  296. // Verify that NcrStatus can be set and retrieved.
  297. EXPECT_NO_THROW(name_change->setNcrStatus(dhcp_ddns::ST_FAILED));
  298. EXPECT_EQ(dhcp_ddns::ST_FAILED, ncr->getStatus());
  299. // Verify that the forward domain can be retrieved.
  300. ASSERT_TRUE(name_change->getForwardDomain());
  301. EXPECT_EQ(forward_domain_, name_change->getForwardDomain());
  302. // Verify that the reverse domain can be retrieved.
  303. ASSERT_TRUE(name_change->getReverseDomain());
  304. EXPECT_EQ(reverse_domain_, name_change->getReverseDomain());
  305. // Neither of these have direct setters, but are tested under server
  306. // selection.
  307. EXPECT_FALSE(name_change->getDNSClient());
  308. EXPECT_FALSE(name_change->getCurrentServer());
  309. // Verify that DNS update status can be set and retrieved.
  310. EXPECT_NO_THROW(name_change->setDnsUpdateStatus(DNSClient::TIMEOUT));
  311. EXPECT_EQ(DNSClient::TIMEOUT, name_change->getDnsUpdateStatus());
  312. // Verify that the DNS update response can be retrieved.
  313. EXPECT_FALSE(name_change->getDnsUpdateResponse());
  314. // Verify that the forward change complete flag can be set and fetched.
  315. EXPECT_NO_THROW(name_change->setForwardChangeCompleted(true));
  316. EXPECT_TRUE(name_change->getForwardChangeCompleted());
  317. // Verify that the reverse change complete flag can be set and fetched.
  318. EXPECT_NO_THROW(name_change->setReverseChangeCompleted(true));
  319. EXPECT_TRUE(name_change->getReverseChangeCompleted());
  320. }
  321. /// @brief Tests state map initialization and validation.
  322. /// This tests the basic concept of state map initialization and verification
  323. /// by manually invoking the map methods normally by StateModel::startModel.
  324. TEST_F(NameChangeTransactionTest, stubStateMapInit) {
  325. NameChangeStubPtr name_change;
  326. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  327. // Verify that the map validation throws prior to the map being
  328. // initialized.
  329. ASSERT_THROW(name_change->verifyStateHandlerMap(), StateModelError);
  330. // Call initStateHandlerMap to initialize the state map.
  331. ASSERT_NO_THROW(name_change->initStateHandlerMap());
  332. // Verify that the map validation succeeds now that the map is initialized.
  333. ASSERT_NO_THROW(name_change->verifyStateHandlerMap());
  334. }
  335. /// @brief Tests server selection methods.
  336. /// Each transaction has a list of one or more servers for each DNS direction
  337. /// it is required to update. The transaction must be able to start at the
  338. /// beginning of a server list and cycle through them one at time, as needed,
  339. /// when a DNS exchange fails due to an IO error. This test verifies the
  340. /// ability to iteratively select a server from the list as the current server.
  341. TEST_F(NameChangeTransactionTest, serverSelectionTest) {
  342. NameChangeStubPtr name_change;
  343. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  344. // Verify that the forward domain and its list of servers can be retrieved.
  345. DdnsDomainPtr& domain = name_change->getForwardDomain();
  346. ASSERT_TRUE(domain);
  347. DnsServerInfoStoragePtr servers = domain->getServers();
  348. ASSERT_TRUE(servers);
  349. // Get the number of entries in the server list.
  350. int num_servers = servers->size();
  351. ASSERT_TRUE(num_servers > 0);
  352. // Verify that we can initialize server selection. This "resets" the
  353. // selection process to start over using the list of servers in the
  354. // given domain.
  355. ASSERT_NO_THROW(name_change->initServerSelection(domain));
  356. // The server selection process determines the current server,
  357. // instantiates a new DNSClient, and a DNS response message buffer.
  358. // We need to save the values before each selection, so we can verify
  359. // they are correct after each selection.
  360. DnsServerInfoPtr prev_server = name_change->getCurrentServer();
  361. DNSClientPtr prev_client = name_change->getDNSClient();
  362. D2UpdateMessagePtr prev_response = name_change->getDnsUpdateResponse();
  363. // Iteratively select through the list of servers.
  364. int passes = 0;
  365. while (name_change->selectNextServer()) {
  366. // Get the new values after the selection has been made.
  367. DnsServerInfoPtr server = name_change->getCurrentServer();
  368. DNSClientPtr client = name_change->getDNSClient();
  369. D2UpdateMessagePtr response = name_change->getDnsUpdateResponse();
  370. // Verify that the new values are not empty.
  371. EXPECT_TRUE(server);
  372. EXPECT_TRUE(client);
  373. EXPECT_TRUE(response);
  374. // Verify that the new values are indeed new.
  375. EXPECT_NE(server, prev_server);
  376. EXPECT_NE(client, prev_client);
  377. EXPECT_NE(response, prev_response);
  378. // Remember the selected values for the next pass.
  379. prev_server = server;
  380. prev_client = client;
  381. prev_response = response;
  382. ++passes;
  383. }
  384. // Verify that the number of passes made equal the number of servers.
  385. EXPECT_EQ (passes, num_servers);
  386. // Repeat the same test using the reverse domain.
  387. // Verify that the reverse domain and its list of servers can be retrieved.
  388. domain = name_change->getReverseDomain();
  389. ASSERT_TRUE(domain);
  390. servers = domain->getServers();
  391. ASSERT_TRUE(servers);
  392. // Get the number of entries in the server list.
  393. num_servers = servers->size();
  394. ASSERT_TRUE(num_servers > 0);
  395. // Verify that we can initialize server selection. This "resets" the
  396. // selection process to start over using the list of servers in the
  397. // given domain.
  398. ASSERT_NO_THROW(name_change->initServerSelection(domain));
  399. // The server selection process determines the current server,
  400. // instantiates a new DNSClient, and a DNS response message buffer.
  401. // We need to save the values before each selection, so we can verify
  402. // they are correct after each selection.
  403. prev_server = name_change->getCurrentServer();
  404. prev_client = name_change->getDNSClient();
  405. prev_response = name_change->getDnsUpdateResponse();
  406. // Iteratively select through the list of servers.
  407. passes = 0;
  408. while (name_change->selectNextServer()) {
  409. // Get the new values after the selection has been made.
  410. DnsServerInfoPtr server = name_change->getCurrentServer();
  411. DNSClientPtr client = name_change->getDNSClient();
  412. D2UpdateMessagePtr response = name_change->getDnsUpdateResponse();
  413. // Verify that the new values are not empty.
  414. EXPECT_TRUE(server);
  415. EXPECT_TRUE(client);
  416. EXPECT_TRUE(response);
  417. // Verify that the new values are indeed new.
  418. EXPECT_NE(server, prev_server);
  419. EXPECT_NE(client, prev_client);
  420. EXPECT_NE(response, prev_response);
  421. // Remember the selected values for the next pass.
  422. prev_server = server;
  423. prev_client = client;
  424. prev_response = response;
  425. ++passes;
  426. }
  427. // Verify that the number of passes made equal the number of servers.
  428. EXPECT_EQ (passes, num_servers);
  429. }
  430. /// @brief Tests the ability to decode state values into text labels.
  431. TEST_F(NameChangeTransactionTest, stateLabels) {
  432. NameChangeStubPtr name_change;
  433. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  434. // Verify StateModel labels.
  435. EXPECT_EQ("StateModel::NEW_ST",
  436. name_change->getStateLabel(StateModel::NEW_ST));
  437. EXPECT_EQ("StateModel::END_ST",
  438. name_change->getStateLabel(StateModel::END_ST));
  439. // Verify NameChangeTransaction labels
  440. EXPECT_EQ("NameChangeTransaction::READY_ST",
  441. name_change->getStateLabel(NameChangeTransaction::READY_ST));
  442. EXPECT_EQ("NameChangeTransaction::SELECTING_FWD_SERVER_ST",
  443. name_change->getStateLabel(NameChangeTransaction::
  444. SELECTING_FWD_SERVER_ST));
  445. EXPECT_EQ("NameChangeTransaction::SELECTING_REV_SERVER_ST",
  446. name_change->getStateLabel(NameChangeTransaction::
  447. SELECTING_REV_SERVER_ST));
  448. EXPECT_EQ("NameChangeTransaction::PROCESS_TRANS_OK_ST",
  449. name_change->getStateLabel(NameChangeTransaction::
  450. PROCESS_TRANS_OK_ST));
  451. EXPECT_EQ("NameChangeTransaction::PROCESS_TRANS_FAILED_ST",
  452. name_change->getStateLabel(NameChangeTransaction::
  453. PROCESS_TRANS_FAILED_ST));
  454. // Verify Stub states
  455. EXPECT_EQ("NameChangeStub::DOING_UPDATE_ST",
  456. name_change->getStateLabel(NameChangeStub::DOING_UPDATE_ST));
  457. // Verify unknown state.
  458. EXPECT_EQ("Unknown", name_change->getStateLabel(-1));
  459. }
  460. /// @brief Tests the ability to decode event values into text labels.
  461. TEST_F(NameChangeTransactionTest, eventLabels) {
  462. NameChangeStubPtr name_change;
  463. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  464. // Verify StateModel labels.
  465. EXPECT_EQ("StateModel::NOP_EVT",
  466. name_change->getEventLabel(StateModel::NOP_EVT));
  467. EXPECT_EQ("StateModel::START_EVT",
  468. name_change->getEventLabel(StateModel::START_EVT));
  469. EXPECT_EQ("StateModel::END_EVT",
  470. name_change->getEventLabel(StateModel::END_EVT));
  471. EXPECT_EQ("StateModel::FAIL_EVT",
  472. name_change->getEventLabel(StateModel::FAIL_EVT));
  473. // Verify NameChangeTransactionLabels
  474. EXPECT_EQ("NameChangeTransaction::SELECT_SERVER_EVT",
  475. name_change->getEventLabel(NameChangeTransaction::
  476. SELECT_SERVER_EVT));
  477. EXPECT_EQ("NameChangeTransaction::SERVER_SELECTED_EVT",
  478. name_change->getEventLabel(NameChangeTransaction::
  479. SERVER_SELECTED_EVT));
  480. EXPECT_EQ("NameChangeTransaction::SERVER_IO_ERROR_EVT",
  481. name_change->getEventLabel(NameChangeTransaction::
  482. SERVER_IO_ERROR_EVT));
  483. EXPECT_EQ("NameChangeTransaction::NO_MORE_SERVERS_EVT",
  484. name_change->getEventLabel(NameChangeTransaction::
  485. NO_MORE_SERVERS_EVT));
  486. EXPECT_EQ("NameChangeTransaction::IO_COMPLETED_EVT",
  487. name_change->getEventLabel(NameChangeTransaction::
  488. IO_COMPLETED_EVT));
  489. EXPECT_EQ("NameChangeTransaction::UPDATE_OK_EVT",
  490. name_change->getEventLabel(NameChangeTransaction::
  491. UPDATE_OK_EVT));
  492. EXPECT_EQ("NameChangeTransaction::UPDATE_FAILED_EVT",
  493. name_change->getEventLabel(NameChangeTransaction::
  494. UPDATE_FAILED_EVT));
  495. // Verify stub class labels.
  496. EXPECT_EQ("NameChangeStub::SEND_UPDATE_EVT",
  497. name_change->getEventLabel(NameChangeStub::SEND_UPDATE_EVT));
  498. // Verify unknown state.
  499. EXPECT_EQ("Unknown", name_change->getEventLabel(-1));
  500. }
  501. /// @brief Tests that the transaction will be "failed" upon model errors.
  502. TEST_F(NameChangeTransactionTest, modelFailure) {
  503. NameChangeStubPtr name_change;
  504. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  505. // We will cause a model failure by attempting to submit an event to
  506. // NEW_ST. Let's make sure that state is NEW_ST and that NEW_ST has no
  507. // handler.
  508. ASSERT_EQ(NameChangeTransaction::NEW_ST, name_change->getState());
  509. ASSERT_THROW(name_change->getStateHandler(NameChangeTransaction::NEW_ST),
  510. StateModelError);
  511. // Now call runStateModel() which should not throw.
  512. EXPECT_NO_THROW(name_change->runModel(NameChangeTransaction::START_EVT));
  513. // Verify that the model reports are done but failed.
  514. EXPECT_TRUE(name_change->isModelDone());
  515. EXPECT_TRUE(name_change->didModelFail());
  516. // Verify that the transaction has failed.
  517. EXPECT_EQ(dhcp_ddns::ST_FAILED, name_change->getNcrStatus());
  518. }
  519. /// @brief Tests the ability to use startTransaction to initate the state
  520. /// model execution, and DNSClient callback, operator(), to resume the
  521. /// the model with a update successful outcome.
  522. TEST_F(NameChangeTransactionTest, successfulUpdateTest) {
  523. NameChangeStubPtr name_change;
  524. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  525. EXPECT_TRUE(name_change->isModelNew());
  526. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  527. // Launch the transaction by calling startTransaction. The state model
  528. // should run up until the "IO" operation is initiated in DOING_UPDATE_ST.
  529. ASSERT_NO_THROW(name_change->startTransaction());
  530. // Verify that the model is running but waiting, and that forward change
  531. // completion is still false.
  532. EXPECT_TRUE(name_change->isModelRunning());
  533. EXPECT_TRUE(name_change->isModelWaiting());
  534. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  535. // Simulate completion of DNSClient exchange by invoking the callback, as
  536. // DNSClient would. This should cause the state model to progress through
  537. // completion.
  538. EXPECT_NO_THROW((*name_change)(DNSClient::SUCCESS));
  539. // The model should have worked through to completion.
  540. // Verify that the model is done and not failed.
  541. EXPECT_TRUE(name_change->isModelDone());
  542. EXPECT_FALSE(name_change->didModelFail());
  543. // Verify that NCR status is completed, and that the forward change
  544. // was completed.
  545. EXPECT_EQ(dhcp_ddns::ST_COMPLETED, name_change->getNcrStatus());
  546. EXPECT_TRUE(name_change->getForwardChangeCompleted());
  547. }
  548. /// @brief Tests the ability to use startTransaction to initate the state
  549. /// model execution, and DNSClient callback, operator(), to resume the
  550. /// the model with a update failure outcome.
  551. TEST_F(NameChangeTransactionTest, failedUpdateTest) {
  552. NameChangeStubPtr name_change;
  553. ASSERT_NO_THROW(name_change = makeCannedTransaction());
  554. // Launch the transaction by calling startTransaction. The state model
  555. // should run up until the "IO" operation is initiated in DOING_UPDATE_ST.
  556. ASSERT_NO_THROW(name_change->startTransaction());
  557. // Vefity that the model is running but waiting, and that the forward
  558. // change has not been completed.
  559. EXPECT_TRUE(name_change->isModelRunning());
  560. EXPECT_TRUE(name_change->isModelWaiting());
  561. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  562. // Simulate completion of DNSClient exchange by invoking the callback, as
  563. // DNSClient would. This should cause the state model to progress through
  564. // to completion.
  565. EXPECT_NO_THROW((*name_change)(DNSClient::TIMEOUT));
  566. // The model should have worked through to completion.
  567. // Verify that the model is done and not failed.
  568. EXPECT_TRUE(name_change->isModelDone());
  569. EXPECT_FALSE(name_change->didModelFail());
  570. // Verify that the NCR status is failed and that the forward change
  571. // was not completed.
  572. EXPECT_EQ(dhcp_ddns::ST_FAILED, name_change->getNcrStatus());
  573. EXPECT_FALSE(name_change->getForwardChangeCompleted());
  574. }
  575. }