d2_cfg_mgr_unittests.cc 64 KB

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