d2_update_mgr_unittests.cc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. // Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <asiolink/io_service.h>
  8. #include <d2/d2_update_mgr.h>
  9. #include <util/time_utilities.h>
  10. #include <d_test_stubs.h>
  11. #include <nc_test_utils.h>
  12. #include <boost/function.hpp>
  13. #include <boost/bind.hpp>
  14. #include <gtest/gtest.h>
  15. #include <gtest/gtest.h>
  16. #include <algorithm>
  17. #include <vector>
  18. using namespace std;
  19. using namespace isc;
  20. using namespace isc::dhcp_ddns;
  21. using namespace isc::d2;
  22. namespace {
  23. /// @brief Wrapper class for D2UpdateMgr providing access to non-public methods.
  24. ///
  25. /// This class facilitates testing by making non-public methods accessible so
  26. /// they can be invoked directly in test routines.
  27. class D2UpdateMgrWrapper : public D2UpdateMgr {
  28. public:
  29. /// @brief Constructor
  30. ///
  31. /// Parameters match those needed by D2UpdateMgr.
  32. D2UpdateMgrWrapper(D2QueueMgrPtr& queue_mgr, D2CfgMgrPtr& cfg_mgr,
  33. asiolink::IOServicePtr& io_service,
  34. const size_t max_transactions = MAX_TRANSACTIONS_DEFAULT)
  35. : D2UpdateMgr(queue_mgr, cfg_mgr, io_service, max_transactions) {
  36. }
  37. /// @brief Destructor
  38. virtual ~D2UpdateMgrWrapper() {
  39. }
  40. // Expose the protected methods to be tested.
  41. using D2UpdateMgr::checkFinishedTransactions;
  42. using D2UpdateMgr::pickNextJob;
  43. using D2UpdateMgr::makeTransaction;
  44. };
  45. /// @brief Defines a pointer to a D2UpdateMgr instance.
  46. typedef boost::shared_ptr<D2UpdateMgrWrapper> D2UpdateMgrWrapperPtr;
  47. /// @brief Test fixture for testing D2UpdateMgr.
  48. ///
  49. /// Note this class uses D2UpdateMgrWrapper class to exercise non-public
  50. /// aspects of D2UpdateMgr. D2UpdateMgr depends on both D2QueueMgr and
  51. /// D2CfgMgr. This fixture provides an instance of each, plus a canned,
  52. /// valid DHCP_DDNS configuration sufficient to test D2UpdateMgr's basic
  53. /// functions.
  54. class D2UpdateMgrTest : public TimedIO, public ConfigParseTest {
  55. public:
  56. D2QueueMgrPtr queue_mgr_;
  57. D2CfgMgrPtr cfg_mgr_;
  58. D2UpdateMgrWrapperPtr update_mgr_;
  59. std::vector<NameChangeRequestPtr> canned_ncrs_;
  60. size_t canned_count_;
  61. D2UpdateMgrTest() {
  62. queue_mgr_.reset(new D2QueueMgr(io_service_));
  63. cfg_mgr_.reset(new D2CfgMgr());
  64. update_mgr_.reset(new D2UpdateMgrWrapper(queue_mgr_, cfg_mgr_,
  65. io_service_));
  66. makeCannedNcrs();
  67. makeCannedConfig();
  68. }
  69. ~D2UpdateMgrTest() {
  70. }
  71. /// @brief Creates a list of valid NameChangeRequest.
  72. ///
  73. /// This method builds a list of NameChangeRequests from a single
  74. /// JSON string request. Each request is assigned a unique DHCID.
  75. void makeCannedNcrs() {
  76. const char* msg_str =
  77. "{"
  78. " \"change-type\" : 0 , "
  79. " \"forward-change\" : true , "
  80. " \"reverse-change\" : false , "
  81. " \"fqdn\" : \"my.example.com.\" , "
  82. " \"ip-address\" : \"192.168.1.2\" , "
  83. " \"dhcid\" : \"0102030405060708\" , "
  84. " \"lease-expires-on\" : \"20130121132405\" , "
  85. " \"lease-length\" : 1300 "
  86. "}";
  87. const char* dhcids[] = { "111111", "222222", "333333", "444444"};
  88. canned_count_ = 4;
  89. for (int i = 0; i < canned_count_; i++) {
  90. dhcp_ddns::NameChangeRequestPtr ncr = NameChangeRequest::
  91. fromJSON(msg_str);
  92. ncr->setDhcid(dhcids[i]);
  93. ncr->setChangeType(i % 2 == 0 ?
  94. dhcp_ddns::CHG_ADD : dhcp_ddns::CHG_REMOVE);
  95. canned_ncrs_.push_back(ncr);
  96. }
  97. }
  98. /// @brief Seeds configuration manager with a valid DHCP_DDNS configuration.
  99. void makeCannedConfig() {
  100. std::string canned_config_ =
  101. "{ "
  102. "\"ip-address\" : \"192.168.1.33\" , "
  103. "\"port\" : 88 , "
  104. "\"tsig-keys\": [] ,"
  105. "\"forward-ddns\" : {"
  106. "\"ddns-domains\": [ "
  107. "{ \"name\": \"example.com.\" , "
  108. " \"dns-servers\" : [ "
  109. " { \"ip-address\": \"127.0.0.1\", \"port\" : 5301 } "
  110. " ] },"
  111. "{ \"name\": \"org.\" , "
  112. " \"dns-servers\" : [ "
  113. " { \"ip-address\": \"127.0.0.1\" } "
  114. " ] }, "
  115. "] }, "
  116. "\"reverse-ddns\" : { "
  117. "\"ddns-domains\": [ "
  118. "{ \"name\": \"1.168.192.in-addr.arpa.\" , "
  119. " \"dns-servers\" : [ "
  120. " { \"ip-address\": \"127.0.0.1\", \"port\" : 5301 } "
  121. " ] }, "
  122. "{ \"name\": \"2.0.3.0.8.B.D.0.1.0.0.2.ip6.arpa.\" , "
  123. " \"dns-servers\" : [ "
  124. " { \"ip-address\": \"127.0.0.1\" } "
  125. " ] } "
  126. "] } }";
  127. // If this configuration fails to parse most tests will fail.
  128. ASSERT_TRUE(fromJSON(canned_config_));
  129. answer_ = cfg_mgr_->parseConfig(config_set_);
  130. ASSERT_TRUE(checkAnswer(0));
  131. }
  132. /// @brief Fakes the completion of a given transaction.
  133. ///
  134. /// @param index index of the request from which the transaction was formed.
  135. /// @param status completion status to assign to the request
  136. void completeTransaction(const size_t index,
  137. const dhcp_ddns::NameChangeStatus& status) {
  138. // add test on index
  139. if (index >= canned_count_) {
  140. ADD_FAILURE() << "request index is out of range: " << index;
  141. }
  142. const dhcp_ddns::D2Dhcid key = canned_ncrs_[index]->getDhcid();
  143. // locate the transaction based on the request DHCID
  144. TransactionList::iterator pos = update_mgr_->findTransaction(key);
  145. if (pos == update_mgr_->transactionListEnd()) {
  146. ADD_FAILURE() << "cannot find transaction for key: " << key.toStr();
  147. }
  148. NameChangeTransactionPtr trans = (*pos).second;
  149. // Update the status of the request
  150. trans->getNcr()->setStatus(status);
  151. // End the model.
  152. trans->endModel();
  153. }
  154. /// @brief Determines if any transactions are waiting for IO completion.
  155. ///
  156. /// @returns True if isModelWaiting() is true for at least one of the current
  157. /// transactions.
  158. bool anyoneWaiting() {
  159. TransactionList::iterator it = update_mgr_->transactionListBegin();
  160. while (it != update_mgr_->transactionListEnd()) {
  161. if (((*it).second)->isModelWaiting()) {
  162. return true;
  163. }
  164. }
  165. return false;
  166. }
  167. /// @brief Process events until all requests have been completed.
  168. ///
  169. /// This method iteratively calls D2UpdateMgr::sweep and executes
  170. /// IOService calls until both the request queue and transaction list
  171. /// are empty or a timeout occurs. Note that in addition to the safety
  172. /// timer, the number of passes through the loop is also limited to
  173. /// a given number. This is a failsafe to guard against an infinite loop
  174. /// in the test.
  175. void processAll(size_t max_passes = 100) {
  176. // Loop until all the transactions have been dequeued and run through to
  177. // completion.
  178. size_t passes = 0;
  179. size_t handlers = 0;
  180. // Set the timeout to slightly more than DNSClient timeout to allow
  181. // timeout processing to occur naturally.
  182. size_t timeout = cfg_mgr_->getD2Params()->getDnsServerTimeout() + 100;
  183. while (update_mgr_->getQueueCount() ||
  184. update_mgr_->getTransactionCount()) {
  185. ++passes;
  186. update_mgr_->sweep();
  187. // If any transactions are waiting on IO, run the service.
  188. if (anyoneWaiting()) {
  189. int cnt = runTimedIO(timeout);
  190. // If cnt is zero then the service stopped unexpectedly.
  191. if (cnt == 0) {
  192. ADD_FAILURE()
  193. << "processALL: IO service stopped unexpectedly,"
  194. << " passes: " << passes << ", handlers executed: "
  195. << handlers;
  196. }
  197. handlers += cnt;
  198. }
  199. // This is a last resort fail safe to ensure we don't go around
  200. // forever. We cut it off the number of passes at 100 (default
  201. // value). This is roughly ten times the number for the longest
  202. // test (currently, multiTransactionTimeout).
  203. if (passes > max_passes) {
  204. ADD_FAILURE() << "processALL failed, too many passes: "
  205. << passes << ", total handlers executed: " << handlers;
  206. }
  207. }
  208. }
  209. };
  210. /// @brief Tests the D2UpdateMgr construction.
  211. /// This test verifies that:
  212. /// 1. Construction with invalid queue manager is not allowed
  213. /// 2. Construction with invalid configuration manager is not allowed
  214. /// 3. Construction with max transactions of zero is not allowed
  215. /// 4. Default construction works and max transactions is defaulted properly
  216. /// 5. Construction with custom max transactions works properly
  217. TEST(D2UpdateMgr, construction) {
  218. asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
  219. D2QueueMgrPtr queue_mgr;
  220. D2CfgMgrPtr cfg_mgr;
  221. D2UpdateMgrPtr update_mgr;
  222. // Verify that constructor fails if given an invalid queue manager.
  223. ASSERT_NO_THROW(cfg_mgr.reset(new D2CfgMgr()));
  224. EXPECT_THROW(D2UpdateMgr(queue_mgr, cfg_mgr, io_service),
  225. D2UpdateMgrError);
  226. // Verify that constructor fails if given an invalid config manager.
  227. ASSERT_NO_THROW(queue_mgr.reset(new D2QueueMgr(io_service)));
  228. ASSERT_NO_THROW(cfg_mgr.reset());
  229. EXPECT_THROW(D2UpdateMgr(queue_mgr, cfg_mgr, io_service),
  230. D2UpdateMgrError);
  231. ASSERT_NO_THROW(cfg_mgr.reset(new D2CfgMgr()));
  232. // Verify that constructor fails with invalid io_service.
  233. io_service.reset();
  234. EXPECT_THROW(D2UpdateMgr(queue_mgr, cfg_mgr, io_service),
  235. D2UpdateMgrError);
  236. io_service.reset(new isc::asiolink::IOService());
  237. // Verify that max transactions cannot be zero.
  238. EXPECT_THROW(D2UpdateMgr(queue_mgr, cfg_mgr, io_service, 0),
  239. D2UpdateMgrError);
  240. // Verify that given valid values, constructor works.
  241. ASSERT_NO_THROW(update_mgr.reset(new D2UpdateMgr(queue_mgr, cfg_mgr,
  242. io_service)));
  243. // Verify that max transactions defaults properly.
  244. EXPECT_EQ(D2UpdateMgr::MAX_TRANSACTIONS_DEFAULT,
  245. update_mgr->getMaxTransactions());
  246. // Verify that constructor permits custom max transactions.
  247. ASSERT_NO_THROW(update_mgr.reset(new D2UpdateMgr(queue_mgr, cfg_mgr,
  248. io_service, 100)));
  249. // Verify that max transactions is correct.
  250. EXPECT_EQ(100, update_mgr->getMaxTransactions());
  251. }
  252. /// @brief Tests the D2UpdateManager's transaction list services
  253. /// This test verifies that:
  254. /// 1. A transaction can be added to the list.
  255. /// 2. Finding a transaction in the list by key works correctly.
  256. /// 3. Looking for a non-existent transaction works properly.
  257. /// 4. Attempting to add a transaction for a DHCID already in the list fails.
  258. /// 5. Removing a transaction by key works properly.
  259. /// 6. Attempting to remove an non-existent transaction does no harm.
  260. TEST_F(D2UpdateMgrTest, transactionList) {
  261. // Grab a canned request for test purposes.
  262. NameChangeRequestPtr& ncr = canned_ncrs_[0];
  263. TransactionList::iterator pos;
  264. // Verify that we can add a transaction.
  265. EXPECT_NO_THROW(update_mgr_->makeTransaction(ncr));
  266. EXPECT_EQ(1, update_mgr_->getTransactionCount());
  267. // Verify that we can find a transaction by key.
  268. EXPECT_NO_THROW(pos = update_mgr_->findTransaction(ncr->getDhcid()));
  269. EXPECT_TRUE(pos != update_mgr_->transactionListEnd());
  270. // Verify that convenience method has same result.
  271. EXPECT_TRUE(update_mgr_->hasTransaction(ncr->getDhcid()));
  272. // Verify that we will not find a transaction that isn't there.
  273. dhcp_ddns::D2Dhcid bogus_id("FFFF");
  274. EXPECT_NO_THROW(pos = update_mgr_->findTransaction(bogus_id));
  275. EXPECT_TRUE(pos == update_mgr_->transactionListEnd());
  276. // Verify that convenience method has same result.
  277. EXPECT_FALSE(update_mgr_->hasTransaction(bogus_id));
  278. // Verify that adding a transaction for the same key fails.
  279. EXPECT_THROW(update_mgr_->makeTransaction(ncr), D2UpdateMgrError);
  280. EXPECT_EQ(1, update_mgr_->getTransactionCount());
  281. // Verify the we can remove a transaction by key.
  282. EXPECT_NO_THROW(update_mgr_->removeTransaction(ncr->getDhcid()));
  283. EXPECT_EQ(0, update_mgr_->getTransactionCount());
  284. // Verify the we can try to remove a non-existent transaction without harm.
  285. EXPECT_NO_THROW(update_mgr_->removeTransaction(ncr->getDhcid()));
  286. }
  287. /// @brief Checks transaction creation when both update directions are enabled.
  288. /// Verifies that when both directions are enabled and servers are matched to
  289. /// the request, that the transaction is created with both directions turned on.
  290. TEST_F(D2UpdateMgrTest, bothEnabled) {
  291. // Grab a canned request for test purposes.
  292. NameChangeRequestPtr& ncr = canned_ncrs_[0];
  293. ncr->setReverseChange(true);
  294. // Verify we are requesting both directions.
  295. ASSERT_TRUE(ncr->isForwardChange());
  296. ASSERT_TRUE(ncr->isReverseChange());
  297. // Verify both both directions are enabled.
  298. ASSERT_TRUE(cfg_mgr_->forwardUpdatesEnabled());
  299. ASSERT_TRUE(cfg_mgr_->reverseUpdatesEnabled());
  300. // Attempt to make a transaction.
  301. ASSERT_NO_THROW(update_mgr_->makeTransaction(ncr));
  302. // Verify we create a transaction with both directions turned on.
  303. EXPECT_EQ(1, update_mgr_->getTransactionCount());
  304. EXPECT_TRUE(ncr->isForwardChange());
  305. EXPECT_TRUE(ncr->isReverseChange());
  306. }
  307. /// @brief Checks transaction creation when reverse updates are disabled.
  308. /// Verifies that when reverse updates are disabled, and there matching forward
  309. /// servers, that the transaction is still created but with only the forward
  310. /// direction turned on.
  311. TEST_F(D2UpdateMgrTest, reverseDisable) {
  312. // Make a NCR which requests both directions.
  313. NameChangeRequestPtr& ncr = canned_ncrs_[0];
  314. ncr->setReverseChange(true);
  315. // Wipe out forward domain list.
  316. DdnsDomainMapPtr emptyDomains(new DdnsDomainMap());
  317. cfg_mgr_->getD2CfgContext()->getReverseMgr()->setDomains(emptyDomains);
  318. // Verify enable methods are correct.
  319. ASSERT_TRUE(cfg_mgr_->forwardUpdatesEnabled());
  320. ASSERT_FALSE(cfg_mgr_->reverseUpdatesEnabled());
  321. // Attempt to make a transaction.
  322. ASSERT_NO_THROW(update_mgr_->makeTransaction(ncr));
  323. // Verify we create a transaction with only forward turned on.
  324. EXPECT_EQ(1, update_mgr_->getTransactionCount());
  325. EXPECT_TRUE(ncr->isForwardChange());
  326. EXPECT_FALSE(ncr->isReverseChange());
  327. }
  328. /// @brief Checks transaction creation when forward updates are disabled.
  329. /// Verifies that when forward updates are disabled, and there matching reverse
  330. /// servers, that the transaction is still created but with only the reverse
  331. /// direction turned on.
  332. TEST_F(D2UpdateMgrTest, forwardDisabled) {
  333. // Make a NCR which requests both directions.
  334. NameChangeRequestPtr& ncr = canned_ncrs_[0];
  335. ncr->setReverseChange(true);
  336. // Wipe out forward domain list.
  337. DdnsDomainMapPtr emptyDomains(new DdnsDomainMap());
  338. cfg_mgr_->getD2CfgContext()->getForwardMgr()->setDomains(emptyDomains);
  339. // Verify enable methods are correct.
  340. ASSERT_FALSE(cfg_mgr_->forwardUpdatesEnabled());
  341. ASSERT_TRUE(cfg_mgr_->reverseUpdatesEnabled());
  342. // Attempt to make a transaction.
  343. ASSERT_NO_THROW(update_mgr_->makeTransaction(ncr));
  344. // Verify we create a transaction with only reverse turned on.
  345. EXPECT_EQ(1, update_mgr_->getTransactionCount());
  346. EXPECT_FALSE(ncr->isForwardChange());
  347. EXPECT_TRUE(ncr->isReverseChange());
  348. }
  349. /// @brief Checks transaction creation when neither update direction is enabled.
  350. /// Verifies that transactions are not created when both forward and reverse
  351. /// directions are disabled.
  352. TEST_F(D2UpdateMgrTest, bothDisabled) {
  353. // Grab a canned request for test purposes.
  354. NameChangeRequestPtr& ncr = canned_ncrs_[0];
  355. ncr->setReverseChange(true);
  356. TransactionList::iterator pos;
  357. // Wipe out both forward and reverse domain lists.
  358. DdnsDomainMapPtr emptyDomains(new DdnsDomainMap());
  359. cfg_mgr_->getD2CfgContext()->getForwardMgr()->setDomains(emptyDomains);
  360. cfg_mgr_->getD2CfgContext()->getReverseMgr()->setDomains(emptyDomains);
  361. // Verify enable methods are correct.
  362. EXPECT_FALSE(cfg_mgr_->forwardUpdatesEnabled());
  363. EXPECT_FALSE(cfg_mgr_->reverseUpdatesEnabled());
  364. // Attempt to make a transaction.
  365. ASSERT_NO_THROW(update_mgr_->makeTransaction(ncr));
  366. // Verify that do not create a transaction.
  367. EXPECT_EQ(0, update_mgr_->getTransactionCount());
  368. }
  369. /// @brief Tests D2UpdateManager's checkFinishedTransactions method.
  370. /// This test verifies that:
  371. /// 1. Completed transactions are removed from the transaction list.
  372. /// 2. Failed transactions are removed from the transaction list.
  373. /// @todo This test will need to expand if and when checkFinishedTransactions
  374. /// method expands to do more than remove them from the list.
  375. TEST_F(D2UpdateMgrTest, checkFinishedTransaction) {
  376. // Ensure we have at least 4 canned requests with which to work.
  377. ASSERT_TRUE(canned_count_ >= 4);
  378. // Create a transaction for each canned request.
  379. for (int i = 0; i < canned_count_; i++) {
  380. EXPECT_NO_THROW(update_mgr_->makeTransaction(canned_ncrs_[i]));
  381. }
  382. // Verify we have that the transaction count is correct.
  383. EXPECT_EQ(canned_count_, update_mgr_->getTransactionCount());
  384. // Verify that all four transactions have been started.
  385. TransactionList::iterator pos;
  386. EXPECT_NO_THROW(pos = update_mgr_->transactionListBegin());
  387. while (pos != update_mgr_->transactionListEnd()) {
  388. NameChangeTransactionPtr trans = (*pos).second;
  389. ASSERT_EQ(dhcp_ddns::ST_PENDING, trans->getNcrStatus());
  390. ASSERT_TRUE(trans->isModelRunning());
  391. ++pos;
  392. }
  393. // Verify that invoking checkFinishedTransactions does not throw.
  394. EXPECT_NO_THROW(update_mgr_->checkFinishedTransactions());
  395. // Since nothing is running IOService, the all four transactions should
  396. // still be in the list.
  397. EXPECT_EQ(canned_count_, update_mgr_->getTransactionCount());
  398. // Now "complete" two of the four.
  399. // Simulate a successful completion.
  400. completeTransaction(1, dhcp_ddns::ST_COMPLETED);
  401. // Simulate a failed completion.
  402. completeTransaction(3, dhcp_ddns::ST_FAILED);
  403. // Verify that invoking checkFinishedTransactions does not throw.
  404. EXPECT_NO_THROW(update_mgr_->checkFinishedTransactions());
  405. // Verify that the list of transactions has decreased by two.
  406. EXPECT_EQ(canned_count_ - 2, update_mgr_->getTransactionCount());
  407. // Vefity that the transaction list is correct.
  408. EXPECT_TRUE(update_mgr_->hasTransaction(canned_ncrs_[0]->getDhcid()));
  409. EXPECT_FALSE(update_mgr_->hasTransaction(canned_ncrs_[1]->getDhcid()));
  410. EXPECT_TRUE(update_mgr_->hasTransaction(canned_ncrs_[2]->getDhcid()));
  411. EXPECT_FALSE(update_mgr_->hasTransaction(canned_ncrs_[3]->getDhcid()));
  412. }
  413. /// @brief Tests D2UpdateManager's pickNextJob method.
  414. /// This test verifies that:
  415. /// 1. pickNextJob will select and make transactions from NCR queue.
  416. /// 2. Requests are removed from the queue once selected
  417. /// 3. Requests for DHCIDs with transactions already in progress are not
  418. /// selected.
  419. /// 4. Requests with no matching servers are removed from the queue and
  420. /// discarded.
  421. TEST_F(D2UpdateMgrTest, pickNextJob) {
  422. // Ensure we have at least 4 canned requests with which to work.
  423. ASSERT_TRUE(canned_count_ >= 4);
  424. // Put each transaction on the queue.
  425. for (int i = 0; i < canned_count_; i++) {
  426. ASSERT_NO_THROW(queue_mgr_->enqueue(canned_ncrs_[i]));
  427. }
  428. // Invoke pickNextJob canned_count_ times which should create a
  429. // transaction for each canned ncr.
  430. for (int i = 0; i < canned_count_; i++) {
  431. EXPECT_NO_THROW(update_mgr_->pickNextJob());
  432. EXPECT_EQ(i + 1, update_mgr_->getTransactionCount());
  433. EXPECT_TRUE(update_mgr_->hasTransaction(canned_ncrs_[i]->getDhcid()));
  434. }
  435. // Verify that the queue has been drained.
  436. EXPECT_EQ(0, update_mgr_->getQueueCount());
  437. // Now verify that a subsequent request for a DCHID for which a
  438. // transaction is in progress, is not dequeued.
  439. // First add the "subsequent" request.
  440. dhcp_ddns::NameChangeRequestPtr
  441. subsequent_ncr(new dhcp_ddns::NameChangeRequest(*(canned_ncrs_[2])));
  442. EXPECT_NO_THROW(queue_mgr_->enqueue(subsequent_ncr));
  443. EXPECT_EQ(1, update_mgr_->getQueueCount());
  444. // Verify that invoking pickNextJob:
  445. // 1. Does not throw
  446. // 2. Does not make a new transaction
  447. // 3. Does not dequeue the entry
  448. EXPECT_NO_THROW(update_mgr_->pickNextJob());
  449. EXPECT_EQ(canned_count_, update_mgr_->getTransactionCount());
  450. EXPECT_EQ(1, update_mgr_->getQueueCount());
  451. // Clear out the queue and transaction list.
  452. queue_mgr_->clearQueue();
  453. update_mgr_->clearTransactionList();
  454. // Make a forward change NCR with an FQDN that has no forward match.
  455. dhcp_ddns::NameChangeRequestPtr
  456. bogus_ncr(new dhcp_ddns::NameChangeRequest(*(canned_ncrs_[0])));
  457. bogus_ncr->setForwardChange(true);
  458. bogus_ncr->setReverseChange(false);
  459. bogus_ncr->setFqdn("bogus.forward.domain.com");
  460. // Put it on the queue up
  461. ASSERT_NO_THROW(queue_mgr_->enqueue(bogus_ncr));
  462. // Verify that invoking pickNextJob:
  463. // 1. Does not throw
  464. // 2. Does not make a new transaction
  465. // 3. Does dequeue the entry
  466. EXPECT_NO_THROW(update_mgr_->pickNextJob());
  467. EXPECT_EQ(0, update_mgr_->getTransactionCount());
  468. EXPECT_EQ(0, update_mgr_->getQueueCount());
  469. // Make a reverse change NCR with an FQDN that has no reverse match.
  470. bogus_ncr.reset(new dhcp_ddns::NameChangeRequest(*(canned_ncrs_[0])));
  471. bogus_ncr->setForwardChange(false);
  472. bogus_ncr->setReverseChange(true);
  473. bogus_ncr->setIpAddress("77.77.77.77");
  474. // Verify that invoking pickNextJob:
  475. // 1. does not throw
  476. // 2. Does not make a new transaction
  477. // 3. Does dequeue the entry
  478. EXPECT_NO_THROW(update_mgr_->pickNextJob());
  479. EXPECT_EQ(0, update_mgr_->getTransactionCount());
  480. EXPECT_EQ(0, update_mgr_->getQueueCount());
  481. }
  482. /// @brief Tests D2UpdateManager's sweep method.
  483. /// Since sweep is primarily a wrapper around checkFinishedTransactions and
  484. /// pickNextJob, along with checks on maximum transaction limits, it mostly
  485. /// verifies that these three pieces work together to move process jobs.
  486. /// Most of what is tested here is tested above.
  487. TEST_F(D2UpdateMgrTest, sweep) {
  488. // Ensure we have at least 4 canned requests with which to work.
  489. ASSERT_TRUE(canned_count_ >= 4);
  490. // Set max transactions to same as current transaction count.
  491. EXPECT_NO_THROW(update_mgr_->setMaxTransactions(canned_count_));
  492. EXPECT_EQ(canned_count_, update_mgr_->getMaxTransactions());
  493. // Put each transaction on the queue.
  494. for (int i = 0; i < canned_count_; i++) {
  495. EXPECT_NO_THROW(queue_mgr_->enqueue(canned_ncrs_[i]));
  496. }
  497. // Invoke sweep canned_count_ times which should create a
  498. // transaction for each canned ncr.
  499. for (int i = 0; i < canned_count_; i++) {
  500. EXPECT_NO_THROW(update_mgr_->sweep());
  501. EXPECT_EQ(i + 1, update_mgr_->getTransactionCount());
  502. EXPECT_TRUE(update_mgr_->hasTransaction(canned_ncrs_[i]->getDhcid()));
  503. }
  504. // Verify that the queue has been drained.
  505. EXPECT_EQ(0, update_mgr_->getQueueCount());
  506. // Verify max transactions can't be less than current transaction count.
  507. EXPECT_THROW(update_mgr_->setMaxTransactions(1), D2UpdateMgrError);
  508. // Queue up a request for a DHCID which has a transaction in progress.
  509. dhcp_ddns::NameChangeRequestPtr
  510. subsequent_ncr(new dhcp_ddns::NameChangeRequest(*(canned_ncrs_[2])));
  511. EXPECT_NO_THROW(queue_mgr_->enqueue(subsequent_ncr));
  512. EXPECT_EQ(1, update_mgr_->getQueueCount());
  513. // Verify that invoking sweep, does not dequeue the job nor make a
  514. // transaction for it.
  515. EXPECT_NO_THROW(update_mgr_->sweep());
  516. EXPECT_EQ(canned_count_, update_mgr_->getTransactionCount());
  517. EXPECT_EQ(1, update_mgr_->getQueueCount());
  518. // Mark the transaction complete.
  519. completeTransaction(2, dhcp_ddns::ST_COMPLETED);
  520. // Verify that invoking sweep, cleans up the completed transaction,
  521. // dequeues the queued job and adds its transaction to the list.
  522. EXPECT_NO_THROW(update_mgr_->sweep());
  523. EXPECT_EQ(canned_count_, update_mgr_->getTransactionCount());
  524. EXPECT_EQ(0, update_mgr_->getQueueCount());
  525. // Queue up a request from a new DHCID.
  526. dhcp_ddns::NameChangeRequestPtr
  527. another_ncr(new dhcp_ddns::NameChangeRequest(*(canned_ncrs_[0])));
  528. another_ncr->setDhcid("AABBCCDDEEFF");
  529. EXPECT_NO_THROW(queue_mgr_->enqueue(another_ncr));
  530. EXPECT_EQ(1, update_mgr_->getQueueCount());
  531. // Verify that sweep does not dequeue the new request as we are at
  532. // maximum transaction count.
  533. EXPECT_NO_THROW(update_mgr_->sweep());
  534. EXPECT_EQ(canned_count_, update_mgr_->getTransactionCount());
  535. EXPECT_EQ(1, update_mgr_->getQueueCount());
  536. // Set max transactions to same as current transaction count.
  537. EXPECT_NO_THROW(update_mgr_->setMaxTransactions(canned_count_ + 1));
  538. // Verify that invoking sweep, dequeues the request and creates
  539. // a transaction for it.
  540. EXPECT_NO_THROW(update_mgr_->sweep());
  541. EXPECT_EQ(canned_count_ + 1, update_mgr_->getTransactionCount());
  542. EXPECT_EQ(0, update_mgr_->getQueueCount());
  543. // Verify that clearing transaction list works.
  544. EXPECT_NO_THROW(update_mgr_->clearTransactionList());
  545. EXPECT_EQ(0, update_mgr_->getTransactionCount());
  546. }
  547. /// @brief Tests integration of NameAddTransaction
  548. /// This test verifies that update manager can create and manage a
  549. /// NameAddTransaction from start to finish. It utilizes a fake server
  550. /// which responds to all requests sent with NOERROR, simulating a
  551. /// successful addition. The transaction processes both forward and
  552. /// reverse changes.
  553. TEST_F(D2UpdateMgrTest, addTransaction) {
  554. // Put each transaction on the queue.
  555. canned_ncrs_[0]->setChangeType(dhcp_ddns::CHG_ADD);
  556. canned_ncrs_[0]->setReverseChange(true);
  557. ASSERT_NO_THROW(queue_mgr_->enqueue(canned_ncrs_[0]));
  558. // Call sweep once, this should:
  559. // 1. Dequeue the request
  560. // 2. Create the transaction
  561. // 3. Start the transaction
  562. ASSERT_NO_THROW(update_mgr_->sweep());
  563. // Get a copy of the transaction.
  564. TransactionList::iterator pos = update_mgr_->transactionListBegin();
  565. ASSERT_TRUE (pos != update_mgr_->transactionListEnd());
  566. NameChangeTransactionPtr trans = (*pos).second;
  567. ASSERT_TRUE(trans);
  568. // At this point the transaction should have constructed
  569. // and sent the DNS request.
  570. ASSERT_TRUE(trans->getCurrentServer());
  571. ASSERT_TRUE(trans->isModelRunning());
  572. ASSERT_EQ(1, trans->getUpdateAttempts());
  573. ASSERT_EQ(StateModel::NOP_EVT, trans->getNextEvent());
  574. // Create a server based on the transaction's current server, and
  575. // start it listening.
  576. FauxServer server(*io_service_, *(trans->getCurrentServer()));
  577. server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR());
  578. // Run sweep and IO until everything is done.
  579. processAll();
  580. // Verify that model succeeded.
  581. EXPECT_FALSE(trans->didModelFail());
  582. // Both completion flags should be true.
  583. EXPECT_TRUE(trans->getForwardChangeCompleted());
  584. EXPECT_TRUE(trans->getReverseChangeCompleted());
  585. // Verify that we went through success state.
  586. EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST,
  587. trans->getPrevState());
  588. EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT,
  589. trans->getLastEvent());
  590. }
  591. /// @brief Tests integration of NameRemoveTransaction
  592. /// This test verifies that update manager can create and manage a
  593. /// NameRemoveTransaction from start to finish. It utilizes a fake server
  594. /// which responds to all requests sent with NOERROR, simulating a
  595. /// successful addition. The transaction processes both forward and
  596. /// reverse changes.
  597. TEST_F(D2UpdateMgrTest, removeTransaction) {
  598. // Put each transaction on the queue.
  599. canned_ncrs_[0]->setChangeType(dhcp_ddns::CHG_REMOVE);
  600. canned_ncrs_[0]->setReverseChange(true);
  601. ASSERT_NO_THROW(queue_mgr_->enqueue(canned_ncrs_[0]));
  602. // Call sweep once, this should:
  603. // 1. Dequeue the request
  604. // 2. Create the transaction
  605. // 3. Start the transaction
  606. ASSERT_NO_THROW(update_mgr_->sweep());
  607. // Get a copy of the transaction.
  608. TransactionList::iterator pos = update_mgr_->transactionListBegin();
  609. ASSERT_TRUE (pos != update_mgr_->transactionListEnd());
  610. NameChangeTransactionPtr trans = (*pos).second;
  611. ASSERT_TRUE(trans);
  612. // At this point the transaction should have constructed
  613. // and sent the DNS request.
  614. ASSERT_TRUE(trans->getCurrentServer());
  615. ASSERT_TRUE(trans->isModelRunning());
  616. ASSERT_EQ(1, trans->getUpdateAttempts());
  617. ASSERT_EQ(StateModel::NOP_EVT, trans->getNextEvent());
  618. // Create a server based on the transaction's current server,
  619. // and start it listening.
  620. FauxServer server(*io_service_, *(trans->getCurrentServer()));
  621. server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR());
  622. // Run sweep and IO until everything is done.
  623. processAll();
  624. // Verify that model succeeded.
  625. EXPECT_FALSE(trans->didModelFail());
  626. // Both completion flags should be true.
  627. EXPECT_TRUE(trans->getForwardChangeCompleted());
  628. EXPECT_TRUE(trans->getReverseChangeCompleted());
  629. // Verify that we went through success state.
  630. EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_OK_ST,
  631. trans->getPrevState());
  632. EXPECT_EQ(NameChangeTransaction::UPDATE_OK_EVT,
  633. trans->getLastEvent());
  634. }
  635. /// @brief Tests handling of a transaction which fails.
  636. /// This test verifies that update manager correctly concludes a transaction
  637. /// which fails to complete successfully. The failure simulated is repeated
  638. /// corrupt responses from the server, which causes an exhaustion of the
  639. /// available servers.
  640. TEST_F(D2UpdateMgrTest, errorTransaction) {
  641. // Put each transaction on the queue.
  642. ASSERT_NO_THROW(queue_mgr_->enqueue(canned_ncrs_[0]));
  643. // Call sweep once, this should:
  644. // 1. Dequeue the request
  645. // 2. Create the transaction
  646. // 3. Start the transaction
  647. ASSERT_NO_THROW(update_mgr_->sweep());
  648. // Get a copy of the transaction.
  649. TransactionList::iterator pos = update_mgr_->transactionListBegin();
  650. ASSERT_TRUE (pos != update_mgr_->transactionListEnd());
  651. NameChangeTransactionPtr trans = (*pos).second;
  652. ASSERT_TRUE(trans);
  653. ASSERT_TRUE(trans->isModelRunning());
  654. ASSERT_EQ(1, trans->getUpdateAttempts());
  655. ASSERT_EQ(StateModel::NOP_EVT, trans->getNextEvent());
  656. ASSERT_TRUE(trans->getCurrentServer());
  657. // Create a server and start it listening.
  658. FauxServer server(*io_service_, *(trans->getCurrentServer()));
  659. server.receive(FauxServer::CORRUPT_RESP);
  660. // Run sweep and IO until everything is done.
  661. processAll();
  662. // Verify that model succeeded.
  663. EXPECT_FALSE(trans->didModelFail());
  664. // Both completion flags should be false.
  665. EXPECT_FALSE(trans->getForwardChangeCompleted());
  666. EXPECT_FALSE(trans->getReverseChangeCompleted());
  667. // Verify that we went through success state.
  668. EXPECT_EQ(NameChangeTransaction::PROCESS_TRANS_FAILED_ST,
  669. trans->getPrevState());
  670. EXPECT_EQ(NameChangeTransaction::NO_MORE_SERVERS_EVT,
  671. trans->getLastEvent());
  672. }
  673. /// @brief Tests processing of multiple transactions.
  674. /// This test verifies that update manager can create and manage a multiple
  675. /// transactions, concurrently. It uses a fake server that responds to all
  676. /// requests sent with NOERROR, simulating successful DNS updates. The
  677. /// transactions are a mix of both adds and removes.
  678. TEST_F(D2UpdateMgrTest, multiTransaction) {
  679. // Queue up all the requests.
  680. int test_count = canned_count_;
  681. for (int i = test_count; i > 0; i--) {
  682. canned_ncrs_[i-1]->setReverseChange(true);
  683. ASSERT_NO_THROW(queue_mgr_->enqueue(canned_ncrs_[i-1]));
  684. }
  685. // Create a server and start it listening. Note this relies on the fact
  686. // that all of configured servers have the same address.
  687. // and start it listening.
  688. asiolink::IOAddress server_ip("127.0.0.1");
  689. FauxServer server(*io_service_, server_ip, 5301);
  690. server.receive(FauxServer::USE_RCODE, dns::Rcode::NOERROR());
  691. // Run sweep and IO until everything is done.
  692. processAll();
  693. for (int i = 0; i < test_count; i++) {
  694. EXPECT_EQ(dhcp_ddns::ST_COMPLETED, canned_ncrs_[i]->getStatus());
  695. }
  696. }
  697. /// @brief Tests processing of multiple transactions.
  698. /// This test verifies that update manager can create and manage a multiple
  699. /// transactions, concurrently. It uses a fake server that responds to all
  700. /// requests sent with NOERROR, simulating successful DNS updates. The
  701. /// transactions are a mix of both adds and removes.
  702. TEST_F(D2UpdateMgrTest, multiTransactionTimeout) {
  703. // Queue up all the requests.
  704. int test_count = canned_count_;
  705. for (int i = test_count; i > 0; i--) {
  706. canned_ncrs_[i-1]->setReverseChange(true);
  707. ASSERT_NO_THROW(queue_mgr_->enqueue(canned_ncrs_[i-1]));
  708. }
  709. // No server is running, so everything will time out.
  710. // Run sweep and IO until everything is done.
  711. processAll();
  712. for (int i = 0; i < test_count; i++) {
  713. EXPECT_EQ(dhcp_ddns::ST_FAILED, canned_ncrs_[i]->getStatus());
  714. }
  715. }
  716. }