counter_test.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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.init(self.TEST_SPECFILE_LOCATION)
  46. self._statistics_data = {}
  47. self._start_time = {}
  48. self._counter_name = "counter"
  49. self._timer_name = "seconds"
  50. self._statistics_spec = [{ "item_name": self._counter_name,
  51. "item_type": "integer",
  52. "item_optional": False,
  53. "item_default": 0 },
  54. { "item_name": self._timer_name,
  55. "item_type": "real",
  56. "item_optional": False,
  57. "item_default": 0.0 }]
  58. def tearDown(self):
  59. self.counter.clear_counters()
  60. def test_clear_counters(self):
  61. self.counter._statistics_data = {'counter': 1}
  62. self.counter.clear_counters()
  63. self.assertEqual(self.counter._statistics_data,
  64. {})
  65. def test_enablediable(self):
  66. self.assertFalse(self.counter._disabled)
  67. self.counter.disable()
  68. self.assertTrue(self.counter._disabled)
  69. self.counter.enable()
  70. self.assertFalse(self.counter._disabled)
  71. def test_add_counter_normal(self):
  72. element = {'counter' : 1}
  73. self.assertEqual(\
  74. counter._add_counter(element, [], 'counter'), 1)
  75. def test_add_counter_wrongspec(self):
  76. self.assertRaises(isc.cc.data.DataNotFoundError,
  77. counter._add_counter,
  78. {}, [], 'counter')
  79. def test_add_counter_empty(self):
  80. self.assertEqual(\
  81. counter._add_counter(
  82. {},
  83. [ { 'item_name' : 'counter',
  84. 'item_type' : 'integer',
  85. 'item_default' : 0 } ],
  86. 'counter'), 0)
  87. def test_add_counter_empty_namedset(self):
  88. elem = {}
  89. spec = [ { 'item_name': 'dirs',
  90. 'item_type': 'named_set',
  91. 'named_set_item_spec': {
  92. 'item_name': 'dir',
  93. 'item_type': 'map',
  94. 'map_item_spec': [
  95. { 'item_name': 'counter1',
  96. 'item_type': 'integer',
  97. 'item_default': 0 },
  98. { 'item_name': 'counter2',
  99. 'item_type': 'integer',
  100. 'item_default': 0 } ]}
  101. }]
  102. self.assertEqual(\
  103. counter._add_counter(elem, spec, 'dirs/foo/counter1'), 0)
  104. self.assertEqual(\
  105. counter._add_counter(elem, spec, 'dirs/bar/counter2'), 0)
  106. def test_timer(self):
  107. t1 = counter._start_timer()
  108. t2 = t1 - timedelta(seconds=1)
  109. self.assertEqual((t1 - t2).seconds, 1)
  110. elem = {}
  111. spec = [{ 'item_name': 'time',
  112. 'item_type': 'real',
  113. 'item_default': 0.0 }]
  114. counter._stop_timer(t2, elem, spec, 'time')
  115. self.assertGreater(counter._get_counter(elem,'time'), 1)
  116. def test_rasing_incrementers(self):
  117. """ use Thread"""
  118. number = 3 # number of the threads
  119. cycle = 10000 # number of counting per thread
  120. self.counter._statistics_data = self._statistics_data
  121. self.counter._statistics_spec = self._statistics_spec
  122. self._start_time = counter._start_timer()
  123. start_functor(number, cycle, self.counter._incrementer,
  124. self._counter_name)
  125. counter._stop_timer(self._start_time,
  126. self._statistics_data,
  127. self._statistics_spec,
  128. self._timer_name)
  129. self.assertEqual(
  130. counter._get_counter(self._statistics_data,
  131. self._counter_name),
  132. number * cycle)
  133. self.assertGreater(
  134. counter._get_counter(self._statistics_data,
  135. self._timer_name), 0)
  136. class BaseTestCounter():
  137. imp.reload(counter)
  138. def setUp(self):
  139. self._module_spec = isc.config.module_spec_from_file(
  140. self.TEST_SPECFILE_LOCATION)
  141. self.counter = counter.init(self.TEST_SPECFILE_LOCATION)
  142. self._statistics_data = {}
  143. self._entire_server = self.counter._entire_server
  144. self._perzone_prefix = self.counter._perzone_prefix
  145. self._xfrrunning_names = self.counter._xfrrunning_names
  146. self._unixsocket_names = self.counter._unixsocket_names
  147. self._ipsocket_names = self.counter._ipsocket_names
  148. self._zones_item_list = self.counter._zones_item_list
  149. self._started = threading.Event()
  150. def test_perzone_counters(self):
  151. # for per-zone counters
  152. for counter_name in self._zones_item_list:
  153. if counter_name.find('time_to_') == 0:
  154. isc.cc.data.set(\
  155. self._statistics_data,
  156. '%s/%s/%s' % (self._perzone_prefix,
  157. TEST_ZONE_NAME_STR,
  158. counter_name), 0.0)
  159. continue
  160. incrementer = self.counter._to_global\
  161. ['inc_%s' % counter_name]
  162. getter = self.counter._to_global\
  163. ['get_%s' % counter_name]
  164. incrementer(TEST_ZONE_NAME_STR)
  165. self.assertEqual(getter(TEST_ZONE_NAME_STR), 1)
  166. # checks disable/enable
  167. self.counter.disable()
  168. incrementer(TEST_ZONE_NAME_STR)
  169. self.assertEqual(getter(TEST_ZONE_NAME_STR), 1)
  170. self.counter.enable()
  171. incrementer(TEST_ZONE_NAME_STR)
  172. self.assertEqual(getter(TEST_ZONE_NAME_STR), 2)
  173. for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
  174. isc.cc.data.set(\
  175. self._statistics_data,
  176. '%s/%s/%s' % (self._perzone_prefix,
  177. zone_str,
  178. counter_name), 2)
  179. # checks other counters
  180. for counter_name in self._zones_item_list:
  181. getter = self.counter._to_global\
  182. ['get_%s' % counter_name]
  183. self.assertGreaterEqual(getter(TEST_ZONE_NAME_STR), 0)
  184. self.check_dump_statistics()
  185. def test_xfrrunning_counters(self):
  186. # for counters of xfer running
  187. for counter_name in self._xfrrunning_names:
  188. incrementer = self.counter._to_global\
  189. ['inc_%s' % counter_name]
  190. getter = self.counter._to_global\
  191. ['get_%s' % counter_name]
  192. decrementer = self.counter._to_global\
  193. ['dec_%s' % counter_name]
  194. incrementer()
  195. self.assertEqual(getter(), 1)
  196. decrementer()
  197. self.assertEqual(getter(), 0)
  198. # checks disable/enable
  199. self.counter.disable()
  200. incrementer()
  201. self.assertEqual(getter(), 0)
  202. self.counter.enable()
  203. incrementer()
  204. self.assertEqual(getter(), 1)
  205. self.counter.disable()
  206. decrementer()
  207. self.assertEqual(getter(), 1)
  208. self.counter.enable()
  209. decrementer()
  210. self.assertEqual(getter(), 0)
  211. self._statistics_data[counter_name] = 0
  212. self.check_dump_statistics()
  213. def check_dump_statistics(self):
  214. """Checks no differences between the value returned from
  215. dump_statistics() and locally collected statistics data. Also
  216. checks the result isn't changed even after the method is
  217. invoked twice. Finally checks it is valid for the the
  218. statistics spec."""
  219. self.assertEqual(self.counter.dump_statistics(),
  220. self._statistics_data)
  221. # Idempotency check
  222. self.assertEqual(self.counter.dump_statistics(),
  223. self._statistics_data)
  224. self.assertTrue(self._module_spec.validate_statistics(
  225. False, self._statistics_data))
  226. def test_unixsocket_counters(self):
  227. # for unixsocket counters
  228. for counter_name in self._unixsocket_names:
  229. incrementer = self.counter._to_global\
  230. ['inc_unixsocket_%s' % counter_name]
  231. getter = self.counter._to_global\
  232. ['get_unixsocket_%s' % counter_name]
  233. incrementer()
  234. self.assertEqual(getter(), 1)
  235. # checks disable/enable
  236. self.counter.disable()
  237. incrementer()
  238. self.assertEqual(getter(), 1)
  239. self.counter.enable()
  240. incrementer()
  241. self.assertEqual(getter(), 2)
  242. isc.cc.data.set(
  243. self._statistics_data,
  244. 'socket/unixdomain/%s' % counter_name, 2)
  245. self.check_dump_statistics()
  246. def test_perzone_timers(self):
  247. # for timer counters
  248. for counter_name in self._zones_item_list:
  249. if counter_name.find('time_to_') == -1:
  250. isc.cc.data.set(\
  251. self._statistics_data,
  252. '%s/%s/%s' % (self._perzone_prefix,
  253. TEST_ZONE_NAME_STR,
  254. counter_name), 0)
  255. continue
  256. starter = self.counter._to_global\
  257. ['start_%s' % counter_name]
  258. stopper = self.counter._to_global\
  259. ['stop_%s' % counter_name]
  260. getter = self.counter._to_global\
  261. ['get_%s' % counter_name]
  262. starter(TEST_ZONE_NAME_STR)
  263. stopper(TEST_ZONE_NAME_STR)
  264. self.assertGreater(getter(TEST_ZONE_NAME_STR), 0)
  265. sec = getter(TEST_ZONE_NAME_STR)
  266. for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
  267. isc.cc.data.set(\
  268. self._statistics_data,
  269. '%s/%s/%s' % (self._perzone_prefix,
  270. zone_str,
  271. counter_name), sec)
  272. # twice exec stopper, then second is not changed
  273. stopper(TEST_ZONE_NAME_STR)
  274. self.assertEqual(getter(TEST_ZONE_NAME_STR), sec)
  275. self.check_dump_statistics()
  276. def test_ipsocket_counters(self):
  277. # for unixsocket counters
  278. for counter_name in self._ipsocket_names:
  279. incrementer = self.counter._to_global\
  280. ['inc_%ssocket_%s' % counter_name]
  281. getter = self.counter._to_global\
  282. ['get_%ssocket_%s' % counter_name]
  283. incrementer()
  284. self.assertEqual(getter(), 1)
  285. # checks disable/enable
  286. self.counter.disable()
  287. incrementer()
  288. self.assertEqual(getter(), 1)
  289. self.counter.enable()
  290. incrementer()
  291. self.assertEqual(getter(), 2)
  292. isc.cc.data.set(
  293. self._statistics_data,
  294. 'socket/%s/tcp/%s' % counter_name, 2)
  295. self.check_dump_statistics()
  296. class TestCounter1(BaseTestCounter, unittest.TestCase):
  297. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec1.spec'
  298. class TestCounter2(BaseTestCounter, unittest.TestCase):
  299. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec2.spec'
  300. class TestCounter3(BaseTestCounter, unittest.TestCase):
  301. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec3.spec'
  302. if __name__== "__main__":
  303. unittest.main()