d2_update_mgr_unittests.cc 34 KB

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