zonemgr_test.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  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. '''Tests for the ZonemgrRefresh and Zonemgr classes '''
  16. import unittest
  17. import os
  18. import tempfile
  19. from zonemgr import *
  20. ZONE_NAME_CLASS1_IN = ("example.net.", "IN")
  21. ZONE_NAME_CLASS1_CH = ("example.net.", "CH")
  22. ZONE_NAME_CLASS2_IN = ("example.org.", "IN")
  23. ZONE_NAME_CLASS2_CH = ("example.org.", "CH")
  24. ZONE_NAME_CLASS3_IN = ("example.com.", "IN")
  25. ZONE_NAME_CLASS3_CH = ("example.com.", "CH")
  26. MAX_TRANSFER_TIMEOUT = 14400
  27. LOWERBOUND_REFRESH = 10
  28. LOWERBOUND_RETRY = 5
  29. REFRESH_JITTER = 0.10
  30. RELOAD_JITTER = 0.75
  31. class ZonemgrTestException(Exception):
  32. pass
  33. class MySession():
  34. def __init__(self):
  35. pass
  36. def group_sendmsg(self, msg, module_name):
  37. if module_name not in ("Auth", "Xfrin"):
  38. raise ZonemgrTestException("module name not exist")
  39. def group_recvmsg(self, nonblock, seq):
  40. return None, None
  41. class FakeConfig:
  42. def __init__(self):
  43. self.zone_list = []
  44. self.set_zone_list_from_name_classes([ZONE_NAME_CLASS1_IN,
  45. ZONE_NAME_CLASS2_CH])
  46. def set_zone_list_from_name_classes(self, zones):
  47. self.zone_list = map(lambda nc: {"name": nc[0], "class": nc[1]}, zones)
  48. def get(self, name):
  49. if name == 'lowerbound_refresh':
  50. return LOWERBOUND_REFRESH
  51. elif name == 'lowerbound_retry':
  52. return LOWERBOUND_RETRY
  53. elif name == 'max_transfer_timeout':
  54. return MAX_TRANSFER_TIMEOUT
  55. elif name == 'refresh_jitter':
  56. return REFRESH_JITTER
  57. elif name == 'reload_jitter':
  58. return RELOAD_JITTER
  59. elif name == 'secondary_zones':
  60. return self.zone_list
  61. else:
  62. raise ValueError('Uknown config option')
  63. class MyZonemgrRefresh(ZonemgrRefresh):
  64. def __init__(self):
  65. self._master_socket, self._slave_socket = socket.socketpair()
  66. self._zonemgr_refresh_info = {}
  67. self._lowerbound_refresh = 10
  68. self._lowerbound_retry = 5
  69. self._reload_jitter = 0.75
  70. self._refresh_jitter = 0.25
  71. def get_zone_soa(zone_name, db_file):
  72. if zone_name == 'example.net.':
  73. return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
  74. 'a.example.net. root.example.net. 2009073106 7200 3600 2419200 21600')
  75. elif zone_name == 'example.org.':
  76. return (1, 2, 'example.org.', 'example.org.sd.', 21600, 'SOA', None,
  77. 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600')
  78. else:
  79. return None
  80. sqlite3_ds.get_zone_soa = get_zone_soa
  81. ZonemgrRefresh.__init__(self, MySession(), "initdb.file",
  82. self._slave_socket, FakeConfig())
  83. current_time = time.time()
  84. self._zonemgr_refresh_info = {
  85. ('example.net.', 'IN'): {
  86. 'last_refresh_time': current_time,
  87. 'next_refresh_time': current_time + 6500,
  88. 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
  89. 'zone_state': 0},
  90. ('example.org.', 'CH'): {
  91. 'last_refresh_time': current_time,
  92. 'next_refresh_time': current_time + 6900,
  93. 'zone_soa_rdata': 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600',
  94. 'zone_state': 0}
  95. }
  96. class TestZonemgrRefresh(unittest.TestCase):
  97. def setUp(self):
  98. self.stderr_backup = sys.stderr
  99. sys.stderr = open(os.devnull, 'w')
  100. self.zone_refresh = MyZonemgrRefresh()
  101. def test_random_jitter(self):
  102. max = 100025.120
  103. jitter = 0
  104. self.assertEqual(max, self.zone_refresh._random_jitter(max, jitter))
  105. jitter = 0.3 * max
  106. for i in range (0, 150):
  107. self.assertTrue((max - jitter) <= self.zone_refresh._random_jitter(max, jitter))
  108. self.assertTrue(self.zone_refresh._random_jitter(max, jitter) <= max)
  109. i += 1;
  110. def test_get_current_time(self):
  111. pass
  112. def test_set_zone_timer(self):
  113. max = 3600
  114. jitter = 900
  115. time1 = time.time()
  116. self.zone_refresh._set_zone_timer(ZONE_NAME_CLASS1_IN, 3600, 900)
  117. time2 = time.time()
  118. zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  119. self.assertTrue((3600 - 900) <= (zone_timeout - time1))
  120. self.assertTrue((zone_timeout - time2) <= 3600)
  121. def test_set_zone_refresh_timer(self):
  122. time1 = time.time()
  123. self.zone_refresh._set_zone_refresh_timer(ZONE_NAME_CLASS1_IN)
  124. zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  125. time2 = time.time()
  126. self.assertTrue((time1 + 7200 * (1 - self.zone_refresh._refresh_jitter)) <= zone_timeout)
  127. self.assertTrue(zone_timeout <= time2 + 7200)
  128. def test_set_zone_retry_timer(self):
  129. time1 = time.time()
  130. self.zone_refresh._set_zone_retry_timer(ZONE_NAME_CLASS1_IN)
  131. zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  132. time2 = time.time()
  133. self.assertTrue((time1 + 3600 * (1 - self.zone_refresh._refresh_jitter)) <= zone_timeout)
  134. self.assertTrue(zone_timeout <= time2 + 3600)
  135. def test_zone_not_exist(self):
  136. self.assertFalse(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS1_IN))
  137. self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS1_CH))
  138. self.assertFalse(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS2_CH))
  139. self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS2_IN))
  140. self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS3_IN))
  141. self.assertTrue(self.zone_refresh._zone_not_exist(ZONE_NAME_CLASS3_CH))
  142. def test_set_zone_notify_timer(self):
  143. time1 = time.time()
  144. self.zone_refresh._set_zone_notify_timer(ZONE_NAME_CLASS1_IN)
  145. zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  146. time2 = time.time()
  147. self.assertTrue(time1 <= zone_timeout)
  148. self.assertTrue(zone_timeout <= time2)
  149. def test_zone_is_expired(self):
  150. current_time = time.time()
  151. zone_expired_time = 2419200
  152. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = \
  153. current_time - zone_expired_time - 1
  154. self.assertTrue(self.zone_refresh._zone_is_expired(ZONE_NAME_CLASS1_IN))
  155. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = \
  156. current_time - zone_expired_time + 1
  157. self.assertFalse(self.zone_refresh._zone_is_expired(ZONE_NAME_CLASS1_IN))
  158. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_EXPIRED
  159. self.assertTrue(self.zone_refresh._zone_is_expired(ZONE_NAME_CLASS1_IN))
  160. def test_get_zone_soa_rdata(self):
  161. soa_rdata1 = 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600'
  162. soa_rdata2 = 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600'
  163. self.assertEqual(soa_rdata1, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS1_IN))
  164. self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS1_CH)
  165. self.assertEqual(soa_rdata2, self.zone_refresh._get_zone_soa_rdata(ZONE_NAME_CLASS2_CH))
  166. self.assertRaises(KeyError, self.zone_refresh._get_zone_soa_rdata, ZONE_NAME_CLASS2_IN)
  167. def test_zonemgr_reload_zone(self):
  168. soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
  169. # We need to restore this not to harm other tests
  170. old_get_zone_soa = sqlite3_ds.get_zone_soa
  171. def get_zone_soa(zone_name, db_file):
  172. return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
  173. 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
  174. sqlite3_ds.get_zone_soa = get_zone_soa
  175. self.zone_refresh.zonemgr_reload_zone(ZONE_NAME_CLASS1_IN)
  176. self.assertEqual(soa_rdata, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"])
  177. sqlite3_ds.get_zone_soa = old_get_zone_soa
  178. def test_get_zone_notifier_master(self):
  179. notify_master = "192.168.1.1"
  180. self.assertEqual(None, self.zone_refresh._get_zone_notifier_master(ZONE_NAME_CLASS1_IN))
  181. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"] = notify_master
  182. self.assertEqual(notify_master, self.zone_refresh._get_zone_notifier_master(ZONE_NAME_CLASS1_IN))
  183. def test_set_zone_notifier_master(self):
  184. notify_master = "192.168.1.1"
  185. self.zone_refresh._set_zone_notifier_master(ZONE_NAME_CLASS1_IN, notify_master)
  186. self.assertEqual(self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]\
  187. ["notify_master"], notify_master)
  188. def test_clear_zone_notifier_master(self):
  189. notify_master = "192.168.1.1"
  190. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"] = notify_master
  191. self.zone_refresh._clear_zone_notifier_master(ZONE_NAME_CLASS1_IN)
  192. self.assertFalse("notify_master" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
  193. self.zone_refresh._clear_zone_notifier_master(ZONE_NAME_CLASS2_CH)
  194. self.assertFalse("notify_master" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_CH].keys())
  195. def test_get_zone_state(self):
  196. self.assertEqual(ZONE_OK, self.zone_refresh._get_zone_state(ZONE_NAME_CLASS1_IN))
  197. self.assertEqual(ZONE_OK, self.zone_refresh._get_zone_state(ZONE_NAME_CLASS2_CH))
  198. def test_set_zone_state(self):
  199. self.zone_refresh._set_zone_state(ZONE_NAME_CLASS1_IN, ZONE_REFRESHING)
  200. self.zone_refresh._set_zone_state(ZONE_NAME_CLASS2_CH, ZONE_EXPIRED)
  201. self.assertEqual(ZONE_REFRESHING, \
  202. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
  203. self.assertEqual(ZONE_EXPIRED, \
  204. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_CH]["zone_state"])
  205. def test_get_zone_refresh_timeout(self):
  206. current_time = time.time()
  207. self.assertFalse("refresh_timeout" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
  208. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"] = current_time
  209. self.assertEqual(current_time, self.zone_refresh._get_zone_refresh_timeout(ZONE_NAME_CLASS1_IN))
  210. def test_set_zone_refresh_timeout(self):
  211. current_time = time.time()
  212. self.zone_refresh._set_zone_refresh_timeout(ZONE_NAME_CLASS1_IN, current_time)
  213. refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"]
  214. self.assertEqual(current_time, refresh_time)
  215. def test_get_zone_next_refresh_time(self):
  216. current_time = time.time()
  217. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"] = current_time
  218. self.assertEqual(current_time, self.zone_refresh._get_zone_next_refresh_time(ZONE_NAME_CLASS1_IN))
  219. def test_set_zone_next_refresh_time(self):
  220. current_time = time.time()
  221. self.zone_refresh._set_zone_next_refresh_time(ZONE_NAME_CLASS1_IN, current_time)
  222. next_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  223. self.assertEqual(current_time, next_refresh_time)
  224. def test_get_zone_last_refresh_time(self):
  225. current_time = time.time()
  226. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = current_time
  227. self.assertEqual(current_time, self.zone_refresh._get_zone_last_refresh_time(ZONE_NAME_CLASS1_IN))
  228. def test_set_zone_last_refresh_time(self):
  229. current_time = time.time()
  230. self.zone_refresh._set_zone_last_refresh_time(ZONE_NAME_CLASS1_IN, current_time)
  231. last_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"]
  232. self.assertEqual(current_time, last_refresh_time)
  233. def test_send_command(self):
  234. self.assertRaises(ZonemgrTestException, self.zone_refresh._send_command, "Unknown", "Notify", None)
  235. def test_zone_mgr_is_empty(self):
  236. self.assertFalse(self.zone_refresh._zone_mgr_is_empty())
  237. self.zone_refresh._zonemgr_refresh_info = {}
  238. self.assertTrue(self.zone_refresh._zone_mgr_is_empty())
  239. def test_zonemgr_add_zone(self):
  240. soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
  241. # This needs to be restored. The following test actually failed if we left
  242. # this unclean
  243. old_get_zone_soa = sqlite3_ds.get_zone_soa
  244. time1 = time.time()
  245. def get_zone_soa(zone_name, db_file):
  246. return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
  247. 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
  248. sqlite3_ds.get_zone_soa = get_zone_soa
  249. self.zone_refresh._zonemgr_refresh_info = {}
  250. self.zone_refresh.zonemgr_add_zone(ZONE_NAME_CLASS1_IN)
  251. self.assertEqual(1, len(self.zone_refresh._zonemgr_refresh_info))
  252. zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"]
  253. self.assertEqual(soa_rdata, zone_soa_rdata)
  254. self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
  255. self.assertTrue("last_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
  256. self.assertTrue("next_refresh_time" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
  257. time2 = time.time()
  258. zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  259. self.assertTrue((time1 + 900 * (1 - self.zone_refresh._reload_jitter)) <= zone_timeout)
  260. self.assertTrue(zone_timeout <= time2 + 900)
  261. def get_zone_soa2(zone_name, db_file):
  262. return None
  263. sqlite3_ds.get_zone_soa = get_zone_soa2
  264. self.assertRaises(ZonemgrException, self.zone_refresh.zonemgr_add_zone, \
  265. ZONE_NAME_CLASS1_IN)
  266. sqlite3_ds.get_zone_soa = old_get_zone_soa
  267. def test_zone_handle_notify(self):
  268. self.zone_refresh.zone_handle_notify(ZONE_NAME_CLASS1_IN,"127.0.0.1")
  269. notify_master = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"]
  270. self.assertEqual("127.0.0.1", notify_master)
  271. zone_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  272. current_time = time.time()
  273. self.assertTrue(zone_timeout <= current_time)
  274. self.assertRaises(ZonemgrException, self.zone_refresh.zone_handle_notify,\
  275. ZONE_NAME_CLASS3_CH, "127.0.0.1")
  276. self.assertRaises(ZonemgrException, self.zone_refresh.zone_handle_notify,\
  277. ZONE_NAME_CLASS3_IN, "127.0.0.1")
  278. def test_zone_refresh_success(self):
  279. soa_rdata = 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600'
  280. def get_zone_soa(zone_name, db_file):
  281. return (1, 2, 'example.net.', 'example.net.sd.', 21600, 'SOA', None,
  282. 'a.example.net. root.example.net. 2009073106 1800 900 2419200 21600')
  283. sqlite3_ds.get_zone_soa = get_zone_soa
  284. time1 = time.time()
  285. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
  286. self.zone_refresh.zone_refresh_success(ZONE_NAME_CLASS1_IN)
  287. time2 = time.time()
  288. zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"]
  289. self.assertEqual(soa_rdata, zone_soa_rdata)
  290. next_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  291. self.assertTrue((time1 + 1800 * (1 - self.zone_refresh._refresh_jitter)) <= next_refresh_time)
  292. self.assertTrue(next_refresh_time <= time2 + 1800)
  293. self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
  294. last_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"]
  295. self.assertTrue(time1 <= last_refresh_time)
  296. self.assertTrue(last_refresh_time <= time2)
  297. self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ("example.test.", "CH"))
  298. self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_success, ZONE_NAME_CLASS3_IN)
  299. def test_zone_refresh_fail(self):
  300. soa_rdata = 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600'
  301. time1 = time.time()
  302. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"] = ZONE_REFRESHING
  303. self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
  304. time2 = time.time()
  305. zone_soa_rdata = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"]
  306. self.assertEqual(soa_rdata, zone_soa_rdata)
  307. next_refresh_time = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["next_refresh_time"]
  308. self.assertTrue(((time1 + 3600 * (1 - self.zone_refresh._refresh_jitter))) <= next_refresh_time)
  309. self.assertTrue(next_refresh_time <= time2 + 3600)
  310. self.assertEqual(ZONE_OK, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
  311. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["last_refresh_time"] = time1 - 2419200
  312. self.zone_refresh.zone_refresh_fail(ZONE_NAME_CLASS1_IN)
  313. self.assertEqual(ZONE_EXPIRED, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"])
  314. self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_CH)
  315. self.assertRaises(ZonemgrException, self.zone_refresh.zone_refresh_fail, ZONE_NAME_CLASS3_IN)
  316. def test_find_need_do_refresh_zone(self):
  317. time1 = time.time()
  318. self.zone_refresh._zonemgr_refresh_info = {
  319. ("example.net.","IN"):{
  320. 'last_refresh_time': time1,
  321. 'next_refresh_time': time1 + 7200,
  322. 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
  323. 'zone_state': ZONE_OK},
  324. ("example.org.","CH"):{
  325. 'last_refresh_time': time1 - 7200,
  326. 'next_refresh_time': time1,
  327. 'refresh_timeout': time1 + MAX_TRANSFER_TIMEOUT,
  328. 'zone_soa_rdata': 'a.example.org. root.example.org. 2009073112 7200 3600 2419200 21600',
  329. 'zone_state': ZONE_REFRESHING}
  330. }
  331. zone_need_refresh = self.zone_refresh._find_need_do_refresh_zone()
  332. self.assertEqual(ZONE_NAME_CLASS1_IN, zone_need_refresh)
  333. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS2_CH]["refresh_timeout"] = time1
  334. zone_need_refresh = self.zone_refresh._find_need_do_refresh_zone()
  335. self.assertEqual(ZONE_NAME_CLASS2_CH, zone_need_refresh)
  336. def test_do_refresh(self):
  337. time1 = time.time()
  338. self.zone_refresh._zonemgr_refresh_info = {
  339. ("example.net.", "IN"):{
  340. 'last_refresh_time': time1 - 7200,
  341. 'next_refresh_time': time1 - 1,
  342. 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
  343. 'zone_state': ZONE_OK}
  344. }
  345. self.zone_refresh._do_refresh(ZONE_NAME_CLASS1_IN)
  346. time2 = time.time()
  347. zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]
  348. self.assertEqual(ZONE_REFRESHING, zone_state)
  349. refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"]
  350. self.assertTrue(time1 + MAX_TRANSFER_TIMEOUT <= refresh_timeout)
  351. self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout)
  352. self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["notify_master"] = "127.0.0.1"
  353. self.zone_refresh._do_refresh(ZONE_NAME_CLASS1_IN)
  354. time2 = time.time()
  355. zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]
  356. self.assertEqual(ZONE_REFRESHING, zone_state)
  357. refresh_timeout = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["refresh_timeout"]
  358. self.assertTrue(time1 + MAX_TRANSFER_TIMEOUT <= refresh_timeout)
  359. self.assertTrue(time2 + MAX_TRANSFER_TIMEOUT >= refresh_timeout)
  360. self.assertFalse("notify_master" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
  361. def test_run_timer(self):
  362. """This case will run timer in daemon thread.
  363. The zone's next_refresh_time is less than now, so zonemgr will do zone refresh
  364. immediately. The zone's state will become "refreshing".
  365. """
  366. time1 = time.time()
  367. self.zone_refresh._zonemgr_refresh_info = {
  368. ("example.net.", "IN"):{
  369. 'last_refresh_time': time1 - 7200,
  370. 'next_refresh_time': time1 - 1,
  371. 'zone_soa_rdata': 'a.example.net. root.example.net. 2009073105 7200 3600 2419200 21600',
  372. 'zone_state': ZONE_OK}
  373. }
  374. self.zone_refresh._check_sock = self.zone_refresh._master_socket
  375. listener = self.zone_refresh.run_timer(daemon=True)
  376. # Shut down the timer thread
  377. self.zone_refresh.shutdown()
  378. # After running timer, the zone's state should become "refreshing".
  379. zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]
  380. self.assertTrue("refresh_timeout" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
  381. self.assertTrue(zone_state == ZONE_REFRESHING)
  382. def test_update_config_data(self):
  383. # make sure it doesn't fail if we only provide secondary zones
  384. config_data = {
  385. "secondary_zones": [ { "name": "example.net.",
  386. "class": "IN" } ]
  387. }
  388. self.zone_refresh.update_config_data(config_data)
  389. # update all values
  390. config_data = {
  391. "lowerbound_refresh" : 60,
  392. "lowerbound_retry" : 30,
  393. "max_transfer_timeout" : 19800,
  394. "refresh_jitter" : 0.25,
  395. "reload_jitter" : 0.75,
  396. "secondary_zones": []
  397. }
  398. self.zone_refresh.update_config_data(config_data)
  399. self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
  400. self.assertEqual(30, self.zone_refresh._lowerbound_retry)
  401. self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
  402. self.assertEqual(0.25, self.zone_refresh._refresh_jitter)
  403. self.assertEqual(0.75, self.zone_refresh._reload_jitter)
  404. # make sure they are not reset when we only update one
  405. config_data = {
  406. "reload_jitter" : 0.35,
  407. }
  408. self.zone_refresh.update_config_data(config_data)
  409. self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
  410. self.assertEqual(30, self.zone_refresh._lowerbound_retry)
  411. self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
  412. self.assertEqual(0.25, self.zone_refresh._refresh_jitter)
  413. self.assertEqual(0.35, self.zone_refresh._reload_jitter)
  414. # and make sure we restore the previous config if something
  415. # goes wrong
  416. config_data = {
  417. "lowerbound_refresh" : 61,
  418. "lowerbound_retry" : 31,
  419. "max_transfer_timeout" : 19801,
  420. "refresh_jitter" : 0.21,
  421. "reload_jitter" : 0.71,
  422. "secondary_zones": [ { "name": "doesnotexist",
  423. "class": "IN" } ]
  424. }
  425. self.assertRaises(ZonemgrException,
  426. self.zone_refresh.update_config_data,
  427. config_data)
  428. self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
  429. self.assertEqual(30, self.zone_refresh._lowerbound_retry)
  430. self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
  431. self.assertEqual(0.25, self.zone_refresh._refresh_jitter)
  432. self.assertEqual(0.35, self.zone_refresh._reload_jitter)
  433. # Make sure we accept 0 as a value
  434. config_data = {
  435. "lowerbound_refresh" : 60,
  436. "lowerbound_retry" : 30,
  437. "max_transfer_timeout" : 19800,
  438. "refresh_jitter" : 0,
  439. "reload_jitter" : 0.75,
  440. "secondary_zones": []
  441. }
  442. self.zone_refresh.update_config_data(config_data)
  443. self.assertEqual(60, self.zone_refresh._lowerbound_refresh)
  444. self.assertEqual(30, self.zone_refresh._lowerbound_retry)
  445. self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
  446. self.assertEqual(0, self.zone_refresh._refresh_jitter)
  447. self.assertEqual(0.75, self.zone_refresh._reload_jitter)
  448. def test_shutdown(self):
  449. self.zone_refresh._check_sock = self.zone_refresh._master_socket
  450. listener = self.zone_refresh.run_timer()
  451. self.assertTrue(listener.is_alive())
  452. # Shut down the timer thread
  453. self.zone_refresh.shutdown()
  454. self.assertFalse(listener.is_alive())
  455. def test_secondary_zones(self):
  456. """Test that we can modify the list of secondary zones"""
  457. config = FakeConfig()
  458. config.zone_list = []
  459. # First, remove everything
  460. self.zone_refresh.update_config_data(config)
  461. self.assertEqual(self.zone_refresh._zonemgr_refresh_info, {})
  462. # Put something in
  463. config.set_zone_list_from_name_classes([ZONE_NAME_CLASS1_IN])
  464. self.zone_refresh.update_config_data(config)
  465. self.assertTrue(("example.net.", "IN") in
  466. self.zone_refresh._zonemgr_refresh_info)
  467. # This one does not exist
  468. config.set_zone_list_from_name_classes(["example.net", "CH"])
  469. self.assertRaises(ZonemgrException,
  470. self.zone_refresh.update_config_data, config)
  471. # So it should not affect the old ones
  472. self.assertTrue(("example.net.", "IN") in
  473. self.zone_refresh._zonemgr_refresh_info)
  474. # Make sure it works even when we "accidentally" forget the final dot
  475. config.set_zone_list_from_name_classes([("example.net", "IN")])
  476. self.zone_refresh.update_config_data(config)
  477. self.assertTrue(("example.net.", "IN") in
  478. self.zone_refresh._zonemgr_refresh_info)
  479. def tearDown(self):
  480. sys.stderr= self.stderr_backup
  481. class MyCCSession():
  482. def __init__(self):
  483. pass
  484. def get_remote_config_value(self, module_name, identifier):
  485. if module_name == "Auth" and identifier == "database_file":
  486. return "initdb.file", False
  487. else:
  488. return "unknown", False
  489. class MyZonemgr(Zonemgr):
  490. def __init__(self):
  491. self._db_file = "initdb.file"
  492. self._zone_refresh = None
  493. self._shutdown_event = threading.Event()
  494. self._cc = MySession()
  495. self._module_cc = MyCCSession()
  496. self._config_data = {
  497. "lowerbound_refresh" : 10,
  498. "lowerbound_retry" : 5,
  499. "max_transfer_timeout" : 14400,
  500. "refresh_jitter" : 0.1,
  501. "reload_jitter" : 0.75,
  502. "secondary_zones": []
  503. }
  504. def _start_zone_refresh_timer(self):
  505. pass
  506. class TestZonemgr(unittest.TestCase):
  507. def setUp(self):
  508. self.zonemgr = MyZonemgr()
  509. def test_config_handler(self):
  510. config_data1 = {
  511. "lowerbound_refresh" : 60,
  512. "lowerbound_retry" : 30,
  513. "max_transfer_timeout" : 14400,
  514. "refresh_jitter" : 0.1,
  515. "reload_jitter" : 0.75,
  516. "secondary_zones": []
  517. }
  518. self.assertEqual(self.zonemgr.config_handler(config_data1),
  519. {"result": [0]})
  520. self.assertEqual(config_data1, self.zonemgr._config_data)
  521. config_data2 = {"zone_name" : "example.net.", "port" : "53", "master" : "192.168.1.1"}
  522. self.zonemgr.config_handler(config_data2)
  523. self.assertEqual(config_data1, self.zonemgr._config_data)
  524. # jitter should not be bigger than half of the original value
  525. config_data3 = {"refresh_jitter" : 0.7}
  526. self.zonemgr.config_handler(config_data3)
  527. self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
  528. # The zone doesn't exist in database, it should be rejected
  529. self.zonemgr._zone_refresh = ZonemgrRefresh(None, "initdb.file", None,
  530. config_data1)
  531. config_data1["secondary_zones"] = [{"name": "nonexistent.example",
  532. "class": "IN"}]
  533. self.assertNotEqual(self.zonemgr.config_handler(config_data1),
  534. {"result": [0]})
  535. # As it is rejected, the old value should be kept
  536. self.assertEqual(0.5, self.zonemgr._config_data.get("refresh_jitter"))
  537. def test_get_db_file(self):
  538. self.assertEqual("initdb.file", self.zonemgr.get_db_file())
  539. def test_parse_cmd_params(self):
  540. params1 = {"zone_name" : "example.com.", "zone_class" : "CH", "master" : "127.0.0.1"}
  541. answer1 = (ZONE_NAME_CLASS3_CH, "127.0.0.1")
  542. self.assertEqual(answer1, self.zonemgr._parse_cmd_params(params1, ZONE_NOTIFY_COMMAND))
  543. params2 = {"zone_name" : "example.com.", "zone_class" : "IN"}
  544. answer2 = ZONE_NAME_CLASS3_IN
  545. self.assertEqual(answer2, self.zonemgr._parse_cmd_params(params2, ZONE_XFRIN_SUCCESS_COMMAND))
  546. self.assertRaises(ZonemgrException, self.zonemgr._parse_cmd_params, params2, ZONE_NOTIFY_COMMAND)
  547. params1 = {"zone_class" : "CH"}
  548. self.assertRaises(ZonemgrException, self.zonemgr._parse_cmd_params, params2, ZONE_NOTIFY_COMMAND)
  549. def test_config_data_check(self):
  550. # jitter should not be bigger than half of the original value
  551. config_data2 = {"refresh_jitter" : 0.2}
  552. config_data3 = {"refresh_jitter" : 0.6}
  553. self.zonemgr._config_data_check(config_data2)
  554. self.assertEqual(0.2, config_data2.get("refresh_jitter"))
  555. self.zonemgr._config_data_check(config_data3)
  556. self.assertEqual(0.5, config_data3.get("refresh_jitter"))
  557. def tearDown(self):
  558. pass
  559. if __name__== "__main__":
  560. unittest.main()