ncr_unittests.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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/ncr_msg.h>
  15. #include <boost/date_time/posix_time/posix_time.hpp>
  16. #include <gtest/gtest.h>
  17. #include <algorithm>
  18. using namespace std;
  19. using namespace isc;
  20. using namespace isc::d2;
  21. using namespace boost::posix_time;
  22. namespace {
  23. /// @brief Defines a list of valid JSON NameChangeRequest renditions.
  24. /// They are used as input to test conversion from JSON.
  25. const char *valid_msgs[] =
  26. {
  27. // Valid Add.
  28. "{"
  29. " \"change_type\" : 0 , "
  30. " \"forward_change\" : true , "
  31. " \"reverse_change\" : false , "
  32. " \"fqdn\" : \"walah.walah.com\" , "
  33. " \"ip_address\" : \"192.168.2.1\" , "
  34. " \"dhcid\" : \"010203040A7F8E3D\" , "
  35. " \"lease_expires_on\" : \"19620121T132405\" , "
  36. " \"lease_length\" : 1300 "
  37. "}",
  38. // Valid Remove.
  39. "{"
  40. " \"change_type\" : 1 , "
  41. " \"forward_change\" : true , "
  42. " \"reverse_change\" : false , "
  43. " \"fqdn\" : \"walah.walah.com\" , "
  44. " \"ip_address\" : \"192.168.2.1\" , "
  45. " \"dhcid\" : \"010203040A7F8E3D\" , "
  46. " \"lease_expires_on\" : \"19620121T132405\" , "
  47. " \"lease_length\" : 1300 "
  48. "}",
  49. // Valid Add with IPv6 address
  50. "{"
  51. " \"change_type\" : 0 , "
  52. " \"forward_change\" : true , "
  53. " \"reverse_change\" : false , "
  54. " \"fqdn\" : \"walah.walah.com\" , "
  55. " \"ip_address\" : \"fe80::2acf:e9ff:fe12:e56f\" , "
  56. " \"dhcid\" : \"010203040A7F8E3D\" , "
  57. " \"lease_expires_on\" : \"19620121T132405\" , "
  58. " \"lease_length\" : 1300 "
  59. "}"
  60. };
  61. /// @brief Defines a list of invalid JSON NameChangeRequest renditions.
  62. /// They are used as input to test conversion from JSON.
  63. const char *invalid_msgs[] =
  64. {
  65. // Invalid change type.
  66. "{"
  67. " \"change_type\" : 7 , "
  68. " \"forward_change\" : true , "
  69. " \"reverse_change\" : false , "
  70. " \"fqdn\" : \"walah.walah.com\" , "
  71. " \"ip_address\" : \"192.168.2.1\" , "
  72. " \"dhcid\" : \"010203040A7F8E3D\" , "
  73. " \"lease_expires_on\" : \"19620121T132405\" , "
  74. " \"lease_length\" : 1300 "
  75. "}",
  76. // Invalid forward change.
  77. "{"
  78. " \"change_type\" : 0 , "
  79. " \"forward_change\" : \"bogus\" , "
  80. " \"reverse_change\" : false , "
  81. " \"fqdn\" : \"walah.walah.com\" , "
  82. " \"ip_address\" : \"192.168.2.1\" , "
  83. " \"dhcid\" : \"010203040A7F8E3D\" , "
  84. " \"lease_expires_on\" : \"19620121T132405\" , "
  85. " \"lease_length\" : 1300 "
  86. "}",
  87. // Invalid reverse change.
  88. "{"
  89. " \"change_type\" : 0 , "
  90. " \"forward_change\" : true , "
  91. " \"reverse_change\" : 500 , "
  92. " \"fqdn\" : \"walah.walah.com\" , "
  93. " \"ip_address\" : \"192.168.2.1\" , "
  94. " \"dhcid\" : \"010203040A7F8E3D\" , "
  95. " \"lease_expires_on\" : \"19620121T132405\" , "
  96. " \"lease_length\" : 1300 "
  97. "}",
  98. // Forward and reverse change both false.
  99. "{"
  100. " \"change_type\" : 0 , "
  101. " \"forward_change\" : false , "
  102. " \"reverse_change\" : false , "
  103. " \"fqdn\" : \"walah.walah.com\" , "
  104. " \"ip_address\" : \"192.168.2.1\" , "
  105. " \"dhcid\" : \"010203040A7F8E3D\" , "
  106. " \"lease_expires_on\" : \"19620121T132405\" , "
  107. " \"lease_length\" : 1300 "
  108. "}",
  109. // Blank FQDN
  110. "{"
  111. " \"change_type\" : 0 , "
  112. " \"forward_change\" : true , "
  113. " \"reverse_change\" : false , "
  114. " \"fqdn\" : \"\" , "
  115. " \"ip_address\" : \"192.168.2.1\" , "
  116. " \"dhcid\" : \"010203040A7F8E3D\" , "
  117. " \"lease_expires_on\" : \"19620121T132405\" , "
  118. " \"lease_length\" : 1300 "
  119. "}",
  120. // Bad IP address
  121. "{"
  122. " \"change_type\" : 0 , "
  123. " \"forward_change\" : true , "
  124. " \"reverse_change\" : false , "
  125. " \"fqdn\" : \"walah.walah.com\" , "
  126. " \"ip_address\" : \"xxxxxx\" , "
  127. " \"dhcid\" : \"010203040A7F8E3D\" , "
  128. " \"lease_expires_on\" : \"19620121T132405\" , "
  129. " \"lease_length\" : 1300 "
  130. "}",
  131. // Blank DHCID
  132. "{"
  133. " \"change_type\" : 0 , "
  134. " \"forward_change\" : true , "
  135. " \"reverse_change\" : false , "
  136. " \"fqdn\" : \"walah.walah.com\" , "
  137. " \"ip_address\" : \"192.168.2.1\" , "
  138. " \"dhcid\" : \"\" , "
  139. " \"lease_expires_on\" : \"19620121T132405\" , "
  140. " \"lease_length\" : 1300 "
  141. "}",
  142. // Odd number of digits in DHCID
  143. "{"
  144. " \"change_type\" : 0 , "
  145. " \"forward_change\" : true , "
  146. " \"reverse_change\" : false , "
  147. " \"fqdn\" : \"walah.walah.com\" , "
  148. " \"ip_address\" : \"192.168.2.1\" , "
  149. " \"dhcid\" : \"010203040A7F8E3\" , "
  150. " \"lease_expires_on\" : \"19620121T132405\" , "
  151. " \"lease_length\" : 1300 "
  152. "}",
  153. // Text in DHCID
  154. "{"
  155. " \"change_type\" : 0 , "
  156. " \"forward_change\" : true , "
  157. " \"reverse_change\" : false , "
  158. " \"fqdn\" : \"walah.walah.com\" , "
  159. " \"ip_address\" : \"192.168.2.1\" , "
  160. " \"dhcid\" : \"THIS IS BOGUS!!!\" , "
  161. " \"lease_expires_on\" : \"19620121T132405\" , "
  162. " \"lease_length\" : 1300 "
  163. "}",
  164. // Invalid lease expiration string
  165. "{"
  166. " \"change_type\" : 0 , "
  167. " \"forward_change\" : true , "
  168. " \"reverse_change\" : false , "
  169. " \"fqdn\" : \"walah.walah.com\" , "
  170. " \"ip_address\" : \"192.168.2.1\" , "
  171. " \"dhcid\" : \"010203040A7F8E3D\" , "
  172. " \"lease_expires_on\" : \"Wed Jun 26 13:46:46 EDT 2013\" , "
  173. " \"lease_length\" : 1300 "
  174. "}",
  175. // Non-integer for lease length.
  176. "{"
  177. " \"change_type\" : 0 , "
  178. " \"forward_change\" : true , "
  179. " \"reverse_change\" : false , "
  180. " \"fqdn\" : \"walah.walah.com\" , "
  181. " \"ip_address\" : \"192.168.2.1\" , "
  182. " \"dhcid\" : \"010203040A7F8E3D\" , "
  183. " \"lease_expires_on\" : \"19620121T132405\" , "
  184. " \"lease_length\" : \"BOGUS\" "
  185. "}"
  186. };
  187. /// @brief Tests the NameChangeRequest constructors.
  188. /// This test verifies that:
  189. /// 1. Default constructor works.
  190. /// 2. "Full" constructor, when given valid parameter values, works.
  191. /// 3. "Full" constructor, given a blank FQDN fails
  192. /// 4. "Full" constructor, given an invalid IP Address FQDN fails
  193. /// 5. "Full" constructor, given a blank DHCID fails
  194. /// 6. "Full" constructor, given an invalid lease expiration fails
  195. /// 7. "Full" constructor, given false for both forward and reverse fails
  196. TEST(NameChangeRequestTest, constructionTests) {
  197. // Verify the default constructor works.
  198. NameChangeRequestPtr ncr;
  199. EXPECT_NO_THROW(ncr.reset(new NameChangeRequest()));
  200. EXPECT_TRUE(ncr);
  201. // Verify that full constructor works.
  202. ptime expiry(second_clock::universal_time());
  203. D2Dhcid dhcid("010203040A7F8E3D");
  204. EXPECT_NO_THROW(ncr.reset(new NameChangeRequest(
  205. CHG_ADD, true, true, "walah.walah.com",
  206. "192.168.1.101", dhcid, expiry, 1300)));
  207. EXPECT_TRUE(ncr);
  208. ncr.reset();
  209. // Verify blank FQDN is detected.
  210. EXPECT_THROW(ncr.reset(new NameChangeRequest(CHG_ADD, true, true, "",
  211. "192.168.1.101", dhcid, expiry, 1300)), NcrMessageError);
  212. // Verify that an invalid IP address is detected.
  213. EXPECT_THROW(ncr.reset(
  214. new NameChangeRequest(CHG_ADD, true, true, "valid.fqdn",
  215. "xxx.168.1.101", dhcid, expiry, 1300)), NcrMessageError);
  216. // Verify that a blank DHCID is detected.
  217. D2Dhcid blank_dhcid;
  218. EXPECT_THROW(ncr.reset(
  219. new NameChangeRequest(CHG_ADD, true, true, "walah.walah.com",
  220. "192.168.1.101", blank_dhcid, expiry, 1300)), NcrMessageError);
  221. // Verify that an invalid lease expiration is detected.
  222. ptime blank_expiry;
  223. EXPECT_THROW(ncr.reset(
  224. new NameChangeRequest(CHG_ADD, true, true, "valid.fqdn",
  225. "192.168.1.101", dhcid, blank_expiry, 1300)), NcrMessageError);
  226. // Verify that one or both of direction flags must be true.
  227. EXPECT_THROW(ncr.reset(
  228. new NameChangeRequest(CHG_ADD, false, false, "valid.fqdn",
  229. "192.168.1.101", dhcid, expiry, 1300)), NcrMessageError);
  230. }
  231. /// @brief Tests the basic workings of D2Dhcid to and from string conversions.
  232. /// It verifies that:
  233. /// 1. DHCID input strings must contain an even number of characters
  234. /// 2. DHCID input strings must contain only hexadecimal character digits
  235. /// 3. A valid DHCID string converts correctly.
  236. /// 4. Converting a D2Dhcid to a string works correctly.
  237. TEST(NameChangeRequestTest, dhcidTest) {
  238. D2Dhcid dhcid;
  239. // Odd number of digits should be rejected.
  240. std::string test_str = "010203040A7F8E3";
  241. EXPECT_THROW(dhcid.fromStr(test_str), NcrMessageError);
  242. // Non digit content should be rejected.
  243. test_str = "0102BOGUSA7F8E3D";
  244. EXPECT_THROW(dhcid.fromStr(test_str), NcrMessageError);
  245. // Verify that valid input converts into a proper byte array.
  246. test_str = "010203040A7F8E3D";
  247. ASSERT_NO_THROW(dhcid.fromStr(test_str));
  248. // Create a test vector of expected byte contents.
  249. const uint8_t bytes[] = { 0x1, 0x2, 0x3, 0x4, 0xA, 0x7F, 0x8E, 0x3D };
  250. std::vector<uint8_t> expected_bytes(bytes, bytes + sizeof(bytes));
  251. // Fetch the byte vector from the dhcid and verify if equals the expected
  252. // content.
  253. const std::vector<uint8_t>& converted_bytes = dhcid.getBytes();
  254. EXPECT_EQ(expected_bytes.size(), converted_bytes.size());
  255. EXPECT_TRUE (std::equal(expected_bytes.begin(),
  256. expected_bytes.begin()+expected_bytes.size(),
  257. converted_bytes.begin()));
  258. // Convert the new dhcid back to string and verify it matches the original
  259. // DHCID input string.
  260. std::string next_str = dhcid.toStr();
  261. EXPECT_EQ(test_str, next_str);
  262. }
  263. /// @brief Tests that boost::posix_time library functions as expected.
  264. /// This test verifies that converting ptimes to and from ISO strings
  265. /// works properly. This test is perhaps unnecessary but just to avoid any
  266. /// OS specific surprises it is better safe than sorry.
  267. TEST(NameChangeRequestTest, boostTime) {
  268. // Create a ptime with the time now.
  269. ptime pt1(second_clock::universal_time());
  270. // Get the ISO date-time string.
  271. std::string pt1_str = to_iso_string(pt1);
  272. // Use the ISO date-time string to create a new ptime.
  273. ptime pt2 = from_iso_string(pt1_str);
  274. // Verify the two times are equal.
  275. EXPECT_EQ (pt1, pt2);
  276. }
  277. /// @brief Verifies the fundamentals of converting from and to JSON.
  278. /// It verifies that:
  279. /// 1. A NameChangeRequest can be created from a valid JSON string.
  280. /// 2. A valid JSON string can be created from a NameChangeRequest
  281. TEST(NameChangeRequestTest, basicJsonTest) {
  282. // Define valid JSON rendition of a request.
  283. std::string msg_str = "{"
  284. "\"change_type\":1,"
  285. "\"forward_change\":true,"
  286. "\"reverse_change\":false,"
  287. "\"fqdn\":\"walah.walah.com\","
  288. "\"ip_address\":\"192.168.2.1\","
  289. "\"dhcid\":\"010203040A7F8E3D\","
  290. "\"lease_expires_on\":\"19620121T132405\","
  291. "\"lease_length\":1300"
  292. "}";
  293. // Verify that a NameChangeRequests can be instantiated from the
  294. // a valid JSON rendition.
  295. NameChangeRequestPtr ncr;
  296. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(msg_str));
  297. ASSERT_TRUE(ncr);
  298. // Verify that the JSON string created by the new request equals the
  299. // original input string.
  300. std::string json_str = ncr->toJSON();
  301. EXPECT_EQ(msg_str, json_str);
  302. }
  303. /// @brief Tests a variety of invalid JSON message strings.
  304. /// This test iterates over a list of JSON messages, each containing a single
  305. /// content error. The list of messages is defined by the global array,
  306. /// invalid_messages. Currently that list contains the following invalid
  307. /// conditions:
  308. /// 1. Invalid change type
  309. /// 2. Invalid forward change
  310. /// 3. Invalid reverse change
  311. /// 4. Forward and reverse change both false
  312. /// 5. Invalid forward change
  313. /// 6. Blank FQDN
  314. /// 7. Bad IP address
  315. /// 8. Blank DHCID
  316. /// 9. Odd number of digits in DHCID
  317. /// 10. Text in DHCID
  318. /// 11. Invalid lease expiration string
  319. /// 12. Non-integer for lease length.
  320. /// If more permutations arise they can easily be added to the list.
  321. TEST(NameChangeRequestTest, invalidMsgChecks) {
  322. // Iterate over the list of JSON strings, attempting to create a
  323. // NameChangeRequest. The attempt should throw a NcrMessageError.
  324. int num_msgs = sizeof(invalid_msgs)/sizeof(char*);
  325. for (int i = 0; i < num_msgs; i++) {
  326. bool it_threw = false;
  327. try {
  328. NameChangeRequest::fromJSON(invalid_msgs[i]);
  329. } catch (NcrMessageError& ex) {
  330. it_threw = true;
  331. std::cout << "Invalid Message: " << ex.what() << std::endl;
  332. }
  333. // If it the conversion didn't fail, log the index message and fail
  334. // the test.
  335. if (!it_threw) {
  336. std::cerr << "Invalid Message not caught, message idx: " << i
  337. << std::endl;
  338. EXPECT_TRUE(it_threw);
  339. }
  340. }
  341. }
  342. /// @brief Tests a variety of valid JSON message strings.
  343. /// This test iterates over a list of JSON messages, each containing a single
  344. /// valid request rendition. The list of messages is defined by the global
  345. /// array, valid_messages. Currently that list contains the following valid
  346. /// messages:
  347. /// 1. Valid, IPv4 Add
  348. /// 2. Valid, IPv4 Remove
  349. /// 3. Valid, IPv6 Add
  350. /// If more permutations arise they can easily be added to the list.
  351. TEST(NameChangeRequestTest, validMsgChecks) {
  352. // Iterate over the list of JSON strings, attempting to create a
  353. // NameChangeRequest. The attempt should succeed.
  354. int num_msgs = sizeof(valid_msgs)/sizeof(char*);
  355. for (int i = 0; i < num_msgs; i++) {
  356. bool it_threw = false;
  357. try {
  358. NameChangeRequest::fromJSON(valid_msgs[i]);
  359. } catch (NcrMessageError& ex) {
  360. it_threw = true;
  361. std::cout << "Message Error: " << ex.what() << std::endl;
  362. }
  363. // If it the conversion failed log the index message and fail
  364. // the test.
  365. if (it_threw) {
  366. std::cerr << "Valid Message failed, message idx: " << i
  367. << std::endl;
  368. EXPECT_TRUE(!it_threw);
  369. }
  370. }
  371. }
  372. /// @brief Tests converting to and from JSON via isc::util buffer classes.
  373. /// This test verifies that:
  374. /// 1. A NameChangeRequest can be rendered in JSON written to an OutputBuffer
  375. /// 2. A InputBuffer containing a valid JSON request rendition can be used
  376. /// to create a NameChangeRequest.
  377. TEST(NameChangeRequestTest, toFromBufferTest) {
  378. // Define a string containing a valid JSON NameChangeRequest rendition.
  379. std::string msg_str = "{"
  380. "\"change_type\":1,"
  381. "\"forward_change\":true,"
  382. "\"reverse_change\":false,"
  383. "\"fqdn\":\"walah.walah.com\","
  384. "\"ip_address\":\"192.168.2.1\","
  385. "\"dhcid\":\"010203040A7F8E3D\","
  386. "\"lease_expires_on\":\"19620121T132405\","
  387. "\"lease_length\":1300"
  388. "}";
  389. // Create a request from JSON directly.
  390. NameChangeRequestPtr ncr;
  391. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(msg_str));
  392. // Verify that we output the request as JSON text to a buffer
  393. // without error.
  394. isc::util::OutputBuffer output_buffer(1024);
  395. ASSERT_NO_THROW(ncr->toFormat(FMT_JSON, output_buffer));
  396. // Make an InputBuffer from the OutputBuffer.
  397. isc::util::InputBuffer input_buffer(output_buffer.getData(),
  398. output_buffer.getLength());
  399. // Verify that we can create a new request from the InputBuffer.
  400. NameChangeRequestPtr ncr2;
  401. ASSERT_NO_THROW(ncr2 =
  402. NameChangeRequest::fromFormat(FMT_JSON, input_buffer));
  403. // Convert the new request to JSON directly.
  404. std::string final_str = ncr2->toJSON();
  405. // Verify that the final string matches the original.
  406. ASSERT_EQ(final_str, msg_str);
  407. }
  408. } // end of anonymous namespace