module_spec_unittests.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // Copyright (C) 2009, 2011 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 <gtest/gtest.h>
  15. #include <config/module_spec.h>
  16. #include <fstream>
  17. #include <boost/foreach.hpp>
  18. #include <config/tests/data_def_unittests_config.h>
  19. using namespace isc::data;
  20. using namespace isc::config;
  21. std::string specfile(const std::string& name) {
  22. return (std::string(TEST_DATA_PATH) + "/" + name);
  23. }
  24. void
  25. moduleSpecError(const std::string& file,
  26. const std::string& error1,
  27. const std::string& error2 = "",
  28. const std::string& error3 = "")
  29. {
  30. EXPECT_THROW(moduleSpecFromFile(specfile(file)), ModuleSpecError);
  31. try {
  32. ModuleSpec dd = moduleSpecFromFile(specfile(file));
  33. } catch (const ModuleSpecError& dde) {
  34. std::string ddew = dde.what();
  35. EXPECT_EQ(error1 + error2 + error3, ddew);
  36. }
  37. }
  38. TEST(ModuleSpec, ReadingSpecfiles) {
  39. // Tests whether we can open specfiles and if we get the
  40. // right parse errors
  41. ModuleSpec dd = moduleSpecFromFile(specfile("spec1.spec"));
  42. EXPECT_EQ(dd.getFullSpec()->get("module_name")
  43. ->stringValue(), "Spec1");
  44. dd = moduleSpecFromFile(specfile("spec2.spec"));
  45. EXPECT_EQ(dd.getFullSpec()->get("config_data")->size(), 6);
  46. moduleSpecError("doesnotexist",
  47. "Error opening ",
  48. specfile("doesnotexist"),
  49. ": No such file or directory");
  50. dd = moduleSpecFromFile(specfile("spec2.spec"));
  51. EXPECT_EQ("[ { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }, { \"command_args\": [ ], \"command_description\": \"Shut down BIND 10\", \"command_name\": \"shutdown\" } ]", dd.getCommandsSpec()->str());
  52. EXPECT_EQ("[ { \"item_default\": \"1970-01-01T00:00:00Z\", \"item_description\": \"A dummy date time\", \"item_format\": \"date-time\", \"item_name\": \"dummy_time\", \"item_optional\": false, \"item_title\": \"Dummy Time\", \"item_type\": \"string\" } ]", dd.getStatisticsSpec()->str());
  53. EXPECT_EQ("Spec2", dd.getModuleName());
  54. EXPECT_EQ("", dd.getModuleDescription());
  55. dd = moduleSpecFromFile(specfile("spec25.spec"));
  56. EXPECT_EQ("Spec25", dd.getModuleName());
  57. EXPECT_EQ("Just an empty module", dd.getModuleDescription());
  58. EXPECT_THROW(moduleSpecFromFile(specfile("spec26.spec")), ModuleSpecError);
  59. EXPECT_THROW(moduleSpecFromFile(specfile("spec34.spec")), ModuleSpecError);
  60. EXPECT_THROW(moduleSpecFromFile(specfile("spec35.spec")), ModuleSpecError);
  61. EXPECT_THROW(moduleSpecFromFile(specfile("spec36.spec")), ModuleSpecError);
  62. EXPECT_THROW(moduleSpecFromFile(specfile("spec37.spec")), ModuleSpecError);
  63. EXPECT_THROW(moduleSpecFromFile(specfile("spec38.spec")), ModuleSpecError);
  64. std::ifstream file;
  65. file.open(specfile("spec1.spec").c_str());
  66. dd = moduleSpecFromFile(file);
  67. EXPECT_EQ(dd.getFullSpec()->get("module_name")
  68. ->stringValue(), "Spec1");
  69. EXPECT_TRUE(isNull(dd.getCommandsSpec()));
  70. EXPECT_TRUE(isNull(dd.getStatisticsSpec()));
  71. std::ifstream file2;
  72. file2.open(specfile("spec8.spec").c_str());
  73. EXPECT_THROW(moduleSpecFromFile(file2), ModuleSpecError);
  74. }
  75. TEST(ModuleSpec, SpecfileItems) {
  76. moduleSpecError("spec3.spec",
  77. "item_name missing in { \"item_default\": 1, \"item_optional\": false, \"item_type\": \"integer\" }");
  78. moduleSpecError("spec4.spec",
  79. "item_type missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": false }");
  80. moduleSpecError("spec5.spec",
  81. "item_optional missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_type\": \"integer\" }");
  82. moduleSpecError("spec6.spec",
  83. "item_default missing in { \"item_name\": \"item1\", \"item_optional\": false, \"item_type\": \"integer\" }");
  84. moduleSpecError("spec9.spec",
  85. "item_default not of type integer");
  86. moduleSpecError("spec10.spec",
  87. "item_default not of type real");
  88. moduleSpecError("spec11.spec",
  89. "item_default not of type boolean");
  90. moduleSpecError("spec12.spec",
  91. "item_default not of type string");
  92. moduleSpecError("spec13.spec",
  93. "item_default not of type list");
  94. moduleSpecError("spec14.spec",
  95. "item_default not of type map");
  96. moduleSpecError("spec15.spec",
  97. "badname is not a valid type name");
  98. }
  99. TEST(ModuleSpec, SpecfileConfigData) {
  100. moduleSpecError("spec7.spec",
  101. "module_name missing in { }");
  102. moduleSpecError("spec8.spec",
  103. "No module_spec in specification");
  104. moduleSpecError("spec16.spec",
  105. "config_data is not a list of elements");
  106. moduleSpecError("spec21.spec",
  107. "commands is not a list of elements");
  108. }
  109. TEST(ModuleSpec, SpecfileStatistics) {
  110. moduleSpecError("spec36.spec", "item_default not valid type of item_format");
  111. moduleSpecError("spec37.spec", "statistics is not a list of elements");
  112. moduleSpecError("spec38.spec", "item_default not valid type of item_format");
  113. }
  114. TEST(ModuleSpec, SpecfileCommands) {
  115. moduleSpecError("spec17.spec",
  116. "command_name missing in { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\" }");
  117. moduleSpecError("spec18.spec",
  118. "command_args missing in { \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }");
  119. moduleSpecError("spec19.spec",
  120. "command_args not of type list");
  121. moduleSpecError("spec20.spec",
  122. "somethingbad is not a valid type name");
  123. }
  124. bool
  125. dataTest(const ModuleSpec& dd, const std::string& data_file_name) {
  126. std::ifstream data_file;
  127. data_file.open(specfile(data_file_name).c_str());
  128. ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
  129. data_file.close();
  130. return (dd.validateConfig(data));
  131. }
  132. bool
  133. statisticsTest(const ModuleSpec& dd, const std::string& data_file_name) {
  134. std::ifstream data_file;
  135. data_file.open(specfile(data_file_name).c_str());
  136. ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
  137. data_file.close();
  138. return (dd.validateStatistics(data));
  139. }
  140. bool
  141. dataTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name,
  142. ElementPtr errors)
  143. {
  144. std::ifstream data_file;
  145. data_file.open(specfile(data_file_name).c_str());
  146. ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
  147. data_file.close();
  148. return (dd.validateConfig(data, true, errors));
  149. }
  150. bool
  151. statisticsTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name,
  152. ElementPtr errors)
  153. {
  154. std::ifstream data_file;
  155. data_file.open(specfile(data_file_name).c_str());
  156. ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
  157. data_file.close();
  158. return (dd.validateStatistics(data, true, errors));
  159. }
  160. TEST(ModuleSpec, DataValidation) {
  161. ModuleSpec dd = moduleSpecFromFile(specfile("spec22.spec"));
  162. EXPECT_TRUE(dataTest(dd, "data22_1.data"));
  163. EXPECT_FALSE(dataTest(dd, "data22_2.data"));
  164. EXPECT_FALSE(dataTest(dd, "data22_3.data"));
  165. EXPECT_FALSE(dataTest(dd, "data22_4.data"));
  166. EXPECT_FALSE(dataTest(dd, "data22_5.data"));
  167. EXPECT_TRUE(dataTest(dd, "data22_6.data"));
  168. EXPECT_TRUE(dataTest(dd, "data22_7.data"));
  169. EXPECT_FALSE(dataTest(dd, "data22_8.data"));
  170. EXPECT_FALSE(dataTest(dd, "data22_9.data"));
  171. // Test if "version" is allowed in config data
  172. // (same data as 22_7, but added "version")
  173. EXPECT_TRUE(dataTest(dd, "data22_10.data"));
  174. ElementPtr errors = Element::createList();
  175. EXPECT_FALSE(dataTestWithErrors(dd, "data22_8.data", errors));
  176. EXPECT_EQ("[ \"Type mismatch\" ]", errors->str());
  177. errors = Element::createList();
  178. EXPECT_FALSE(dataTestWithErrors(dd, "data22_9.data", errors));
  179. EXPECT_EQ("[ \"Unknown item value_does_not_exist\" ]", errors->str());
  180. }
  181. TEST(ModuleSpec, StatisticsValidation) {
  182. ModuleSpec dd = moduleSpecFromFile(specfile("spec33.spec"));
  183. EXPECT_TRUE(statisticsTest(dd, "data33_1.data"));
  184. EXPECT_FALSE(statisticsTest(dd, "data33_2.data"));
  185. ElementPtr errors = Element::createList();
  186. EXPECT_FALSE(statisticsTestWithErrors(dd, "data33_2.data", errors));
  187. EXPECT_EQ("[ \"Format mismatch\", \"Format mismatch\", \"Format mismatch\" ]", errors->str());
  188. }
  189. TEST(ModuleSpec, CommandValidation) {
  190. ModuleSpec dd = moduleSpecFromFile(specfile("spec2.spec"));
  191. ConstElementPtr arg = Element::fromJSON("{}");
  192. ElementPtr errors = Element::createList();
  193. EXPECT_TRUE(dd.validateCommand("shutdown", arg, errors));
  194. EXPECT_EQ(errors->size(), 0);
  195. errors = Element::createList();
  196. EXPECT_FALSE(dd.validateCommand("unknowncommand", arg, errors));
  197. EXPECT_EQ(errors->size(), 1);
  198. EXPECT_EQ(errors->get(0)->stringValue(), "Unknown command unknowncommand");
  199. errors = Element::createList();
  200. EXPECT_FALSE(dd.validateCommand("print_message", arg, errors));
  201. EXPECT_EQ(errors->size(), 1);
  202. EXPECT_EQ(errors->get(0)->stringValue(), "Non-optional value missing");
  203. errors = Element::createList();
  204. arg = Element::fromJSON("{ \"message\": \"Hello\" }");
  205. EXPECT_TRUE(dd.validateCommand("print_message", arg, errors));
  206. EXPECT_EQ(errors->size(), 0);
  207. errors = Element::createList();
  208. arg = Element::fromJSON("{ \"message\": \"Hello\", \"unknown_second_arg\": 1 }");
  209. EXPECT_FALSE(dd.validateCommand("print_message", arg, errors));
  210. EXPECT_EQ(errors->size(), 1);
  211. EXPECT_EQ(errors->get(0)->stringValue(), "Unknown item unknown_second_arg");
  212. errors = Element::createList();
  213. arg = Element::fromJSON("{ \"message\": 1 }");
  214. EXPECT_FALSE(dd.validateCommand("print_message", arg, errors));
  215. EXPECT_EQ(errors->size(), 1);
  216. EXPECT_EQ(errors->get(0)->stringValue(), "Type mismatch");
  217. }
  218. TEST(ModuleSpec, NamedSetValidation) {
  219. ModuleSpec dd = moduleSpecFromFile(specfile("spec32.spec"));
  220. ElementPtr errors = Element::createList();
  221. EXPECT_TRUE(dataTestWithErrors(dd, "data32_1.data", errors));
  222. EXPECT_FALSE(dataTest(dd, "data32_2.data"));
  223. EXPECT_FALSE(dataTest(dd, "data32_3.data"));
  224. }
  225. TEST(ModuleSpec, CheckFormat) {
  226. const std::string json_begin = "{ \"module_spec\": { \"module_name\": \"Foo\", \"statistics\": [ { \"item_name\": \"dummy_time\", \"item_type\": \"string\", \"item_optional\": true, \"item_title\": \"Dummy Time\", \"item_description\": \"A dummy date time\"";
  227. const std::string json_end = " } ] } }";
  228. std::string item_default;
  229. std::string item_format;
  230. std::vector<std::string> specs;
  231. ConstElementPtr el;
  232. specs.clear();
  233. item_default = "\"item_default\": \"2011-05-27T19:42:57Z\",";
  234. item_format = "\"item_format\": \"date-time\"";
  235. specs.push_back("," + item_default + item_format);
  236. item_default = "\"item_default\": \"2011-05-27\",";
  237. item_format = "\"item_format\": \"date\"";
  238. specs.push_back("," + item_default + item_format);
  239. item_default = "\"item_default\": \"19:42:57\",";
  240. item_format = "\"item_format\": \"time\"";
  241. specs.push_back("," + item_default + item_format);
  242. item_format = "\"item_format\": \"date-time\"";
  243. specs.push_back("," + item_format);
  244. item_default = "";
  245. item_format = "\"item_format\": \"date\"";
  246. specs.push_back("," + item_format);
  247. item_default = "";
  248. item_format = "\"item_format\": \"time\"";
  249. specs.push_back("," + item_format);
  250. item_default = "\"item_default\": \"a\"";
  251. specs.push_back("," + item_default);
  252. item_default = "\"item_default\": \"b\"";
  253. specs.push_back("," + item_default);
  254. item_default = "\"item_default\": \"c\"";
  255. specs.push_back("," + item_default);
  256. item_format = "\"item_format\": \"dummy\"";
  257. specs.push_back("," + item_format);
  258. specs.push_back("");
  259. BOOST_FOREACH(std::string s, specs) {
  260. el = Element::fromJSON(json_begin + s + json_end)->get("module_spec");
  261. EXPECT_NO_THROW(ModuleSpec(el, true));
  262. }
  263. specs.clear();
  264. item_default = "\"item_default\": \"2011-05-27T19:42:57Z\",";
  265. item_format = "\"item_format\": \"dummy\"";
  266. specs.push_back("," + item_default + item_format);
  267. item_default = "\"item_default\": \"2011-05-27\",";
  268. item_format = "\"item_format\": \"dummy\"";
  269. specs.push_back("," + item_default + item_format);
  270. item_default = "\"item_default\": \"19:42:57Z\",";
  271. item_format = "\"item_format\": \"dummy\"";
  272. specs.push_back("," + item_default + item_format);
  273. item_default = "\"item_default\": \"2011-13-99T99:99:99Z\",";
  274. item_format = "\"item_format\": \"date-time\"";
  275. specs.push_back("," + item_default + item_format);
  276. item_default = "\"item_default\": \"2011-13-99\",";
  277. item_format = "\"item_format\": \"date\"";
  278. specs.push_back("," + item_default + item_format);
  279. item_default = "\"item_default\": \"99:99:99Z\",";
  280. item_format = "\"item_format\": \"time\"";
  281. specs.push_back("," + item_default + item_format);
  282. item_default = "\"item_default\": \"1\",";
  283. item_format = "\"item_format\": \"date-time\"";
  284. specs.push_back("," + item_default + item_format);
  285. item_default = "\"item_default\": \"1\",";
  286. item_format = "\"item_format\": \"date\"";
  287. specs.push_back("," + item_default + item_format);
  288. item_default = "\"item_default\": \"1\",";
  289. item_format = "\"item_format\": \"time\"";
  290. specs.push_back("," + item_default + item_format);
  291. item_default = "\"item_default\": \"\",";
  292. item_format = "\"item_format\": \"date-time\"";
  293. specs.push_back("," + item_default + item_format);
  294. item_default = "\"item_default\": \"\",";
  295. item_format = "\"item_format\": \"date\"";
  296. specs.push_back("," + item_default + item_format);
  297. item_default = "\"item_default\": \"\",";
  298. item_format = "\"item_format\": \"time\"";
  299. specs.push_back("," + item_default + item_format);
  300. // wrong date-time-type format not ending with "Z"
  301. item_default = "\"item_default\": \"2011-05-27T19:42:57\",";
  302. item_format = "\"item_format\": \"date-time\"";
  303. specs.push_back("," + item_default + item_format);
  304. // wrong date-type format ending with "T"
  305. item_default = "\"item_default\": \"2011-05-27T\",";
  306. item_format = "\"item_format\": \"date\"";
  307. specs.push_back("," + item_default + item_format);
  308. // wrong time-type format ending with "Z"
  309. item_default = "\"item_default\": \"19:42:57Z\",";
  310. item_format = "\"item_format\": \"time\"";
  311. specs.push_back("," + item_default + item_format);
  312. BOOST_FOREACH(std::string s, specs) {
  313. el = Element::fromJSON(json_begin + s + json_end)->get("module_spec");
  314. EXPECT_THROW(ModuleSpec(el, true), ModuleSpecError);
  315. }
  316. }