d2_simple_parser_unittest.cc 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  1. // Copyright (C) 2017 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.com/MPL/2.0/.
  6. #include <config.h>
  7. #include <gtest/gtest.h>
  8. #include <d2/d2_simple_parser.h>
  9. #include <d2/tests/parser_unittest.h>
  10. #include <cc/data.h>
  11. #include <testutils/test_to_element.h>
  12. #include <boost/lexical_cast.hpp>
  13. using namespace isc;
  14. using namespace isc::data;
  15. using namespace isc::d2;
  16. using namespace isc::test;
  17. namespace {
  18. /// @brief Checks if specified element matches the given integer default
  19. ///
  20. /// @param element defaulted element to check
  21. /// @param deflt SimpleDefault which supplied the default value
  22. void checkIntegerValue(const ConstElementPtr& element,
  23. const SimpleDefault& deflt) {
  24. ASSERT_TRUE(element);
  25. // Verify it is an integer.
  26. ASSERT_EQ(Element::integer, element->getType());
  27. // Turn default value string into an int.
  28. int64_t default_value = 0;
  29. ASSERT_NO_THROW(default_value = boost::lexical_cast<int64_t>(deflt.value_));
  30. // Verify it has the expected value.
  31. EXPECT_EQ(default_value, element->intValue());
  32. }
  33. /// @brief Checks if specified element matches the given boolean default
  34. ///
  35. /// @param element defaulted element to check
  36. /// @param deflt SimpleDefault which supplied the default valaue
  37. void checkBooleanValue(const ConstElementPtr& element,
  38. const SimpleDefault& deflt) {
  39. ASSERT_TRUE(element);
  40. // Verify it is a bool.
  41. ASSERT_EQ(Element::boolean, element->getType());
  42. // Turn default value string into a bool.
  43. bool default_value = false;
  44. ASSERT_NO_THROW(boost::lexical_cast<bool>(deflt.value_));
  45. // Verify it has the expected value.
  46. EXPECT_EQ(default_value, element->boolValue());
  47. }
  48. /// @brief Checks if specified element matches the given string default
  49. ///
  50. /// @param element defaulted element to check
  51. /// @param deflt SimpleDefault which supplied the default valaue
  52. void checkStringValue(const ConstElementPtr& element,
  53. const SimpleDefault& deflt) {
  54. ASSERT_TRUE(element);
  55. // Verify it's a string
  56. ASSERT_EQ(Element::string, element->getType());
  57. // Verify it has the expected value
  58. EXPECT_EQ(deflt.value_, element->stringValue());
  59. }
  60. /// TSIGKeyInfo against the given set of values, and that the TSIGKey
  61. /// member points to a key.
  62. ///
  63. /// @param key is a pointer to the TSIGKeyInfo instance to verify
  64. /// @param name is the value to compare against key's name_.
  65. /// @param algorithm is the string value to compare against key's algorithm.
  66. /// @param secret is the value to compare against key's secret.
  67. ///
  68. /// @return returns true if there is a match across the board, otherwise it
  69. /// returns false.
  70. bool checkKey(TSIGKeyInfoPtr key, const std::string& name,
  71. const std::string& algorithm, const std::string& secret,
  72. uint32_t digestbits = 0) {
  73. // Return value, assume its a match.
  74. return (((key) &&
  75. (key->getName() == name) &&
  76. (key->getAlgorithm() == algorithm) &&
  77. (key->getDigestbits() == digestbits) &&
  78. (key->getSecret() == secret) &&
  79. (key->getTSIGKey())));
  80. }
  81. /// @brief Convenience function which compares the contents of the given
  82. /// DnsServerInfo against the given set of values.
  83. ///
  84. /// It is structured in such a way that each value is checked, and output
  85. /// is generated for all that do not match.
  86. ///
  87. /// @param server is a pointer to the server to check against.
  88. /// @param hostname is the value to compare against server's hostname_.
  89. /// @param ip_address is the string value to compare against server's
  90. /// ip_address_.
  91. /// @param port is the value to compare against server's port.
  92. ///
  93. /// @return returns true if there is a match across the board, otherwise it
  94. /// returns false.
  95. bool checkServer(DnsServerInfoPtr server, const char* hostname,
  96. const char *ip_address, uint32_t port)
  97. {
  98. // Return value, assume its a match.
  99. bool result = true;
  100. if (!server) {
  101. EXPECT_TRUE(server);
  102. return false;
  103. }
  104. // Check hostname.
  105. if (server->getHostname() != hostname) {
  106. EXPECT_EQ(hostname, server->getHostname());
  107. result = false;
  108. }
  109. // Check IP address.
  110. if (server->getIpAddress().toText() != ip_address) {
  111. EXPECT_EQ(ip_address, server->getIpAddress().toText());
  112. result = false;
  113. }
  114. // Check port.
  115. if (server->getPort() != port) {
  116. EXPECT_EQ (port, server->getPort());
  117. result = false;
  118. }
  119. return (result);
  120. }
  121. /// @brief Base class test fixture for testing JSON and element parsing
  122. /// for D2 configuration elements. It combines the three phases of
  123. /// configuration parsing normally orchestrated by D2CfgMgr:
  124. /// 1. Submit the JSON text to the JSON parser
  125. /// 2. Add defaults to the element tree produced by the JSON parser
  126. /// 3. Pass the element tree into the appropriate SimpleParser derivation
  127. /// to parse the element tree into D2 objects.
  128. class D2SimpleParserTest : public ::testing::Test {
  129. public:
  130. /// @brief Constructor
  131. ///
  132. /// @param parser_type specifies the parsing starting point at which
  133. /// the JSON parser should begin. It defaults to PARSER_JSON. See @c
  134. /// D2ParserContext::ParserType for all possible values.
  135. D2SimpleParserTest(const D2ParserContext::ParserType&
  136. parser_type = D2ParserContext::PARSER_JSON)
  137. : parser_type_(parser_type) {
  138. reset();
  139. }
  140. /// @brief Destructor
  141. virtual ~D2SimpleParserTest() {
  142. reset();
  143. }
  144. /// @brief Parses JSON text and compares the results against an expected
  145. /// outcome.
  146. ///
  147. /// The JSON text is submitted to the D2ParserContext for parsing. Any
  148. /// errors emitted here are caught and compared against the expected
  149. /// error or flagged as unexpected.
  150. /// Next, the virtual method, setDefaults()is invoked. his method should
  151. /// be used by derivations to add default values to the element tree
  152. /// produced by the JSON parser.
  153. /// Lastly, it passes the element tree into the virtual method,
  154. /// parseElement(). This method should be used by derivations to create
  155. /// the appropriate element parser to parse the element tree into the
  156. /// appropriate D2 object(s).
  157. ///
  158. /// @param json JSON text to parse
  159. /// @param exp_error exact text of the error message expected or ""
  160. /// if parsing should succeed.
  161. ::testing::AssertionResult parseOrFail(const std::string& json,
  162. const std::string& exp_error) {
  163. try {
  164. // Free up objects created by previous invocation
  165. reset();
  166. // Submit JSON text to JSON parser. We convert the result to
  167. // a mutable element tree to allow defaults to be added.
  168. D2ParserContext context;
  169. data::ElementPtr elem = boost::const_pointer_cast<Element>
  170. (context.parseString(json, parser_type_));
  171. // Add any defaults
  172. setDefaults(elem);
  173. // Now pares the element tree into object(s).
  174. parseElement(elem);
  175. } catch (const std::exception& ex) {
  176. std::string caught_error = ex.what();
  177. if (exp_error.empty()) {
  178. return ::testing::AssertionFailure()
  179. << "Unexpected error: " << caught_error
  180. << "\n json: [" << json << "]";
  181. }
  182. if (exp_error != caught_error) {
  183. return ::testing::AssertionFailure()
  184. << "Wrong error detected, expected: "
  185. << exp_error << ", got: " << caught_error
  186. << "\n json: [" << json << "]";
  187. }
  188. return ::testing::AssertionSuccess();
  189. }
  190. if (!exp_error.empty()) {
  191. return ::testing::AssertionFailure()
  192. << "Unexpected parsing success "
  193. << exp_error << "\n json: [" << json << "]";
  194. }
  195. return ::testing::AssertionSuccess();
  196. }
  197. protected:
  198. /// @brief Free up objects created by element parsing
  199. /// This method is invoked at the beginning of @c parseOrFail() to
  200. /// ensure any D2 object(s) that were created by a prior invocation are
  201. /// destroyed. This permits parsing to be conducted more than once
  202. /// in the same test.
  203. virtual void reset(){};
  204. /// @brief Adds default values to the given element tree
  205. ///
  206. /// Derivations are expected to use the appropriate methods in
  207. /// D2SimpleParser to add defaults values.
  208. ///
  209. /// @param config element tree in which defaults should be added
  210. /// @return the number of default items added to the tree
  211. virtual size_t setDefaults(data::ElementPtr config) {
  212. static_cast<void>(config);
  213. return (0);
  214. }
  215. /// @brief Parses a given element tree into D2 object(s)
  216. ///
  217. /// Derivations are expected to create the appropriate element
  218. /// parser and pass it the element tree for parsing. Any object(s)
  219. /// created should likely be saved for content verification
  220. /// outside of this method.
  221. ///
  222. /// @param config element tree to parse
  223. virtual void parseElement(data::ConstElementPtr config) {
  224. static_cast<void>(config);
  225. }
  226. D2ParserContext::ParserType parser_type_;
  227. };
  228. /// @brief Convenience macros for calling parseOrFail
  229. #define PARSE_OK(a) EXPECT_TRUE((parseOrFail(a, "")))
  230. #define PARSE_FAIL(a,b) EXPECT_TRUE((parseOrFail(a, b)))
  231. // This test checks if global defaults are properly set for D2.
  232. TEST_F(D2SimpleParserTest, globalD2Defaults) {
  233. ElementPtr empty = isc::d2::test::parseJSON("{ }");
  234. size_t num = 0;
  235. EXPECT_NO_THROW(num = D2SimpleParser::setAllDefaults(empty));
  236. // We expect 5 parameters to be inserted.
  237. EXPECT_EQ(num, 8);
  238. // Let's go over all parameters we have defaults for.
  239. BOOST_FOREACH(SimpleDefault deflt, D2SimpleParser::D2_GLOBAL_DEFAULTS) {
  240. ConstElementPtr x;
  241. ASSERT_NO_THROW(x = empty->get(deflt.name_));
  242. EXPECT_TRUE(x);
  243. if (x) {
  244. if (deflt.type_ == Element::integer) {
  245. checkIntegerValue(x, deflt);
  246. } else if (deflt.type_ == Element::boolean) {
  247. checkBooleanValue(x, deflt);
  248. } else if (deflt.type_ == Element::string) {
  249. checkStringValue(x, deflt);
  250. } else {
  251. // add them if we need to. Like what do you if it's a map?
  252. ADD_FAILURE() << "default type not supported:" << deflt.name_
  253. << " ,type: " << deflt.type_;
  254. }
  255. }
  256. }
  257. }
  258. /// @brief Test fixture class for testing TSIGKeyInfo parsing.
  259. class TSIGKeyInfoParserTest : public D2SimpleParserTest {
  260. public:
  261. /// @brief Constructor
  262. TSIGKeyInfoParserTest()
  263. : D2SimpleParserTest(D2ParserContext::PARSER_TSIG_KEY) {
  264. }
  265. /// @brief Free up the keys created by parsing
  266. virtual void reset() {
  267. key_.reset();
  268. };
  269. /// @brief Destructor
  270. virtual ~TSIGKeyInfoParserTest() {
  271. reset();
  272. };
  273. /// @brief Adds TSIG Key default values to the given TSIG Key element
  274. ///
  275. /// @param config TSIG Key element to which defaults should be added
  276. ///
  277. /// @return the number of default items added to the tree
  278. size_t setDefaults(data::ElementPtr config) {
  279. return (SimpleParser::setDefaults(config, D2SimpleParser::
  280. TSIG_KEY_DEFAULTS));
  281. }
  282. /// @brief Attempts to parse the given element into a TSIGKeyInfo
  283. ///
  284. /// Assumes the given element is a Map containing the attributes for
  285. /// a TSIG Key. If parsing is successful the new TSIGKeyInfo instance
  286. /// is retained in the member, key_;
  287. ///
  288. /// @param config element to parse
  289. void parseElement(data::ConstElementPtr config) {
  290. TSIGKeyInfoParser parser;
  291. key_ = parser.parse(config);
  292. }
  293. /// @brief Retains the TSIGKeyInfo created by a successful parsing
  294. TSIGKeyInfoPtr key_;
  295. };
  296. /// @brief Test fixture class for testing TSIGKeyInfo list parsing.
  297. class TSIGKeyInfoListParserTest : public D2SimpleParserTest {
  298. public:
  299. /// @brief Constructor
  300. TSIGKeyInfoListParserTest()
  301. : D2SimpleParserTest(D2ParserContext::PARSER_TSIG_KEYS) {
  302. }
  303. /// @brief Destructor
  304. virtual ~TSIGKeyInfoListParserTest() {
  305. reset();
  306. }
  307. /// @brief Free up the keys created by parsing
  308. virtual void reset() {
  309. keys_.reset();
  310. };
  311. /// @brief Adds TSIG Key default values to a list of TSIG Key elements
  312. ///
  313. /// @param config list of TSIG Key elements to which defaults should be
  314. /// added
  315. ///
  316. /// @return the number of default items added to the tree
  317. size_t setDefaults(data::ElementPtr config) {
  318. return (SimpleParser::setListDefaults(config, D2SimpleParser::
  319. TSIG_KEY_DEFAULTS));
  320. }
  321. /// @brief Attempts to parse the given element into a list of TSIGKeyInfos
  322. ///
  323. /// Assumes the given element is a list containing one or more TSIG Keys
  324. /// elements. If parsing is successful the list of TSIGKeyInfo instances
  325. /// is retained in the member, keys_;
  326. ///
  327. /// @param config element to parse
  328. void parseElement(data::ConstElementPtr config) {
  329. TSIGKeyInfoListParser parser;
  330. keys_ = parser.parse(config);
  331. }
  332. /// @brief Retains the TSIGKeyInfos created by a successful parsing
  333. TSIGKeyInfoMapPtr keys_;
  334. };
  335. /// @brief Test fixture class for testing DnsServerInfo parsing.
  336. class DnsServerInfoParserTest : public D2SimpleParserTest {
  337. public:
  338. /// @brief Constructor
  339. DnsServerInfoParserTest()
  340. : D2SimpleParserTest(D2ParserContext::PARSER_DNS_SERVER) {
  341. }
  342. /// @brief Destructor
  343. virtual ~DnsServerInfoParserTest() {
  344. reset();
  345. }
  346. /// @brief Free up the server created by parsing
  347. virtual void reset() {
  348. server_.reset();
  349. }
  350. /// @brief Adds DNS Server default values to the given DNS Server element
  351. ///
  352. /// @param config DNS Server element to which defaults should be added
  353. ///
  354. /// @return the number of default items added to the tree
  355. virtual size_t setDefaults(data::ElementPtr config) {
  356. return (SimpleParser::setDefaults(config, D2SimpleParser::
  357. DNS_SERVER_DEFAULTS));
  358. }
  359. /// @brief Attempts to parse the given element into a DnsServerInfo
  360. ///
  361. /// Assumes the given element is a map containing the attributes for
  362. /// a DNS Server. If parsing is successful the new DnsServerInfo instance
  363. /// is retained in the member, server_;
  364. ///
  365. /// @param config element to parse
  366. virtual void parseElement(data::ConstElementPtr config) {
  367. DnsServerInfoParser parser;
  368. server_ = parser.parse(config);
  369. }
  370. /// @brief Retains the DnsServerInfo created by a successful parsing
  371. DnsServerInfoPtr server_;
  372. };
  373. /// @brief Test fixture class for testing DnsServerInfoList parsing.
  374. class DnsServerInfoListParserTest : public D2SimpleParserTest {
  375. public:
  376. /// @brief Constructor
  377. DnsServerInfoListParserTest()
  378. : D2SimpleParserTest(D2ParserContext::PARSER_DNS_SERVERS) {
  379. }
  380. /// @brief Destructor
  381. virtual ~DnsServerInfoListParserTest() {
  382. reset();
  383. }
  384. /// @brief Free up the servers created by parsing
  385. virtual void reset() {
  386. servers_.reset();
  387. }
  388. /// @brief Adds DNS Server default values to a list of DNS Server elements
  389. ///
  390. /// @param config list of DNS Server elements to which defaults should be
  391. /// added
  392. ///
  393. /// @return the number of default items added to the tree
  394. virtual size_t setDefaults(data::ElementPtr config) {
  395. return (SimpleParser::setListDefaults(config, D2SimpleParser::
  396. DNS_SERVER_DEFAULTS));
  397. }
  398. /// @brief Attempts to parse the given element into a list of DnsServerInfos
  399. ///
  400. /// Assumes the given element is a list containing one or more DNS Servers
  401. /// elements. If parsing is successful the list of DnsServerInfo instances
  402. /// is retained in the member, keys_;
  403. ///
  404. /// @param config element to parse
  405. virtual void parseElement(data::ConstElementPtr config) {
  406. DnsServerInfoListParser parser;
  407. servers_ = parser.parse(config);
  408. }
  409. /// @brief Retains the DnsServerInfos created by a successful parsing
  410. DnsServerInfoStoragePtr servers_;
  411. };
  412. /// @brief Test fixture class for testing DDnsDomain parsing.
  413. class DdnsDomainParserTest : public D2SimpleParserTest {
  414. public:
  415. /// @brief Constructor
  416. DdnsDomainParserTest(const D2ParserContext::ParserType& parser_type
  417. = D2ParserContext::PARSER_DDNS_DOMAIN)
  418. : D2SimpleParserTest(parser_type), keys_(new TSIGKeyInfoMap()) {
  419. }
  420. /// @brief Destructor
  421. virtual ~DdnsDomainParserTest() {
  422. reset();
  423. }
  424. /// @brief Free up the domain created by parsing
  425. virtual void reset() {
  426. domain_.reset();
  427. }
  428. /// @brief Add TSIGKeyInfos to the key map
  429. ///
  430. /// @param name the name of the key
  431. /// @param algorithm the algorithm of the key
  432. /// @param secret the secret value of the key
  433. void addKey(const std::string& name, const std::string& algorithm,
  434. const std::string& secret) {
  435. TSIGKeyInfoPtr key_info(new TSIGKeyInfo(name, algorithm, secret));
  436. (*keys_)[name]=key_info;
  437. }
  438. /// @brief Adds DDNS Domain values to the given DDNS Domain element
  439. ///
  440. /// @param config DDNS Domain element to which defaults should be added
  441. ///
  442. /// @return the number of default items added to the tree
  443. virtual size_t setDefaults(data::ElementPtr config) {
  444. return (D2SimpleParser::setDdnsDomainDefaults(config, D2SimpleParser::
  445. DDNS_DOMAIN_DEFAULTS));
  446. }
  447. /// @brief Attempts to parse the given element into a DdnsDomain
  448. ///
  449. /// Assumes the given element is a map containing the attributes for
  450. /// a DDNS Domain. If parsing is successful the new DdnsDomain instance
  451. /// is retained in the member, server_;
  452. ///
  453. /// @param config element to parse
  454. virtual void parseElement(data::ConstElementPtr config) {
  455. DdnsDomainParser parser;
  456. domain_ = parser.parse(config, keys_);
  457. }
  458. /// @brief Retains the DdnsDomain created by a successful parsing
  459. DdnsDomainPtr domain_;
  460. /// @brief Storage for TSIGKeys, used by DdnsDomainParser to validate
  461. /// domain keys
  462. TSIGKeyInfoMapPtr keys_;
  463. };
  464. class DdnsDomainListParserTest : public DdnsDomainParserTest {
  465. public:
  466. /// @brief Constructor
  467. DdnsDomainListParserTest()
  468. // We need the list context type to parse lists correctly
  469. : DdnsDomainParserTest(D2ParserContext::PARSER_DDNS_DOMAINS) {
  470. }
  471. /// @brief Destructor
  472. virtual ~DdnsDomainListParserTest() {
  473. reset();
  474. }
  475. /// @brief Free up domains created by parsing
  476. virtual void reset() {
  477. domains_.reset();
  478. }
  479. /// @brief Adds DDNS Domain default values to a list of DDNS Domain elements
  480. ///
  481. /// @param config list of DDNS Domain elements to which defaults should be
  482. /// added
  483. ///
  484. /// @return the number of default items added to the tree
  485. virtual size_t setDefaults(data::ElementPtr config) {
  486. size_t cnt = 0;
  487. // We don't use SimpleParser::setListDefaults() as this does
  488. // not handle sub-lists or sub-maps
  489. BOOST_FOREACH(ElementPtr domain, config->listValue()) {
  490. cnt += D2SimpleParser::
  491. setDdnsDomainDefaults(domain, D2SimpleParser::
  492. DDNS_DOMAIN_DEFAULTS);
  493. }
  494. return (cnt);
  495. }
  496. /// @brief Attempts to parse the given element into a list of DdnsDomains
  497. ///
  498. /// Assumes the given element is a list containing one or more DDNS Domains
  499. /// elements. If parsing is successful the list of DdnsDomain instances
  500. /// is retained in the member, keys_;
  501. ///
  502. /// @param config element to parse
  503. virtual void parseElement(data::ConstElementPtr config) {
  504. DdnsDomainListParser parser;
  505. domains_ = parser.parse(config, keys_);
  506. }
  507. /// @brief Retains the DdnsDomains created by a successful parsing
  508. DdnsDomainMapPtr domains_;
  509. };
  510. /// @brief Tests the enforcement of data validation when parsing TSIGKeyInfos.
  511. /// It verifies that:
  512. /// 1. Name cannot be blank.
  513. /// 2. Algorithm cannot be blank.
  514. /// 3. Secret cannot be blank.
  515. TEST_F(TSIGKeyInfoParserTest, invalidEntry) {
  516. // Name cannot be blank.
  517. std::string config = "{"
  518. " \"name\": \"\" , "
  519. " \"algorithm\": \"HMAC-MD5\" , "
  520. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  521. "}";
  522. PARSE_FAIL(config, "<string>:1.9: TSIG key name cannot be blank");
  523. // Algorithm cannot be be blank.
  524. config = "{"
  525. " \"name\": \"d2_key_one\" , "
  526. " \"algorithm\": \"\" , "
  527. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  528. "}";
  529. PARSE_FAIL(config, "<string>:1.38: TSIG key algorithm cannot be blank");
  530. // Algorithm must be a valid algorithm
  531. config = "{"
  532. " \"name\": \"d2_key_one\" , "
  533. " \"algorithm\": \"bogus\" , "
  534. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  535. "}";
  536. PARSE_FAIL(config, "tsig-key : Unknown TSIG Key algorithm:"
  537. " bogus (<string>:1:40)");
  538. // Secret cannot be blank
  539. config = "{"
  540. " \"name\": \"d2_key_one\" , "
  541. " \"algorithm\": \"HMAC-MD5\" , "
  542. " \"secret\": \"\" "
  543. "}";
  544. PARSE_FAIL(config, "<string>:1.62: TSIG key secret cannot be blank");
  545. // Secret must be valid for algorithm
  546. config = "{"
  547. " \"name\": \"d2_key_one\" , "
  548. " \"algorithm\": \"HMAC-MD5\" , "
  549. " \"digest-bits\": 120 , "
  550. " \"secret\": \"bogus\" "
  551. "}";
  552. PARSE_FAIL(config, "Cannot make TSIGKey: Incomplete input for base64:"
  553. " bogus (<string>:1:1)");
  554. }
  555. /// @brief Verifies that TSIGKeyInfo parsing creates a proper TSIGKeyInfo
  556. /// when given a valid combination of entries.
  557. TEST_F(TSIGKeyInfoParserTest, validEntry) {
  558. // Valid entries for TSIG key, all items are required.
  559. std::string config = "{"
  560. " \"name\": \"d2_key_one\" , "
  561. " \"algorithm\": \"HMAC-MD5\" , "
  562. " \"digest-bits\": 120 , "
  563. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  564. "}";
  565. // Verify that it parses.
  566. PARSE_OK(config);
  567. ASSERT_TRUE(key_);
  568. // Verify the key contents.
  569. EXPECT_TRUE(checkKey(key_, "d2_key_one", "HMAC-MD5",
  570. "dGhpcyBrZXkgd2lsbCBtYXRjaA==", 120));
  571. // Verify unparsing.
  572. runToElementTest<TSIGKeyInfo>(config, *key_);
  573. }
  574. /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
  575. /// entries is detected.
  576. TEST_F(TSIGKeyInfoListParserTest, invalidTSIGKeyList) {
  577. // Construct a list of keys with an invalid key entry.
  578. std::string config = "["
  579. " { \"name\": \"key1\" , "
  580. " \"algorithm\": \"HMAC-MD5\" ,"
  581. " \"digest-bits\": 120 , "
  582. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  583. " },"
  584. // this entry has an invalid algorithm
  585. " { \"name\": \"key2\" , "
  586. " \"algorithm\": \"\" ,"
  587. " \"digest-bits\": 120 , "
  588. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  589. " },"
  590. " { \"name\": \"key3\" , "
  591. " \"algorithm\": \"HMAC-MD5\" ,"
  592. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  593. " }"
  594. " ]";
  595. PARSE_FAIL(config, "<string>:1.151: TSIG key algorithm cannot be blank");
  596. }
  597. /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
  598. /// entries is detected.
  599. TEST_F(TSIGKeyInfoListParserTest, duplicateTSIGKey) {
  600. // Construct a list of keys with an invalid key entry.
  601. std::string config = "["
  602. " { \"name\": \"key1\" , "
  603. " \"algorithm\": \"HMAC-MD5\" ,"
  604. " \"digest-bits\": 120 , "
  605. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  606. " },"
  607. " { \"name\": \"key2\" , "
  608. " \"algorithm\": \"HMAC-MD5\" ,"
  609. " \"digest-bits\": 120 , "
  610. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  611. " },"
  612. " { \"name\": \"key1\" , "
  613. " \"algorithm\": \"HMAC-MD5\" ,"
  614. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  615. " }"
  616. " ]";
  617. PARSE_FAIL(config,
  618. "Duplicate TSIG key name specified : key1 (<string>:1:239)");
  619. }
  620. /// @brief Verifies a valid list of TSIG Keys parses correctly.
  621. /// Also verifies that all of the supported algorithm names work.
  622. TEST_F(TSIGKeyInfoListParserTest, validTSIGKeyList) {
  623. // Construct a valid list of keys.
  624. std::string config = "["
  625. " { \"name\": \"key1\" , "
  626. " \"algorithm\": \"HMAC-MD5\" ,"
  627. " \"digest-bits\": 80 , "
  628. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  629. " },"
  630. " { \"name\": \"key2\" , "
  631. " \"algorithm\": \"HMAC-SHA1\" ,"
  632. " \"digest-bits\": 80 , "
  633. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  634. " },"
  635. " { \"name\": \"key3\" , "
  636. " \"algorithm\": \"HMAC-SHA256\" ,"
  637. " \"digest-bits\": 128 , "
  638. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  639. " },"
  640. " { \"name\": \"key4\" , "
  641. " \"algorithm\": \"HMAC-SHA224\" ,"
  642. " \"digest-bits\": 112 , "
  643. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  644. " },"
  645. " { \"name\": \"key5\" , "
  646. " \"algorithm\": \"HMAC-SHA384\" ,"
  647. " \"digest-bits\": 192 , "
  648. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  649. " },"
  650. " { \"name\": \"key6\" , "
  651. " \"algorithm\": \"HMAC-SHA512\" ,"
  652. " \"digest-bits\": 256 , "
  653. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  654. " }"
  655. " ]";
  656. PARSE_OK(config);
  657. ASSERT_TRUE(keys_);
  658. std::string ref_secret = "dGhpcyBrZXkgd2lsbCBtYXRjaA==";
  659. // Verify the correct number of keys are present
  660. int count = keys_->size();
  661. ASSERT_EQ(6, count);
  662. // Find the 1st key and retrieve it.
  663. TSIGKeyInfoMap::iterator gotit = keys_->find("key1");
  664. ASSERT_TRUE(gotit != keys_->end());
  665. TSIGKeyInfoPtr& key = gotit->second;
  666. // Verify the key contents.
  667. EXPECT_TRUE(checkKey(key, "key1", TSIGKeyInfo::HMAC_MD5_STR,
  668. ref_secret, 80));
  669. // Find the 2nd key and retrieve it.
  670. gotit = keys_->find("key2");
  671. ASSERT_TRUE(gotit != keys_->end());
  672. key = gotit->second;
  673. // Verify the key contents.
  674. EXPECT_TRUE(checkKey(key, "key2", TSIGKeyInfo::HMAC_SHA1_STR,
  675. ref_secret, 80));
  676. // Find the 3rd key and retrieve it.
  677. gotit = keys_->find("key3");
  678. ASSERT_TRUE(gotit != keys_->end());
  679. key = gotit->second;
  680. // Verify the key contents.
  681. EXPECT_TRUE(checkKey(key, "key3", TSIGKeyInfo::HMAC_SHA256_STR,
  682. ref_secret, 128));
  683. // Find the 4th key and retrieve it.
  684. gotit = keys_->find("key4");
  685. ASSERT_TRUE(gotit != keys_->end());
  686. key = gotit->second;
  687. // Verify the key contents.
  688. EXPECT_TRUE(checkKey(key, "key4", TSIGKeyInfo::HMAC_SHA224_STR,
  689. ref_secret, 112));
  690. // Find the 5th key and retrieve it.
  691. gotit = keys_->find("key5");
  692. ASSERT_TRUE(gotit != keys_->end());
  693. key = gotit->second;
  694. // Verify the key contents.
  695. EXPECT_TRUE(checkKey(key, "key5", TSIGKeyInfo::HMAC_SHA384_STR,
  696. ref_secret, 192));
  697. // Find the 6th key and retrieve it.
  698. gotit = keys_->find("key6");
  699. ASSERT_TRUE(gotit != keys_->end());
  700. key = gotit->second;
  701. // Verify the key contents.
  702. EXPECT_TRUE(checkKey(key, "key6", TSIGKeyInfo::HMAC_SHA512_STR,
  703. ref_secret, 256));
  704. }
  705. /// @brief Tests the enforcement of data validation when parsing DnsServerInfos.
  706. /// It verifies that:
  707. /// 1. Specifying both a hostname and an ip address is not allowed.
  708. /// 2. Specifying both blank a hostname and blank ip address is not allowed.
  709. /// 3. Specifying a negative port number is not allowed.
  710. TEST_F(DnsServerInfoParserTest, invalidEntry) {
  711. // Create a config in which both host and ip address are supplied.
  712. // Verify that parsing fails.
  713. std::string config = "{ \"hostname\": \"pegasus.example\", "
  714. " \"ip-address\": \"127.0.0.1\", "
  715. " \"port\": 100} ";
  716. PARSE_FAIL(config, "<string>:1.13: hostname is not yet supported");
  717. // Neither host nor ip address supplied
  718. // Verify that builds fails.
  719. config = "{ \"hostname\": \"\", "
  720. " \"ip-address\": \"\", "
  721. " \"port\": 100} ";
  722. PARSE_FAIL(config, "Dns Server must specify one or the other"
  723. " of hostname or IP address (<string>:1:1)");
  724. // Create a config with a negative port number.
  725. // Verify that build fails.
  726. config = "{ \"hostname\": \"\", "
  727. " \"ip-address\": \"192.168.5.6\" ,"
  728. " \"port\": -100 }";
  729. PARSE_FAIL(config, "<string>:1.60-63: port must be greater than zero but less than 65536");
  730. }
  731. /// @brief Verifies that DnsServerInfo parsing creates a proper DnsServerInfo
  732. /// when given a valid combination of entries.
  733. /// It verifies that:
  734. /// 1. A DnsServerInfo entry is correctly made, when given only a hostname.
  735. /// 2. A DnsServerInfo entry is correctly made, when given ip address and port.
  736. /// 3. A DnsServerInfo entry is correctly made, when given only an ip address.
  737. TEST_F(DnsServerInfoParserTest, validEntry) {
  738. /// @todo When resolvable hostname is supported you'll need this test.
  739. /// // Valid entries for dynamic host
  740. /// std::string config = "{ \"hostname\": \"pegasus.example\" }";
  741. /// ASSERT_TRUE(fromJSON(config));
  742. /// // Verify that it builds and commits without throwing.
  743. /// ASSERT_NO_THROW(parser_->build(config_set_));
  744. /// ASSERT_NO_THROW(parser_->commit());
  745. /// //Verify the correct number of servers are present
  746. /// int count = servers_->size();
  747. /// EXPECT_EQ(1, count);
  748. /// Verify the server exists and has the correct values.
  749. /// DnsServerInfoPtr server = (*servers_)[0];
  750. /// EXPECT_TRUE(checkServer(server, "pegasus.example",
  751. /// DnsServerInfo::EMPTY_IP_STR,
  752. /// DnsServerInfo::STANDARD_DNS_PORT));
  753. /// // Start over for a new test.
  754. /// reset();
  755. // Valid entries for static ip
  756. std::string config = " { \"hostname\" : \"\", "
  757. " \"ip-address\": \"127.0.0.1\" , "
  758. " \"port\": 100 }";
  759. PARSE_OK(config);
  760. ASSERT_TRUE(server_);
  761. EXPECT_TRUE(checkServer(server_, "", "127.0.0.1", 100));
  762. // Verify unparsing.
  763. runToElementTest<DnsServerInfo>(config, *server_);
  764. // Valid entries for static ip, no port
  765. // This will fail without invoking set defaults
  766. config = " { \"ip-address\": \"192.168.2.5\" }";
  767. PARSE_OK(config);
  768. ASSERT_TRUE(server_);
  769. EXPECT_TRUE(checkServer(server_, "", "192.168.2.5",
  770. DnsServerInfo::STANDARD_DNS_PORT));
  771. }
  772. /// @brief Verifies that attempting to parse an invalid list of DnsServerInfo
  773. /// entries is detected.
  774. TEST_F(DnsServerInfoListParserTest, invalidServerList) {
  775. // Construct a list of servers with an invalid server entry.
  776. std::string config = "[ { \"ip-address\": \"127.0.0.1\" }, "
  777. "{ \"ip-address\": \"\" }, "
  778. "{ \"ip-address\": \"127.0.0.2\" } ]";
  779. PARSE_FAIL(config, "Dns Server must specify one or the other"
  780. " of hostname or IP address (<string>:1:34)");
  781. ASSERT_FALSE(servers_);
  782. }
  783. /// @brief Verifies that a list of DnsServerInfo entries parses correctly given
  784. /// a valid configuration.
  785. TEST_F(DnsServerInfoListParserTest, validServerList) {
  786. // Create a valid list of servers.
  787. std::string config = "[ { \"ip-address\": \"127.0.0.1\" }, "
  788. "{ \"ip-address\": \"127.0.0.2\" }, "
  789. "{ \"ip-address\": \"127.0.0.3\" } ]";
  790. PARSE_OK(config);
  791. // Verify that the server storage contains the correct number of servers.
  792. ASSERT_EQ(3, servers_->size());
  793. // Verify the first server exists and has the correct values.
  794. DnsServerInfoPtr server = (*servers_)[0];
  795. EXPECT_TRUE(checkServer(server, "", "127.0.0.1",
  796. DnsServerInfo::STANDARD_DNS_PORT));
  797. // Verify the second server exists and has the correct values.
  798. server = (*servers_)[1];
  799. EXPECT_TRUE(checkServer(server, "", "127.0.0.2",
  800. DnsServerInfo::STANDARD_DNS_PORT));
  801. // Verify the third server exists and has the correct values.
  802. server = (*servers_)[2];
  803. EXPECT_TRUE(checkServer(server, "", "127.0.0.3",
  804. DnsServerInfo::STANDARD_DNS_PORT));
  805. }
  806. /// @brief Tests the enforcement of data validation when parsing DdnsDomains.
  807. /// It verifies that:
  808. /// 1. Domain storage cannot be null when constructing a DdnsDomainParser.
  809. /// 2. The name entry is not optional.
  810. /// 3. The server list may not be empty.
  811. /// 4. That a mal-formed server entry is detected.
  812. /// 5. That an undefined key name is detected.
  813. TEST_F(DdnsDomainParserTest, invalidDomain) {
  814. // Create a domain configuration without a name
  815. std::string config = "{ \"key-name\": \"d2_key.example.com\" , "
  816. " \"dns-servers\" : [ "
  817. " { \"ip-address\": \"127.0.0.1\" , "
  818. " \"port\": 100 },"
  819. " { \"ip-address\": \"127.0.0.2\" , "
  820. " \"port\": 200 },"
  821. " { \"ip-address\": \"127.0.0.3\" , "
  822. " \"port\": 300 } ] } ";
  823. PARSE_FAIL(config, "missing parameter 'name' (<string>:1:1)");
  824. // Create a domain configuration with an empty server list.
  825. config = "{ \"name\": \"example.com\" , "
  826. " \"key-name\": \"\" , "
  827. " \"dns-servers\" : [ "
  828. " ] } ";
  829. PARSE_FAIL(config, "<string>:1.69: syntax error, unexpected ], expecting {");
  830. // Create a domain configuration with a mal-formed server entry.
  831. config = "{ \"name\": \"example.com\" , "
  832. " \"key-name\": \"\" , "
  833. " \"dns-servers\" : [ "
  834. " { \"ip-address\": \"127.0.0.3\" , "
  835. " \"port\": -1 } ] } ";
  836. PARSE_FAIL(config, "<string>:1.111-112: port must be greater than zero but less than 65536");
  837. // Create a domain configuration without an defined key name
  838. config = "{ \"name\": \"example.com\" , "
  839. " \"key-name\": \"d2_key.example.com\" , "
  840. " \"dns-servers\" : [ "
  841. " { \"ip-address\": \"127.0.0.3\" , "
  842. " \"port\": 300 } ] } ";
  843. PARSE_FAIL(config, "DdnsDomain : example.com specifies"
  844. " an undefined key: d2_key.example.com (<string>:1:41)");
  845. }
  846. /// @brief Verifies the basics of parsing of a DdnsDomain.
  847. TEST_F(DdnsDomainParserTest, validDomain) {
  848. // Add a TSIG key to the test key map, so key validation will pass.
  849. addKey("d2_key.example.com", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  850. // Create a valid domain configuration entry containing three valid
  851. // servers.
  852. std::string config =
  853. "{ \"name\": \"example.com\" , "
  854. " \"key-name\": \"d2_key.example.com\" , "
  855. " \"dns-servers\" : [ "
  856. " { \"ip-address\": \"127.0.0.1\" , "
  857. " \"port\": 100 },"
  858. " { \"ip-address\": \"127.0.0.2\" , "
  859. " \"port\": 200 },"
  860. " { \"ip-address\": \"127.0.0.3\" , "
  861. " \"port\": 300 } ] } ";
  862. PARSE_OK(config);
  863. // Domain should exist
  864. ASSERT_TRUE(domain_);
  865. // Verify the name and key_name values.
  866. EXPECT_EQ("example.com", domain_->getName());
  867. EXPECT_EQ("d2_key.example.com", domain_->getKeyName());
  868. ASSERT_TRUE(domain_->getTSIGKeyInfo());
  869. ASSERT_TRUE(domain_->getTSIGKeyInfo()->getTSIGKey());
  870. // Verify that the server list exists and contains the correct number of
  871. // servers.
  872. const DnsServerInfoStoragePtr& servers = domain_->getServers();
  873. EXPECT_TRUE(servers);
  874. EXPECT_EQ(3, servers->size());
  875. // Fetch each server and verify its contents.
  876. DnsServerInfoPtr server = (*servers)[0];
  877. EXPECT_TRUE(server);
  878. EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
  879. server = (*servers)[1];
  880. EXPECT_TRUE(server);
  881. EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
  882. server = (*servers)[2];
  883. EXPECT_TRUE(server);
  884. EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
  885. // Verify unparsing.
  886. ElementPtr json;
  887. ASSERT_NO_THROW(json = Element::fromJSON(config));
  888. ConstElementPtr servers_json;
  889. ASSERT_NO_THROW(servers_json = json->get("dns-servers"));
  890. ASSERT_TRUE(servers_json);
  891. ASSERT_EQ(Element::list, servers_json->getType());
  892. for (size_t i = 0; i < servers_json->size(); ++i) {
  893. ElementPtr server_json;
  894. ASSERT_NO_THROW(server_json = servers_json->getNonConst(i));
  895. ASSERT_NO_THROW(server_json->set("hostname",
  896. Element::create(std::string())));
  897. }
  898. runToElementTest<DdnsDomain>(json, *domain_);
  899. }
  900. /// @brief Tests the fundamentals of parsing DdnsDomain lists.
  901. /// This test verifies that given a valid domain list configuration
  902. /// it will accurately parse and populate each domain in the list.
  903. TEST_F(DdnsDomainListParserTest, validList) {
  904. // Add keys to key map so key validation passes.
  905. addKey("d2_key.example.com", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  906. addKey("d2_key.billcat.net", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  907. // Create a valid domain list configuration, with two domains
  908. // that have three servers each.
  909. std::string config =
  910. "[ "
  911. "{ \"name\": \"example.com\" , "
  912. " \"key-name\": \"d2_key.example.com\" , "
  913. " \"dns-servers\" : [ "
  914. " { \"ip-address\": \"127.0.0.1\" , "
  915. " \"port\": 100 },"
  916. " { \"ip-address\": \"127.0.0.2\" , "
  917. " \"port\": 200 },"
  918. " { \"ip-address\": \"127.0.0.3\" , "
  919. " \"port\": 300 } ] } "
  920. ", "
  921. "{ \"name\": \"billcat.net\" , "
  922. " \"key-name\": \"d2_key.billcat.net\" , "
  923. " \"dns-servers\" : [ "
  924. " { \"ip-address\": \"127.0.0.4\" , "
  925. " \"port\": 400 },"
  926. " { \"ip-address\": \"127.0.0.5\" , "
  927. " \"port\": 500 },"
  928. " { \"ip-address\": \"127.0.0.6\" , "
  929. " \"port\": 600 } ] } "
  930. "] ";
  931. // Verify that the domain list parses without error.
  932. PARSE_OK(config);
  933. ASSERT_TRUE(domains_);
  934. EXPECT_EQ(2, domains_->size());
  935. // Verify that the first domain exists and can be retrieved.
  936. DdnsDomainMap::iterator gotit = domains_->find("example.com");
  937. ASSERT_TRUE(gotit != domains_->end());
  938. DdnsDomainPtr& domain = gotit->second;
  939. // Verify the name and key_name values of the first domain.
  940. EXPECT_EQ("example.com", domain->getName());
  941. EXPECT_EQ("d2_key.example.com", domain->getKeyName());
  942. // Verify the TSIGKeyInfo name and that the actual key was created
  943. ASSERT_TRUE(domain->getTSIGKeyInfo());
  944. EXPECT_EQ(domain->getKeyName(), domain->getTSIGKeyInfo()->getName());
  945. EXPECT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  946. // Verify the each of the first domain's servers
  947. DnsServerInfoStoragePtr servers = domain->getServers();
  948. EXPECT_TRUE(servers);
  949. EXPECT_EQ(3, servers->size());
  950. DnsServerInfoPtr server = (*servers)[0];
  951. EXPECT_TRUE(server);
  952. EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
  953. server = (*servers)[1];
  954. EXPECT_TRUE(server);
  955. EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
  956. server = (*servers)[2];
  957. EXPECT_TRUE(server);
  958. EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
  959. // Verify second domain
  960. gotit = domains_->find("billcat.net");
  961. ASSERT_TRUE(gotit != domains_->end());
  962. domain = gotit->second;
  963. // Verify the name and key_name values of the second domain.
  964. EXPECT_EQ("billcat.net", domain->getName());
  965. EXPECT_EQ("d2_key.billcat.net", domain->getKeyName());
  966. ASSERT_TRUE(domain->getTSIGKeyInfo());
  967. EXPECT_EQ(domain->getKeyName(), domain->getTSIGKeyInfo()->getName());
  968. EXPECT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  969. // Verify the each of second domain's servers
  970. servers = domain->getServers();
  971. EXPECT_TRUE(servers);
  972. servers->size();
  973. EXPECT_EQ(3, servers->size());
  974. server = (*servers)[0];
  975. EXPECT_TRUE(server);
  976. EXPECT_TRUE(checkServer(server, "", "127.0.0.4", 400));
  977. server = (*servers)[1];
  978. EXPECT_TRUE(server);
  979. EXPECT_TRUE(checkServer(server, "", "127.0.0.5", 500));
  980. server = (*servers)[2];
  981. EXPECT_TRUE(server);
  982. EXPECT_TRUE(checkServer(server, "", "127.0.0.6", 600));
  983. }
  984. /// @brief Tests that a domain list configuration cannot contain duplicates.
  985. TEST_F(DdnsDomainListParserTest, duplicateDomain) {
  986. // Create a domain list configuration that contains two domains with
  987. // the same name.
  988. std::string config =
  989. "[ "
  990. "{ \"name\": \"example.com\" , "
  991. " \"dns-servers\" : [ "
  992. " { \"ip-address\": \"127.0.0.3\" , "
  993. " \"port\": 300 } ] } "
  994. ", "
  995. "{ \"name\": \"example.com\" , "
  996. " \"dns-servers\" : [ "
  997. " { \"ip-address\": \"127.0.0.3\" , "
  998. " \"port\": 300 } ] } "
  999. "] ";
  1000. // Verify that the parsing fails.
  1001. PARSE_FAIL(config,
  1002. "Duplicate domain specified:example.com (<string>:1:115)");
  1003. }
  1004. };