counters_test.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. self.counters = counters.Counters(self.TEST_SPECFILE_LOCATION)
  45. def test_clear_counters(self):
  46. self.assertRaises(isc.cc.data.DataNotFoundError,
  47. self.counters.get, 'counter')
  48. self.counters.inc('counter')
  49. self.assertEqual(self.counters.get('counter'), 1)
  50. self.counters.clear_all()
  51. self.assertRaises(isc.cc.data.DataNotFoundError,
  52. self.counters.get, 'counter')
  53. def test_enablediable(self):
  54. self.assertFalse(self.counters._disabled)
  55. self.counters.disable()
  56. self.assertTrue(self.counters._disabled)
  57. self.counters.enable()
  58. self.assertFalse(self.counters._disabled)
  59. def test_add_counter_normal(self):
  60. element = {'counter' : 1}
  61. self.assertEqual(\
  62. counters._add_counter(element, [], 'counter'), 1)
  63. def test_add_counter_wrongspec(self):
  64. self.assertRaises(isc.cc.data.DataNotFoundError,
  65. counters._add_counter,
  66. {}, [], 'counter')
  67. def test_add_counter_empty(self):
  68. self.assertEqual(\
  69. counters._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. counters._add_counter(elem, spec, 'dirs/foo/counter1'), 0)
  92. self.assertEqual(\
  93. counters._add_counter(elem, spec, 'dirs/bar/counter2'), 0)
  94. def test_timer(self):
  95. t1 = counters._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. counters._stop_timer(t2, elem, spec, 'time')
  103. self.assertGreaterEqual(counters._get_counter(elem,'time'), 1.0)
  104. def test_rasing_incrementers(self):
  105. """ use Thread"""
  106. concurrency = 3 # number of the threads
  107. number = 10000 # number of counting per thread
  108. counter_name = "counter"
  109. timer_name = "seconds"
  110. start_time = counters._start_timer()
  111. start_functor(concurrency, number, self.counters.inc,
  112. counter_name)
  113. counters._stop_timer(start_time,
  114. self.counters._statistics_data,
  115. self.counters._statistics_spec,
  116. timer_name)
  117. self.assertEqual(
  118. counters._get_counter(self.counters._statistics_data,
  119. counter_name),
  120. concurrency * number)
  121. self.assertGreaterEqual(
  122. counters._get_counter(self.counters._statistics_data,
  123. timer_name), 0.0)
  124. def test_concat(self):
  125. # only strings
  126. a = ( 'a','b','c','d' )
  127. self.assertEqual('a/b/c/d', counters._concat(*a))
  128. self.assertEqual('aTbTcTd', counters._concat(*a, sep='T'))
  129. self.assertEqual('a\\b\\c\\d', counters._concat(*a, sep='\\'))
  130. # mixed with other types
  131. b = a + (1,)
  132. self.assertRaises(TypeError, counters._concat, *b)
  133. b = a + (1.1,)
  134. self.assertRaises(TypeError, counters._concat, *b)
  135. b = a + ([],)
  136. self.assertRaises(TypeError, counters._concat, *b)
  137. b = a + ({},)
  138. self.assertRaises(TypeError, counters._concat, *b)
  139. def test_none_of_arg_of_counters(self):
  140. """Test Counters raises ModuleSpecError when specifying not valid
  141. argument"""
  142. self.assertRaises(isc.config.module_spec.ModuleSpecError,
  143. counters.Counters, None)
  144. self.assertRaises(isc.config.module_spec.ModuleSpecError,
  145. counters.Counters, '/foo/bar')
  146. class BaseTestCounters():
  147. def setUp(self):
  148. self._statistics_data = {}
  149. self.counters = counters.Counters(self.TEST_SPECFILE_LOCATION)
  150. def check_get_statistics(self):
  151. """Checks no differences between the value returned from
  152. get_statistics() and locally collected statistics data. Also
  153. checks the result isn't changed even after the method is
  154. invoked twice. Finally checks it is valid for the the
  155. statistics spec."""
  156. self.assertEqual(self.counters.get_statistics(),
  157. self._statistics_data)
  158. # Idempotency check
  159. self.assertEqual(self.counters.get_statistics(),
  160. self._statistics_data)
  161. if self.TEST_SPECFILE_LOCATION:
  162. self.assertTrue(isc.config.module_spec_from_file(
  163. self.TEST_SPECFILE_LOCATION).validate_statistics(
  164. False, self._statistics_data))
  165. else:
  166. self.assertTrue(isc.config.ModuleSpec(
  167. {'module_name': 'Foo',
  168. 'statistics': self.counters._statistics_spec}
  169. ).validate_statistics(
  170. False, self._statistics_data))
  171. def test_undefined_item(self):
  172. # test DataNotFoundError raising when specifying item defined
  173. # in the specfile
  174. self.assertRaises(isc.cc.data.DataNotFoundError,
  175. self.counters.inc, '__undefined__')
  176. self.assertRaises(isc.cc.data.DataNotFoundError,
  177. self.counters.dec, '__undefined__')
  178. self.counters.start_timer('__undefined__')
  179. self.assertRaises(isc.cc.data.DataNotFoundError,
  180. self.counters.stop_timer, '__undefined__')
  181. self.assertRaises(isc.cc.data.DataNotFoundError,
  182. self.counters.get, '__undefined__')
  183. class TestCounters1(unittest.TestCase, BaseTestCounters):
  184. TEST_SPECFILE_LOCATION = TESTDATA_SRCDIR + os.sep + 'test_spec1.spec'
  185. def setUp(self):
  186. BaseTestCounters.setUp(self)
  187. def test_counters(self):
  188. spec = isc.config.module_spec_from_file(self.TEST_SPECFILE_LOCATION)
  189. self.assertEqual(spec.get_statistics_spec(),
  190. self.counters._statistics_spec)
  191. for name in isc.config.spec_name_list(self.counters._statistics_spec):
  192. self.counters.inc(name)
  193. self.assertEqual(self.counters.get(name), 1)
  194. # checks disable/enable
  195. self.counters.disable()
  196. self.counters.inc(name)
  197. self.assertEqual(self.counters.get(name), 1)
  198. self.counters.enable()
  199. self.counters.inc(name)
  200. self.assertEqual(self.counters.get(name), 2)
  201. self._statistics_data = {'counter':2, 'seconds': 2.0}
  202. self.check_get_statistics()
  203. if __name__== "__main__":
  204. unittest.main()