bindctl_test.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. import unittest
  16. import isc.cc.data
  17. import os
  18. from isc.config.config_data import ConfigData, MultiConfigData
  19. from isc.config.module_spec import ModuleSpec
  20. from bindctl import cmdparse
  21. from bindctl import bindcmd
  22. from bindctl.moduleinfo import *
  23. from bindctl.exception import *
  24. try:
  25. from collections import OrderedDict
  26. except ImportError:
  27. from mycollections import OrderedDict
  28. class TestCmdLex(unittest.TestCase):
  29. def my_assert_raise(self, exception_type, cmd_line):
  30. self.assertRaises(exception_type, cmdparse.BindCmdParse, cmd_line)
  31. def testCommandWithoutParameter(self):
  32. cmd = cmdparse.BindCmdParse("zone add")
  33. assert cmd.module == "zone"
  34. assert cmd.command == "add"
  35. self.assertEqual(len(cmd.params), 0)
  36. def testCommandWithParameters(self):
  37. lines = {"zone add zone_name = cnnic.cn, file = cnnic.cn.file master=1.1.1.1",
  38. "zone add zone_name = \"cnnic.cn\", file ='cnnic.cn.file' master=1.1.1.1 ",
  39. "zone add zone_name = 'cnnic.cn\", file ='cnnic.cn.file' master=1.1.1.1, " }
  40. for cmd_line in lines:
  41. cmd = cmdparse.BindCmdParse(cmd_line)
  42. assert cmd.module == "zone"
  43. assert cmd.command == "add"
  44. assert cmd.params["zone_name"] == "cnnic.cn"
  45. assert cmd.params["file"] == "cnnic.cn.file"
  46. assert cmd.params["master"] == '1.1.1.1'
  47. def testCommandWithParamters_2(self):
  48. '''Test whether the parameters in key=value can be parsed properly.'''
  49. cmd = cmdparse.BindCmdParse('zone cmd name = 1:34::2')
  50. self.assertEqual(cmd.params['name'], '1:34::2')
  51. cmd = cmdparse.BindCmdParse('zone cmd name = 1\"\'34**&2 value=44\"\'\"')
  52. self.assertEqual(cmd.params['name'], '1\"\'34**&2')
  53. self.assertEqual(cmd.params['value'], '44\"\'\"')
  54. cmd = cmdparse.BindCmdParse('zone cmd name = 1\"\'34**&2 ,value= 44\"\'\"')
  55. self.assertEqual(cmd.params['name'], '1\"\'34**&2')
  56. self.assertEqual(cmd.params['value'], '44\"\'\"')
  57. cmd = cmdparse.BindCmdParse('zone cmd name = 1\'34**&2value=44\"\'\" value = \"==============\'')
  58. self.assertEqual(cmd.params['name'], '1\'34**&2value=44\"\'\"')
  59. self.assertEqual(cmd.params['value'], '==============')
  60. cmd = cmdparse.BindCmdParse('zone cmd name = \"1234, 567890 \" value ==&*/')
  61. self.assertEqual(cmd.params['name'], '1234, 567890 ')
  62. self.assertEqual(cmd.params['value'], '=&*/')
  63. def testCommandWithListParam(self):
  64. cmd = cmdparse.BindCmdParse("zone set zone_name='cnnic.cn', master='1.1.1.1, 2.2.2.2'")
  65. assert cmd.params["master"] == '1.1.1.1, 2.2.2.2'
  66. def testCommandWithHelpParam(self):
  67. cmd = cmdparse.BindCmdParse("zone add help")
  68. assert cmd.params["help"] == "help"
  69. cmd = cmdparse.BindCmdParse("zone add help *&)&)*&&$#$^%")
  70. assert cmd.params["help"] == "help"
  71. self.assertEqual(len(cmd.params), 1)
  72. def testCmdModuleNameFormatError(self):
  73. self.my_assert_raise(CmdModuleNameFormatError, "zone=good")
  74. self.my_assert_raise(CmdModuleNameFormatError, "zo/ne")
  75. self.my_assert_raise(CmdModuleNameFormatError, "")
  76. self.my_assert_raise(CmdModuleNameFormatError, "=zone")
  77. self.my_assert_raise(CmdModuleNameFormatError, "zone,")
  78. def testCmdMissCommandNameFormatError(self):
  79. self.my_assert_raise(CmdMissCommandNameFormatError, "zone")
  80. self.my_assert_raise(CmdMissCommandNameFormatError, "zone ")
  81. self.my_assert_raise(CmdMissCommandNameFormatError, "help ")
  82. def testCmdCommandNameFormatError(self):
  83. self.my_assert_raise(CmdCommandNameFormatError, "zone =d")
  84. self.my_assert_raise(CmdCommandNameFormatError, "zone z=d")
  85. self.my_assert_raise(CmdCommandNameFormatError, "zone z-d ")
  86. self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/")
  87. self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/ \"")
  88. class TestCmdSyntax(unittest.TestCase):
  89. def _create_bindcmd(self):
  90. """Create one bindcmd"""
  91. tool = bindcmd.BindCmdInterpreter()
  92. string_spec = { 'item_type' : 'string',
  93. 'item_optional' : False,
  94. 'item_default' : ''}
  95. int_spec = { 'item_type' : 'integer',
  96. 'item_optional' : False,
  97. 'item_default' : 10}
  98. zone_file_param = ParamInfo(name = "zone_file", param_spec = string_spec)
  99. zone_name = ParamInfo(name = 'zone_name', param_spec = string_spec)
  100. load_cmd = CommandInfo(name = "load")
  101. load_cmd.add_param(zone_file_param)
  102. load_cmd.add_param(zone_name)
  103. param_master = ParamInfo(name = "master", optional = True, param_spec = string_spec)
  104. param_master = ParamInfo(name = "port", optional = True, param_spec = int_spec)
  105. param_allow_update = ParamInfo(name = "allow_update", optional = True, param_spec = string_spec)
  106. set_cmd = CommandInfo(name = "set")
  107. set_cmd.add_param(param_master)
  108. set_cmd.add_param(param_allow_update)
  109. set_cmd.add_param(zone_name)
  110. reload_all_cmd = CommandInfo(name = "reload_all")
  111. zone_module = ModuleInfo(name = "zone")
  112. zone_module.add_command(load_cmd)
  113. zone_module.add_command(set_cmd)
  114. zone_module.add_command(reload_all_cmd)
  115. tool.add_module_info(zone_module)
  116. return tool
  117. def setUp(self):
  118. self.bindcmd = self._create_bindcmd()
  119. def no_assert_raise(self, cmd_line):
  120. cmd = cmdparse.BindCmdParse(cmd_line)
  121. self.bindcmd._validate_cmd(cmd)
  122. def my_assert_raise(self, exception_type, cmd_line):
  123. cmd = cmdparse.BindCmdParse(cmd_line)
  124. self.assertRaises(exception_type, self.bindcmd._validate_cmd, cmd)
  125. def testValidateSuccess(self):
  126. self.no_assert_raise("zone load zone_file='cn' zone_name='cn'")
  127. self.no_assert_raise("zone load zone_file='cn', zone_name='cn', ")
  128. self.no_assert_raise("zone help ")
  129. self.no_assert_raise("zone load help ")
  130. self.no_assert_raise("zone help help='dd' ")
  131. self.no_assert_raise("zone set allow_update='1.1.1.1' zone_name='cn'")
  132. self.no_assert_raise("zone set zone_name='cn'")
  133. self.my_assert_raise(isc.cc.data.DataTypeError, "zone set zone_name ='cn', port='cn'")
  134. self.no_assert_raise("zone reload_all")
  135. def testCmdUnknownModuleSyntaxError(self):
  136. self.my_assert_raise(CmdUnknownModuleSyntaxError, "zoned d")
  137. self.my_assert_raise(CmdUnknownModuleSyntaxError, "dd dd ")
  138. def testCmdUnknownCmdSyntaxError(self):
  139. self.my_assert_raise(CmdUnknownCmdSyntaxError, "zone dd")
  140. def testCmdMissParamSyntaxError(self):
  141. self.my_assert_raise(CmdMissParamSyntaxError, "zone load zone_file='cn'")
  142. self.my_assert_raise(CmdMissParamSyntaxError, "zone load zone_name='cn'")
  143. self.my_assert_raise(CmdMissParamSyntaxError, "zone set allow_update='1.1.1.1'")
  144. self.my_assert_raise(CmdMissParamSyntaxError, "zone set ")
  145. def testCmdUnknownParamSyntaxError(self):
  146. self.my_assert_raise(CmdUnknownParamSyntaxError, "zone load zone_d='cn'")
  147. self.my_assert_raise(CmdUnknownParamSyntaxError, "zone reload_all zone_name = 'cn'")
  148. class TestModuleInfo(unittest.TestCase):
  149. def test_get_param_name_by_position(self):
  150. cmd = CommandInfo('command')
  151. cmd.add_param(ParamInfo('name'))
  152. cmd.add_param(ParamInfo('age'))
  153. cmd.add_param(ParamInfo('data', optional = True))
  154. cmd.add_param(ParamInfo('sex'))
  155. self.assertEqual('name', cmd.get_param_name_by_position(0, 2))
  156. self.assertEqual('age', cmd.get_param_name_by_position(1, 2))
  157. self.assertEqual('sex', cmd.get_param_name_by_position(2, 3))
  158. self.assertEqual('data', cmd.get_param_name_by_position(2, 4))
  159. self.assertEqual('data', cmd.get_param_name_by_position(2, 4))
  160. self.assertRaises(KeyError, cmd.get_param_name_by_position, 4, 4)
  161. class TestNameSequence(unittest.TestCase):
  162. """
  163. Test if the module/command/parameters is saved in the order creation
  164. """
  165. def _create_bindcmd(self):
  166. """Create one bindcmd"""
  167. self._cmd = CommandInfo(name = "load")
  168. self.module = ModuleInfo(name = "zone")
  169. self.tool = bindcmd.BindCmdInterpreter()
  170. for random_str in self.random_names:
  171. self._cmd.add_param(ParamInfo(name = random_str))
  172. self.module.add_command(CommandInfo(name = random_str))
  173. self.tool.add_module_info(ModuleInfo(name = random_str))
  174. def setUp(self):
  175. self.random_names = ['1erdfeDDWsd', '3fe', '2009erd', 'Fe231', 'tere142', 'rei8WD']
  176. self._create_bindcmd()
  177. def testSequence(self):
  178. param_names = self._cmd.get_param_names()
  179. cmd_names = self.module.get_command_names()
  180. module_names = self.tool.get_module_names()
  181. i = 0
  182. while i < len(self.random_names):
  183. assert self.random_names[i] == param_names[i+1]
  184. assert self.random_names[i] == cmd_names[i+1]
  185. assert self.random_names[i] == module_names[i+1]
  186. i = i + 1
  187. # tine class to fake a UIModuleCCSession, but only the config data
  188. # parts for the next set of tests
  189. class FakeCCSession(MultiConfigData):
  190. def __init__(self):
  191. self._local_changes = {}
  192. self._current_config = {}
  193. self._specifications = {}
  194. self.add_foo_spec()
  195. def add_foo_spec(self):
  196. spec = { "module_name": "foo",
  197. "config_data": [
  198. { "item_name": "an_int",
  199. "item_type": "integer",
  200. "item_optional": False,
  201. "item_default": 1
  202. },
  203. { "item_name": "a_list",
  204. "item_type": "list",
  205. "item_optional": False,
  206. "item_default": [],
  207. "list_item_spec":
  208. { "item_name": "a_string",
  209. "item_type": "string",
  210. "item_optional": False,
  211. "item_default": "bar"
  212. }
  213. }
  214. ]
  215. }
  216. self.set_specification(ModuleSpec(spec))
  217. class TestConfigCommands(unittest.TestCase):
  218. def setUp(self):
  219. self.tool = bindcmd.BindCmdInterpreter()
  220. mod_info = ModuleInfo(name = "foo")
  221. self.tool.add_module_info(mod_info)
  222. self.tool.config_data = FakeCCSession()
  223. def test_apply_cfg_command_int(self):
  224. self.tool.location = '/'
  225. self.assertEqual((1, MultiConfigData.DEFAULT),
  226. self.tool.config_data.get_value("/foo/an_int"))
  227. cmd = cmdparse.BindCmdParse("config set identifier=\"foo/an_int\" value=\"5\"")
  228. self.tool.apply_config_cmd(cmd)
  229. self.assertEqual((5, MultiConfigData.LOCAL),
  230. self.tool.config_data.get_value("/foo/an_int"))
  231. # this should raise a NotFoundError
  232. cmd = cmdparse.BindCmdParse("config set identifier=\"foo/bar\" value=\"[]\"")
  233. self.assertRaises(isc.cc.data.DataNotFoundError, self.tool.apply_config_cmd, cmd)
  234. # this should raise a TypeError
  235. cmd = cmdparse.BindCmdParse("config set identifier=\"foo/an_int\" value=\"[]\"")
  236. self.assertRaises(isc.cc.data.DataTypeError, self.tool.apply_config_cmd, cmd)
  237. # this is a very specific one for use with a set of list tests
  238. # to try out the flexibility of the parser (only in the next test)
  239. def clt(self, full_cmd_string, item_value):
  240. cmd = cmdparse.BindCmdParse(full_cmd_string)
  241. self.tool.apply_config_cmd(cmd)
  242. self.assertEqual(([item_value], MultiConfigData.LOCAL),
  243. self.tool.config_data.get_value("/foo/a_list"))
  244. def test_apply_cfg_command_list(self):
  245. self.tool.location = '/'
  246. self.assertEqual(([], MultiConfigData.DEFAULT),
  247. self.tool.config_data.get_value("/foo/a_list"))
  248. self.clt("config set identifier=\"foo/a_list\" value=[\"a\"]", "a")
  249. self.clt("config set identifier=\"foo/a_list\" value =[\"b\"]", "b")
  250. self.clt("config set identifier=\"foo/a_list\" value= [\"c\"]", "c")
  251. self.clt("config set identifier=\"foo/a_list\" value = [\"d\"]", "d")
  252. self.clt("config set identifier =\"foo/a_list\" value=[\"e\"]", "e")
  253. self.clt("config set identifier= \"foo/a_list\" value=[\"f\"]", "f")
  254. self.clt("config set identifier = \"foo/a_list\" value=[\"g\"]", "g")
  255. self.clt("config set identifier = \"foo/a_list\" value = [\"h\"]", "h")
  256. self.clt("config set identifier = \"foo/a_list\" value=[\"i\" ]", "i")
  257. self.clt("config set identifier = \"foo/a_list\" value=[ \"j\"]", "j")
  258. self.clt("config set identifier = \"foo/a_list\" value=[ \"k\" ]", "k")
  259. # this should raise a TypeError
  260. cmd = cmdparse.BindCmdParse("config set identifier=\"foo/a_list\" value=\"a\"")
  261. self.assertRaises(isc.cc.data.DataTypeError, self.tool.apply_config_cmd, cmd)
  262. cmd = cmdparse.BindCmdParse("config set identifier=\"foo/a_list\" value=[1]")
  263. self.assertRaises(isc.cc.data.DataTypeError, self.tool.apply_config_cmd, cmd)
  264. class TestBindCmdInterpreter(unittest.TestCase):
  265. def _create_invalid_csv_file(self, csvfilename):
  266. import csv
  267. csvfile = open(csvfilename, 'w')
  268. writer = csv.writer(csvfile)
  269. writer.writerow(['name1'])
  270. writer.writerow(['name2'])
  271. csvfile.close()
  272. def test_get_saved_user_info(self):
  273. cmd = bindcmd.BindCmdInterpreter()
  274. users = cmd._get_saved_user_info('/notexist', 'cvs_file.cvs')
  275. self.assertEqual([], users)
  276. csvfilename = 'csv_file.csv'
  277. self._create_invalid_csv_file(csvfilename)
  278. users = cmd._get_saved_user_info('./', csvfilename)
  279. self.assertEqual([], users)
  280. os.remove(csvfilename)
  281. if __name__== "__main__":
  282. unittest.main()