d2_cfg_mgr_unittests.cc 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790
  1. // Copyright (C) 2013-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.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <config/module_spec.h>
  8. #include <d2/d2_config.h>
  9. #include <d2/d2_cfg_mgr.h>
  10. #include <d2/d2_simple_parser.h>
  11. #include <d2/parser_context.h>
  12. #include <d2/tests/parser_unittest.h>
  13. #include <dhcpsrv/testutils/config_result_check.h>
  14. #include <process/testutils/d_test_stubs.h>
  15. #include <test_data_files_config.h>
  16. #include <util/encode/base64.h>
  17. #include <boost/foreach.hpp>
  18. #include <boost/scoped_ptr.hpp>
  19. #include <gtest/gtest.h>
  20. using namespace std;
  21. using namespace isc;
  22. using namespace isc::d2;
  23. using namespace isc::process;
  24. namespace {
  25. /// @brief Function to create full path to the spec file
  26. ///
  27. /// The full path is dependent upon the value of D2_SRC_DIR which
  28. /// whose value is generated from test_data_files_config.h.in
  29. ///
  30. /// @param name file name to which the path should be prepended
  31. std::string specfile(const std::string& name) {
  32. return (std::string(D2_SRC_DIR) + "/" + name);
  33. }
  34. /// @brief Function to create full path to test data file
  35. ///
  36. /// The full path is dependent upon the value of D2_TEST_DATA_DIR which
  37. /// whose value is generated from test_data_files_config.h.in
  38. ///
  39. /// @param name file name to which the path should be prepended
  40. std::string testDataFile(const std::string& name) {
  41. return (std::string(D2_TEST_DATA_DIR) + "/" + name);
  42. }
  43. /// @brief Test fixture class for testing D2CfgMgr class.
  44. /// It maintains an member instance of D2CfgMgr and provides methods for
  45. /// converting JSON strings to configuration element sets, checking parse
  46. /// results, and accessing the configuration context.
  47. class D2CfgMgrTest : public ConfigParseTest {
  48. public:
  49. /// @brief Constructor
  50. D2CfgMgrTest():cfg_mgr_(new D2CfgMgr()), d2_params_() {
  51. }
  52. /// @brief Destructor
  53. ~D2CfgMgrTest() {
  54. }
  55. /// @brief Configuration manager instance.
  56. D2CfgMgrPtr cfg_mgr_;
  57. /// @brief Build JSON configuration string for a D2Params element
  58. ///
  59. /// Constructs a JSON string for "params" element using replacable
  60. /// parameters.
  61. ///
  62. /// @param ip_address string to insert as ip_address value
  63. /// @param port integer to insert as port value
  64. /// @param dns_server_timeout integer to insert as dns_server_timeout value
  65. /// @param ncr_protocol string to insert as ncr_protocol value
  66. /// @param ncr_format string to insert as ncr_format value
  67. ///
  68. /// @return std::string containing the JSON configuration text
  69. std::string makeParamsConfigString(const std::string& ip_address,
  70. const int port,
  71. const int dns_server_timeout,
  72. const std::string& ncr_protocol,
  73. const std::string& ncr_format) {
  74. std::ostringstream config;
  75. config <<
  76. "{"
  77. " \"ip-address\": \"" << ip_address << "\" , "
  78. " \"port\": " << port << " , "
  79. " \"dns-server-timeout\": " << dns_server_timeout << " , "
  80. " \"ncr-protocol\": \"" << ncr_protocol << "\" , "
  81. " \"ncr-format\": \"" << ncr_format << "\", "
  82. "\"tsig-keys\": [], "
  83. "\"forward-ddns\" : {}, "
  84. "\"reverse-ddns\" : {} "
  85. "}";
  86. return (config.str());
  87. }
  88. /// @brief Enumeration to select between expected configuration outcomes
  89. enum RunConfigMode {
  90. SHOULD_PASS,
  91. SHOULD_FAIL
  92. };
  93. /// @brief Parses a configuration string and tests against a given outcome
  94. ///
  95. /// Convenience method which accepts JSON text and an expected pass or fail
  96. /// outcome. It converts the text into an ElementPtr and passes that to
  97. /// configuration manager's parseConfig method. It then tests the
  98. /// parse result against the expected outcome If they do not match it
  99. /// the method asserts a failure. If they do match, it refreshes the
  100. /// the D2Params pointer with the newly parsed instance.
  101. ///
  102. /// @param config_str the JSON configuration text to parse
  103. /// @param mode indicator if the parsing should fail or not. It defaults
  104. /// defaults to SHOULD_PASS.
  105. ///
  106. void runConfig(std::string config_str, RunConfigMode mode=SHOULD_PASS) {
  107. // We assume the config string is valid JSON.
  108. ASSERT_TRUE(fromJSON(config_str));
  109. // Parse the configuration and verify we got the expected outcome.
  110. answer_ = cfg_mgr_->parseConfig(config_set_);
  111. ASSERT_TRUE(checkAnswer(mode == SHOULD_FAIL));
  112. // Verify that the D2 context can be retrieved and is not null.
  113. D2CfgContextPtr context;
  114. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  115. // Verify that the global scalars have the proper values.
  116. d2_params_ = context->getD2Params();
  117. ASSERT_TRUE(d2_params_);
  118. }
  119. /// @brief Check parse result against expected outcome and position info
  120. ///
  121. /// This method analyzes the given parsing result against an expected outcome
  122. /// of SHOULD_PASS or SHOULD_FAIL. If it is expected to fail, the comment
  123. /// contained within the result is searched for Element::Position information
  124. /// which should contain the given file name. It does not attempt to verify
  125. /// the numerical values for line number and col.
  126. ///
  127. /// @param answer Element set containing an integer result code and string
  128. /// comment.
  129. /// @param mode indicator if the parsing should fail or not.
  130. /// @param file_name name of the file containing the configuration text
  131. /// parsed. It defaults to "<string>" which is the value present if the
  132. /// configuration text did not originate from a file. (i.e. one did not use
  133. /// isc::data::Element::fromJSONFile() to read the JSON text).
  134. void
  135. checkAnswerWithError(isc::data::ConstElementPtr answer,
  136. RunConfigMode mode, std::string file_name="<string>") {
  137. int rcode = 0;
  138. isc::data::ConstElementPtr comment;
  139. comment = isc::config::parseAnswer(rcode, answer);
  140. if (mode == SHOULD_PASS) {
  141. if (rcode == 0) {
  142. return;
  143. }
  144. FAIL() << "Parsing was expected to pass but failed : " << rcode
  145. << " comment: " << *comment;
  146. }
  147. if (rcode == 0) {
  148. FAIL() << "Parsing was expected to fail but passed : "
  149. << " comment: " << *comment;
  150. }
  151. // Parsing was expected to fail, test for position info.
  152. if (isc::dhcp::test::errorContainsPosition(answer, file_name)) {
  153. return;
  154. }
  155. FAIL() << "Parsing failed as expected but lacks position : " << *comment
  156. << ", filename:" << file_name;
  157. }
  158. /// @brief Pointer the D2Params most recently parsed.
  159. D2ParamsPtr d2_params_;
  160. };
  161. /// @brief Tests that the spec file is valid.
  162. /// Verifies that the DHCP-DDNS configuration specification file
  163. // is valid.
  164. TEST(D2SpecTest, basicSpec) {
  165. ASSERT_NO_THROW(isc::config::
  166. moduleSpecFromFile(specfile("dhcp-ddns.spec")));
  167. }
  168. /// @brief Convenience function which compares the contents of the given
  169. /// DnsServerInfo against the given set of values.
  170. ///
  171. /// It is structured in such a way that each value is checked, and output
  172. /// is generate for all that do not match.
  173. ///
  174. /// @param server is a pointer to the server to check against.
  175. /// @param hostname is the value to compare against server's hostname_.
  176. /// @param ip_address is the string value to compare against server's
  177. /// ip_address_.
  178. /// @param port is the value to compare against server's port.
  179. ///
  180. /// @return returns true if there is a match across the board, otherwise it
  181. /// returns false.
  182. bool checkServer(DnsServerInfoPtr server, const char* hostname,
  183. const char *ip_address, uint32_t port)
  184. {
  185. // Return value, assume its a match.
  186. bool result = true;
  187. if (!server) {
  188. EXPECT_TRUE(server);
  189. return false;
  190. }
  191. // Check hostname.
  192. if (server->getHostname() != hostname) {
  193. EXPECT_EQ(hostname, server->getHostname());
  194. result = false;
  195. }
  196. // Check IP address.
  197. if (server->getIpAddress().toText() != ip_address) {
  198. EXPECT_EQ(ip_address, server->getIpAddress().toText());
  199. result = false;
  200. }
  201. // Check port.
  202. if (server->getPort() != port) {
  203. EXPECT_EQ (port, server->getPort());
  204. result = false;
  205. }
  206. return (result);
  207. }
  208. /// @brief Convenience function which compares the contents of the given
  209. /// TSIGKeyInfo against the given set of values, and that the TSIGKey
  210. /// member points to a key.
  211. ///
  212. /// @param key is a pointer to the TSIGKeyInfo instance to verify
  213. /// @param name is the value to compare against key's name_.
  214. /// @param algorithm is the string value to compare against key's algorithm.
  215. /// @param secret is the value to compare against key's secret.
  216. ///
  217. /// @return returns true if there is a match across the board, otherwise it
  218. /// returns false.
  219. bool checkKey(TSIGKeyInfoPtr key, const std::string& name,
  220. const std::string& algorithm, const std::string& secret,
  221. uint32_t digestbits = 0) {
  222. // Return value, assume its a match.
  223. return (((key) &&
  224. (key->getName() == name) &&
  225. (key->getAlgorithm() == algorithm) &&
  226. (key->getDigestbits() == digestbits) &&
  227. (key->getSecret() == secret) &&
  228. (key->getTSIGKey())));
  229. }
  230. /// @brief Test fixture class for testing DnsServerInfo parsing.
  231. class TSIGKeyInfoTest : public ConfigParseTest {
  232. public:
  233. /// @brief Constructor
  234. TSIGKeyInfoTest() {
  235. }
  236. /// @brief Destructor
  237. ~TSIGKeyInfoTest() {
  238. }
  239. /// @brief Pointer to the current parser instance.
  240. TSIGKeyInfoParser parser_;
  241. };
  242. /// @brief Test fixture class for testing DnsServerInfo parsing.
  243. class TSIGKeyInfoListTest : public ConfigParseTest {
  244. public:
  245. /// @brief Constructor
  246. TSIGKeyInfoListTest() {
  247. }
  248. /// @brief Destructor
  249. ~TSIGKeyInfoListTest() {
  250. }
  251. /// @brief Pointer to the current parser instance.
  252. TSIGKeyInfoListParser parser_;
  253. };
  254. /// @brief Test fixture class for testing DnsServerInfo parsing.
  255. class DnsServerInfoTest : public ConfigParseTest {
  256. public:
  257. /// @brief Constructor
  258. DnsServerInfoTest() {
  259. reset();
  260. }
  261. /// @brief Destructor
  262. ~DnsServerInfoTest() {
  263. }
  264. /// @brief Wipe out the current storage and parser and replace
  265. /// them with new ones.
  266. void reset() {
  267. servers_.reset(new DnsServerInfoStorage());
  268. parser_.reset(new DnsServerInfoParser("test", servers_));
  269. }
  270. /// @brief Storage for "committing" servers.
  271. DnsServerInfoStoragePtr servers_;
  272. /// @brief Pointer to the current parser instance.
  273. isc::dhcp::ParserPtr parser_;
  274. };
  275. /// @brief Test fixture class for testing DDnsDomain parsing.
  276. class DdnsDomainTest : public ConfigParseTest {
  277. public:
  278. /// @brief Constructor
  279. DdnsDomainTest() {
  280. reset();
  281. }
  282. /// @brief Destructor
  283. ~DdnsDomainTest() {
  284. }
  285. /// @brief Wipe out the current storage and parser and replace
  286. /// them with new ones.
  287. void reset() {
  288. keys_.reset(new TSIGKeyInfoMap());
  289. domains_.reset(new DdnsDomainMap());
  290. parser_.reset(new DdnsDomainParser("test", domains_, keys_));
  291. }
  292. /// @brief Add TSIGKeyInfos to the key map
  293. ///
  294. /// @param name the name of the key
  295. /// @param algorithm the algorithm of the key
  296. /// @param secret the secret value of the key
  297. void addKey(const std::string& name, const std::string& algorithm,
  298. const std::string& secret) {
  299. TSIGKeyInfoPtr key_info(new TSIGKeyInfo(name, algorithm, secret));
  300. (*keys_)[name]=key_info;
  301. }
  302. /// @brief Storage for "committing" domains.
  303. DdnsDomainMapPtr domains_;
  304. /// @brief Storage for TSIGKeys
  305. TSIGKeyInfoMapPtr keys_;
  306. /// @brief Pointer to the current parser instance.
  307. isc::dhcp::ParserPtr parser_;
  308. };
  309. /// @brief Tests a basic valid configuration for D2Param.
  310. TEST_F(D2CfgMgrTest, validParamsEntry) {
  311. // Verify that ip_address can be valid v4 address.
  312. std::string config = makeParamsConfigString ("192.0.0.1", 777, 333,
  313. "UDP", "JSON");
  314. runConfig(config);
  315. EXPECT_EQ(isc::asiolink::IOAddress("192.0.0.1"),
  316. d2_params_->getIpAddress());
  317. EXPECT_EQ(777, d2_params_->getPort());
  318. EXPECT_EQ(333, d2_params_->getDnsServerTimeout());
  319. EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_params_->getNcrProtocol());
  320. EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_params_->getNcrFormat());
  321. // Verify that ip_address can be valid v6 address.
  322. config = makeParamsConfigString ("3001::5", 777, 333, "UDP", "JSON");
  323. runConfig(config);
  324. // Verify that the global scalars have the proper values.
  325. EXPECT_EQ(isc::asiolink::IOAddress("3001::5"),
  326. d2_params_->getIpAddress());
  327. // Verify the configuration summary.
  328. EXPECT_EQ("listening on 3001::5, port 777, using UDP",
  329. d2_params_->getConfigSummary());
  330. }
  331. /// @brief Tests default values for D2Params.
  332. /// It verifies that D2Params is populated with default value for optional
  333. /// parameter if not supplied in the configuration.
  334. /// Currently they are all optional.
  335. TEST_F(D2CfgMgrTest, defaultValues) {
  336. ElementPtr defaults = isc::d2::test::parseJSON("{ }");
  337. ASSERT_NO_THROW(D2SimpleParser::setAllDefaults(defaults));
  338. // Check that omitting ip_address gets you its default
  339. std::string config =
  340. "{"
  341. " \"port\": 777 , "
  342. " \"dns-server-timeout\": 333 , "
  343. " \"ncr-protocol\": \"UDP\" , "
  344. " \"ncr-format\": \"JSON\", "
  345. "\"tsig-keys\": [], "
  346. "\"forward-ddns\" : {}, "
  347. "\"reverse-ddns\" : {} "
  348. "}";
  349. runConfig(config);
  350. ConstElementPtr deflt;
  351. ASSERT_NO_THROW(deflt = defaults->get("ip-address"));
  352. ASSERT_TRUE(deflt);
  353. EXPECT_EQ(deflt->stringValue(), d2_params_->getIpAddress().toText());
  354. // Check that omitting port gets you its default
  355. config =
  356. "{"
  357. " \"ip-address\": \"192.0.0.1\" , "
  358. " \"dns-server-timeout\": 333 , "
  359. " \"ncr-protocol\": \"UDP\" , "
  360. " \"ncr-format\": \"JSON\", "
  361. "\"tsig-keys\": [], "
  362. "\"forward-ddns\" : {}, "
  363. "\"reverse-ddns\" : {} "
  364. "}";
  365. runConfig(config);
  366. ASSERT_NO_THROW(deflt = defaults->get("port"));
  367. ASSERT_TRUE(deflt);
  368. EXPECT_EQ(deflt->intValue(), d2_params_->getPort());
  369. // Check that omitting timeout gets you its default
  370. config =
  371. "{"
  372. " \"ip-address\": \"192.0.0.1\" , "
  373. " \"port\": 777 , "
  374. " \"ncr-protocol\": \"UDP\" , "
  375. " \"ncr-format\": \"JSON\", "
  376. "\"tsig-keys\": [], "
  377. "\"forward-ddns\" : {}, "
  378. "\"reverse-ddns\" : {} "
  379. "}";
  380. runConfig(config);
  381. ASSERT_NO_THROW(deflt = defaults->get("dns-server-timeout"));
  382. ASSERT_TRUE(deflt);
  383. EXPECT_EQ(deflt->intValue(), d2_params_->getDnsServerTimeout());
  384. // Check that omitting protocol gets you its default
  385. config =
  386. "{"
  387. " \"ip-address\": \"192.0.0.1\" , "
  388. " \"port\": 777 , "
  389. " \"dns-server-timeout\": 333 , "
  390. " \"ncr-format\": \"JSON\", "
  391. "\"tsig-keys\": [], "
  392. "\"forward-ddns\" : {}, "
  393. "\"reverse-ddns\" : {} "
  394. "}";
  395. runConfig(config);
  396. ASSERT_NO_THROW(deflt = defaults->get("ncr-protocol"));
  397. ASSERT_TRUE(deflt);
  398. EXPECT_EQ(dhcp_ddns::stringToNcrProtocol(deflt->stringValue()),
  399. d2_params_->getNcrProtocol());
  400. // Check that omitting format gets you its default
  401. config =
  402. "{"
  403. " \"ip-address\": \"192.0.0.1\" , "
  404. " \"port\": 777 , "
  405. " \"dns-server-timeout\": 333 , "
  406. " \"ncr-protocol\": \"UDP\", "
  407. "\"tsig-keys\": [], "
  408. "\"forward-ddns\" : {}, "
  409. "\"reverse-ddns\" : {} "
  410. "}";
  411. runConfig(config);
  412. ASSERT_NO_THROW(deflt = defaults->get("ncr-format"));
  413. ASSERT_TRUE(deflt);
  414. EXPECT_EQ(dhcp_ddns::stringToNcrFormat(deflt->stringValue()),
  415. d2_params_->getNcrFormat());
  416. }
  417. /// @brief Tests the unsupported scalar parameters and objects are detected.
  418. TEST_F(D2CfgMgrTest, unsupportedTopLevelItems) {
  419. // Check that an unsupported top level parameter fails.
  420. std::string config =
  421. "{"
  422. " \"ip-address\": \"127.0.0.1\", "
  423. " \"port\": 777 , "
  424. " \"dns-server-timeout\": 333 , "
  425. " \"ncr-protocol\": \"UDP\" , "
  426. " \"ncr-format\": \"JSON\", "
  427. "\"tsig-keys\": [], "
  428. "\"forward-ddns\" : {}, "
  429. "\"reverse-ddns\" : {}, "
  430. "\"bogus-param\" : true "
  431. "}";
  432. runConfig(config, SHOULD_FAIL);
  433. // Check that unsupported top level objects fails. For
  434. // D2 these fail as they are not in the parse order.
  435. config =
  436. "{"
  437. " \"ip-address\": \"127.0.0.1\", "
  438. " \"port\": 777 , "
  439. " \"dns-server-timeout\": 333 , "
  440. " \"ncr-protocol\": \"UDP\" , "
  441. " \"ncr-format\": \"JSON\", "
  442. "\"tsig-keys\": [], "
  443. "\"bogus-object-one\" : {}, "
  444. "\"forward-ddns\" : {}, "
  445. "\"reverse-ddns\" : {}, "
  446. "\"bogus-object-two\" : {} "
  447. "}";
  448. runConfig(config, SHOULD_FAIL);
  449. }
  450. /// @brief Tests the enforcement of data validation when parsing D2Params.
  451. /// It verifies that:
  452. /// -# ip_address cannot be "0.0.0.0"
  453. /// -# ip_address cannot be "::"
  454. /// -# port cannot be 0
  455. /// -# dns_server_timeout cannat be 0
  456. /// -# ncr_protocol must be valid
  457. /// -# ncr_format must be valid
  458. TEST_F(D2CfgMgrTest, invalidEntry) {
  459. // Cannot use IPv4 ANY address
  460. std::string config = makeParamsConfigString ("0.0.0.0", 777, 333,
  461. "UDP", "JSON");
  462. runConfig(config, SHOULD_FAIL);
  463. // Cannot use IPv6 ANY address
  464. config = makeParamsConfigString ("::", 777, 333, "UDP", "JSON");
  465. runConfig(config, SHOULD_FAIL);
  466. // Cannot use port 0
  467. config = makeParamsConfigString ("127.0.0.1", 0, 333, "UDP", "JSON");
  468. runConfig(config, SHOULD_FAIL);
  469. // Cannot use dns server timeout of 0
  470. config = makeParamsConfigString ("127.0.0.1", 777, 0, "UDP", "JSON");
  471. runConfig(config, SHOULD_FAIL);
  472. // Invalid protocol
  473. config = makeParamsConfigString ("127.0.0.1", 777, 333, "BOGUS", "JSON");
  474. runConfig(config, SHOULD_FAIL);
  475. // Unsupported protocol
  476. config = makeParamsConfigString ("127.0.0.1", 777, 333, "TCP", "JSON");
  477. runConfig(config, SHOULD_FAIL);
  478. // Invalid format
  479. config = makeParamsConfigString ("127.0.0.1", 777, 333, "UDP", "BOGUS");
  480. runConfig(config, SHOULD_FAIL);
  481. }
  482. /// @brief Tests the enforcement of data validation when parsing TSIGKeyInfos.
  483. /// It verifies that:
  484. /// 1. Name cannot be blank.
  485. /// 2. Algorithm cannot be blank.
  486. /// 3. Secret cannot be blank.
  487. TEST_F(TSIGKeyInfoTest, invalidEntry) {
  488. // Config with a blank name entry.
  489. std::string config = "{"
  490. " \"name\": \"\" , "
  491. " \"algorithm\": \"HMAC-MD5\" , "
  492. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  493. "}";
  494. ASSERT_TRUE(fromJSON(config));
  495. // Verify that build fails on blank name.
  496. EXPECT_THROW(parser_.parse(config_set_), D2CfgError);
  497. // Config with a blank algorithm entry.
  498. config = "{"
  499. " \"name\": \"d2_key_one\" , "
  500. " \"algorithm\": \"\" , "
  501. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  502. "}";
  503. ASSERT_TRUE(fromJSON(config));
  504. // Verify that build fails on blank algorithm.
  505. EXPECT_THROW(parser_.parse(config_set_), D2CfgError);
  506. // Config with an invalid algorithm entry.
  507. config = "{"
  508. " \"name\": \"d2_key_one\" , "
  509. " \"algorithm\": \"bogus\" , "
  510. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  511. "}";
  512. ASSERT_TRUE(fromJSON(config));
  513. // Verify that build fails on blank algorithm.
  514. EXPECT_THROW(parser_.parse(config_set_), D2CfgError);
  515. // Config with a blank secret entry.
  516. config = "{"
  517. " \"name\": \"d2_key_one\" , "
  518. " \"algorithm\": \"HMAC-MD5\" , "
  519. " \"secret\": \"\" "
  520. "}";
  521. ASSERT_TRUE(fromJSON(config));
  522. // Verify that build fails blank secret
  523. EXPECT_THROW(parser_.parse(config_set_), D2CfgError);
  524. // Config with an invalid secret entry.
  525. config = "{"
  526. " \"name\": \"d2_key_one\" , "
  527. " \"algorithm\": \"HMAC-MD5\" , "
  528. " \"secret\": \"bogus\" "
  529. "}";
  530. ASSERT_TRUE(fromJSON(config));
  531. // Verify that build fails an invalid secret
  532. EXPECT_THROW(parser_.parse(config_set_), D2CfgError);
  533. }
  534. /// @brief Verifies that TSIGKeyInfo parsing creates a proper TSIGKeyInfo
  535. /// when given a valid combination of entries.
  536. TEST_F(TSIGKeyInfoTest, validEntry) {
  537. // Valid entries for TSIG key, all items are required.
  538. std::string config = "{"
  539. " \"name\": \"d2_key_one\" , "
  540. " \"algorithm\": \"HMAC-MD5\" , "
  541. " \"digest-bits\": 120 , "
  542. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  543. "}";
  544. ASSERT_TRUE(fromJSON(config));
  545. // Verify that it builds and commits without throwing.
  546. //ASSERT_NO_THROW(parser_->build(config_set_));
  547. TSIGKeyInfoPtr key;
  548. ASSERT_NO_THROW(key = parser_.parse(config_set_));
  549. ASSERT_TRUE(key);
  550. // Verify the key contents.
  551. EXPECT_TRUE(checkKey(key, "d2_key_one", "HMAC-MD5",
  552. "dGhpcyBrZXkgd2lsbCBtYXRjaA==", 120));
  553. }
  554. /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
  555. /// entries is detected.
  556. TEST_F(TSIGKeyInfoListTest, invalidTSIGKeyList) {
  557. // Construct a list of keys with an invalid key entry.
  558. std::string config = "["
  559. " { \"name\": \"key1\" , "
  560. " \"algorithm\": \"HMAC-MD5\" ,"
  561. " \"digest-bits\": 120 , "
  562. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  563. " },"
  564. // this entry has an invalid algorithm
  565. " { \"name\": \"key2\" , "
  566. " \"algorithm\": \"\" ,"
  567. " \"digest-bits\": 120 , "
  568. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  569. " },"
  570. " { \"name\": \"key3\" , "
  571. " \"algorithm\": \"HMAC-MD5\" ,"
  572. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  573. " }"
  574. " ]";
  575. ASSERT_TRUE(fromJSON(config));
  576. // Verify that the list builds with errors.
  577. EXPECT_THROW(parser_.parse(config_set_), D2CfgError);
  578. }
  579. /// @brief Verifies that attempting to parse an invalid list of TSIGKeyInfo
  580. /// entries is detected.
  581. TEST_F(TSIGKeyInfoListTest, duplicateTSIGKey) {
  582. // Construct a list of keys with an invalid key entry.
  583. std::string config = "["
  584. " { \"name\": \"key1\" , "
  585. " \"algorithm\": \"HMAC-MD5\" ,"
  586. " \"digest-bits\": 120 , "
  587. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  588. " },"
  589. " { \"name\": \"key2\" , "
  590. " \"algorithm\": \"HMAC-MD5\" ,"
  591. " \"digest-bits\": 120 , "
  592. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  593. " },"
  594. " { \"name\": \"key1\" , "
  595. " \"algorithm\": \"HMAC-MD5\" ,"
  596. " \"secret\": \"GWG/Xfbju4O2iXGqkSu4PQ==\" "
  597. " }"
  598. " ]";
  599. ASSERT_TRUE(fromJSON(config));
  600. // Verify that the list builds without errors.
  601. EXPECT_THROW(parser_.parse(config_set_), D2CfgError);
  602. }
  603. /// @brief Verifies a valid list of TSIG Keys parses correctly.
  604. /// Also verifies that all of the supported algorithm names work.
  605. TEST_F(TSIGKeyInfoListTest, validTSIGKeyList) {
  606. // Construct a valid list of keys.
  607. std::string config = "["
  608. " { \"name\": \"key1\" , "
  609. " \"algorithm\": \"HMAC-MD5\" ,"
  610. " \"digest-bits\": 80 , "
  611. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  612. " },"
  613. " { \"name\": \"key2\" , "
  614. " \"algorithm\": \"HMAC-SHA1\" ,"
  615. " \"digest-bits\": 80 , "
  616. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  617. " },"
  618. " { \"name\": \"key3\" , "
  619. " \"algorithm\": \"HMAC-SHA256\" ,"
  620. " \"digest-bits\": 128 , "
  621. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  622. " },"
  623. " { \"name\": \"key4\" , "
  624. " \"algorithm\": \"HMAC-SHA224\" ,"
  625. " \"digest-bits\": 112 , "
  626. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  627. " },"
  628. " { \"name\": \"key5\" , "
  629. " \"algorithm\": \"HMAC-SHA384\" ,"
  630. " \"digest-bits\": 192 , "
  631. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  632. " },"
  633. " { \"name\": \"key6\" , "
  634. " \"algorithm\": \"HMAC-SHA512\" ,"
  635. " \"digest-bits\": 256 , "
  636. " \"secret\": \"dGhpcyBrZXkgd2lsbCBtYXRjaA==\" "
  637. " }"
  638. " ]";
  639. ASSERT_TRUE(fromJSON(config));
  640. TSIGKeyInfoMapPtr keys;
  641. ASSERT_NO_THROW(keys = parser_.parse(config_set_));
  642. std::string ref_secret = "dGhpcyBrZXkgd2lsbCBtYXRjaA==";
  643. // Verify the correct number of keys are present
  644. int count = keys->size();
  645. ASSERT_EQ(6, count);
  646. // Find the 1st key and retrieve it.
  647. TSIGKeyInfoMap::iterator gotit = keys->find("key1");
  648. ASSERT_TRUE(gotit != keys->end());
  649. TSIGKeyInfoPtr& key = gotit->second;
  650. // Verify the key contents.
  651. EXPECT_TRUE(checkKey(key, "key1", TSIGKeyInfo::HMAC_MD5_STR,
  652. ref_secret, 80));
  653. // Find the 2nd key and retrieve it.
  654. gotit = keys->find("key2");
  655. ASSERT_TRUE(gotit != keys->end());
  656. key = gotit->second;
  657. // Verify the key contents.
  658. EXPECT_TRUE(checkKey(key, "key2", TSIGKeyInfo::HMAC_SHA1_STR,
  659. ref_secret, 80));
  660. // Find the 3rd key and retrieve it.
  661. gotit = keys->find("key3");
  662. ASSERT_TRUE(gotit != keys->end());
  663. key = gotit->second;
  664. // Verify the key contents.
  665. EXPECT_TRUE(checkKey(key, "key3", TSIGKeyInfo::HMAC_SHA256_STR,
  666. ref_secret, 128));
  667. // Find the 4th key and retrieve it.
  668. gotit = keys->find("key4");
  669. ASSERT_TRUE(gotit != keys->end());
  670. key = gotit->second;
  671. // Verify the key contents.
  672. EXPECT_TRUE(checkKey(key, "key4", TSIGKeyInfo::HMAC_SHA224_STR,
  673. ref_secret, 112));
  674. // Find the 5th key and retrieve it.
  675. gotit = keys->find("key5");
  676. ASSERT_TRUE(gotit != keys->end());
  677. key = gotit->second;
  678. // Verify the key contents.
  679. EXPECT_TRUE(checkKey(key, "key5", TSIGKeyInfo::HMAC_SHA384_STR,
  680. ref_secret, 192));
  681. // Find the 6th key and retrieve it.
  682. gotit = keys->find("key6");
  683. ASSERT_TRUE(gotit != keys->end());
  684. key = gotit->second;
  685. // Verify the key contents.
  686. EXPECT_TRUE(checkKey(key, "key6", TSIGKeyInfo::HMAC_SHA512_STR,
  687. ref_secret, 256));
  688. }
  689. /// @brief Tests the enforcement of data validation when parsing DnsServerInfos.
  690. /// It verifies that:
  691. /// 1. Specifying both a hostname and an ip address is not allowed.
  692. /// 2. Specifying both blank a hostname and blank ip address is not allowed.
  693. /// 3. Specifying a negative port number is not allowed.
  694. TEST_F(DnsServerInfoTest, invalidEntry) {
  695. // Create a config in which both host and ip address are supplied.
  696. // Verify that build fails.
  697. std::string config = "{ \"hostname\": \"pegasus.tmark\", "
  698. " \"ip-address\": \"127.0.0.1\" } ";
  699. ASSERT_TRUE(fromJSON(config));
  700. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  701. // Neither host nor ip address supplied
  702. // Verify that builds fails.
  703. config = "{ \"hostname\": \"\", "
  704. " \"ip-address\": \"\" } ";
  705. ASSERT_TRUE(fromJSON(config));
  706. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  707. // Create a config with a negative port number.
  708. // Verify that build fails.
  709. config = "{ \"ip-address\": \"192.168.5.6\" ,"
  710. " \"port\": -100 }";
  711. ASSERT_TRUE(fromJSON(config));
  712. EXPECT_THROW (parser_->build(config_set_), isc::BadValue);
  713. }
  714. /// @brief Verifies that DnsServerInfo parsing creates a proper DnsServerInfo
  715. /// when given a valid combination of entries.
  716. /// It verifies that:
  717. /// 1. A DnsServerInfo entry is correctly made, when given only a hostname.
  718. /// 2. A DnsServerInfo entry is correctly made, when given ip address and port.
  719. /// 3. A DnsServerInfo entry is correctly made, when given only an ip address.
  720. TEST_F(DnsServerInfoTest, validEntry) {
  721. /// @todo When resolvable hostname is supported you'll need this test.
  722. /// // Valid entries for dynamic host
  723. /// std::string config = "{ \"hostname\": \"pegasus.tmark\" }";
  724. /// ASSERT_TRUE(fromJSON(config));
  725. /// // Verify that it builds and commits without throwing.
  726. /// ASSERT_NO_THROW(parser_->build(config_set_));
  727. /// ASSERT_NO_THROW(parser_->commit());
  728. /// //Verify the correct number of servers are present
  729. /// int count = servers_->size();
  730. /// EXPECT_EQ(1, count);
  731. /// Verify the server exists and has the correct values.
  732. /// DnsServerInfoPtr server = (*servers_)[0];
  733. /// EXPECT_TRUE(checkServer(server, "pegasus.tmark",
  734. /// DnsServerInfo::EMPTY_IP_STR,
  735. /// DnsServerInfo::STANDARD_DNS_PORT));
  736. /// // Start over for a new test.
  737. /// reset();
  738. // Valid entries for static ip
  739. std::string config = " { \"ip-address\": \"127.0.0.1\" , "
  740. " \"port\": 100 }";
  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, "", "127.0.0.1", 100));
  751. // Start over for a new test.
  752. reset();
  753. // Valid entries for static ip, no port
  754. config = " { \"ip-address\": \"192.168.2.5\" }";
  755. ASSERT_TRUE(fromJSON(config));
  756. // Verify that it builds and commits without throwing.
  757. ASSERT_NO_THROW(parser_->build(config_set_));
  758. ASSERT_NO_THROW(parser_->commit());
  759. // Verify the correct number of servers are present
  760. count = servers_->size();
  761. EXPECT_EQ(1, count);
  762. // Verify the server exists and has the correct values.
  763. server = (*servers_)[0];
  764. EXPECT_TRUE(checkServer(server, "", "192.168.2.5",
  765. DnsServerInfo::STANDARD_DNS_PORT));
  766. }
  767. /// @brief Verifies that attempting to parse an invalid list of DnsServerInfo
  768. /// entries is detected.
  769. TEST_F(ConfigParseTest, invalidServerList) {
  770. // Construct a list of servers with an invalid server entry.
  771. std::string config = "[ { \"ip-address\": \"127.0.0.1\" }, "
  772. "{ \"ip-address\": \"\" }, "
  773. "{ \"ip-address\": \"127.0.0.2\" } ]";
  774. ASSERT_TRUE(fromJSON(config));
  775. // Create the server storage and list parser.
  776. DnsServerInfoStoragePtr servers(new DnsServerInfoStorage());
  777. isc::dhcp::ParserPtr parser;
  778. ASSERT_NO_THROW(parser.reset(new DnsServerInfoListParser("test", servers)));
  779. // Verify that build fails.
  780. EXPECT_THROW(parser->build(config_set_), D2CfgError);
  781. }
  782. /// @brief Verifies that a list of DnsServerInfo entries parses correctly given
  783. /// a valid configuration.
  784. TEST_F(ConfigParseTest, validServerList) {
  785. // Create a valid list of servers.
  786. std::string config = "[ { \"ip-address\": \"127.0.0.1\" }, "
  787. "{ \"ip-address\": \"127.0.0.2\" }, "
  788. "{ \"ip-address\": \"127.0.0.3\" } ]";
  789. ASSERT_TRUE(fromJSON(config));
  790. // Create the server storage and list parser.
  791. DnsServerInfoStoragePtr servers(new DnsServerInfoStorage());
  792. isc::dhcp::ParserPtr parser;
  793. ASSERT_NO_THROW(parser.reset(new DnsServerInfoListParser("test", servers)));
  794. // Verfiy that the list builds and commits without error.
  795. ASSERT_NO_THROW(parser->build(config_set_));
  796. ASSERT_NO_THROW(parser->commit());
  797. // Verify that the server storage contains the correct number of servers.
  798. int count = servers->size();
  799. EXPECT_EQ(3, count);
  800. // Verify the first server exists and has the correct values.
  801. DnsServerInfoPtr server = (*servers)[0];
  802. EXPECT_TRUE(checkServer(server, "", "127.0.0.1",
  803. DnsServerInfo::STANDARD_DNS_PORT));
  804. // Verify the second server exists and has the correct values.
  805. server = (*servers)[1];
  806. EXPECT_TRUE(checkServer(server, "", "127.0.0.2",
  807. DnsServerInfo::STANDARD_DNS_PORT));
  808. // Verify the third server exists and has the correct values.
  809. server = (*servers)[2];
  810. EXPECT_TRUE(checkServer(server, "", "127.0.0.3",
  811. DnsServerInfo::STANDARD_DNS_PORT));
  812. }
  813. /// @brief Tests the enforcement of data validation when parsing DdnsDomains.
  814. /// It verifies that:
  815. /// 1. Domain storage cannot be null when constructing a DdnsDomainParser.
  816. /// 2. The name entry is not optional.
  817. /// 3. The server list man not be empty.
  818. /// 4. That a mal-formed server entry is detected.
  819. /// 5. That an undefined key name is detected.
  820. TEST_F(DdnsDomainTest, invalidDdnsDomainEntry) {
  821. // Verify that attempting to construct the parser with null storage fails.
  822. DdnsDomainMapPtr domains;
  823. ASSERT_THROW(isc::dhcp::ParserPtr(
  824. new DdnsDomainParser("test", domains, keys_)), D2CfgError);
  825. // Create a domain configuration without a name
  826. std::string config = "{ \"key-name\": \"d2_key.tmark.org\" , "
  827. " \"dns-servers\" : [ "
  828. " { \"ip-address\": \"127.0.0.1\" , "
  829. " \"port\": 100 },"
  830. " { \"ip-address\": \"127.0.0.2\" , "
  831. " \"port\": 200 },"
  832. " { \"ip-address\": \"127.0.0.3\" , "
  833. " \"port\": 300 } ] } ";
  834. ASSERT_TRUE(fromJSON(config));
  835. // Verify that the domain configuration builds fails.
  836. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  837. // Create a domain configuration with an empty server list.
  838. config = "{ \"name\": \"tmark.org\" , "
  839. " \"key-name\": \"d2_key.tmark.org\" , "
  840. " \"dns-servers\" : [ "
  841. " ] } ";
  842. ASSERT_TRUE(fromJSON(config));
  843. // Verify that the domain configuration build fails.
  844. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  845. // Create a domain configuration with a mal-formed server entry.
  846. config = "{ \"name\": \"tmark.org\" , "
  847. " \"key-name\": \"d2_key.tmark.org\" , "
  848. " \"dns-servers\" : [ "
  849. " { \"ip-address\": \"127.0.0.3\" , "
  850. " \"port\": -1 } ] } ";
  851. ASSERT_TRUE(fromJSON(config));
  852. // Verify that the domain configuration build fails.
  853. EXPECT_THROW(parser_->build(config_set_), isc::BadValue);
  854. // Create a domain configuration without an defined key name
  855. config = "{ \"name\": \"tmark.org\" , "
  856. " \"key-name\": \"d2_key.tmark.org\" , "
  857. " \"dns-servers\" : [ "
  858. " { \"ip-address\": \"127.0.0.3\" , "
  859. " \"port\": 300 } ] } ";
  860. ASSERT_TRUE(fromJSON(config));
  861. // Verify that the domain configuration build fails.
  862. EXPECT_THROW(parser_->build(config_set_), D2CfgError);
  863. }
  864. /// @brief Verifies the basics of parsing DdnsDomains.
  865. /// It verifies that:
  866. /// 1. Valid construction of DdnsDomainParser functions.
  867. /// 2. Given a valid, configuration entry, DdnsDomainParser parses
  868. /// correctly.
  869. /// (It indirectly verifies the operation of DdnsDomainMap).
  870. TEST_F(DdnsDomainTest, ddnsDomainParsing) {
  871. // Create a valid domain configuration entry containing three valid
  872. // servers.
  873. std::string config =
  874. "{ \"name\": \"tmark.org\" , "
  875. " \"key-name\": \"d2_key.tmark.org\" , "
  876. " \"dns-servers\" : [ "
  877. " { \"ip-address\": \"127.0.0.1\" , "
  878. " \"port\": 100 },"
  879. " { \"ip-address\": \"127.0.0.2\" , "
  880. " \"port\": 200 },"
  881. " { \"ip-address\": \"127.0.0.3\" , "
  882. " \"port\": 300 } ] } ";
  883. ASSERT_TRUE(fromJSON(config));
  884. // Add a TSIG key to the test key map, so key validation will pass.
  885. addKey("d2_key.tmark.org", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  886. // Verify that the domain configuration builds and commits without error.
  887. ASSERT_NO_THROW(parser_->build(config_set_));
  888. ASSERT_NO_THROW(parser_->commit());
  889. // Verify that the domain storage contains the correct number of domains.
  890. int count = domains_->size();
  891. EXPECT_EQ(1, count);
  892. // Verify that the expected domain exists and can be retrieved from
  893. // the storage.
  894. DdnsDomainMap::iterator gotit = domains_->find("tmark.org");
  895. ASSERT_TRUE(gotit != domains_->end());
  896. DdnsDomainPtr& domain = gotit->second;
  897. // Verify the name and key_name values.
  898. EXPECT_EQ("tmark.org", domain->getName());
  899. EXPECT_EQ("d2_key.tmark.org", domain->getKeyName());
  900. ASSERT_TRUE(domain->getTSIGKeyInfo());
  901. ASSERT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  902. // Verify that the server list exists and contains the correct number of
  903. // servers.
  904. const DnsServerInfoStoragePtr& servers = domain->getServers();
  905. EXPECT_TRUE(servers);
  906. count = servers->size();
  907. EXPECT_EQ(3, count);
  908. // Fetch each server and verify its contents.
  909. DnsServerInfoPtr server = (*servers)[0];
  910. EXPECT_TRUE(server);
  911. EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
  912. server = (*servers)[1];
  913. EXPECT_TRUE(server);
  914. EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
  915. server = (*servers)[2];
  916. EXPECT_TRUE(server);
  917. EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
  918. }
  919. /// @brief Tests the fundamentals of parsing DdnsDomain lists.
  920. /// This test verifies that given a valid domain list configuration
  921. /// it will accurately parse and populate each domain in the list.
  922. TEST_F(DdnsDomainTest, DdnsDomainListParsing) {
  923. // Create a valid domain list configuration, with two domains
  924. // that have three servers each.
  925. std::string config =
  926. "[ "
  927. "{ \"name\": \"tmark.org\" , "
  928. " \"key-name\": \"d2_key.tmark.org\" , "
  929. " \"dns-servers\" : [ "
  930. " { \"ip-address\": \"127.0.0.1\" , "
  931. " \"port\": 100 },"
  932. " { \"ip-address\": \"127.0.0.2\" , "
  933. " \"port\": 200 },"
  934. " { \"ip-address\": \"127.0.0.3\" , "
  935. " \"port\": 300 } ] } "
  936. ", "
  937. "{ \"name\": \"billcat.net\" , "
  938. " \"key-name\": \"d2_key.billcat.net\" , "
  939. " \"dns-servers\" : [ "
  940. " { \"ip-address\": \"127.0.0.4\" , "
  941. " \"port\": 400 },"
  942. " { \"ip-address\": \"127.0.0.5\" , "
  943. " \"port\": 500 },"
  944. " { \"ip-address\": \"127.0.0.6\" , "
  945. " \"port\": 600 } ] } "
  946. "] ";
  947. ASSERT_TRUE(fromJSON(config));
  948. // Add keys to key map so key validation passes.
  949. addKey("d2_key.tmark.org", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  950. addKey("d2_key.billcat.net", "HMAC-MD5", "GWG/Xfbju4O2iXGqkSu4PQ==");
  951. // Create the list parser
  952. isc::dhcp::ParserPtr list_parser;
  953. ASSERT_NO_THROW(list_parser.reset(
  954. new DdnsDomainListParser("test", domains_, keys_)));
  955. // Verify that the domain configuration builds and commits without error.
  956. ASSERT_NO_THROW(list_parser->build(config_set_));
  957. ASSERT_NO_THROW(list_parser->commit());
  958. // Verify that the domain storage contains the correct number of domains.
  959. int count = domains_->size();
  960. EXPECT_EQ(2, count);
  961. // Verify that the first domain exists and can be retrieved.
  962. DdnsDomainMap::iterator gotit = domains_->find("tmark.org");
  963. ASSERT_TRUE(gotit != domains_->end());
  964. DdnsDomainPtr& domain = gotit->second;
  965. // Verify the name and key_name values of the first domain.
  966. EXPECT_EQ("tmark.org", domain->getName());
  967. EXPECT_EQ("d2_key.tmark.org", domain->getKeyName());
  968. ASSERT_TRUE(domain->getTSIGKeyInfo());
  969. ASSERT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  970. // Verify the each of the first domain's servers
  971. DnsServerInfoStoragePtr servers = domain->getServers();
  972. EXPECT_TRUE(servers);
  973. count = servers->size();
  974. EXPECT_EQ(3, count);
  975. DnsServerInfoPtr server = (*servers)[0];
  976. EXPECT_TRUE(server);
  977. EXPECT_TRUE(checkServer(server, "", "127.0.0.1", 100));
  978. server = (*servers)[1];
  979. EXPECT_TRUE(server);
  980. EXPECT_TRUE(checkServer(server, "", "127.0.0.2", 200));
  981. server = (*servers)[2];
  982. EXPECT_TRUE(server);
  983. EXPECT_TRUE(checkServer(server, "", "127.0.0.3", 300));
  984. // Verify second domain
  985. gotit = domains_->find("billcat.net");
  986. ASSERT_TRUE(gotit != domains_->end());
  987. domain = gotit->second;
  988. // Verify the name and key_name values of the second domain.
  989. EXPECT_EQ("billcat.net", domain->getName());
  990. EXPECT_EQ("d2_key.billcat.net", domain->getKeyName());
  991. ASSERT_TRUE(domain->getTSIGKeyInfo());
  992. ASSERT_TRUE(domain->getTSIGKeyInfo()->getTSIGKey());
  993. // Verify the each of second domain's servers
  994. servers = domain->getServers();
  995. EXPECT_TRUE(servers);
  996. count = servers->size();
  997. EXPECT_EQ(3, count);
  998. server = (*servers)[0];
  999. EXPECT_TRUE(server);
  1000. EXPECT_TRUE(checkServer(server, "", "127.0.0.4", 400));
  1001. server = (*servers)[1];
  1002. EXPECT_TRUE(server);
  1003. EXPECT_TRUE(checkServer(server, "", "127.0.0.5", 500));
  1004. server = (*servers)[2];
  1005. EXPECT_TRUE(server);
  1006. EXPECT_TRUE(checkServer(server, "", "127.0.0.6", 600));
  1007. }
  1008. /// @brief Tests that a domain list configuration cannot contain duplicates.
  1009. TEST_F(DdnsDomainTest, duplicateDomain) {
  1010. // Create a domain list configuration that contains two domains with
  1011. // the same name.
  1012. std::string config =
  1013. "[ "
  1014. "{ \"name\": \"tmark.org\" , "
  1015. " \"dns-servers\" : [ "
  1016. " { \"ip-address\": \"127.0.0.3\" , "
  1017. " \"port\": 300 } ] } "
  1018. ", "
  1019. "{ \"name\": \"tmark.org\" , "
  1020. " \"dns-servers\" : [ "
  1021. " { \"ip-address\": \"127.0.0.3\" , "
  1022. " \"port\": 300 } ] } "
  1023. "] ";
  1024. ASSERT_TRUE(fromJSON(config));
  1025. // Create the list parser
  1026. isc::dhcp::ParserPtr list_parser;
  1027. ASSERT_NO_THROW(list_parser.reset(
  1028. new DdnsDomainListParser("test", domains_, keys_)));
  1029. // Verify that the parse build fails.
  1030. EXPECT_THROW(list_parser->build(config_set_), D2CfgError);
  1031. }
  1032. /// @brief Tests construction of D2CfgMgr
  1033. /// This test verifies that a D2CfgMgr constructs properly.
  1034. TEST(D2CfgMgr, construction) {
  1035. boost::scoped_ptr<D2CfgMgr> cfg_mgr;
  1036. // Verify that configuration manager constructions without error.
  1037. ASSERT_NO_THROW(cfg_mgr.reset(new D2CfgMgr()));
  1038. // Verify that the context can be retrieved and is not null.
  1039. D2CfgContextPtr context;
  1040. ASSERT_NO_THROW(context = cfg_mgr->getD2CfgContext());
  1041. EXPECT_TRUE(context);
  1042. // Verify that the forward manager can be retrieved and is not null.
  1043. EXPECT_TRUE(context->getForwardMgr());
  1044. // Verify that the reverse manager can be retrieved and is not null.
  1045. EXPECT_TRUE(context->getReverseMgr());
  1046. // Verify that the manager can be destructed without error.
  1047. EXPECT_NO_THROW(cfg_mgr.reset());
  1048. }
  1049. /// @brief Tests the parsing of a complete, valid DHCP-DDNS configuration.
  1050. /// This tests passes the configuration into an instance of D2CfgMgr just
  1051. /// as it would be done by d2_process in response to a configuration update
  1052. /// event.
  1053. TEST_F(D2CfgMgrTest, fullConfig) {
  1054. // Create a configuration with all of application level parameters, plus
  1055. // both the forward and reverse ddns managers. Both managers have two
  1056. // domains with three servers per domain.
  1057. std::string config = "{ "
  1058. "\"ip-address\" : \"192.168.1.33\" , "
  1059. "\"port\" : 88 , "
  1060. " \"dns-server-timeout\": 333 , "
  1061. " \"ncr-protocol\": \"UDP\" , "
  1062. " \"ncr-format\": \"JSON\", "
  1063. "\"tsig-keys\": ["
  1064. "{"
  1065. " \"name\": \"d2_key.tmark.org\" , "
  1066. " \"algorithm\": \"hmac-md5\" , "
  1067. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  1068. "},"
  1069. "{"
  1070. " \"name\": \"d2_key.billcat.net\" , "
  1071. " \"algorithm\": \"hmac-md5\" , "
  1072. " \"digest-bits\": 120 , "
  1073. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  1074. "}"
  1075. "],"
  1076. "\"forward-ddns\" : {"
  1077. "\"ddns-domains\": [ "
  1078. "{ \"name\": \"tmark.org\" , "
  1079. " \"key-name\": \"d2_key.tmark.org\" , "
  1080. " \"dns-servers\" : [ "
  1081. " { \"ip-address\": \"127.0.0.1\" } , "
  1082. " { \"ip-address\": \"127.0.0.2\" } , "
  1083. " { \"ip-address\": \"127.0.0.3\"} "
  1084. " ] } "
  1085. ", "
  1086. "{ \"name\": \"billcat.net\" , "
  1087. " \"key-name\": \"d2_key.billcat.net\" , "
  1088. " \"dns-servers\" : [ "
  1089. " { \"ip-address\": \"127.0.0.4\" } , "
  1090. " { \"ip-address\": \"127.0.0.5\" } , "
  1091. " { \"ip-address\": \"127.0.0.6\" } "
  1092. " ] } "
  1093. "] },"
  1094. "\"reverse-ddns\" : {"
  1095. "\"ddns-domains\": [ "
  1096. "{ \"name\": \" 0.168.192.in.addr.arpa.\" , "
  1097. " \"key-name\": \"d2_key.tmark.org\" , "
  1098. " \"dns-servers\" : [ "
  1099. " { \"ip-address\": \"127.0.1.1\" } , "
  1100. " { \"ip-address\": \"127.0.2.1\" } , "
  1101. " { \"ip-address\": \"127.0.3.1\" } "
  1102. " ] } "
  1103. ", "
  1104. "{ \"name\": \" 0.247.106.in.addr.arpa.\" , "
  1105. " \"key-name\": \"d2_key.billcat.net\" , "
  1106. " \"dns-servers\" : [ "
  1107. " { \"ip-address\": \"127.0.4.1\" }, "
  1108. " { \"ip-address\": \"127.0.5.1\" } , "
  1109. " { \"ip-address\": \"127.0.6.1\" } "
  1110. " ] } "
  1111. "] } }";
  1112. ASSERT_TRUE(fromJSON(config));
  1113. // Verify that we can parse the configuration.
  1114. answer_ = cfg_mgr_->parseConfig(config_set_);
  1115. ASSERT_TRUE(checkAnswer(0));
  1116. // Verify that the D2 context can be retrieved and is not null.
  1117. D2CfgContextPtr context;
  1118. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1119. // Verify that the global scalars have the proper values.
  1120. D2ParamsPtr& d2_params = context->getD2Params();
  1121. ASSERT_TRUE(d2_params);
  1122. EXPECT_EQ(isc::asiolink::IOAddress("192.168.1.33"),
  1123. d2_params->getIpAddress());
  1124. EXPECT_EQ(88, d2_params->getPort());
  1125. EXPECT_EQ(333, d2_params->getDnsServerTimeout());
  1126. EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_params->getNcrProtocol());
  1127. EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_params->getNcrFormat());
  1128. // Verify that the forward manager can be retrieved.
  1129. DdnsDomainListMgrPtr mgr = context->getForwardMgr();
  1130. ASSERT_TRUE(mgr);
  1131. // Verify that the forward manager has the correct number of domains.
  1132. DdnsDomainMapPtr domains = mgr->getDomains();
  1133. ASSERT_TRUE(domains);
  1134. int count = domains->size();
  1135. EXPECT_EQ(2, count);
  1136. // Verify that the server count in each of the forward manager domains.
  1137. // NOTE that since prior tests have validated server parsing, we are are
  1138. // assuming that the servers did in fact parse correctly if the correct
  1139. // number of them are there.
  1140. DdnsDomainMapPair domain_pair;
  1141. BOOST_FOREACH(domain_pair, (*domains)) {
  1142. DdnsDomainPtr domain = domain_pair.second;
  1143. DnsServerInfoStoragePtr servers = domain->getServers();
  1144. count = servers->size();
  1145. EXPECT_TRUE(servers);
  1146. EXPECT_EQ(3, count);
  1147. }
  1148. // Verify that the reverse manager can be retrieved.
  1149. mgr = context->getReverseMgr();
  1150. ASSERT_TRUE(mgr);
  1151. // Verify that the reverse manager has the correct number of domains.
  1152. domains = mgr->getDomains();
  1153. count = domains->size();
  1154. EXPECT_EQ(2, count);
  1155. // Verify that the server count in each of the reverse manager domains.
  1156. // NOTE that since prior tests have validated server parsing, we are are
  1157. // assuming that the servers did in fact parse correctly if the correct
  1158. // number of them are there.
  1159. BOOST_FOREACH(domain_pair, (*domains)) {
  1160. DdnsDomainPtr domain = domain_pair.second;
  1161. DnsServerInfoStoragePtr servers = domain->getServers();
  1162. count = servers->size();
  1163. EXPECT_TRUE(servers);
  1164. EXPECT_EQ(3, count);
  1165. }
  1166. // Test directional update flags.
  1167. EXPECT_TRUE(cfg_mgr_->forwardUpdatesEnabled());
  1168. EXPECT_TRUE(cfg_mgr_->reverseUpdatesEnabled());
  1169. // Verify that parsing the exact same configuration a second time
  1170. // does not cause a duplicate value errors.
  1171. answer_ = cfg_mgr_->parseConfig(config_set_);
  1172. ASSERT_TRUE(checkAnswer(0));
  1173. }
  1174. /// @brief Tests the basics of the D2CfgMgr FQDN-domain matching
  1175. /// This test uses a valid configuration to exercise the D2CfgMgr
  1176. /// forward FQDN-to-domain matching.
  1177. /// It verifies that:
  1178. /// 1. Given an FQDN which exactly matches a domain's name, that domain is
  1179. /// returned as match.
  1180. /// 2. Given a FQDN for sub-domain in the list, returns the proper match.
  1181. /// 3. Given a FQDN that matches no domain name, returns the wild card domain
  1182. /// as a match.
  1183. TEST_F(D2CfgMgrTest, forwardMatch) {
  1184. // Create configuration with one domain, one sub domain, and the wild
  1185. // card.
  1186. std::string config = "{ "
  1187. "\"ip-address\" : \"192.168.1.33\" , "
  1188. "\"port\" : 88 , "
  1189. "\"tsig-keys\": [] ,"
  1190. "\"forward-ddns\" : {"
  1191. "\"ddns-domains\": [ "
  1192. "{ \"name\": \"tmark.org\" , "
  1193. " \"dns-servers\" : [ "
  1194. " { \"ip-address\": \"127.0.0.1\" } "
  1195. " ] } "
  1196. ", "
  1197. "{ \"name\": \"one.tmark.org\" , "
  1198. " \"dns-servers\" : [ "
  1199. " { \"ip-address\": \"127.0.0.2\" } "
  1200. " ] } "
  1201. ", "
  1202. "{ \"name\": \"*\" , "
  1203. " \"dns-servers\" : [ "
  1204. " { \"ip-address\": \"127.0.0.3\" } "
  1205. " ] } "
  1206. "] }, "
  1207. "\"reverse-ddns\" : {} "
  1208. "}";
  1209. ASSERT_TRUE(fromJSON(config));
  1210. // Verify that we can parse the configuration.
  1211. answer_ = cfg_mgr_->parseConfig(config_set_);
  1212. ASSERT_TRUE(checkAnswer(0));
  1213. // Verify that the D2 context can be retrieved and is not null.
  1214. D2CfgContextPtr context;
  1215. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1216. // Test directional update flags.
  1217. EXPECT_TRUE(cfg_mgr_->forwardUpdatesEnabled());
  1218. EXPECT_FALSE(cfg_mgr_->reverseUpdatesEnabled());
  1219. DdnsDomainPtr match;
  1220. // Verify that an exact match works.
  1221. EXPECT_TRUE(cfg_mgr_->matchForward("tmark.org", match));
  1222. EXPECT_EQ("tmark.org", match->getName());
  1223. // Verify that search is case insensisitive.
  1224. EXPECT_TRUE(cfg_mgr_->matchForward("TMARK.ORG", match));
  1225. EXPECT_EQ("tmark.org", match->getName());
  1226. // Verify that an exact match works.
  1227. EXPECT_TRUE(cfg_mgr_->matchForward("one.tmark.org", match));
  1228. EXPECT_EQ("one.tmark.org", match->getName());
  1229. // Verify that a FQDN for sub-domain matches.
  1230. EXPECT_TRUE(cfg_mgr_->matchForward("blue.tmark.org", match));
  1231. EXPECT_EQ("tmark.org", match->getName());
  1232. // Verify that a FQDN for sub-domain matches.
  1233. EXPECT_TRUE(cfg_mgr_->matchForward("red.one.tmark.org", match));
  1234. EXPECT_EQ("one.tmark.org", match->getName());
  1235. // Verify that an FQDN with no match, returns the wild card domain.
  1236. EXPECT_TRUE(cfg_mgr_->matchForward("shouldbe.wildcard", match));
  1237. EXPECT_EQ("*", match->getName());
  1238. // Verify that an attempt to match an empty FQDN throws.
  1239. ASSERT_THROW(cfg_mgr_->matchForward("", match), D2CfgError);
  1240. }
  1241. /// @brief Tests domain matching when there is no wild card domain.
  1242. /// This test verifies that matches are found only for FQDNs that match
  1243. /// some or all of a domain name. FQDNs without matches should not return
  1244. /// a match.
  1245. TEST_F(D2CfgMgrTest, matchNoWildcard) {
  1246. // Create a configuration with one domain, one sub-domain, and NO wild card.
  1247. std::string config = "{ "
  1248. "\"ip-address\" : \"192.168.1.33\" , "
  1249. "\"port\" : 88 , "
  1250. "\"tsig-keys\": [] ,"
  1251. "\"forward-ddns\" : {"
  1252. "\"ddns-domains\": [ "
  1253. "{ \"name\": \"tmark.org\" , "
  1254. " \"dns-servers\" : [ "
  1255. " { \"ip-address\": \"127.0.0.1\" } "
  1256. " ] } "
  1257. ", "
  1258. "{ \"name\": \"one.tmark.org\" , "
  1259. " \"dns-servers\" : [ "
  1260. " { \"ip-address\": \"127.0.0.2\" } "
  1261. " ] } "
  1262. "] }, "
  1263. "\"reverse-ddns\" : {} "
  1264. " }";
  1265. ASSERT_TRUE(fromJSON(config));
  1266. // Verify that we can parse the configuration.
  1267. answer_ = cfg_mgr_->parseConfig(config_set_);
  1268. ASSERT_TRUE(checkAnswer(0));
  1269. // Verify that the D2 context can be retrieved and is not null.
  1270. D2CfgContextPtr context;
  1271. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1272. DdnsDomainPtr match;
  1273. // Verify that full or partial matches, still match.
  1274. EXPECT_TRUE(cfg_mgr_->matchForward("tmark.org", match));
  1275. EXPECT_EQ("tmark.org", match->getName());
  1276. EXPECT_TRUE(cfg_mgr_->matchForward("blue.tmark.org", match));
  1277. EXPECT_EQ("tmark.org", match->getName());
  1278. EXPECT_TRUE(cfg_mgr_->matchForward("red.one.tmark.org", match));
  1279. EXPECT_EQ("one.tmark.org", match->getName());
  1280. // Verify that a FQDN with no match, fails to match.
  1281. EXPECT_FALSE(cfg_mgr_->matchForward("shouldbe.wildcard", match));
  1282. }
  1283. /// @brief Tests domain matching when there is ONLY a wild card domain.
  1284. /// This test verifies that any FQDN matches the wild card.
  1285. TEST_F(D2CfgMgrTest, matchAll) {
  1286. std::string config = "{ "
  1287. "\"ip-address\" : \"192.168.1.33\" , "
  1288. "\"port\" : 88 , "
  1289. "\"tsig-keys\": [] ,"
  1290. "\"forward-ddns\" : {"
  1291. "\"ddns-domains\": [ "
  1292. "{ \"name\": \"*\" , "
  1293. " \"dns-servers\" : [ "
  1294. " { \"ip-address\": \"127.0.0.1\" } "
  1295. " ] } "
  1296. "] }, "
  1297. "\"reverse-ddns\" : {} "
  1298. "}";
  1299. ASSERT_TRUE(fromJSON(config));
  1300. // Verify that we can parse the configuration.
  1301. answer_ = cfg_mgr_->parseConfig(config_set_);
  1302. ASSERT_TRUE(checkAnswer(0));
  1303. // Verify that the D2 context can be retrieved and is not null.
  1304. D2CfgContextPtr context;
  1305. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1306. // Verify that wild card domain is returned for any FQDN.
  1307. DdnsDomainPtr match;
  1308. EXPECT_TRUE(cfg_mgr_->matchForward("tmark.org", match));
  1309. EXPECT_EQ("*", match->getName());
  1310. EXPECT_TRUE(cfg_mgr_->matchForward("shouldbe.wildcard", match));
  1311. EXPECT_EQ("*", match->getName());
  1312. // Verify that an attempt to match an empty FQDN still throws.
  1313. ASSERT_THROW(cfg_mgr_->matchReverse("", match), D2CfgError);
  1314. }
  1315. /// @brief Tests the basics of the D2CfgMgr reverse FQDN-domain matching
  1316. /// This test uses a valid configuration to exercise the D2CfgMgr's
  1317. /// reverse FQDN-to-domain matching.
  1318. /// It verifies that:
  1319. /// 1. Given an FQDN which exactly matches a domain's name, that domain is
  1320. /// returned as match.
  1321. /// 2. Given a FQDN for sub-domain in the list, returns the proper match.
  1322. /// 3. Given a FQDN that matches no domain name, returns the wild card domain
  1323. /// as a match.
  1324. TEST_F(D2CfgMgrTest, matchReverse) {
  1325. std::string config = "{ "
  1326. "\"ip-address\" : \"192.168.1.33\" , "
  1327. "\"port\" : 88 , "
  1328. "\"tsig-keys\": [] ,"
  1329. "\"forward-ddns\" : {}, "
  1330. "\"reverse-ddns\" : {"
  1331. "\"ddns-domains\": [ "
  1332. "{ \"name\": \"5.100.168.192.in-addr.arpa.\" , "
  1333. " \"dns-servers\" : [ "
  1334. " { \"ip-address\": \"127.0.0.1\" } "
  1335. " ] }, "
  1336. "{ \"name\": \"100.200.192.in-addr.arpa.\" , "
  1337. " \"dns-servers\" : [ "
  1338. " { \"ip-address\": \"127.0.0.1\" } "
  1339. " ] }, "
  1340. "{ \"name\": \"170.192.in-addr.arpa.\" , "
  1341. " \"dns-servers\" : [ "
  1342. " { \"ip-address\": \"127.0.0.1\" } "
  1343. " ] }, "
  1344. // Note mixed case to test case insensitivity.
  1345. "{ \"name\": \"2.0.3.0.8.b.d.0.1.0.0.2.IP6.ARPA.\" , "
  1346. " \"dns-servers\" : [ "
  1347. " { \"ip-address\": \"127.0.0.1\" } "
  1348. " ] },"
  1349. "{ \"name\": \"*\" , "
  1350. " \"dns-servers\" : [ "
  1351. " { \"ip-address\": \"127.0.0.1\" } "
  1352. " ] } "
  1353. "] } }";
  1354. ASSERT_TRUE(fromJSON(config));
  1355. // Verify that we can parse the configuration.
  1356. answer_ = cfg_mgr_->parseConfig(config_set_);
  1357. ASSERT_TRUE(checkAnswer(0));
  1358. // Verify that the D2 context can be retrieved and is not null.
  1359. D2CfgContextPtr context;
  1360. ASSERT_NO_THROW(context = cfg_mgr_->getD2CfgContext());
  1361. // Test directional update flags.
  1362. EXPECT_FALSE(cfg_mgr_->forwardUpdatesEnabled());
  1363. EXPECT_TRUE(cfg_mgr_->reverseUpdatesEnabled());
  1364. DdnsDomainPtr match;
  1365. // Verify an exact match.
  1366. EXPECT_TRUE(cfg_mgr_->matchReverse("192.168.100.5", match));
  1367. EXPECT_EQ("5.100.168.192.in-addr.arpa.", match->getName());
  1368. // Verify a sub-domain match.
  1369. EXPECT_TRUE(cfg_mgr_->matchReverse("192.200.100.27", match));
  1370. EXPECT_EQ("100.200.192.in-addr.arpa.", match->getName());
  1371. // Verify a sub-domain match.
  1372. EXPECT_TRUE(cfg_mgr_->matchReverse("192.170.50.30", match));
  1373. EXPECT_EQ("170.192.in-addr.arpa.", match->getName());
  1374. // Verify a wild card match.
  1375. EXPECT_TRUE(cfg_mgr_->matchReverse("1.1.1.1", match));
  1376. EXPECT_EQ("*", match->getName());
  1377. // Verify a IPv6 match.
  1378. EXPECT_TRUE(cfg_mgr_->matchReverse("2001:db8:302:99::",match));
  1379. EXPECT_EQ("2.0.3.0.8.b.d.0.1.0.0.2.IP6.ARPA.", match->getName());
  1380. // Verify a IPv6 wild card match.
  1381. EXPECT_TRUE(cfg_mgr_->matchReverse("2001:db8:99:302::",match));
  1382. EXPECT_EQ("*", match->getName());
  1383. // Verify that an attempt to match an invalid IP address throws.
  1384. ASSERT_THROW(cfg_mgr_->matchReverse("", match), D2CfgError);
  1385. }
  1386. /// @brief Tests D2 config parsing against a wide range of config permutations.
  1387. ///
  1388. /// It tests for both syntax errors that the JSON parsing (D2ParserContext)
  1389. /// should detect as well as post-JSON parsing logic errors generated by
  1390. /// the Element parsers (i.e...SimpleParser/DhcpParser derivations)
  1391. ///
  1392. ///
  1393. /// It iterates over all of the test configurations described in given file.
  1394. /// The file content is JSON specialized to this test. The format of the file
  1395. /// is:
  1396. ///
  1397. /// @code
  1398. /// # The file must open with a list. It's name is arbitrary.
  1399. ///
  1400. /// { "test_list" :
  1401. /// [
  1402. ///
  1403. /// # Test one starts here:
  1404. /// {
  1405. ///
  1406. /// # Each test has:
  1407. /// # 1. description - optional text description
  1408. /// # 2. syntax-error - text of syntax error D2Parser is expected to emit
  1409. /// # (defaults to blank = no error expected)
  1410. /// # 3. logic-error - indicator if post-parsing element logic should fail
  1411. /// # (defaults to false)
  1412. /// # 4. data - configuration text to parse
  1413. /// #
  1414. /// "description" : "<text describing test>",
  1415. /// "syntax-error" : ""|"<exact text from parser including position>" ,
  1416. /// "logic_error" : <true|false> ,
  1417. /// "data" :
  1418. /// {
  1419. /// # configuration elements here
  1420. /// "bool_val" : false,
  1421. /// "some_map" : {}
  1422. /// # :
  1423. /// }
  1424. /// }
  1425. ///
  1426. /// # Next test would start here
  1427. /// ,
  1428. /// {
  1429. /// }
  1430. ///
  1431. /// ]}
  1432. ///
  1433. /// @endcode
  1434. ///
  1435. /// (The file supports comments per Element::fromJSONFile())
  1436. ///
  1437. TEST_F(D2CfgMgrTest, configPermutations) {
  1438. std::string test_file = testDataFile("d2_cfg_tests.json");
  1439. isc::data::ConstElementPtr tests;
  1440. // Read contents of the file and parse it as JSON. Note it must contain
  1441. // all valid JSON, we aren't testing JSON parsing.
  1442. try {
  1443. tests = isc::data::Element::fromJSONFile(test_file, true);
  1444. } catch (const std::exception& ex) {
  1445. FAIL() << "ERROR parsing file : " << test_file << " : " << ex.what();
  1446. }
  1447. // Read in each test For each test, read:
  1448. //
  1449. // 1. description - optional text description
  1450. // 2. syntax-error - error text JSON parser should emit including position,
  1451. // defaults to blank (i.e. no error)
  1452. // 3. logic-error - bool indicator if post-JSON element processing should
  1453. // fail
  1454. // (defaults to false)
  1455. // 4. data - configuration text to parse
  1456. //
  1457. // Next attempt to parse the configuration by passing it into
  1458. // D2CfgMgr::parseConfig(). Then check the parsing outcome against the
  1459. // expected outcome as given by logic-error.
  1460. isc::data::ConstElementPtr test;
  1461. ASSERT_TRUE(tests->get("test-list"));
  1462. BOOST_FOREACH(test, tests->get("test-list")->listValue()) {
  1463. // Grab the description.
  1464. std::string description = "<no desc>";
  1465. isc::data::ConstElementPtr elem = test->get("description");
  1466. if (elem) {
  1467. elem->getValue(description);
  1468. }
  1469. // Grab the outcome flag, logic-error, defaults to false if it's
  1470. // not specified.
  1471. bool logic_error = false;
  1472. elem = test->get("logic-error");
  1473. if (elem) {
  1474. elem->getValue(logic_error);
  1475. }
  1476. // If the JSON parsing is expected to detect an error, the test
  1477. // should have specified the error message text.
  1478. std::string expected_syntax_error = "";
  1479. elem = test->get("syntax-error");
  1480. if (elem) {
  1481. elem->getValue(expected_syntax_error);
  1482. }
  1483. // Grab the test's configuration data.
  1484. isc::data::ConstElementPtr data = test->get("data");
  1485. ASSERT_TRUE(data) << "No data for test: "
  1486. << " : " << test->getPosition();
  1487. // Submit the configuration text to the D2Parser. This is somewhat
  1488. // artifical as normally the JSON parsing is invoked by @c
  1489. // DController::configFromFile(). Doing it here, explicitly, allows us
  1490. // test both syntax and logic errors without the weight of a full
  1491. // server. Currently the assumption is that the test data is the
  1492. // content permitted within a DhcpDdns element only.
  1493. try {
  1494. // First we turn the test data back into JSON text
  1495. D2ParserContext context;
  1496. stringstream os;
  1497. data->toJSON(os);
  1498. // Parse the test data
  1499. data = context.parseString(os.str(),
  1500. D2ParserContext::PARSER_SUB_DHCPDDNS);
  1501. } catch (const std::exception& ex) {
  1502. if (expected_syntax_error.empty()) {
  1503. // We have an unexpected syntax error.
  1504. ADD_FAILURE() << description << ", "
  1505. << "Unexpected syntax error:" << ex.what();
  1506. } else {
  1507. // We expected and got a syntax error, we need to make sure
  1508. // we got the right one.
  1509. EXPECT_EQ(expected_syntax_error, ex.what())
  1510. << description << ", syntax error mismatch";
  1511. }
  1512. // Expected or not, skip logic testing on syntax errors.
  1513. continue;
  1514. }
  1515. // Attempt to Element parse the configuration. We verify that we get the
  1516. // expected outcome, and if it was supposed to fail that the explanation
  1517. // contains position information.
  1518. checkAnswerWithError(cfg_mgr_->parseConfig(data),
  1519. (logic_error ? SHOULD_FAIL : SHOULD_PASS));
  1520. }
  1521. }
  1522. } // end of anonymous namespace