cfgmgr_test.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. # Copyright (C) 2010 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. # $Id$
  16. #
  17. # Tests for the configuration manager module
  18. #
  19. import unittest
  20. import os
  21. from isc.config.cfgmgr import *
  22. from isc.config import config_data
  23. from unittest_fakesession import FakeModuleCCSession
  24. class TestConfigManagerData(unittest.TestCase):
  25. def setUp(self):
  26. self.data_path = os.environ['CONFIG_TESTDATA_PATH']
  27. self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
  28. self.config_manager_data = ConfigManagerData(self.writable_data_path)
  29. self.assert_(self.config_manager_data)
  30. def test_init(self):
  31. self.assertEqual(self.config_manager_data.data['version'],
  32. config_data.BIND10_CONFIG_DATA_VERSION)
  33. self.assertEqual(self.config_manager_data.data_path,
  34. self.writable_data_path)
  35. self.assertEqual(self.config_manager_data.db_filename,
  36. self.writable_data_path + os.sep + "b10-config.db")
  37. def test_read_from_file(self):
  38. ConfigManagerData.read_from_file(self.writable_data_path)
  39. self.assertRaises(ConfigManagerDataEmpty,
  40. ConfigManagerData.read_from_file,
  41. "doesnotexist")
  42. self.assertRaises(ConfigManagerDataReadError,
  43. ConfigManagerData.read_from_file,
  44. self.data_path, "b10-config-bad1.db")
  45. self.assertRaises(ConfigManagerDataReadError,
  46. ConfigManagerData.read_from_file,
  47. self.data_path, "b10-config-bad2.db")
  48. self.assertRaises(ConfigManagerDataReadError,
  49. ConfigManagerData.read_from_file,
  50. self.data_path, "b10-config-bad3.db")
  51. self.assertRaises(ConfigManagerDataReadError,
  52. ConfigManagerData.read_from_file,
  53. self.data_path, "b10-config-bad4.db")
  54. def test_write_to_file(self):
  55. output_file_name = "b10-config-write-test"
  56. self.config_manager_data.write_to_file(output_file_name)
  57. new_config = ConfigManagerData(self.data_path, output_file_name)
  58. self.assertEqual(self.config_manager_data, new_config)
  59. os.remove(output_file_name)
  60. def test_equality(self):
  61. # tests the __eq__ function. Equality is only defined
  62. # by equality of the .data element. If data_path or db_filename
  63. # are different, but the contents are the same, it's still
  64. # considered equal
  65. cfd1 = ConfigManagerData(self.data_path)
  66. cfd2 = ConfigManagerData(self.data_path)
  67. self.assertEqual(cfd1, cfd2)
  68. cfd2.data_path = "some/unknown/path"
  69. self.assertEqual(cfd1, cfd2)
  70. cfd2.db_filename = "bad_file.name"
  71. self.assertEqual(cfd1, cfd2)
  72. cfd2.data['test'] = { 'a': [ 1, 2, 3]}
  73. self.assertNotEqual(cfd1, cfd2)
  74. class TestConfigManager(unittest.TestCase):
  75. def setUp(self):
  76. self.data_path = os.environ['CONFIG_TESTDATA_PATH']
  77. self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
  78. self.fake_session = FakeModuleCCSession()
  79. self.cm = ConfigManager(self.writable_data_path, self.fake_session)
  80. self.name = "TestModule"
  81. self.spec = isc.config.module_spec_from_file(self.data_path + os.sep + "/spec2.spec")
  82. def test_init(self):
  83. self.assert_(self.cm.module_specs == {})
  84. self.assert_(self.cm.data_path == self.writable_data_path)
  85. self.assert_(self.cm.config != None)
  86. self.assert_(self.fake_session.has_subscription("ConfigManager"))
  87. self.assert_(self.fake_session.has_subscription("Boss", "ConfigManager"))
  88. self.assertFalse(self.cm.running)
  89. def test_notify_boss(self):
  90. self.cm.notify_boss()
  91. msg = self.fake_session.get_message("Boss", None)
  92. self.assert_(msg)
  93. # this one is actually wrong, but 'current status quo'
  94. self.assertEqual(msg, {"running": "configmanager"})
  95. def test_set_module_spec(self):
  96. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  97. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  98. self.cm.set_module_spec(module_spec)
  99. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  100. def test_remove_module_spec(self):
  101. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  102. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  103. self.cm.set_module_spec(module_spec)
  104. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  105. self.cm.remove_module_spec(module_spec.get_module_name())
  106. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  107. def test_get_module_spec(self):
  108. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  109. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  110. self.cm.set_module_spec(module_spec)
  111. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  112. module_spec2 = self.cm.get_module_spec(module_spec.get_module_name())
  113. self.assertEqual(module_spec, module_spec2)
  114. def test_get_config_spec(self):
  115. config_spec = self.cm.get_config_spec()
  116. self.assertEqual(config_spec, {})
  117. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  118. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  119. self.cm.set_module_spec(module_spec)
  120. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  121. config_spec = self.cm.get_config_spec()
  122. self.assertEqual(config_spec, { 'Spec1': None })
  123. self.cm.remove_module_spec('Spec1')
  124. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
  125. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  126. self.cm.set_module_spec(module_spec)
  127. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  128. config_spec = self.cm.get_config_spec()
  129. self.assertEqual(config_spec['Spec2'], module_spec.get_config_spec())
  130. config_spec = self.cm.get_config_spec('Spec2')
  131. self.assertEqual(config_spec['Spec2'], module_spec.get_config_spec())
  132. def test_get_commands_spec(self):
  133. commands_spec = self.cm.get_commands_spec()
  134. self.assertEqual(commands_spec, {})
  135. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  136. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  137. self.cm.set_module_spec(module_spec)
  138. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  139. commands_spec = self.cm.get_commands_spec()
  140. self.assertEqual(commands_spec, { 'Spec1': None })
  141. self.cm.remove_module_spec('Spec1')
  142. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
  143. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  144. self.cm.set_module_spec(module_spec)
  145. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  146. commands_spec = self.cm.get_commands_spec()
  147. self.assertEqual(commands_spec['Spec2'], module_spec.get_commands_spec())
  148. commands_spec = self.cm.get_commands_spec('Spec2')
  149. self.assertEqual(commands_spec['Spec2'], module_spec.get_commands_spec())
  150. def test_read_config(self):
  151. self.assertEqual(self.cm.config.data, {'version': config_data.BIND10_CONFIG_DATA_VERSION})
  152. self.cm.read_config()
  153. # due to what get written, the value here is what the last set_config command in test_handle_msg does
  154. self.assertEqual(self.cm.config.data, {'TestModule': {'test': 125}, 'version': config_data.BIND10_CONFIG_DATA_VERSION})
  155. self.cm.data_path = "/no_such_path"
  156. self.cm.read_config()
  157. self.assertEqual(self.cm.config.data, {'version': config_data.BIND10_CONFIG_DATA_VERSION})
  158. def test_write_config(self):
  159. # tested in ConfigManagerData tests
  160. pass
  161. def _handle_msg_helper(self, msg, expected_answer):
  162. answer = self.cm.handle_msg(msg)
  163. self.assertEqual(expected_answer, answer)
  164. def test_handle_msg(self):
  165. self._handle_msg_helper({}, { 'result': [ 1, 'Unknown message format: {}']})
  166. self._handle_msg_helper("", { 'result': [ 1, 'Unknown message format: ']})
  167. self._handle_msg_helper({ "command": [ "badcommand" ] }, { 'result': [ 1, "Unknown command: badcommand"]})
  168. self._handle_msg_helper({ "command": [ "get_commands_spec" ] }, { 'result': [ 0, {} ]})
  169. self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, {} ]})
  170. self._handle_msg_helper({ "command": [ "get_module_spec", { "module_name": "Spec2" } ] }, { 'result': [ 0, {} ]})
  171. #self._handle_msg_helper({ "command": [ "get_module_spec", { "module_name": "nosuchmodule" } ] },
  172. # {'result': [1, 'No specification for module nosuchmodule']})
  173. self._handle_msg_helper({ "command": [ "get_module_spec", 1 ] },
  174. {'result': [1, 'Bad get_module_spec command, argument not a dict']})
  175. self._handle_msg_helper({ "command": [ "get_module_spec", { } ] },
  176. {'result': [1, 'Bad module_name in get_module_spec command']})
  177. self._handle_msg_helper({ "command": [ "get_config" ] }, { 'result': [ 0, { 'version': config_data.BIND10_CONFIG_DATA_VERSION } ]})
  178. self._handle_msg_helper({ "command": [ "get_config", { "module_name": "nosuchmodule" } ] },
  179. {'result': [0, { 'version': config_data.BIND10_CONFIG_DATA_VERSION }]})
  180. self._handle_msg_helper({ "command": [ "get_config", 1 ] },
  181. {'result': [1, 'Bad get_config command, argument not a dict']})
  182. self._handle_msg_helper({ "command": [ "get_config", { } ] },
  183. {'result': [1, 'Bad module_name in get_config command']})
  184. self._handle_msg_helper({ "command": [ "set_config" ] },
  185. {'result': [1, 'Wrong number of arguments']})
  186. self._handle_msg_helper({ "command": [ "set_config", [{}]] },
  187. {'result': [0]})
  188. self.assertEqual(len(self.fake_session.message_queue), 0)
  189. # the targets of some of these tests expect specific answers, put
  190. # those in our fake msgq first.
  191. my_ok_answer = { 'result': [ 0 ] }
  192. # Send the 'ok' that cfgmgr expects back to the fake queue first
  193. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  194. # then send the command
  195. self._handle_msg_helper({ "command": [ "set_config", [self.name, { "test": 123 }] ] },
  196. my_ok_answer)
  197. # The cfgmgr should have eaten the ok message, and sent out an update again
  198. self.assertEqual(len(self.fake_session.message_queue), 1)
  199. self.assertEqual({'command': [ 'config_update', {'test': 123}]},
  200. self.fake_session.get_message(self.name, None))
  201. # and the queue should now be empty again
  202. self.assertEqual(len(self.fake_session.message_queue), 0)
  203. # below are variations of the theme above
  204. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  205. self._handle_msg_helper({ "command": [ "set_config", [self.name, { "test": 124 }] ] },
  206. my_ok_answer)
  207. self.assertEqual(len(self.fake_session.message_queue), 1)
  208. self.assertEqual({'command': [ 'config_update', {'test': 124}]},
  209. self.fake_session.get_message(self.name, None))
  210. self.assertEqual(len(self.fake_session.message_queue), 0)
  211. # This is the last 'succes' one, the value set here is what test_read_config expects
  212. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  213. self._handle_msg_helper({ "command": [ "set_config", [ { self.name: { "test": 125 } }] ] },
  214. my_ok_answer )
  215. self.assertEqual(len(self.fake_session.message_queue), 1)
  216. self.assertEqual({'command': [ 'config_update', {'test': 125}]},
  217. self.fake_session.get_message(self.name, None))
  218. self.assertEqual(len(self.fake_session.message_queue), 0)
  219. my_bad_answer = { 'result': [1, "bad_answer"] }
  220. self.fake_session.group_sendmsg(my_bad_answer, "ConfigManager")
  221. self._handle_msg_helper({ "command": [ "set_config", [ self.name, { "test": 125 }] ] },
  222. my_bad_answer )
  223. self.assertEqual(len(self.fake_session.message_queue), 1)
  224. self.assertEqual({'command': [ 'config_update', {'test': 125}]},
  225. self.fake_session.get_message(self.name, None))
  226. self.assertEqual(len(self.fake_session.message_queue), 0)
  227. self._handle_msg_helper({ "command": [ "set_config", [ ] ] },
  228. {'result': [1, 'Wrong number of arguments']} )
  229. self._handle_msg_helper({ "command": [ "set_config", [ self.name, { "test": 125 }] ] },
  230. { 'result': [1, 'No answer message from TestModule']} )
  231. #self.assertEqual(len(self.fake_session.message_queue), 1)
  232. #self.assertEqual({'config_update': {'test': 124}},
  233. # self.fake_session.get_message(self.name, None))
  234. #self.assertEqual({'version': 1, 'TestModule': {'test': 124}}, self.cm.config.data)
  235. #
  236. self._handle_msg_helper({ "command":
  237. ["module_spec", self.spec.get_full_spec()]
  238. },
  239. {'result': [0]})
  240. self._handle_msg_helper({ "command": [ "module_spec", { 'foo': 1 } ] },
  241. {'result': [1, 'Error in data definition: no module_name in module_spec']})
  242. self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_full_spec() } ]})
  243. self._handle_msg_helper({ "command": [ "get_commands_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_commands_spec() } ]})
  244. # re-add this once we have new way to propagate spec changes (1 instead of the current 2 messages)
  245. #self.assertEqual(len(self.fake_session.message_queue), 2)
  246. # the name here is actually wrong (and hardcoded), but needed in the current version
  247. # TODO: fix that
  248. #self.assertEqual({'specification_update': [ self.name, self.spec ] },
  249. # self.fake_session.get_message("Cmdctl", None))
  250. #self.assertEqual({'commands_update': [ self.name, self.commands ] },
  251. # self.fake_session.get_message("Cmdctl", None))
  252. self._handle_msg_helper({ "command":
  253. ["shutdown"]
  254. },
  255. {'result': [0]})
  256. def test_run(self):
  257. self.fake_session.group_sendmsg({ "command": [ "get_commands_spec" ] }, "ConfigManager")
  258. self.fake_session.group_sendmsg({ "command": [ "shutdown" ] }, "ConfigManager")
  259. self.cm.run()
  260. pass
  261. if __name__ == '__main__':
  262. if not 'CONFIG_TESTDATA_PATH' in os.environ or not 'CONFIG_WR_TESTDATA_PATH' in os.environ:
  263. print("You need to set the environment variable CONFIG_TESTDATA_PATH and CONFIG_WR_TESTDATA_PATH to point to the directory containing the test data files")
  264. exit(1)
  265. unittest.main()