module_spec_unittests.cc 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Copyright (C) 2009 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 <config/tests/data_def_unittests_config.h>
  18. using namespace isc::data;
  19. using namespace isc::config;
  20. std::string specfile(const std::string& name) {
  21. return (std::string(TEST_DATA_PATH) + "/" + name);
  22. }
  23. void
  24. moduleSpecError(const std::string& file,
  25. const std::string& error1,
  26. const std::string& error2 = "",
  27. const std::string& error3 = "")
  28. {
  29. EXPECT_THROW(moduleSpecFromFile(specfile(file)), ModuleSpecError);
  30. try {
  31. ModuleSpec dd = moduleSpecFromFile(specfile(file));
  32. } catch (const ModuleSpecError& dde) {
  33. std::string ddew = dde.what();
  34. EXPECT_EQ(error1 + error2 + error3, ddew);
  35. }
  36. }
  37. TEST(ModuleSpec, ReadingSpecfiles) {
  38. // Tests whether we can open specfiles and if we get the
  39. // right parse errors
  40. ModuleSpec dd = moduleSpecFromFile(specfile("spec1.spec"));
  41. EXPECT_EQ(dd.getFullSpec()->get("module_name")
  42. ->stringValue(), "Spec1");
  43. dd = moduleSpecFromFile(specfile("spec2.spec"));
  44. EXPECT_EQ(dd.getFullSpec()->get("config_data")->size(), 6);
  45. moduleSpecError("doesnotexist",
  46. "Error opening ",
  47. specfile("doesnotexist"),
  48. ": No such file or directory");
  49. dd = moduleSpecFromFile(specfile("spec2.spec"));
  50. 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());
  51. EXPECT_EQ("Spec2", dd.getModuleName());
  52. EXPECT_EQ("", dd.getModuleDescription());
  53. dd = moduleSpecFromFile(specfile("spec25.spec"));
  54. EXPECT_EQ("Spec25", dd.getModuleName());
  55. EXPECT_EQ("Just an empty module", dd.getModuleDescription());
  56. EXPECT_THROW(moduleSpecFromFile(specfile("spec26.spec")), ModuleSpecError);
  57. std::ifstream file;
  58. file.open(specfile("spec1.spec").c_str());
  59. dd = moduleSpecFromFile(file);
  60. EXPECT_EQ(dd.getFullSpec()->get("module_name")
  61. ->stringValue(), "Spec1");
  62. EXPECT_TRUE(isNull(dd.getCommandsSpec()));
  63. std::ifstream file2;
  64. file2.open(specfile("spec8.spec").c_str());
  65. EXPECT_THROW(moduleSpecFromFile(file2), ModuleSpecError);
  66. }
  67. TEST(ModuleSpec, SpecfileItems) {
  68. moduleSpecError("spec3.spec",
  69. "item_name missing in { \"item_default\": 1, \"item_optional\": false, \"item_type\": \"integer\" }");
  70. moduleSpecError("spec4.spec",
  71. "item_type missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": false }");
  72. moduleSpecError("spec5.spec",
  73. "item_optional missing in { \"item_default\": 1, \"item_name\": \"item1\", \"item_type\": \"integer\" }");
  74. moduleSpecError("spec6.spec",
  75. "item_default missing in { \"item_name\": \"item1\", \"item_optional\": false, \"item_type\": \"integer\" }");
  76. moduleSpecError("spec9.spec",
  77. "item_default not of type integer");
  78. moduleSpecError("spec10.spec",
  79. "item_default not of type real");
  80. moduleSpecError("spec11.spec",
  81. "item_default not of type boolean");
  82. moduleSpecError("spec12.spec",
  83. "item_default not of type string");
  84. moduleSpecError("spec13.spec",
  85. "item_default not of type list");
  86. moduleSpecError("spec14.spec",
  87. "item_default not of type map");
  88. moduleSpecError("spec15.spec",
  89. "badname is not a valid type name");
  90. }
  91. TEST(ModuleSpec, SpecfileConfigData) {
  92. moduleSpecError("spec7.spec",
  93. "module_name missing in { }");
  94. moduleSpecError("spec8.spec",
  95. "No module_spec in specification");
  96. moduleSpecError("spec16.spec",
  97. "config_data is not a list of elements");
  98. moduleSpecError("spec21.spec",
  99. "commands is not a list of elements");
  100. }
  101. TEST(ModuleSpec, SpecfileCommands) {
  102. moduleSpecError("spec17.spec",
  103. "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\" }");
  104. moduleSpecError("spec18.spec",
  105. "command_args missing in { \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }");
  106. moduleSpecError("spec19.spec",
  107. "command_args not of type list");
  108. moduleSpecError("spec20.spec",
  109. "somethingbad is not a valid type name");
  110. }
  111. bool
  112. dataTest(const ModuleSpec& dd, const std::string& data_file_name) {
  113. std::ifstream data_file;
  114. data_file.open(specfile(data_file_name).c_str());
  115. ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
  116. data_file.close();
  117. return (dd.validateConfig(data));
  118. }
  119. bool
  120. dataTestWithErrors(const ModuleSpec& dd, const std::string& data_file_name,
  121. ElementPtr errors)
  122. {
  123. std::ifstream data_file;
  124. data_file.open(specfile(data_file_name).c_str());
  125. ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
  126. data_file.close();
  127. return (dd.validateConfig(data, true, errors));
  128. }
  129. TEST(ModuleSpec, DataValidation) {
  130. ModuleSpec dd = moduleSpecFromFile(specfile("spec22.spec"));
  131. EXPECT_TRUE(dataTest(dd, "data22_1.data"));
  132. EXPECT_FALSE(dataTest(dd, "data22_2.data"));
  133. EXPECT_FALSE(dataTest(dd, "data22_3.data"));
  134. EXPECT_FALSE(dataTest(dd, "data22_4.data"));
  135. EXPECT_FALSE(dataTest(dd, "data22_5.data"));
  136. EXPECT_TRUE(dataTest(dd, "data22_6.data"));
  137. EXPECT_TRUE(dataTest(dd, "data22_7.data"));
  138. EXPECT_FALSE(dataTest(dd, "data22_8.data"));
  139. EXPECT_FALSE(dataTest(dd, "data22_9.data"));
  140. // Test if "version" is allowed in config data
  141. // (same data as 22_7, but added "version")
  142. EXPECT_TRUE(dataTest(dd, "data22_10.data"));
  143. ElementPtr errors = Element::createList();
  144. EXPECT_FALSE(dataTestWithErrors(dd, "data22_8.data", errors));
  145. EXPECT_EQ("[ \"Type mismatch\" ]", errors->str());
  146. errors = Element::createList();
  147. EXPECT_FALSE(dataTestWithErrors(dd, "data22_9.data", errors));
  148. EXPECT_EQ("[ \"Unknown item value_does_not_exist\" ]", errors->str());
  149. }
  150. TEST(ModuleSpec, CommandValidation) {
  151. ModuleSpec dd = moduleSpecFromFile(specfile("spec2.spec"));
  152. ConstElementPtr arg = Element::fromJSON("{}");
  153. ElementPtr errors = Element::createList();
  154. EXPECT_TRUE(dd.validateCommand("shutdown", arg, errors));
  155. EXPECT_EQ(errors->size(), 0);
  156. errors = Element::createList();
  157. EXPECT_FALSE(dd.validateCommand("unknowncommand", arg, errors));
  158. EXPECT_EQ(errors->size(), 1);
  159. EXPECT_EQ(errors->get(0)->stringValue(), "Unknown command unknowncommand");
  160. errors = Element::createList();
  161. EXPECT_FALSE(dd.validateCommand("print_message", arg, errors));
  162. EXPECT_EQ(errors->size(), 1);
  163. EXPECT_EQ(errors->get(0)->stringValue(), "Non-optional value missing");
  164. errors = Element::createList();
  165. arg = Element::fromJSON("{ \"message\": \"Hello\" }");
  166. EXPECT_TRUE(dd.validateCommand("print_message", arg, errors));
  167. EXPECT_EQ(errors->size(), 0);
  168. errors = Element::createList();
  169. arg = Element::fromJSON("{ \"message\": \"Hello\", \"unknown_second_arg\": 1 }");
  170. EXPECT_FALSE(dd.validateCommand("print_message", arg, errors));
  171. EXPECT_EQ(errors->size(), 1);
  172. EXPECT_EQ(errors->get(0)->stringValue(), "Unknown item unknown_second_arg");
  173. errors = Element::createList();
  174. arg = Element::fromJSON("{ \"message\": 1 }");
  175. EXPECT_FALSE(dd.validateCommand("print_message", arg, errors));
  176. EXPECT_EQ(errors->size(), 1);
  177. EXPECT_EQ(errors->get(0)->stringValue(), "Type mismatch");
  178. }
  179. TEST(ModuleSpec, NamedMapValidation) {
  180. ModuleSpec dd = moduleSpecFromFile(specfile("spec32.spec"));
  181. ElementPtr errors = Element::createList();
  182. EXPECT_TRUE(dataTestWithErrors(dd, "data32_1.data", errors));
  183. std::cout << "[XX] ERRORS: " << *errors << std::endl;
  184. EXPECT_FALSE(dataTest(dd, "data32_2.data"));
  185. EXPECT_FALSE(dataTest(dd, "data32_3.data"));
  186. }