counters_test.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. # Copyright (C) 2012-2013 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.counters'''
  16. import unittest
  17. import threading
  18. from datetime import timedelta
  19. import os
  20. import imp
  21. import isc.config
  22. TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
  23. from isc.statistics import counters
  24. def setup_functor(event, cycle, functor, *args):
  25. """Waits until the event is started, and then invokes the functor
  26. by times of the cycle with args."""
  27. event.wait()
  28. for i in range(cycle): functor(*args)
  29. def start_functor(concurrency, number, functor, *args):
  30. """Creates the threads of the number and makes them start. Sets
  31. the event and waits until these threads are finished."""
  32. threads = []
  33. event = threading.Event()
  34. for i in range(concurrency):
  35. threads.append(threading.Thread(\
  36. target=setup_functor, \
  37. args=(event, number, functor,) + args))
  38. for th in threads: th.start()
  39. event.set()
  40. for th in threads: th.join()
  41. class TestBasicMethods(unittest.TestCase):
  42. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec1.spec'
  43. def setUp(self):
  44. imp.reload(counters)
  45. self.counters = counters.Counters(self.TEST_SPECFILE_LOCATION)
  46. def tearDown(self):
  47. self.counters.clear_all()
  48. def test_clear_counters(self):
  49. self.assertRaises(isc.cc.data.DataNotFoundError,
  50. self.counters.get, 'counter')
  51. self.counters.inc('counter')
  52. self.assertEqual(self.counters.get('counter'), 1)
  53. self.counters.clear_all()
  54. self.assertRaises(isc.cc.data.DataNotFoundError,
  55. self.counters.get, 'counter')
  56. def test_enablediable(self):
  57. self.assertFalse(self.counters._disabled)
  58. self.counters.disable()
  59. self.assertTrue(self.counters._disabled)
  60. self.counters.enable()
  61. self.assertFalse(self.counters._disabled)
  62. def test_add_counter_normal(self):
  63. element = {'counter' : 1}
  64. self.assertEqual(\
  65. counters._add_counter(element, [], 'counter'), 1)
  66. def test_add_counter_wrongspec(self):
  67. self.assertRaises(isc.cc.data.DataNotFoundError,
  68. counters._add_counter,
  69. {}, [], 'counter')
  70. def test_add_counter_empty(self):
  71. self.assertEqual(\
  72. counters._add_counter(
  73. {},
  74. [ { 'item_name' : 'counter',
  75. 'item_type' : 'integer',
  76. 'item_default' : 0 } ],
  77. 'counter'), 0)
  78. def test_add_counter_empty_namedset(self):
  79. elem = {}
  80. spec = [ { 'item_name': 'dirs',
  81. 'item_type': 'named_set',
  82. 'named_set_item_spec': {
  83. 'item_name': 'dir',
  84. 'item_type': 'map',
  85. 'map_item_spec': [
  86. { 'item_name': 'counter1',
  87. 'item_type': 'integer',
  88. 'item_default': 0 },
  89. { 'item_name': 'counter2',
  90. 'item_type': 'integer',
  91. 'item_default': 0 } ]}
  92. }]
  93. self.assertEqual(\
  94. counters._add_counter(elem, spec, 'dirs/foo/counter1'), 0)
  95. self.assertEqual(\
  96. counters._add_counter(elem, spec, 'dirs/bar/counter2'), 0)
  97. def test_timer(self):
  98. t1 = counters._start_timer()
  99. t2 = t1 - timedelta(seconds=1)
  100. self.assertEqual((t1 - t2).seconds, 1)
  101. elem = {}
  102. spec = [{ 'item_name': 'time',
  103. 'item_type': 'real',
  104. 'item_default': 0.0 }]
  105. counters._stop_timer(t2, elem, spec, 'time')
  106. self.assertGreaterEqual(counters._get_counter(elem,'time'), 1.0)
  107. def test_rasing_incrementers(self):
  108. """ use Thread"""
  109. concurrency = 3 # number of the threads
  110. number = 10000 # number of counting per thread
  111. counter_name = "counter"
  112. timer_name = "seconds"
  113. start_time = counters._start_timer()
  114. start_functor(concurrency, number, self.counters.inc,
  115. counter_name)
  116. counters._stop_timer(start_time,
  117. self.counters._statistics._data,
  118. self.counters._statistics._spec,
  119. timer_name)
  120. self.assertEqual(
  121. counters._get_counter(self.counters._statistics._data,
  122. counter_name),
  123. concurrency * number)
  124. self.assertGreaterEqual(
  125. counters._get_counter(self.counters._statistics._data,
  126. timer_name), 0.0)
  127. def test_concat(self):
  128. # only strings
  129. a = ( 'a','b','c','d' )
  130. self.assertEqual('a/b/c/d', counters._concat(*a))
  131. self.assertEqual('aTbTcTd', counters._concat(*a, sep='T'))
  132. self.assertEqual('a\\b\\c\\d', counters._concat(*a, sep='\\'))
  133. # mixed with other types
  134. b = a + (1,)
  135. self.assertRaises(TypeError, counters._concat, *b)
  136. b = a + (1.1,)
  137. self.assertRaises(TypeError, counters._concat, *b)
  138. b = a + ([],)
  139. self.assertRaises(TypeError, counters._concat, *b)
  140. b = a + ({},)
  141. self.assertRaises(TypeError, counters._concat, *b)
  142. class BaseTestCounters():
  143. def setUp(self):
  144. imp.reload(counters)
  145. self._statistics_data = {}
  146. self.counters = counters.Counters(self.TEST_SPECFILE_LOCATION)
  147. def tearDown(self):
  148. self.counters.clear_all()
  149. def check_get_statistics(self):
  150. """Checks no differences between the value returned from
  151. get_statistics() and locally collected statistics data. Also
  152. checks the result isn't changed even after the method is
  153. invoked twice. Finally checks it is valid for the the
  154. statistics spec."""
  155. self.assertEqual(self.counters.get_statistics(),
  156. self._statistics_data)
  157. # Idempotency check
  158. self.assertEqual(self.counters.get_statistics(),
  159. self._statistics_data)
  160. if self.TEST_SPECFILE_LOCATION:
  161. self.assertTrue(isc.config.module_spec_from_file(
  162. self.TEST_SPECFILE_LOCATION).validate_statistics(
  163. False, self._statistics_data))
  164. else:
  165. self.assertTrue(isc.config.ModuleSpec(
  166. {'module_name': 'Foo',
  167. 'statistics': self.counters._statistics._spec}
  168. ).validate_statistics(
  169. False, self._statistics_data))
  170. def test_undefined_item(self):
  171. # test DataNotFoundError raising when specifying item defined
  172. # in the specfile
  173. self.assertRaises(isc.cc.data.DataNotFoundError,
  174. self.counters.inc, '__undefined__')
  175. self.assertRaises(isc.cc.data.DataNotFoundError,
  176. self.counters.dec, '__undefined__')
  177. self.counters.start_timer('__undefined__')
  178. self.assertRaises(isc.cc.data.DataNotFoundError,
  179. self.counters.stop_timer, '__undefined__')
  180. self.assertRaises(isc.cc.data.DataNotFoundError,
  181. self.counters.get, '__undefined__')
  182. class TestCounters0(unittest.TestCase, BaseTestCounters):
  183. TEST_SPECFILE_LOCATION = None
  184. def setUp(self):
  185. BaseTestCounters.setUp(self)
  186. def tearDown(self):
  187. BaseTestCounters.tearDown(self)
  188. class TestCounters1(unittest.TestCase, BaseTestCounters):
  189. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec1.spec'
  190. def setUp(self):
  191. BaseTestCounters.setUp(self)
  192. def tearDown(self):
  193. BaseTestCounters.tearDown(self)
  194. if __name__== "__main__":
  195. unittest.main()