b10-stats_test.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. # Copyright (C) 2010, 2011, 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. """
  16. In each of these tests we start several virtual components. They are
  17. not the real components, no external processes are started. They are
  18. just simple mock objects running each in its own thread and pretending
  19. to be bind10 modules. This helps testing the stats module in a close
  20. to real environment.
  21. """
  22. import unittest
  23. import os
  24. import threading
  25. import io
  26. import time
  27. import imp
  28. import stats
  29. import isc.cc.session
  30. from test_utils import BaseModules, ThreadingServerManager, MyStats, SignalHandler, send_command, send_shutdown
  31. from isc.testutils.ccsession_mock import MockModuleCCSession
  32. class TestUtilties(unittest.TestCase):
  33. items = [
  34. { 'item_name': 'test_int1', 'item_type': 'integer', 'item_default': 12345 },
  35. { 'item_name': 'test_real1', 'item_type': 'real', 'item_default': 12345.6789 },
  36. { 'item_name': 'test_bool1', 'item_type': 'boolean', 'item_default': True },
  37. { 'item_name': 'test_str1', 'item_type': 'string', 'item_default': 'ABCD' },
  38. { 'item_name': 'test_list1', 'item_type': 'list', 'item_default': [1,2,3],
  39. 'list_item_spec' : { 'item_name': 'number', 'item_type': 'integer' } },
  40. { 'item_name': 'test_map1', 'item_type': 'map', 'item_default': {'a':1,'b':2,'c':3},
  41. 'map_item_spec' : [ { 'item_name': 'a', 'item_type': 'integer'},
  42. { 'item_name': 'b', 'item_type': 'integer'},
  43. { 'item_name': 'c', 'item_type': 'integer'} ] },
  44. { 'item_name': 'test_int2', 'item_type': 'integer' },
  45. { 'item_name': 'test_real2', 'item_type': 'real' },
  46. { 'item_name': 'test_bool2', 'item_type': 'boolean' },
  47. { 'item_name': 'test_str2', 'item_type': 'string' },
  48. { 'item_name': 'test_list2', 'item_type': 'list',
  49. 'list_item_spec' : { 'item_name': 'number', 'item_type': 'integer' } },
  50. { 'item_name': 'test_map2', 'item_type': 'map',
  51. 'map_item_spec' : [ { 'item_name': 'A', 'item_type': 'integer'},
  52. { 'item_name': 'B', 'item_type': 'integer'},
  53. { 'item_name': 'C', 'item_type': 'integer'} ] },
  54. { 'item_name': 'test_none', 'item_type': 'none' },
  55. { 'item_name': 'test_list3', 'item_type': 'list', 'item_default': ["one","two","three"],
  56. 'list_item_spec' : { 'item_name': 'number', 'item_type': 'string' } },
  57. { 'item_name': 'test_map3', 'item_type': 'map', 'item_default': {'a':'one','b':'two','c':'three'},
  58. 'map_item_spec' : [ { 'item_name': 'a', 'item_type': 'string'},
  59. { 'item_name': 'b', 'item_type': 'string'},
  60. { 'item_name': 'c', 'item_type': 'string'} ] }
  61. ]
  62. def setUp(self):
  63. self.const_timestamp = 1308730448.965706
  64. self.const_timetuple = (2011, 6, 22, 8, 14, 8, 2, 173, 0)
  65. self.const_datetime = '2011-06-22T08:14:08Z'
  66. stats.time = lambda : self.const_timestamp
  67. stats.gmtime = lambda : self.const_timetuple
  68. def test_get_spec_defaults(self):
  69. self.assertEqual(
  70. stats.get_spec_defaults(self.items), {
  71. 'test_int1' : 12345 ,
  72. 'test_real1' : 12345.6789 ,
  73. 'test_bool1' : True ,
  74. 'test_str1' : 'ABCD' ,
  75. 'test_list1' : [1,2,3] ,
  76. 'test_map1' : {'a':1,'b':2,'c':3},
  77. 'test_int2' : 0 ,
  78. 'test_real2' : 0.0,
  79. 'test_bool2' : False,
  80. 'test_str2' : "",
  81. 'test_list2' : [0],
  82. 'test_map2' : { 'A' : 0, 'B' : 0, 'C' : 0 },
  83. 'test_none' : None,
  84. 'test_list3' : [ "one", "two", "three" ],
  85. 'test_map3' : { 'a' : 'one', 'b' : 'two', 'c' : 'three' } })
  86. self.assertEqual(stats.get_spec_defaults(None), {})
  87. self.assertRaises(KeyError, stats.get_spec_defaults, [{'item_name':'Foo'}])
  88. def test_get_timestamp(self):
  89. self.assertEqual(stats.get_timestamp(), self.const_timestamp)
  90. def test_get_datetime(self):
  91. self.assertEqual(stats.get_datetime(), self.const_datetime)
  92. self.assertNotEqual(stats.get_datetime(
  93. (2011, 6, 22, 8, 23, 40, 2, 173, 0)), self.const_datetime)
  94. class TestCallback(unittest.TestCase):
  95. def setUp(self):
  96. self.dummy_func = lambda *x, **y : (x, y)
  97. self.dummy_args = (1,2,3)
  98. self.dummy_kwargs = {'a':1,'b':2,'c':3}
  99. self.cback1 = stats.Callback(
  100. command=self.dummy_func,
  101. args=self.dummy_args,
  102. kwargs=self.dummy_kwargs
  103. )
  104. self.cback2 = stats.Callback(
  105. args=self.dummy_args,
  106. kwargs=self.dummy_kwargs
  107. )
  108. self.cback3 = stats.Callback(
  109. command=self.dummy_func,
  110. kwargs=self.dummy_kwargs
  111. )
  112. self.cback4 = stats.Callback(
  113. command=self.dummy_func,
  114. args=self.dummy_args
  115. )
  116. def test_init(self):
  117. self.assertEqual((self.cback1.command, self.cback1.args, self.cback1.kwargs),
  118. (self.dummy_func, self.dummy_args, self.dummy_kwargs))
  119. self.assertEqual((self.cback2.command, self.cback2.args, self.cback2.kwargs),
  120. (None, self.dummy_args, self.dummy_kwargs))
  121. self.assertEqual((self.cback3.command, self.cback3.args, self.cback3.kwargs),
  122. (self.dummy_func, (), self.dummy_kwargs))
  123. self.assertEqual((self.cback4.command, self.cback4.args, self.cback4.kwargs),
  124. (self.dummy_func, self.dummy_args, {}))
  125. def test_call(self):
  126. self.assertEqual(self.cback1(), (self.dummy_args, self.dummy_kwargs))
  127. self.assertEqual(self.cback1(100, 200), ((100, 200), self.dummy_kwargs))
  128. self.assertEqual(self.cback1(a=100, b=200), (self.dummy_args, {'a':100, 'b':200}))
  129. self.assertEqual(self.cback2(), None)
  130. self.assertEqual(self.cback3(), ((), self.dummy_kwargs))
  131. self.assertEqual(self.cback3(100, 200), ((100, 200), self.dummy_kwargs))
  132. self.assertEqual(self.cback3(a=100, b=200), ((), {'a':100, 'b':200}))
  133. self.assertEqual(self.cback4(), (self.dummy_args, {}))
  134. self.assertEqual(self.cback4(100, 200), ((100, 200), {}))
  135. self.assertEqual(self.cback4(a=100, b=200), (self.dummy_args, {'a':100, 'b':200}))
  136. class TestStats(unittest.TestCase):
  137. def setUp(self):
  138. # set the signal handler for deadlock
  139. self.sig_handler = SignalHandler(self.fail)
  140. self.base = BaseModules()
  141. self.stats = stats.Stats()
  142. self.const_timestamp = 1308730448.965706
  143. self.const_datetime = '2011-06-22T08:14:08Z'
  144. self.const_default_datetime = '1970-01-01T00:00:00Z'
  145. def tearDown(self):
  146. self.base.shutdown()
  147. # reset the signal handler
  148. self.sig_handler.reset()
  149. def test_init(self):
  150. self.assertEqual(self.stats.module_name, 'Stats')
  151. self.assertFalse(self.stats.running)
  152. self.assertTrue('command_show' in self.stats.callbacks)
  153. self.assertTrue('command_status' in self.stats.callbacks)
  154. self.assertTrue('command_shutdown' in self.stats.callbacks)
  155. self.assertTrue('command_show' in self.stats.callbacks)
  156. self.assertTrue('command_showschema' in self.stats.callbacks)
  157. self.assertEqual(self.stats.config['poll-interval'], 60)
  158. def test_init_undefcmd(self):
  159. spec_str = """\
  160. {
  161. "module_spec": {
  162. "module_name": "Stats",
  163. "module_description": "Stats daemon",
  164. "config_data": [],
  165. "commands": [
  166. {
  167. "command_name": "_undef_command_",
  168. "command_description": "a undefined command in stats",
  169. "command_args": []
  170. }
  171. ],
  172. "statistics": []
  173. }
  174. }
  175. """
  176. orig_spec_location = stats.SPECFILE_LOCATION
  177. stats.SPECFILE_LOCATION = io.StringIO(spec_str)
  178. self.assertRaises(stats.StatsError, stats.Stats)
  179. stats.SPECFILE_LOCATION = orig_spec_location
  180. def test_start(self):
  181. # start without err
  182. self.stats_server = ThreadingServerManager(MyStats)
  183. self.stats = self.stats_server.server
  184. self.assertFalse(self.stats.running)
  185. self.stats_server.run()
  186. self.assertEqual(send_command("status", "Stats"),
  187. (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
  188. self.assertTrue(self.stats.running)
  189. # Due to a race-condition related to the threads used in these
  190. # tests, use of the mock session and the stopped check (see
  191. # below), are temporarily disabled
  192. # See ticket #1668
  193. # Override moduleCCSession so we can check if send_stopping is called
  194. #self.stats.mccs = MockModuleCCSession()
  195. self.assertEqual(send_shutdown("Stats"), (0, None))
  196. self.assertFalse(self.stats.running)
  197. # Call server.shutdown with argument True so the thread.join() call
  198. # blocks and we are sure the main loop has finished (and set
  199. # mccs.stopped)
  200. self.stats_server.shutdown(True)
  201. # Also temporarily disabled for #1668, see above
  202. #self.assertTrue(self.stats.mccs.stopped)
  203. def test_handlers(self):
  204. self.stats_server = ThreadingServerManager(MyStats)
  205. self.stats = self.stats_server.server
  206. self.stats_server.run()
  207. # command_handler
  208. self.assertEqual(
  209. send_command(
  210. 'show', 'Stats',
  211. params={ 'owner' : 'Boss',
  212. 'name' : 'boot_time' }),
  213. (0, {'Boss': {'boot_time': self.const_datetime}}))
  214. self.assertEqual(
  215. send_command(
  216. 'show', 'Stats',
  217. params={ 'owner' : 'Boss',
  218. 'name' : 'boot_time' }),
  219. (0, {'Boss': {'boot_time': self.const_datetime}}))
  220. self.assertEqual(
  221. send_command('status', 'Stats'),
  222. (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
  223. (rcode, value) = send_command('show', 'Stats')
  224. self.assertEqual(rcode, 0)
  225. self.assertEqual(len(value), 3)
  226. self.assertTrue('Boss' in value)
  227. self.assertTrue('Stats' in value)
  228. self.assertTrue('Auth' in value)
  229. self.assertEqual(len(value['Stats']), 5)
  230. self.assertEqual(len(value['Boss']), 1)
  231. self.assertTrue('boot_time' in value['Boss'])
  232. self.assertEqual(value['Boss']['boot_time'], self.const_datetime)
  233. self.assertTrue('report_time' in value['Stats'])
  234. self.assertTrue('boot_time' in value['Stats'])
  235. self.assertTrue('last_update_time' in value['Stats'])
  236. self.assertTrue('timestamp' in value['Stats'])
  237. self.assertTrue('lname' in value['Stats'])
  238. (rcode, value) = send_command('showschema', 'Stats')
  239. self.assertEqual(rcode, 0)
  240. self.assertEqual(len(value), 3)
  241. self.assertTrue('Boss' in value)
  242. self.assertTrue('Stats' in value)
  243. self.assertTrue('Auth' in value)
  244. self.assertEqual(len(value['Stats']), 5)
  245. self.assertEqual(len(value['Boss']), 1)
  246. for item in value['Boss']:
  247. self.assertTrue(len(item) == 7)
  248. self.assertTrue('item_name' in item)
  249. self.assertTrue('item_type' in item)
  250. self.assertTrue('item_optional' in item)
  251. self.assertTrue('item_default' in item)
  252. self.assertTrue('item_title' in item)
  253. self.assertTrue('item_description' in item)
  254. self.assertTrue('item_format' in item)
  255. for item in value['Stats']:
  256. self.assertTrue(len(item) == 6 or len(item) == 7)
  257. self.assertTrue('item_name' in item)
  258. self.assertTrue('item_type' in item)
  259. self.assertTrue('item_optional' in item)
  260. self.assertTrue('item_default' in item)
  261. self.assertTrue('item_title' in item)
  262. self.assertTrue('item_description' in item)
  263. if len(item) == 7:
  264. self.assertTrue('item_format' in item)
  265. self.assertEqual(
  266. send_command('__UNKNOWN__', 'Stats'),
  267. (1, "Unknown command: '__UNKNOWN__'"))
  268. self.stats_server.shutdown()
  269. def test_update_modules(self):
  270. self.assertEqual(len(self.stats.modules), 3) # Auth, Boss, Stats
  271. self.stats.update_modules()
  272. self.assertTrue('Stats' in self.stats.modules)
  273. self.assertTrue('Boss' in self.stats.modules)
  274. self.assertFalse('Dummy' in self.stats.modules)
  275. my_statistics_data = stats.get_spec_defaults(self.stats.modules['Stats'].get_statistics_spec())
  276. self.assertTrue('report_time' in my_statistics_data)
  277. self.assertTrue('boot_time' in my_statistics_data)
  278. self.assertTrue('last_update_time' in my_statistics_data)
  279. self.assertTrue('timestamp' in my_statistics_data)
  280. self.assertTrue('lname' in my_statistics_data)
  281. self.assertEqual(my_statistics_data['report_time'], self.const_default_datetime)
  282. self.assertEqual(my_statistics_data['boot_time'], self.const_default_datetime)
  283. self.assertEqual(my_statistics_data['last_update_time'], self.const_default_datetime)
  284. self.assertEqual(my_statistics_data['timestamp'], 0.0)
  285. self.assertEqual(my_statistics_data['lname'], "")
  286. my_statistics_data = stats.get_spec_defaults(self.stats.modules['Boss'].get_statistics_spec())
  287. self.assertTrue('boot_time' in my_statistics_data)
  288. self.assertEqual(my_statistics_data['boot_time'], self.const_default_datetime)
  289. orig_parse_answer = stats.isc.config.ccsession.parse_answer
  290. stats.isc.config.ccsession.parse_answer = lambda x: (99, 'error')
  291. self.assertRaises(stats.StatsError, self.stats.update_modules)
  292. stats.isc.config.ccsession.parse_answer = orig_parse_answer
  293. def test_get_statistics_data(self):
  294. my_statistics_data = self.stats.get_statistics_data()
  295. self.assertTrue('Stats' in my_statistics_data)
  296. self.assertTrue('Boss' in my_statistics_data)
  297. self.assertTrue('boot_time' in my_statistics_data['Boss'])
  298. my_statistics_data = self.stats.get_statistics_data(owner='Stats')
  299. self.assertTrue('Stats' in my_statistics_data)
  300. self.assertTrue('report_time' in my_statistics_data['Stats'])
  301. self.assertTrue('boot_time' in my_statistics_data['Stats'])
  302. self.assertTrue('last_update_time' in my_statistics_data['Stats'])
  303. self.assertTrue('timestamp' in my_statistics_data['Stats'])
  304. self.assertTrue('lname' in my_statistics_data['Stats'])
  305. self.assertRaises(stats.StatsError, self.stats.get_statistics_data, owner='Foo')
  306. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='report_time')
  307. self.assertEqual(my_statistics_data['Stats']['report_time'], self.const_default_datetime)
  308. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='boot_time')
  309. self.assertTrue('boot_time' in my_statistics_data['Stats'])
  310. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='last_update_time')
  311. self.assertTrue('last_update_time' in my_statistics_data['Stats'])
  312. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='timestamp')
  313. self.assertEqual(my_statistics_data['Stats']['timestamp'], 0.0)
  314. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='lname')
  315. self.assertTrue(len(my_statistics_data['Stats']['lname']) >0)
  316. self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
  317. owner='Stats', name='Bar')
  318. self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
  319. owner='Foo', name='Bar')
  320. self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
  321. name='Bar')
  322. def test_update_statistics_data(self):
  323. # success
  324. self.assertEqual(self.stats.statistics_data['Stats']['lname'],
  325. self.stats.cc_session.lname)
  326. self.stats.update_statistics_data(
  327. 'Stats', self.stats.cc_session.lname,
  328. {'lname': 'foo@bar'})
  329. self.assertEqual(self.stats.statistics_data['Stats']['lname'],
  330. 'foo@bar')
  331. # error case
  332. self.assertEqual(self.stats.update_statistics_data('Stats', None,
  333. {'lname': 0.0}),
  334. ['0.0 should be a string'])
  335. self.assertEqual(self.stats.update_statistics_data('Dummy', None,
  336. {'foo': 'bar'}),
  337. ['unknown module name: Dummy'])
  338. def test_update_statistics_data_withmid(self):
  339. # one id of Auth
  340. self.stats.update_statistics_data('Auth', "bar@foo",
  341. {'queries.tcp':1001})
  342. self.assertTrue('Auth' in self.stats.statistics_data)
  343. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  344. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 1001 + 3 * 4)
  345. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  346. self.assertTrue('bar@foo' in self.stats.statistics_data_bymid['Auth'])
  347. self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid['Auth']['bar@foo'])
  348. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo']['queries.tcp'], 1001)
  349. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo'],
  350. {'queries.tcp': 1001})
  351. # check consolidation of statistics data
  352. self.stats.update_statistics_data('Auth', "bar2@foo",
  353. {'queries.tcp':2001})
  354. self.assertTrue('Auth' in self.stats.statistics_data)
  355. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  356. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 3002 + 3 * 4)
  357. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  358. self.assertTrue('bar@foo' in self.stats.statistics_data_bymid['Auth'])
  359. self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid['Auth']['bar@foo'])
  360. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo']['queries.tcp'], 1001)
  361. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo'],
  362. {'queries.tcp': 1001})
  363. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar2@foo'],
  364. {'queries.tcp': 2001})
  365. # kill running Auth but the statistics data is preserved
  366. self.assertEqual(self.base.boss.server.pid_list[0][0], 9999)
  367. killed = self.base.boss.server.pid_list.pop(0)
  368. self.stats.update_statistics_data()
  369. self.assertTrue('Auth' in self.stats.statistics_data)
  370. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  371. self.assertTrue('queries.udp' in self.stats.statistics_data['Auth'])
  372. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 3002 + 3 * 4)
  373. self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'], 2 * 4)
  374. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  375. # restore statistics data of killed auth
  376. self.base.boss.server.pid_list = [ killed ] + self.base.boss.server.pid_list[:]
  377. self.stats.update_statistics_data('Auth',
  378. "bar@foo",
  379. {'queries.tcp': 1001})
  380. # another mid of Auth
  381. self.stats.update_statistics_data('Auth',
  382. "bar3@foo",
  383. {'queries.tcp':1002,
  384. 'queries.udp':1003})
  385. self.assertTrue('Auth' in self.stats.statistics_data)
  386. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  387. self.assertTrue('queries.udp' in self.stats.statistics_data['Auth'])
  388. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 4004 + 3 * 4)
  389. self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'], 1003 + 2 * 4)
  390. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  391. self.assertTrue('bar@foo' in self.stats.statistics_data_bymid['Auth'])
  392. self.assertTrue('bar3@foo' in self.stats.statistics_data_bymid['Auth'])
  393. self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid['Auth']['bar@foo'])
  394. self.assertTrue('queries.udp' in self.stats.statistics_data_bymid['Auth']['bar3@foo'])
  395. self.assertTrue('queries.udp' in self.stats.statistics_data_bymid['Auth']['bar3@foo'])
  396. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo']['queries.tcp'], 1001)
  397. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar3@foo']['queries.tcp'], 1002)
  398. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar3@foo']['queries.udp'], 1003)
  399. def test_config(self):
  400. orig_get_timestamp = stats.get_timestamp
  401. stats.get_timestamp = lambda : self.const_timestamp
  402. stats_server = ThreadingServerManager(MyStats)
  403. stat = stats_server.server
  404. # test updating poll-interval
  405. self.assertEqual(stat.config['poll-interval'], 60)
  406. self.assertEqual(stat.get_interval(), 60)
  407. self.assertEqual(stat.next_polltime, self.const_timestamp + 60)
  408. self.assertEqual(stat.config_handler({'poll-interval': 120}),
  409. isc.config.create_answer(0))
  410. self.assertEqual(stat.config['poll-interval'], 120)
  411. self.assertEqual(stat.get_interval(), 120)
  412. self.assertEqual(stat.next_polltime, self.const_timestamp + 120)
  413. stats.get_timestamp = orig_get_timestamp
  414. self.assertEqual(stat.config_handler({'poll-interval': "foo"}),
  415. isc.config.create_answer(1, 'foo should be an integer'))
  416. self.assertEqual(stat.config_handler({'poll-interval': -1}),
  417. isc.config.create_answer(1, 'Negative integer ignored'))
  418. # unknown item
  419. self.assertEqual(
  420. stat.config_handler({'_UNKNOWN_KEY_': None}),
  421. isc.config.ccsession.create_answer(
  422. 1, "unknown item _UNKNOWN_KEY_"))
  423. # test no change if zero interval time
  424. self.assertEqual(stat.config_handler({'poll-interval': 0}),
  425. isc.config.create_answer(0))
  426. self.assertEqual(stat.config['poll-interval'], 0)
  427. stats_server.run()
  428. self.assertEqual(
  429. send_command(
  430. 'show', 'Stats',
  431. params={ 'owner' : 'Boss',
  432. 'name' : 'boot_time' }),
  433. (0, {'Boss': {'boot_time': self.const_datetime}}))
  434. stats_server.shutdown()
  435. def test_commands(self):
  436. # status
  437. self.assertEqual(self.stats.command_status(),
  438. isc.config.create_answer(
  439. 0, "Stats is up. (PID " + str(os.getpid()) + ")"))
  440. # shutdown
  441. self.stats.running = True
  442. self.assertEqual(self.stats.command_shutdown(),
  443. isc.config.create_answer(0))
  444. self.assertFalse(self.stats.running)
  445. def test_command_show(self):
  446. self.assertEqual(self.stats.command_show(owner='Foo', name=None),
  447. isc.config.create_answer(
  448. 1, "specified arguments are incorrect: owner: Foo, name: None"))
  449. self.assertEqual(self.stats.command_show(owner='Foo', name='_bar_'),
  450. isc.config.create_answer(
  451. 1, "specified arguments are incorrect: owner: Foo, name: _bar_"))
  452. self.assertEqual(self.stats.command_show(owner='Foo', name='bar'),
  453. isc.config.create_answer(
  454. 1, "specified arguments are incorrect: owner: Foo, name: bar"))
  455. self.assertEqual(self.stats.command_show(owner='Auth'),
  456. isc.config.create_answer(
  457. 0, {'Auth':{ 'queries.udp': 8,
  458. 'queries.tcp': 12,
  459. 'queries.perzone': [{ 'zonename': 'test1.example',
  460. 'queries.udp': 16,
  461. 'queries.tcp': 20 }
  462. ]}}))
  463. self.assertEqual(self.stats.command_show(owner='Auth', name='queries.udp'),
  464. isc.config.create_answer(
  465. 0, {'Auth': {'queries.udp':8}}))
  466. self.assertEqual(self.stats.command_show(owner='Auth', name='queries.perzone'),
  467. isc.config.create_answer(
  468. 0, {'Auth': {'queries.perzone': [{ 'zonename': 'test1.example',
  469. 'queries.udp': 16,
  470. 'queries.tcp': 20 }]}}))
  471. orig_get_datetime = stats.get_datetime
  472. orig_get_timestamp = stats.get_timestamp
  473. stats.get_datetime = lambda x=None: self.const_datetime
  474. stats.get_timestamp = lambda : self.const_timestamp
  475. self.assertEqual(self.stats.command_show(owner='Stats', name='report_time'),
  476. isc.config.create_answer(
  477. 0, {'Stats': {'report_time':self.const_datetime}}))
  478. self.assertEqual(self.stats.command_show(owner='Stats', name='timestamp'),
  479. isc.config.create_answer(
  480. 0, {'Stats': {'timestamp':self.const_timestamp}}))
  481. stats.get_datetime = orig_get_datetime
  482. stats.get_timestamp = orig_get_timestamp
  483. self.stats.mccs.specification = isc.config.module_spec.ModuleSpec(
  484. { "module_name": self.stats.module_name,
  485. "statistics": [] } )
  486. self.assertRaises(
  487. stats.StatsError, self.stats.command_show, owner='Foo', name='bar')
  488. def test_command_showchema(self):
  489. (rcode, value) = isc.config.ccsession.parse_answer(
  490. self.stats.command_showschema())
  491. self.assertEqual(rcode, 0)
  492. self.assertEqual(len(value), 3)
  493. self.assertTrue('Stats' in value)
  494. self.assertTrue('Boss' in value)
  495. self.assertTrue('Auth' in value)
  496. self.assertFalse('__Dummy__' in value)
  497. schema = value['Stats']
  498. self.assertEqual(len(schema), 5)
  499. for item in schema:
  500. self.assertTrue(len(item) == 6 or len(item) == 7)
  501. self.assertTrue('item_name' in item)
  502. self.assertTrue('item_type' in item)
  503. self.assertTrue('item_optional' in item)
  504. self.assertTrue('item_default' in item)
  505. self.assertTrue('item_title' in item)
  506. self.assertTrue('item_description' in item)
  507. if len(item) == 7:
  508. self.assertTrue('item_format' in item)
  509. schema = value['Boss']
  510. self.assertEqual(len(schema), 1)
  511. for item in schema:
  512. self.assertTrue(len(item) == 7)
  513. self.assertTrue('item_name' in item)
  514. self.assertTrue('item_type' in item)
  515. self.assertTrue('item_optional' in item)
  516. self.assertTrue('item_default' in item)
  517. self.assertTrue('item_title' in item)
  518. self.assertTrue('item_description' in item)
  519. self.assertTrue('item_format' in item)
  520. schema = value['Auth']
  521. self.assertEqual(len(schema), 3)
  522. for item in schema:
  523. if item['item_type'] == 'list':
  524. self.assertEqual(len(item), 7)
  525. else:
  526. self.assertEqual(len(item), 6)
  527. self.assertTrue('item_name' in item)
  528. self.assertTrue('item_type' in item)
  529. self.assertTrue('item_optional' in item)
  530. self.assertTrue('item_default' in item)
  531. self.assertTrue('item_title' in item)
  532. self.assertTrue('item_description' in item)
  533. (rcode, value) = isc.config.ccsession.parse_answer(
  534. self.stats.command_showschema(owner='Stats'))
  535. self.assertEqual(rcode, 0)
  536. self.assertTrue('Stats' in value)
  537. self.assertFalse('Boss' in value)
  538. self.assertFalse('Auth' in value)
  539. for item in value['Stats']:
  540. self.assertTrue(len(item) == 6 or len(item) == 7)
  541. self.assertTrue('item_name' in item)
  542. self.assertTrue('item_type' in item)
  543. self.assertTrue('item_optional' in item)
  544. self.assertTrue('item_default' in item)
  545. self.assertTrue('item_title' in item)
  546. self.assertTrue('item_description' in item)
  547. if len(item) == 7:
  548. self.assertTrue('item_format' in item)
  549. (rcode, value) = isc.config.ccsession.parse_answer(
  550. self.stats.command_showschema(owner='Stats', name='report_time'))
  551. self.assertEqual(rcode, 0)
  552. self.assertTrue('Stats' in value)
  553. self.assertFalse('Boss' in value)
  554. self.assertFalse('Auth' in value)
  555. self.assertEqual(len(value['Stats'][0]), 7)
  556. self.assertTrue('item_name' in value['Stats'][0])
  557. self.assertTrue('item_type' in value['Stats'][0])
  558. self.assertTrue('item_optional' in value['Stats'][0])
  559. self.assertTrue('item_default' in value['Stats'][0])
  560. self.assertTrue('item_title' in value['Stats'][0])
  561. self.assertTrue('item_description' in value['Stats'][0])
  562. self.assertTrue('item_format' in value['Stats'][0])
  563. self.assertEqual(value['Stats'][0]['item_name'], 'report_time')
  564. self.assertEqual(value['Stats'][0]['item_format'], 'date-time')
  565. self.assertEqual(self.stats.command_showschema(owner='Foo'),
  566. isc.config.create_answer(
  567. 1, "specified arguments are incorrect: owner: Foo, name: None"))
  568. self.assertEqual(self.stats.command_showschema(owner='Foo', name='bar'),
  569. isc.config.create_answer(
  570. 1, "specified arguments are incorrect: owner: Foo, name: bar"))
  571. self.assertEqual(self.stats.command_showschema(owner='Auth'),
  572. isc.config.create_answer(
  573. 0, {'Auth': [{
  574. "item_default": 0,
  575. "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially",
  576. "item_name": "queries.tcp",
  577. "item_optional": False,
  578. "item_title": "Queries TCP",
  579. "item_type": "integer"
  580. },
  581. {
  582. "item_default": 0,
  583. "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially",
  584. "item_name": "queries.udp",
  585. "item_optional": False,
  586. "item_title": "Queries UDP",
  587. "item_type": "integer"
  588. },
  589. {
  590. "item_name": "queries.perzone",
  591. "item_type": "list",
  592. "item_optional": False,
  593. "item_default": [
  594. {
  595. "zonename" : "test1.example",
  596. "queries.udp" : 1,
  597. "queries.tcp" : 2
  598. },
  599. {
  600. "zonename" : "test2.example",
  601. "queries.udp" : 3,
  602. "queries.tcp" : 4
  603. }
  604. ],
  605. "item_title": "Queries per zone",
  606. "item_description": "Queries per zone",
  607. "list_item_spec": {
  608. "item_name": "zones",
  609. "item_type": "map",
  610. "item_optional": False,
  611. "item_default": {},
  612. "map_item_spec": [
  613. {
  614. "item_name": "zonename",
  615. "item_type": "string",
  616. "item_optional": False,
  617. "item_default": "",
  618. "item_title": "Zonename",
  619. "item_description": "Zonename"
  620. },
  621. {
  622. "item_name": "queries.udp",
  623. "item_type": "integer",
  624. "item_optional": False,
  625. "item_default": 0,
  626. "item_title": "Queries UDP per zone",
  627. "item_description": "A number of UDP query counts per zone"
  628. },
  629. {
  630. "item_name": "queries.tcp",
  631. "item_type": "integer",
  632. "item_optional": False,
  633. "item_default": 0,
  634. "item_title": "Queries TCP per zone",
  635. "item_description": "A number of TCP query counts per zone"
  636. }
  637. ]
  638. }
  639. }]}))
  640. self.assertEqual(self.stats.command_showschema(owner='Auth', name='queries.tcp'),
  641. isc.config.create_answer(
  642. 0, {'Auth': [{
  643. "item_default": 0,
  644. "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially",
  645. "item_name": "queries.tcp",
  646. "item_optional": False,
  647. "item_title": "Queries TCP",
  648. "item_type": "integer"
  649. }]}))
  650. self.assertEqual(self.stats.command_showschema(owner='Auth', name='queries.perzone'),
  651. isc.config.create_answer(
  652. 0, {'Auth':[{
  653. "item_name": "queries.perzone",
  654. "item_type": "list",
  655. "item_optional": False,
  656. "item_default": [
  657. {
  658. "zonename" : "test1.example",
  659. "queries.udp" : 1,
  660. "queries.tcp" : 2
  661. },
  662. {
  663. "zonename" : "test2.example",
  664. "queries.udp" : 3,
  665. "queries.tcp" : 4
  666. }
  667. ],
  668. "item_title": "Queries per zone",
  669. "item_description": "Queries per zone",
  670. "list_item_spec": {
  671. "item_name": "zones",
  672. "item_type": "map",
  673. "item_optional": False,
  674. "item_default": {},
  675. "map_item_spec": [
  676. {
  677. "item_name": "zonename",
  678. "item_type": "string",
  679. "item_optional": False,
  680. "item_default": "",
  681. "item_title": "Zonename",
  682. "item_description": "Zonename"
  683. },
  684. {
  685. "item_name": "queries.udp",
  686. "item_type": "integer",
  687. "item_optional": False,
  688. "item_default": 0,
  689. "item_title": "Queries UDP per zone",
  690. "item_description": "A number of UDP query counts per zone"
  691. },
  692. {
  693. "item_name": "queries.tcp",
  694. "item_type": "integer",
  695. "item_optional": False,
  696. "item_default": 0,
  697. "item_title": "Queries TCP per zone",
  698. "item_description": "A number of TCP query counts per zone"
  699. }
  700. ]
  701. }
  702. }]}))
  703. self.assertEqual(self.stats.command_showschema(owner='Stats', name='bar'),
  704. isc.config.create_answer(
  705. 1, "specified arguments are incorrect: owner: Stats, name: bar"))
  706. self.assertEqual(self.stats.command_showschema(name='bar'),
  707. isc.config.create_answer(
  708. 1, "module name is not specified"))
  709. def test_polling(self):
  710. stats_server = ThreadingServerManager(MyStats)
  711. stat = stats_server.server
  712. stats_server.run()
  713. self.assertEqual(
  714. send_command('status', 'Stats'),
  715. (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
  716. # check statistics data of 'Boss'
  717. boss = self.base.boss.server
  718. self.assertEqual(
  719. stat.statistics_data_bymid['Boss'][boss.cc_session.lname],
  720. {'boot_time': self.const_datetime})
  721. self.assertEqual(
  722. len(stat.statistics_data_bymid['Boss']), 1)
  723. self.assertEqual(
  724. stat.statistics_data['Boss'],
  725. {'boot_time': self.const_datetime})
  726. # check statistics data of each 'Auth' instances
  727. list_auth = ['', '2', '3', '4']
  728. for i in list_auth:
  729. auth = getattr(self.base,"auth"+i).server
  730. self.assertEqual(
  731. stat.statistics_data_bymid['Auth']\
  732. [auth.cc_session.lname],
  733. {'queries.perzone': auth.queries_per_zone,
  734. 'queries.tcp': auth.queries_tcp,
  735. 'queries.udp': auth.queries_udp})
  736. n = len(stat.statistics_data_bymid['Auth'])
  737. self.assertEqual(n, len(list_auth))
  738. # check consolidation of statistics data of the auth
  739. # instances
  740. self.assertEqual(
  741. stat.statistics_data['Auth'],
  742. {'queries.perzone': [
  743. {'zonename':
  744. auth.queries_per_zone[0]['zonename'],
  745. 'queries.tcp':
  746. auth.queries_per_zone[0]['queries.tcp']*n,
  747. 'queries.udp':
  748. auth.queries_per_zone[0]['queries.udp']*n}],
  749. 'queries.tcp': auth.queries_tcp*n,
  750. 'queries.udp': auth.queries_udp*n})
  751. # check statistics data of 'Stats'
  752. self.assertEqual(
  753. len(stat.statistics_data['Stats']), 5)
  754. self.assertTrue('boot_time' in
  755. stat.statistics_data['Stats'])
  756. self.assertTrue('last_update_time' in
  757. stat.statistics_data['Stats'])
  758. self.assertTrue('report_time' in
  759. stat.statistics_data['Stats'])
  760. self.assertTrue('timestamp' in
  761. stat.statistics_data['Stats'])
  762. self.assertEqual(
  763. stat.statistics_data['Stats']['lname'],
  764. stat.mccs._session.lname)
  765. stats_server.shutdown()
  766. def test_polling2(self):
  767. # set invalid statistics
  768. boss = self.base.boss.server
  769. boss.statistics_data = {'boot_time':1}
  770. stats_server = ThreadingServerManager(MyStats)
  771. stat = stats_server.server
  772. stats_server.run()
  773. self.assertEqual(
  774. send_command('status', 'Stats'),
  775. (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
  776. # check default statistics data of 'Boss'
  777. self.assertEqual(
  778. stat.statistics_data['Boss'],
  779. {'boot_time': self.const_default_datetime})
  780. stats_server.shutdown()
  781. class TestOSEnv(unittest.TestCase):
  782. def test_osenv(self):
  783. """
  784. test for the environ variable "B10_FROM_SOURCE"
  785. "B10_FROM_SOURCE" is set in Makefile
  786. """
  787. # test case having B10_FROM_SOURCE
  788. self.assertTrue("B10_FROM_SOURCE" in os.environ)
  789. self.assertEqual(stats.SPECFILE_LOCATION, \
  790. os.environ["B10_FROM_SOURCE"] + os.sep + \
  791. "src" + os.sep + "bin" + os.sep + "stats" + \
  792. os.sep + "stats.spec")
  793. # test case not having B10_FROM_SOURCE
  794. path = os.environ["B10_FROM_SOURCE"]
  795. os.environ.pop("B10_FROM_SOURCE")
  796. self.assertFalse("B10_FROM_SOURCE" in os.environ)
  797. # import stats again
  798. imp.reload(stats)
  799. # revert the changes
  800. os.environ["B10_FROM_SOURCE"] = path
  801. imp.reload(stats)
  802. def test_main():
  803. unittest.main()
  804. if __name__ == "__main__":
  805. test_main()