module_spec_test.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. # Copyright (C) 2009 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. #
  16. # Tests for the module_spec module
  17. #
  18. import unittest
  19. import os
  20. from isc.config import ModuleSpec, ModuleSpecError
  21. import isc.cc.data
  22. class TestModuleSpec(unittest.TestCase):
  23. def setUp(self):
  24. if 'CONFIG_TESTDATA_PATH' in os.environ:
  25. self.data_path = os.environ['CONFIG_TESTDATA_PATH']
  26. else:
  27. self.data_path = "../../../testdata"
  28. def spec_file(self, filename):
  29. return(self.data_path + os.sep + filename)
  30. def read_spec_file(self, filename):
  31. return isc.config.module_spec_from_file(self.spec_file(filename))
  32. def spec1(self, dd):
  33. module_spec = dd.get_full_spec()
  34. self.assert_('module_name' in module_spec)
  35. self.assertEqual(module_spec['module_name'], "Spec1")
  36. def test_open_file_name(self):
  37. dd = self.read_spec_file("spec1.spec")
  38. self.spec1(dd)
  39. def test_open_file_obj(self):
  40. file1 = open(self.spec_file("spec1.spec"))
  41. dd = isc.config.module_spec_from_file(file1)
  42. self.spec1(dd)
  43. def test_open_bad_file_obj(self):
  44. self.assertRaises(ModuleSpecError, isc.config.module_spec_from_file, 1)
  45. # contains single quotes which json parser does not accept
  46. self.assertRaises(ModuleSpecError, isc.config.module_spec_from_file, self.spec_file("spec28.spec"), False)
  47. my_spec_file = open(self.spec_file("spec28.spec"))
  48. self.assertRaises(ModuleSpecError, isc.config.module_spec_from_file, my_spec_file, False)
  49. self.assertRaises(ModuleSpecError, isc.config.module_spec_from_file, self.spec_file("does_not_exist"), False)
  50. def test_bad_specfiles(self):
  51. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec3.spec")
  52. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec4.spec")
  53. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec5.spec")
  54. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec6.spec")
  55. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec7.spec")
  56. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec8.spec")
  57. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec9.spec")
  58. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec10.spec")
  59. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec11.spec")
  60. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec12.spec")
  61. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec13.spec")
  62. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec14.spec")
  63. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec15.spec")
  64. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec16.spec")
  65. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec17.spec")
  66. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec18.spec")
  67. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec19.spec")
  68. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec20.spec")
  69. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec21.spec")
  70. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec26.spec")
  71. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec34.spec")
  72. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec35.spec")
  73. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec36.spec")
  74. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec37.spec")
  75. self.assertRaises(ModuleSpecError, self.read_spec_file, "spec38.spec")
  76. def validate_data(self, specfile_name, datafile_name):
  77. dd = self.read_spec_file(specfile_name);
  78. data_file = open(self.spec_file(datafile_name))
  79. data_str = data_file.read()
  80. data = isc.cc.data.parse_value_str(data_str)
  81. return dd.validate_config(True, data)
  82. def test_data_validation(self):
  83. self.assertEqual(True, self.validate_data("spec22.spec", "data22_1.data"))
  84. self.assertEqual(False, self.validate_data("spec22.spec", "data22_2.data"))
  85. self.assertEqual(False, self.validate_data("spec22.spec", "data22_3.data"))
  86. self.assertEqual(False, self.validate_data("spec22.spec", "data22_4.data"))
  87. self.assertEqual(False, self.validate_data("spec22.spec", "data22_5.data"))
  88. self.assertEqual(True, self.validate_data("spec22.spec", "data22_6.data"))
  89. self.assertEqual(True, self.validate_data("spec22.spec", "data22_7.data"))
  90. self.assertEqual(False, self.validate_data("spec22.spec", "data22_8.data"))
  91. self.assertEqual(True, self.validate_data("spec32.spec", "data32_1.data"))
  92. self.assertEqual(False, self.validate_data("spec32.spec", "data32_2.data"))
  93. self.assertEqual(False, self.validate_data("spec32.spec", "data32_3.data"))
  94. def validate_command_params(self, specfile_name, datafile_name, cmd_name):
  95. dd = self.read_spec_file(specfile_name);
  96. data_file = open(self.spec_file(datafile_name))
  97. data_str = data_file.read()
  98. params = isc.cc.data.parse_value_str(data_str)
  99. return dd.validate_command(cmd_name, params)
  100. def test_command_validation(self):
  101. # tests for a command that doesn't take an argument
  102. self.assertEqual(True, self.read_spec_file("spec2.spec").validate_command("shutdown", None));
  103. self.assertEqual(False, self.read_spec_file("spec2.spec").validate_command("shutdown", '{"val": 1}'));
  104. self.assertEqual(True, self.validate_command_params("spec27.spec", "data22_1.data", 'cmd1'))
  105. self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_2.data",'cmd1'))
  106. self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_3.data", 'cmd1'))
  107. self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_4.data", 'cmd1'))
  108. self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_5.data", 'cmd1'))
  109. self.assertEqual(True, self.validate_command_params("spec27.spec", "data22_6.data", 'cmd1'))
  110. self.assertEqual(True, self.validate_command_params("spec27.spec", "data22_7.data", 'cmd1'))
  111. self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_8.data", 'cmd1'))
  112. self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_8.data", 'cmd2'))
  113. def test_statistics_validation(self):
  114. def _validate_stat(specfile_name, datafile_name):
  115. dd = self.read_spec_file(specfile_name);
  116. data_file = open(self.spec_file(datafile_name))
  117. data_str = data_file.read()
  118. data = isc.cc.data.parse_value_str(data_str)
  119. return dd.validate_statistics(True, data, [])
  120. self.assertFalse(self.read_spec_file("spec1.spec").validate_statistics(True, None, None));
  121. self.assertTrue(_validate_stat("spec33.spec", "data33_1.data"))
  122. self.assertFalse(_validate_stat("spec33.spec", "data33_2.data"))
  123. def test_init(self):
  124. self.assertRaises(ModuleSpecError, ModuleSpec, 1)
  125. module_spec = isc.config.module_spec_from_file(self.spec_file("spec1.spec"), False)
  126. self.spec1(module_spec)
  127. module_spec = isc.config.module_spec_from_file(self.spec_file("spec25.spec"), True)
  128. self.assertEqual("Spec25", module_spec.get_module_name())
  129. self.assertEqual("Just an empty module", module_spec.get_module_description())
  130. def test_str(self):
  131. module_spec = isc.config.module_spec_from_file(self.spec_file("spec1.spec"), False)
  132. self.assertEqual(module_spec.__str__(), "{'module_name': 'Spec1'}")
  133. def test_check_module_spec(self):
  134. self.assertRaises(ModuleSpecError, isc.config.module_spec._check, 1)
  135. def test_check_command_spec(self):
  136. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_command_spec, 1 )
  137. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_command_spec, [ 1 ] )
  138. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_command_spec,
  139. [ { 'command_name': 1,
  140. 'command_description': 'just for testing',
  141. 'command_args': [
  142. { 'item_name': 'arg1',
  143. 'item_type': 'string',
  144. 'item_optional': True
  145. }
  146. ]
  147. }
  148. ]
  149. )
  150. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_command_spec,
  151. [ { 'command_name': 'test_command',
  152. 'command_description': 1,
  153. 'command_args': [
  154. { 'item_name': 'arg1',
  155. 'item_type': 'string',
  156. 'item_optional': True
  157. }
  158. ]
  159. }
  160. ]
  161. )
  162. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_command_spec,
  163. [ { 'command_name': 'test_command',
  164. 'command_args': [ 1 ]
  165. }
  166. ]
  167. )
  168. def test_check_item_spec(self):
  169. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec, 1 )
  170. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  171. { 'item_name': 1,
  172. 'item_type': "string",
  173. 'item_optional': False,
  174. 'item_default': "asdf"
  175. }
  176. )
  177. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  178. { 'item_name': "an_item",
  179. 'item_type': "bad_type",
  180. 'item_optional': False,
  181. 'item_default': "asdf"
  182. }
  183. )
  184. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  185. { 'item_name': "an_item",
  186. 'item_type': 1,
  187. 'item_optional': False,
  188. 'item_default': "asdf"
  189. }
  190. )
  191. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  192. { 'item_name': "an_item",
  193. 'item_type': "string",
  194. 'item_optional': False,
  195. }
  196. )
  197. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  198. { 'item_name': "an_item",
  199. 'item_type': "string",
  200. 'item_optional': 1,
  201. }
  202. )
  203. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  204. { 'item_name': "an_item",
  205. 'item_type': "string",
  206. 'item_optional': False,
  207. 'item_default': 1
  208. }
  209. )
  210. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  211. { 'item_name': "an_item",
  212. 'item_type': "list",
  213. 'item_optional': False,
  214. 'item_default': []
  215. }
  216. )
  217. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  218. { 'item_name': "an_item",
  219. 'item_type': "list",
  220. 'item_optional': False,
  221. 'item_default': [],
  222. 'list_item_spec': 1
  223. }
  224. )
  225. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  226. { 'item_name': "an_item",
  227. 'item_type': "map",
  228. 'item_optional': False,
  229. 'item_default': {}
  230. }
  231. )
  232. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  233. { 'item_name': "an_item",
  234. 'item_type': "map",
  235. 'item_optional': False,
  236. 'item_default': {},
  237. 'map_item_spec': 1
  238. }
  239. )
  240. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  241. { 'item_name': "an_item",
  242. 'item_type': "map",
  243. 'item_optional': False,
  244. 'item_default': {},
  245. 'map_item_spec': [ 1 ]
  246. }
  247. )
  248. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  249. { 'item_name': "a_datetime",
  250. 'item_type': "string",
  251. 'item_optional': False,
  252. 'item_default': 1,
  253. 'item_format': "date-time"
  254. }
  255. )
  256. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  257. { 'item_name': "a_date",
  258. 'item_type': "string",
  259. 'item_optional': False,
  260. 'item_default': 1,
  261. 'item_format': "date"
  262. }
  263. )
  264. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  265. { 'item_name': "a_time",
  266. 'item_type': "string",
  267. 'item_optional': False,
  268. 'item_default': 1,
  269. 'item_format': "time"
  270. }
  271. )
  272. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  273. { 'item_name': "a_datetime",
  274. 'item_type': "string",
  275. 'item_optional': False,
  276. 'item_default': "2011-05-27T19:42:57Z",
  277. 'item_format': "dummy-format"
  278. }
  279. )
  280. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  281. { 'item_name': "a_date",
  282. 'item_type': "string",
  283. 'item_optional': False,
  284. 'item_default': "2011-05-27",
  285. 'item_format': "dummy-format"
  286. }
  287. )
  288. self.assertRaises(ModuleSpecError, isc.config.module_spec._check_item_spec,
  289. { 'item_name': "a_time",
  290. 'item_type': "string",
  291. 'item_optional': False,
  292. 'item_default': "19:42:57Z",
  293. 'item_format': "dummy-format"
  294. }
  295. )
  296. def test_check_format(self):
  297. self.assertTrue(isc.config.module_spec._check_format('2011-05-27T19:42:57Z', 'date-time'))
  298. self.assertTrue(isc.config.module_spec._check_format('2011-05-27', 'date'))
  299. self.assertTrue(isc.config.module_spec._check_format('19:42:57', 'time'))
  300. self.assertFalse(isc.config.module_spec._check_format('2011-05-27T19:42:57Z', 'dummy'))
  301. self.assertFalse(isc.config.module_spec._check_format('2011-05-27', 'dummy'))
  302. self.assertFalse(isc.config.module_spec._check_format('19:42:57', 'dummy'))
  303. self.assertFalse(isc.config.module_spec._check_format('2011-13-99T99:99:99Z', 'date-time'))
  304. self.assertFalse(isc.config.module_spec._check_format('2011-13-99', 'date'))
  305. self.assertFalse(isc.config.module_spec._check_format('99:99:99', 'time'))
  306. self.assertFalse(isc.config.module_spec._check_format('', 'date-time'))
  307. self.assertFalse(isc.config.module_spec._check_format(None, 'date-time'))
  308. self.assertFalse(isc.config.module_spec._check_format(None, None))
  309. # wrong date-time-type format not ending with "Z"
  310. self.assertFalse(isc.config.module_spec._check_format('2011-05-27T19:42:57', 'date-time'))
  311. # wrong date-type format ending with "T"
  312. self.assertFalse(isc.config.module_spec._check_format('2011-05-27T', 'date'))
  313. # wrong time-type format ending with "Z"
  314. self.assertFalse(isc.config.module_spec._check_format('19:42:57Z', 'time'))
  315. def test_validate_type(self):
  316. errors = []
  317. self.assertEqual(True, isc.config.module_spec._validate_type({ 'item_type': 'integer' }, 1, errors))
  318. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'integer' }, "a", None))
  319. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'integer' }, "a", errors))
  320. self.assertEqual(['a should be an integer'], errors)
  321. errors = []
  322. self.assertEqual(True, isc.config.module_spec._validate_type({ 'item_type': 'real' }, 1.1, errors))
  323. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'real' }, "a", None))
  324. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'real' }, "a", errors))
  325. self.assertEqual(['a should be a real'], errors)
  326. errors = []
  327. self.assertEqual(True, isc.config.module_spec._validate_type({ 'item_type': 'boolean' }, True, errors))
  328. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'boolean' }, "a", None))
  329. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'boolean' }, "a", errors))
  330. self.assertEqual(['a should be a boolean'], errors)
  331. errors = []
  332. self.assertEqual(True, isc.config.module_spec._validate_type({ 'item_type': 'string' }, "a", errors))
  333. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'string' }, 1, None))
  334. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'string' }, 1, errors))
  335. self.assertEqual(['1 should be a string'], errors)
  336. errors = []
  337. self.assertEqual(True, isc.config.module_spec._validate_type({ 'item_type': 'list' }, [ 1, 1], errors))
  338. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'list' }, 1, None))
  339. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'list' }, 1, errors))
  340. self.assertEqual(['1 should be a list'], errors)
  341. errors = []
  342. self.assertEqual(True, isc.config.module_spec._validate_type({ 'item_type': 'map' }, {"a": 1}, errors))
  343. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'map' }, 1, None))
  344. self.assertEqual(False, isc.config.module_spec._validate_type({ 'item_type': 'map' }, 1, errors))
  345. self.assertEqual(['1 should be a map'], errors)
  346. def test_validate_format(self):
  347. errors = []
  348. self.assertEqual(True, isc.config.module_spec._validate_format({ 'item_format': 'date-time' }, "2011-05-27T19:42:57Z", errors))
  349. self.assertEqual(False, isc.config.module_spec._validate_format({ 'item_format': 'date-time' }, "a", None))
  350. self.assertEqual(False, isc.config.module_spec._validate_format({ 'item_format': 'date-time' }, "a", errors))
  351. self.assertEqual(['format type of a should be date-time'], errors)
  352. errors = []
  353. self.assertEqual(True, isc.config.module_spec._validate_format({ 'item_format': 'date' }, "2011-05-27", errors))
  354. self.assertEqual(False, isc.config.module_spec._validate_format({ 'item_format': 'date' }, "a", None))
  355. self.assertEqual(False, isc.config.module_spec._validate_format({ 'item_format': 'date' }, "a", errors))
  356. self.assertEqual(['format type of a should be date'], errors)
  357. errors = []
  358. self.assertEqual(True, isc.config.module_spec._validate_format({ 'item_format': 'time' }, "19:42:57", errors))
  359. self.assertEqual(False, isc.config.module_spec._validate_format({ 'item_format': 'time' }, "a", None))
  360. self.assertEqual(False, isc.config.module_spec._validate_format({ 'item_format': 'time' }, "a", errors))
  361. self.assertEqual(['format type of a should be time'], errors)
  362. def test_validate_spec(self):
  363. spec = { 'item_name': "an_item",
  364. 'item_type': "string",
  365. 'item_optional': False,
  366. 'item_default': "asdf"
  367. }
  368. errors = []
  369. self.assertEqual(False, isc.config.module_spec._validate_spec(spec, True, {}, None))
  370. self.assertEqual(False, isc.config.module_spec._validate_spec(spec, True, {}, errors))
  371. self.assertEqual(['non-optional item an_item missing'], errors)
  372. def test_validate_unknown_items(self):
  373. spec = [{ 'item_name': "an_item",
  374. 'item_type': "string",
  375. 'item_optional': True,
  376. 'item_default': "asdf"
  377. }]
  378. errors = []
  379. self.assertEqual(True, isc.config.module_spec._validate_spec_list(spec, True, None, None))
  380. self.assertEqual(False, isc.config.module_spec._validate_spec_list(spec, True, { 'does_not_exist': 1 }, None))
  381. self.assertEqual(False, isc.config.module_spec._validate_spec_list(spec, True, { 'does_not_exist': 1 }, errors))
  382. self.assertEqual(['unknown item does_not_exist'], errors)
  383. if __name__ == '__main__':
  384. unittest.main()