cfgmgr_test.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  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. #
  16. # Tests for the configuration manager module
  17. #
  18. import unittest
  19. import os
  20. from isc.config.cfgmgr import *
  21. from isc.config import config_data
  22. from unittest_fakesession import FakeModuleCCSession
  23. class TestConfigManagerData(unittest.TestCase):
  24. def setUp(self):
  25. self.data_path = os.environ['CONFIG_TESTDATA_PATH']
  26. self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
  27. self.config_manager_data = ConfigManagerData(self.writable_data_path,
  28. file_name="b10-config.db")
  29. self.assert_(self.config_manager_data)
  30. def test_abs_file(self):
  31. """
  32. Test what happens if we give the config manager an absolute path.
  33. It shouldn't append the data path to it.
  34. """
  35. abs_path = self.data_path + os.sep + "b10-config-imaginary.db"
  36. data = ConfigManagerData(self.data_path, abs_path)
  37. self.assertEqual(abs_path, data.db_filename)
  38. self.assertEqual(self.data_path, data.data_path)
  39. def test_init(self):
  40. self.assertEqual(self.config_manager_data.data['version'],
  41. config_data.BIND10_CONFIG_DATA_VERSION)
  42. self.assertEqual(self.config_manager_data.data_path,
  43. self.writable_data_path)
  44. self.assertEqual(self.config_manager_data.db_filename,
  45. self.writable_data_path + os.sep + "b10-config.db")
  46. def test_read_from_file(self):
  47. ConfigManagerData.read_from_file(self.writable_data_path, "b10-config.db")
  48. self.assertRaises(ConfigManagerDataEmpty,
  49. ConfigManagerData.read_from_file,
  50. "doesnotexist", "b10-config.db")
  51. self.assertRaises(ConfigManagerDataReadError,
  52. ConfigManagerData.read_from_file,
  53. self.data_path, "b10-config-bad1.db")
  54. self.assertRaises(ConfigManagerDataReadError,
  55. ConfigManagerData.read_from_file,
  56. self.data_path, "b10-config-bad2.db")
  57. self.assertRaises(ConfigManagerDataReadError,
  58. ConfigManagerData.read_from_file,
  59. self.data_path, "b10-config-bad3.db")
  60. self.assertRaises(ConfigManagerDataReadError,
  61. ConfigManagerData.read_from_file,
  62. self.data_path, "b10-config-bad4.db")
  63. def test_write_to_file(self):
  64. output_file_name = "b10-config-write-test"
  65. self.config_manager_data.write_to_file(output_file_name)
  66. new_config = ConfigManagerData(self.data_path, output_file_name)
  67. self.assertEqual(self.config_manager_data, new_config)
  68. os.remove(output_file_name)
  69. def test_rename_config_file(self):
  70. output_file_name = "b10-config-rename-test"
  71. renamed_file_name = "b10-config-rename-test.bak"
  72. if os.path.exists(output_file_name):
  73. os.remove(output_file_name)
  74. if os.path.exists(renamed_file_name):
  75. os.remove(renamed_file_name)
  76. # The original does not exist, so the new one should not be created
  77. self.config_manager_data.rename_config_file(output_file_name)
  78. self.assertFalse(os.path.exists(output_file_name))
  79. self.assertFalse(os.path.exists(renamed_file_name))
  80. # now create a file to rename, and call rename again
  81. self.config_manager_data.write_to_file(output_file_name)
  82. self.config_manager_data.rename_config_file(output_file_name)
  83. self.assertFalse(os.path.exists(output_file_name))
  84. self.assertTrue(os.path.exists(renamed_file_name))
  85. # Test with explicit renamed file argument
  86. self.config_manager_data.rename_config_file(renamed_file_name,
  87. output_file_name)
  88. self.assertTrue(os.path.exists(output_file_name))
  89. self.assertFalse(os.path.exists(renamed_file_name))
  90. # clean up again to be nice
  91. if os.path.exists(output_file_name):
  92. os.remove(output_file_name)
  93. if os.path.exists(renamed_file_name):
  94. os.remove(renamed_file_name)
  95. def test_equality(self):
  96. # tests the __eq__ function. Equality is only defined
  97. # by equality of the .data element. If data_path or db_filename
  98. # are different, but the contents are the same, it's still
  99. # considered equal
  100. cfd1 = ConfigManagerData(self.data_path, file_name="b10-config.db")
  101. cfd2 = ConfigManagerData(self.data_path, file_name="b10-config.db")
  102. self.assertEqual(cfd1, cfd2)
  103. cfd2.data_path = "some/unknown/path"
  104. self.assertEqual(cfd1, cfd2)
  105. cfd2.db_filename = "bad_file.name"
  106. self.assertEqual(cfd1, cfd2)
  107. cfd2.data['test'] = { 'a': [ 1, 2, 3]}
  108. self.assertNotEqual(cfd1, cfd2)
  109. class TestConfigManager(unittest.TestCase):
  110. def setUp(self):
  111. self.data_path = os.environ['CONFIG_TESTDATA_PATH']
  112. self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
  113. self.fake_session = FakeModuleCCSession()
  114. self.cm = ConfigManager(self.writable_data_path,
  115. database_filename="b10-config.db",
  116. session=self.fake_session)
  117. self.name = "TestModule"
  118. self.spec = isc.config.module_spec_from_file(self.data_path + os.sep + "/spec2.spec")
  119. def test_paths(self):
  120. """
  121. Test data_path and database filename is passed trough to
  122. underlying ConfigManagerData.
  123. """
  124. cm = ConfigManager("datapath", "filename", self.fake_session)
  125. self.assertEqual("datapath" + os.sep + "filename",
  126. cm.config.db_filename)
  127. # It should preserve it while reading
  128. cm.read_config()
  129. self.assertEqual("datapath" + os.sep + "filename",
  130. cm.config.db_filename)
  131. def test_init(self):
  132. self.assert_(self.cm.module_specs == {})
  133. self.assert_(self.cm.data_path == self.writable_data_path)
  134. self.assert_(self.cm.config != None)
  135. self.assert_(self.fake_session.has_subscription("ConfigManager"))
  136. self.assert_(self.fake_session.has_subscription("Boss", "ConfigManager"))
  137. self.assertFalse(self.cm.running)
  138. def test_notify_boss(self):
  139. self.cm.notify_boss()
  140. msg = self.fake_session.get_message("Boss", None)
  141. self.assert_(msg)
  142. # this one is actually wrong, but 'current status quo'
  143. self.assertEqual(msg, {"running": "ConfigManager"})
  144. def test_set_module_spec(self):
  145. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  146. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  147. self.cm.set_module_spec(module_spec)
  148. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  149. self.assert_(module_spec.get_module_name() not in
  150. self.cm.virtual_modules)
  151. def test_remove_module_spec(self):
  152. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  153. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  154. self.cm.set_module_spec(module_spec)
  155. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  156. self.cm.remove_module_spec(module_spec.get_module_name())
  157. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  158. self.assert_(module_spec.get_module_name() not in
  159. self.cm.virtual_modules)
  160. def test_add_remove_virtual_module(self):
  161. module_spec = isc.config.module_spec.module_spec_from_file(
  162. self.data_path + os.sep + "spec1.spec")
  163. check_func = lambda: True
  164. # Make sure it's not in there before
  165. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  166. self.assert_(module_spec.get_module_name() not in
  167. self.cm.virtual_modules)
  168. # Add it there
  169. self.cm.set_virtual_module(module_spec, check_func)
  170. # Check it's in there
  171. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  172. self.assertEqual(self.cm.module_specs[module_spec.get_module_name()],
  173. module_spec)
  174. self.assertEqual(self.cm.virtual_modules[module_spec.get_module_name()],
  175. check_func)
  176. # Remove it again
  177. self.cm.remove_module_spec(module_spec.get_module_name())
  178. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  179. self.assert_(module_spec.get_module_name() not in
  180. self.cm.virtual_modules)
  181. def test_get_module_spec(self):
  182. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  183. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  184. self.cm.set_module_spec(module_spec)
  185. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  186. module_spec2 = self.cm.get_module_spec(module_spec.get_module_name())
  187. self.assertEqual(module_spec.get_full_spec(), module_spec2)
  188. self.assertEqual({}, self.cm.get_module_spec("nosuchmodule"))
  189. def test_get_config_spec(self):
  190. config_spec = self.cm.get_config_spec()
  191. self.assertEqual(config_spec, {})
  192. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  193. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  194. self.cm.set_module_spec(module_spec)
  195. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  196. config_spec = self.cm.get_config_spec()
  197. self.assertEqual(config_spec, { 'Spec1': None })
  198. self.cm.remove_module_spec('Spec1')
  199. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
  200. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  201. self.cm.set_module_spec(module_spec)
  202. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  203. config_spec = self.cm.get_config_spec()
  204. self.assertEqual(config_spec['Spec2'], module_spec.get_config_spec())
  205. config_spec = self.cm.get_config_spec('Spec2')
  206. self.assertEqual(config_spec['Spec2'], module_spec.get_config_spec())
  207. def test_get_commands_spec(self):
  208. commands_spec = self.cm.get_commands_spec()
  209. self.assertEqual(commands_spec, {})
  210. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  211. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  212. self.cm.set_module_spec(module_spec)
  213. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  214. commands_spec = self.cm.get_commands_spec()
  215. self.assertEqual(commands_spec, { 'Spec1': None })
  216. self.cm.remove_module_spec('Spec1')
  217. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
  218. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  219. self.cm.set_module_spec(module_spec)
  220. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  221. commands_spec = self.cm.get_commands_spec()
  222. self.assertEqual(commands_spec['Spec2'], module_spec.get_commands_spec())
  223. commands_spec = self.cm.get_commands_spec('Spec2')
  224. self.assertEqual(commands_spec['Spec2'], module_spec.get_commands_spec())
  225. def test_get_statistics_spec(self):
  226. statistics_spec = self.cm.get_statistics_spec()
  227. self.assertEqual(statistics_spec, {})
  228. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec1.spec")
  229. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  230. self.cm.set_module_spec(module_spec)
  231. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  232. statistics_spec = self.cm.get_statistics_spec()
  233. self.assertEqual(statistics_spec, { 'Spec1': None })
  234. self.cm.remove_module_spec('Spec1')
  235. module_spec = isc.config.module_spec.module_spec_from_file(self.data_path + os.sep + "spec2.spec")
  236. self.assert_(module_spec.get_module_name() not in self.cm.module_specs)
  237. self.cm.set_module_spec(module_spec)
  238. self.assert_(module_spec.get_module_name() in self.cm.module_specs)
  239. statistics_spec = self.cm.get_statistics_spec()
  240. self.assertEqual(statistics_spec['Spec2'], module_spec.get_statistics_spec())
  241. statistics_spec = self.cm.get_statistics_spec('Spec2')
  242. self.assertEqual(statistics_spec['Spec2'], module_spec.get_statistics_spec())
  243. def test_read_config(self):
  244. self.assertEqual(self.cm.config.data, {'version': config_data.BIND10_CONFIG_DATA_VERSION})
  245. self.cm.data_path = "/no_such_path"
  246. self.cm.read_config()
  247. self.assertEqual(self.cm.config.data, {'version': config_data.BIND10_CONFIG_DATA_VERSION})
  248. def test_write_config(self):
  249. # tested in ConfigManagerData tests
  250. pass
  251. def _handle_msg_helper(self, msg, expected_answer):
  252. answer = self.cm.handle_msg(msg)
  253. self.assertEqual(expected_answer, answer)
  254. def test_handle_msg_basic_commands(self):
  255. # Some basic commands, where not much interaction happens, just
  256. # check the result
  257. self._handle_msg_helper({},
  258. { 'result': [ 1, 'Unknown message format: {}']})
  259. self._handle_msg_helper("",
  260. { 'result': [ 1, 'Unknown message format: ']})
  261. self._handle_msg_helper({ "command": [ "badcommand" ] },
  262. { 'result': [ 1, "Unknown command: badcommand"]})
  263. self._handle_msg_helper({ "command": [ "get_commands_spec" ] },
  264. { 'result': [ 0, {} ]})
  265. self._handle_msg_helper({ "command": [ "get_statistics_spec" ] },
  266. { 'result': [ 0, {} ]})
  267. self._handle_msg_helper({ "command": [ "get_module_spec" ] },
  268. { 'result': [ 0, {} ]})
  269. self._handle_msg_helper({ "command": [ "get_module_spec",
  270. { "module_name": "Spec2" } ] },
  271. { 'result': [ 0, {} ]})
  272. self._handle_msg_helper({ "command": [ "get_module_spec", 1 ] },
  273. {'result': [1, 'Bad get_module_spec command, '+
  274. 'argument not a dict']})
  275. self._handle_msg_helper({ "command": [ "get_module_spec", { } ] },
  276. {'result': [1, 'Bad module_name in '+
  277. 'get_module_spec command']})
  278. self._handle_msg_helper({ "command": [ "get_config" ] },
  279. { 'result': [ 0, { 'version':
  280. config_data.BIND10_CONFIG_DATA_VERSION }]})
  281. self._handle_msg_helper({ "command": [ "get_config",
  282. { "module_name": "nosuchmodule" } ] },
  283. {'result': [0, { 'version':
  284. config_data.BIND10_CONFIG_DATA_VERSION }]})
  285. self._handle_msg_helper({ "command": [ "get_config", 1 ] },
  286. {'result': [1, 'Bad get_config command, '+
  287. 'argument not a dict']})
  288. self._handle_msg_helper({ "command": [ "get_config", { } ] },
  289. {'result': [1, 'Bad module_name in '+
  290. 'get_config command']})
  291. self._handle_msg_helper({ "command": [ "set_config" ] },
  292. {'result': [1, 'Wrong number of arguments']})
  293. self._handle_msg_helper({ "command": [ "set_config", [{}]] },
  294. {'result': [0]})
  295. self.assertEqual(len(self.fake_session.message_queue), 0)
  296. def test_handle_msg_module_and_stats_commands(self):
  297. self._handle_msg_helper({ "command":
  298. ["module_spec", self.spec.get_full_spec()]
  299. },
  300. {'result': [0]})
  301. # There should be a message on the queue about the 'new' Spec2 module
  302. # from ConfigManager to Cmdctl, containing its name and full
  303. # specification
  304. self.assertEqual(ccsession.create_command(
  305. ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE,
  306. [ self.spec.get_module_name(),
  307. self.spec.get_full_spec()]),
  308. self.fake_session.get_message("Cmdctl", None))
  309. self._handle_msg_helper({ "command": [ "module_spec", { 'foo': 1 } ] },
  310. {'result': [1, 'Error in data definition: no '+
  311. 'module_name in module_spec']})
  312. self._handle_msg_helper({ "command": [ "get_module_spec" ] },
  313. { 'result': [ 0, { self.spec.get_module_name():
  314. self.spec.get_full_spec() } ]})
  315. self._handle_msg_helper({ "command": [ "get_module_spec",
  316. { "module_name" : "Spec2" } ] },
  317. { 'result': [ 0, self.spec.get_full_spec() ] })
  318. self._handle_msg_helper({ "command": [ "get_commands_spec" ] },
  319. { 'result': [ 0, { self.spec.get_module_name():
  320. self.spec.get_commands_spec()}]})
  321. self._handle_msg_helper({ "command": [ "get_statistics_spec" ] },
  322. { 'result': [ 0, { self.spec.get_module_name():
  323. self.spec.get_statistics_spec()}]})
  324. def __test_handle_msg_update_config_helper(self, new_config):
  325. # Helper function for the common pattern in
  326. # test_handle_msg_update_config; send 'set config', check for
  327. # update message, check if config has indeed been updated
  328. my_ok_answer = { 'result': [ 0 ] }
  329. # Send the 'ok' that cfgmgr expects back to the fake queue first
  330. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  331. config_version = config_data.BIND10_CONFIG_DATA_VERSION
  332. self._handle_msg_helper({ "command": [ "set_config",
  333. [ { "version": config_version,
  334. self.name: new_config } ] ] },
  335. my_ok_answer)
  336. # The cfgmgr should have eaten the ok message, and sent out an update
  337. # message
  338. self.assertEqual(len(self.fake_session.message_queue), 1)
  339. self.assertEqual({'command': [ 'config_update', new_config]},
  340. self.fake_session.get_message(self.name, None))
  341. # Config should have been updated
  342. self.assertEqual(self.cm.config.data, {self.name: new_config,
  343. 'version': config_version})
  344. # and the queue should now be empty again
  345. self.assertEqual(len(self.fake_session.message_queue), 0)
  346. def test_handle_msg_update_config(self):
  347. # Update the configuration and check results a few times
  348. # only work the first time
  349. self.__test_handle_msg_update_config_helper({ "test": 123 })
  350. self.__test_handle_msg_update_config_helper({ "test": 124 })
  351. self.__test_handle_msg_update_config_helper({ "test": 125 })
  352. self.__test_handle_msg_update_config_helper({ "test": 126 })
  353. # Now send an error result (i.e. config not accepted)
  354. my_bad_answer = { 'result': [1, "bad config"] }
  355. self.fake_session.group_sendmsg(my_bad_answer, "ConfigManager")
  356. self._handle_msg_helper({ "command": [ "set_config",
  357. [self.name, { "test": 127 }] ] },
  358. my_bad_answer )
  359. self.assertEqual(len(self.fake_session.message_queue), 1)
  360. self.assertEqual({'command': [ 'config_update', {'test': 127}]},
  361. self.fake_session.get_message(self.name, None))
  362. # Config should not be updated due to the error
  363. self.cm.read_config()
  364. self.assertEqual(self.cm.config.data, { self.name: {'test': 126},
  365. 'version': config_data.BIND10_CONFIG_DATA_VERSION})
  366. self.assertEqual(len(self.fake_session.message_queue), 0)
  367. self.fake_session.group_sendmsg(None, 'ConfigManager')
  368. self._handle_msg_helper({ "command": [ "set_config", [ ] ] },
  369. {'result': [1, 'Wrong number of arguments']} )
  370. self._handle_msg_helper({ "command": [ "set_config",
  371. [ self.name, { "test": 128 }]]},
  372. { 'result': [1, 'No answer message '+
  373. 'from TestModule']} )
  374. # This command should leave a message to the TestModule to update its
  375. # configuration (since the TestModule did not eat it)
  376. self.assertEqual(len(self.fake_session.message_queue), 1)
  377. self.assertEqual(
  378. ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
  379. { "test": 128 }),
  380. self.fake_session.get_message("TestModule", None))
  381. # Make sure queue is empty now
  382. self.assertEqual(len(self.fake_session.message_queue), 0)
  383. # Shutdown should result in 'ok' answer
  384. self._handle_msg_helper({ "command":
  385. ["shutdown"]
  386. },
  387. {'result': [0]})
  388. def test_stopping_message(self):
  389. # Update the system by announcing this module
  390. self._handle_msg_helper({ "command":
  391. ["module_spec", self.spec.get_full_spec()]
  392. },
  393. {'result': [0]})
  394. # This causes a update to be sent from the ConfigManager to the CmdCtl
  395. # channel, containing the new module's name and full specification
  396. self.assertEqual(ccsession.create_command(
  397. ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE,
  398. [ self.spec.get_module_name(),
  399. self.spec.get_full_spec()]),
  400. self.fake_session.get_message("Cmdctl", None))
  401. # A stopping message should get no response, but should cause another
  402. # message to be sent, if it is a known module
  403. self._handle_msg_helper({ "command": [ "stopping",
  404. { "module_name": "Spec2"}] },
  405. None)
  406. self.assertEqual(len(self.fake_session.message_queue), 1)
  407. self.assertEqual({'command': [ 'module_specification_update',
  408. ['Spec2', None] ] },
  409. self.fake_session.get_message("Cmdctl", None))
  410. # but if the 'stopping' module is either unknown or not running,
  411. # no followup message should be sent
  412. self._handle_msg_helper({ "command":
  413. [ "stopping",
  414. { "module_name": "NoSuchModule" } ] },
  415. None)
  416. self.assertEqual(len(self.fake_session.message_queue), 0)
  417. def test_set_config_virtual(self):
  418. """Test that if the module is virtual, we don't send it over the
  419. message bus, but call the checking function.
  420. """
  421. # We run the same three times, with different return values
  422. def single_test(value, returnFunc, expectedResult):
  423. # Because closures can't assign to closed-in variables, we pass
  424. # it trough self
  425. self.called_with = None
  426. def check_test(new_data):
  427. self.called_with = new_data
  428. return returnFunc()
  429. # Register our virtual module
  430. self.cm.set_virtual_module(self.spec, check_test)
  431. # The fake session will throw now if it tries to read a response.
  432. # Handy, we don't need to find a complicated way to check for it.
  433. result = self.cm.handle_msg(ccsession.create_command(
  434. ccsession.COMMAND_SET_CONFIG,
  435. [self.spec.get_module_name(), { "item1": value }]))
  436. # Check the correct result is passed and our function was called
  437. # With correct data
  438. self.assertEqual(self.called_with['item1'], value)
  439. self.assertEqual(result, {'result': expectedResult})
  440. if expectedResult[0] == 0:
  441. # Check it provided the correct notification
  442. self.assertEqual(len(self.fake_session.message_queue), 1)
  443. self.assertEqual({'command': [ 'config_update',
  444. {'item1': value}]},
  445. self.fake_session.get_message('Spec2', None))
  446. # and the queue should now be empty again
  447. self.assertEqual(len(self.fake_session.message_queue), 0)
  448. else:
  449. # It shouldn't send anything on error
  450. self.assertEqual(len(self.fake_session.message_queue), 0)
  451. # Success
  452. single_test(5, lambda: None, [0])
  453. # Graceful error
  454. single_test(6, lambda: "Just error", [1, "Just error"])
  455. # Exception from the checker
  456. def raiser():
  457. raise Exception("Just exception")
  458. single_test(7, raiser, [1, "Exception: Just exception"])
  459. def test_set_config_all(self):
  460. my_ok_answer = { 'result': [ 0 ] }
  461. self.assertEqual({"version": 2}, self.cm.config.data)
  462. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  463. self.cm.handle_msg(ccsession.create_command(
  464. ccsession.COMMAND_SET_CONFIG, ["test", { "value1": 123 }]))
  465. self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION,
  466. "test": { "value1": 123 }
  467. }, self.cm.config.data)
  468. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  469. self.cm.handle_msg(ccsession.create_command(
  470. ccsession.COMMAND_SET_CONFIG, ["test", { "value1": 124 }]))
  471. self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION,
  472. "test": { "value1": 124 }
  473. }, self.cm.config.data)
  474. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  475. self.cm.handle_msg(ccsession.create_command(
  476. ccsession.COMMAND_SET_CONFIG, ["test", { "value2": True }]))
  477. self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION,
  478. "test": { "value1": 124,
  479. "value2": True
  480. }
  481. }, self.cm.config.data)
  482. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  483. self.cm.handle_msg(ccsession.create_command(
  484. ccsession.COMMAND_SET_CONFIG, ["test", { "value3": [ 1, 2, 3 ] }]))
  485. self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION,
  486. "test": { "value1": 124,
  487. "value2": True,
  488. "value3": [ 1, 2, 3 ]
  489. }
  490. }, self.cm.config.data)
  491. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  492. self.cm.handle_msg(ccsession.create_command(
  493. ccsession.COMMAND_SET_CONFIG, ["test", { "value2": False }]))
  494. self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION,
  495. "test": { "value1": 124,
  496. "value2": False,
  497. "value3": [ 1, 2, 3 ]
  498. }
  499. }, self.cm.config.data)
  500. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  501. self.cm.handle_msg(ccsession.create_command(
  502. ccsession.COMMAND_SET_CONFIG, ["test", { "value1": None }]))
  503. self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION,
  504. "test": { "value2": False,
  505. "value3": [ 1, 2, 3 ]
  506. }
  507. }, self.cm.config.data)
  508. self.fake_session.group_sendmsg(my_ok_answer, "ConfigManager")
  509. self.cm.handle_msg(ccsession.create_command(
  510. ccsession.COMMAND_SET_CONFIG, ["test", { "value3": [ 1 ] }]))
  511. self.assertEqual({"version": config_data.BIND10_CONFIG_DATA_VERSION,
  512. "test": { "value2": False,
  513. "value3": [ 1 ]
  514. }
  515. }, self.cm.config.data)
  516. def test_run(self):
  517. self.fake_session.group_sendmsg({ "command": [ "get_commands_spec" ] }, "ConfigManager")
  518. self.fake_session.group_sendmsg({ "command": [ "get_statistics_spec" ] }, "ConfigManager")
  519. self.fake_session.group_sendmsg({ "command": [ "stopping", { "module_name": "FooModule" } ] }, "ConfigManager")
  520. self.fake_session.group_sendmsg({ "command": [ "shutdown" ] }, "ConfigManager")
  521. self.assertEqual(len(self.fake_session.message_queue), 4)
  522. self.cm.run()
  523. # All commands should have been read out by run()
  524. # Three of the commands should have been responded to, so the queue
  525. # should now contain three answers
  526. self.assertEqual(len(self.fake_session.message_queue), 3)
  527. if __name__ == '__main__':
  528. if not 'CONFIG_TESTDATA_PATH' in os.environ or not 'CONFIG_WR_TESTDATA_PATH' in os.environ:
  529. 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")
  530. exit(1)
  531. isc.log.init("unittests")
  532. isc.log.resetUnitTestRootLogger()
  533. unittest.main()