counter_test.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. # Copyright (C) 2012 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 isc.statistics.counter'''
  16. import unittest
  17. import threading
  18. from datetime import timedelta
  19. import os
  20. import imp
  21. import isc.config
  22. TEST_ZONE_NAME_STR = "example.com."
  23. TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
  24. from isc.statistics import counter
  25. def setup_functor(event, cycle, functor, *args):
  26. """Waits until the event is started, and then invokes the functor
  27. by times of the cycle with args."""
  28. event.wait()
  29. for i in range(cycle): functor(*args)
  30. def start_functor(number, cycle, functor, *args):
  31. """Creates the threads of the number and makes them start. Sets
  32. the event and waits until these threads are finished."""
  33. threads = []
  34. event = threading.Event()
  35. for i in range(number):
  36. threads.append(threading.Thread(\
  37. target=setup_functor, \
  38. args=(event, cycle, functor,) + args))
  39. for th in threads: th.start()
  40. event.set()
  41. for th in threads: th.join()
  42. class TestBasicMethods(unittest.TestCase):
  43. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec1.spec'
  44. def setUp(self):
  45. self.counter = counter.Counter(self.TEST_SPECFILE_LOCATION)
  46. def tearDown(self):
  47. self.counter.clear_counters()
  48. def test_clear_counters(self):
  49. self.counter._statistics_data = {'counter': 1}
  50. self.counter.clear_counters()
  51. self.assertEqual(self.counter._statistics_data,
  52. {})
  53. def test_enablediable(self):
  54. self.assertFalse(self.counter._disabled)
  55. self.counter.disable()
  56. self.assertTrue(self.counter._disabled)
  57. self.counter.enable()
  58. self.assertFalse(self.counter._disabled)
  59. def test_add_counter_normal(self):
  60. element = {'counter' : 1}
  61. self.assertEqual(\
  62. counter._add_counter(element, [], 'counter'), 1)
  63. def test_add_counter_wrongspec(self):
  64. self.assertRaises(isc.cc.data.DataNotFoundError,
  65. counter._add_counter,
  66. {}, [], 'counter')
  67. def test_add_counter_empty(self):
  68. self.assertEqual(\
  69. counter._add_counter(
  70. {},
  71. [ { 'item_name' : 'counter',
  72. 'item_type' : 'integer',
  73. 'item_default' : 0 } ],
  74. 'counter'), 0)
  75. def test_add_counter_empty_namedset(self):
  76. elem = {}
  77. spec = [ { 'item_name': 'dirs',
  78. 'item_type': 'named_set',
  79. 'named_set_item_spec': {
  80. 'item_name': 'dir',
  81. 'item_type': 'map',
  82. 'map_item_spec': [
  83. { 'item_name': 'counter1',
  84. 'item_type': 'integer',
  85. 'item_default': 0 },
  86. { 'item_name': 'counter2',
  87. 'item_type': 'integer',
  88. 'item_default': 0 } ]}
  89. }]
  90. self.assertEqual(\
  91. counter._add_counter(elem, spec, 'dirs/foo/counter1'), 0)
  92. self.assertEqual(\
  93. counter._add_counter(elem, spec, 'dirs/bar/counter2'), 0)
  94. def test_timer(self):
  95. t1 = counter._start_timer()
  96. t2 = t1 - timedelta(seconds=1)
  97. self.assertEqual((t1 - t2).seconds, 1)
  98. elem = {}
  99. spec = [{ 'item_name': 'time',
  100. 'item_type': 'real',
  101. 'item_default': 0.0 }]
  102. counter._stop_timer(t2, elem, spec, 'time')
  103. self.assertGreater(counter._get_counter(elem,'time'), 1)
  104. def test_rasing_incrementers(self):
  105. """ use Thread"""
  106. number = 3 # number of the threads
  107. cycle = 10000 # number of counting per thread
  108. statistics_data = {}
  109. counter_name = "counter"
  110. timer_name = "seconds"
  111. statistics_spec = \
  112. isc.config.module_spec_from_file(self.TEST_SPECFILE_LOCATION)\
  113. .get_statistics_spec()
  114. self.counter._statistics_data = statistics_data
  115. self.counter._statistics_spec = statistics_spec
  116. start_time = counter._start_timer()
  117. start_functor(number, cycle, self.counter._incrementer,
  118. counter_name)
  119. counter._stop_timer(start_time,
  120. statistics_data,
  121. statistics_spec,
  122. timer_name)
  123. self.assertEqual(
  124. counter._get_counter(statistics_data,
  125. counter_name),
  126. number * cycle)
  127. self.assertGreater(
  128. counter._get_counter(statistics_data,
  129. timer_name), 0)
  130. class BaseTestCounter():
  131. def setUp(self):
  132. self._statistics_data = {}
  133. self.counter = counter.Counter(self.TEST_SPECFILE_LOCATION)
  134. self._entire_server = self.counter._entire_server
  135. self._perzone_prefix = self.counter._perzone_prefix
  136. def tearDown(self):
  137. self.counter.clear_counters()
  138. def check_dump_statistics(self):
  139. """Checks no differences between the value returned from
  140. dump_statistics() and locally collected statistics data. Also
  141. checks the result isn't changed even after the method is
  142. invoked twice. Finally checks it is valid for the the
  143. statistics spec."""
  144. self.assertEqual(self.counter.dump_statistics(),
  145. self._statistics_data)
  146. # Idempotency check
  147. self.assertEqual(self.counter.dump_statistics(),
  148. self._statistics_data)
  149. if self.TEST_SPECFILE_LOCATION:
  150. self.assertTrue(isc.config.module_spec_from_file(
  151. self.TEST_SPECFILE_LOCATION).validate_statistics(
  152. False, self._statistics_data))
  153. else:
  154. self.assertTrue(isc.config.ModuleSpec(
  155. {'module_name': 'Foo',
  156. 'statistics': self.counter._statistics._spec}
  157. ).validate_statistics(
  158. False, self._statistics_data))
  159. def test_perzone_counters(self):
  160. # for per-zone counters
  161. for name in self.counter._zones_item_list:
  162. args = (self._perzone_prefix, TEST_ZONE_NAME_STR, name)
  163. if name.find('time_to_') == 0:
  164. self.counter.start(*args)
  165. self.counter.stop(*args)
  166. self.assertGreater(self.counter.get(*args), 0)
  167. sec = self.counter.get(*args)
  168. for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
  169. isc.cc.data.set(self._statistics_data,
  170. '%s/%s/%s' % (args[0], zone_str, name), sec)
  171. # twice exec stopper, then second is not changed
  172. self.counter.stop(*args)
  173. self.assertEqual(self.counter.get(*args), sec)
  174. else:
  175. self.counter.inc(*args)
  176. self.assertEqual(self.counter.get(*args), 1)
  177. # checks disable/enable
  178. self.counter.disable()
  179. self.counter.inc(*args)
  180. self.assertEqual(self.counter.get(*args), 1)
  181. self.counter.enable()
  182. self.counter.inc(*args)
  183. self.assertEqual(self.counter.get(*args), 2)
  184. for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
  185. isc.cc.data.set(self._statistics_data,
  186. '%s/%s/%s' % (args[0], zone_str, name), 2)
  187. self.check_dump_statistics()
  188. def test_xfrrunning_counters(self):
  189. # for counters of xfer running
  190. _suffix = 'xfr_running'
  191. _xfrrunning_names = \
  192. isc.config.spec_name_list(self.counter._statistics._spec,
  193. "", True)
  194. for name in _xfrrunning_names:
  195. if name.find(_suffix) != 1: continue
  196. args = name.split('/')
  197. self.counter.inc(*args)
  198. self.assertEqual(self.counter.get(*args), 1)
  199. self.counter.dec(*args)
  200. self.assertEqual(self.counter.get(*args), 0)
  201. # checks disable/enable
  202. self.counter.disable()
  203. self.counter.inc(*args)
  204. self.assertEqual(self.counter.get(*args), 0)
  205. self.counter.enable()
  206. self.counter.inc(*args)
  207. self.assertEqual(self.counter.get(*args), 1)
  208. self.counter.disable()
  209. self.counter.dec(*args)
  210. self.assertEqual(self.counter.get(*args), 1)
  211. self.counter.enable()
  212. self.counter.dec(*args)
  213. self.assertEqual(self.counter.get(*args), 0)
  214. self._statistics_data[name] = 0
  215. self.check_dump_statistics()
  216. def test_socket_counters(self):
  217. # for ipsocket/unixsocket counters
  218. _prefix = 'socket/'
  219. _socket_names = \
  220. isc.config.spec_name_list(self.counter._statistics._spec,
  221. "", True)
  222. for name in _socket_names:
  223. if name.find(_prefix) != 0: continue
  224. args = name.split('/')
  225. self.counter.inc(*args)
  226. self.assertEqual(self.counter.get(*args), 1)
  227. # checks disable/enable
  228. self.counter.disable()
  229. self.counter.inc(*args)
  230. self.assertEqual(self.counter.get(*args), 1)
  231. self.counter.enable()
  232. self.counter.inc(*args)
  233. self.assertEqual(self.counter.get(*args), 2)
  234. isc.cc.data.set(
  235. self._statistics_data, '/'.join(args), 2)
  236. self.check_dump_statistics()
  237. def test_undefined_item(self):
  238. # test DataNotFoundError raising when specifying item defined
  239. # in the specfile
  240. self.assertRaises(isc.cc.data.DataNotFoundError,
  241. self.counter.inc, '__undefined__')
  242. self.assertRaises(isc.cc.data.DataNotFoundError,
  243. self.counter.dec, '__undefined__')
  244. self.counter.start('__undefined__')
  245. self.assertRaises(isc.cc.data.DataNotFoundError,
  246. self.counter.stop, '__undefined__')
  247. self.assertRaises(isc.cc.data.DataNotFoundError,
  248. self.counter.get, '__undefined__')
  249. class TestCounter0(unittest.TestCase, BaseTestCounter):
  250. TEST_SPECFILE_LOCATION = None
  251. def setUp(self):
  252. BaseTestCounter.setUp(self)
  253. def tearDown(self):
  254. BaseTestCounter.tearDown(self)
  255. class TestCounter1(unittest.TestCase, BaseTestCounter):
  256. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec1.spec'
  257. def setUp(self):
  258. BaseTestCounter.setUp(self)
  259. def tearDown(self):
  260. BaseTestCounter.tearDown(self)
  261. class TestCounter2(unittest.TestCase, BaseTestCounter):
  262. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec2.spec'
  263. def setUp(self):
  264. BaseTestCounter.setUp(self)
  265. def tearDown(self):
  266. BaseTestCounter.tearDown(self)
  267. class TestCounter3(unittest.TestCase, BaseTestCounter):
  268. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec3.spec'
  269. def setUp(self):
  270. BaseTestCounter.setUp(self)
  271. def tearDown(self):
  272. BaseTestCounter.tearDown(self)
  273. if __name__== "__main__":
  274. unittest.main()