b10-stats_test.py 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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. # start with err
  204. self.stats = stats.Stats()
  205. self.stats.update_statistics_data = lambda x,**y: ['an error']
  206. self.assertRaises(stats.StatsError, self.stats.start)
  207. def test_handlers(self):
  208. self.stats_server = ThreadingServerManager(MyStats)
  209. self.stats = self.stats_server.server
  210. self.stats_server.run()
  211. # command_handler
  212. self.assertEqual(
  213. send_command(
  214. 'show', 'Stats',
  215. params={ 'owner' : 'Boss',
  216. 'name' : 'boot_time' }),
  217. (0, {'Boss': {'boot_time': self.const_datetime}}))
  218. self.assertEqual(
  219. send_command(
  220. 'show', 'Stats',
  221. params={ 'owner' : 'Boss',
  222. 'name' : 'boot_time' }),
  223. (0, {'Boss': {'boot_time': self.const_datetime}}))
  224. self.assertEqual(
  225. send_command('status', 'Stats'),
  226. (0, "Stats is up. (PID " + str(os.getpid()) + ")"))
  227. (rcode, value) = send_command('show', 'Stats')
  228. self.assertEqual(rcode, 0)
  229. self.assertEqual(len(value), 3)
  230. self.assertTrue('Boss' in value)
  231. self.assertTrue('Stats' in value)
  232. self.assertTrue('Auth' in value)
  233. self.assertEqual(len(value['Stats']), 5)
  234. self.assertEqual(len(value['Boss']), 1)
  235. self.assertTrue('boot_time' in value['Boss'])
  236. self.assertEqual(value['Boss']['boot_time'], self.const_datetime)
  237. self.assertTrue('report_time' in value['Stats'])
  238. self.assertTrue('boot_time' in value['Stats'])
  239. self.assertTrue('last_update_time' in value['Stats'])
  240. self.assertTrue('timestamp' in value['Stats'])
  241. self.assertTrue('lname' in value['Stats'])
  242. (rcode, value) = send_command('showschema', 'Stats')
  243. self.assertEqual(rcode, 0)
  244. self.assertEqual(len(value), 3)
  245. self.assertTrue('Boss' in value)
  246. self.assertTrue('Stats' in value)
  247. self.assertTrue('Auth' in value)
  248. self.assertEqual(len(value['Stats']), 5)
  249. self.assertEqual(len(value['Boss']), 1)
  250. for item in value['Boss']:
  251. self.assertTrue(len(item) == 7)
  252. self.assertTrue('item_name' in item)
  253. self.assertTrue('item_type' in item)
  254. self.assertTrue('item_optional' in item)
  255. self.assertTrue('item_default' in item)
  256. self.assertTrue('item_title' in item)
  257. self.assertTrue('item_description' in item)
  258. self.assertTrue('item_format' in item)
  259. for item in value['Stats']:
  260. self.assertTrue(len(item) == 6 or len(item) == 7)
  261. self.assertTrue('item_name' in item)
  262. self.assertTrue('item_type' in item)
  263. self.assertTrue('item_optional' in item)
  264. self.assertTrue('item_default' in item)
  265. self.assertTrue('item_title' in item)
  266. self.assertTrue('item_description' in item)
  267. if len(item) == 7:
  268. self.assertTrue('item_format' in item)
  269. self.assertEqual(
  270. send_command('__UNKNOWN__', 'Stats'),
  271. (1, "Unknown command: '__UNKNOWN__'"))
  272. self.stats_server.shutdown()
  273. def test_update_modules(self):
  274. self.assertEqual(len(self.stats.modules), 0)
  275. self.stats.update_modules()
  276. self.assertTrue('Stats' in self.stats.modules)
  277. self.assertTrue('Boss' in self.stats.modules)
  278. self.assertFalse('Dummy' in self.stats.modules)
  279. my_statistics_data = stats.get_spec_defaults(self.stats.modules['Stats'].get_statistics_spec())
  280. self.assertTrue('report_time' in my_statistics_data)
  281. self.assertTrue('boot_time' in my_statistics_data)
  282. self.assertTrue('last_update_time' in my_statistics_data)
  283. self.assertTrue('timestamp' in my_statistics_data)
  284. self.assertTrue('lname' in my_statistics_data)
  285. self.assertEqual(my_statistics_data['report_time'], self.const_default_datetime)
  286. self.assertEqual(my_statistics_data['boot_time'], self.const_default_datetime)
  287. self.assertEqual(my_statistics_data['last_update_time'], self.const_default_datetime)
  288. self.assertEqual(my_statistics_data['timestamp'], 0.0)
  289. self.assertEqual(my_statistics_data['lname'], "")
  290. my_statistics_data = stats.get_spec_defaults(self.stats.modules['Boss'].get_statistics_spec())
  291. self.assertTrue('boot_time' in my_statistics_data)
  292. self.assertEqual(my_statistics_data['boot_time'], self.const_default_datetime)
  293. orig_parse_answer = stats.isc.config.ccsession.parse_answer
  294. stats.isc.config.ccsession.parse_answer = lambda x: (99, 'error')
  295. self.assertRaises(stats.StatsError, self.stats.update_modules)
  296. stats.isc.config.ccsession.parse_answer = orig_parse_answer
  297. def test_get_statistics_data(self):
  298. my_statistics_data = self.stats.get_statistics_data()
  299. self.assertTrue('Stats' in my_statistics_data)
  300. self.assertTrue('Boss' in my_statistics_data)
  301. self.assertTrue('boot_time' in my_statistics_data['Boss'])
  302. my_statistics_data = self.stats.get_statistics_data(owner='Stats')
  303. self.assertTrue('Stats' in my_statistics_data)
  304. self.assertTrue('report_time' in my_statistics_data['Stats'])
  305. self.assertTrue('boot_time' in my_statistics_data['Stats'])
  306. self.assertTrue('last_update_time' in my_statistics_data['Stats'])
  307. self.assertTrue('timestamp' in my_statistics_data['Stats'])
  308. self.assertTrue('lname' in my_statistics_data['Stats'])
  309. self.assertRaises(stats.StatsError, self.stats.get_statistics_data, owner='Foo')
  310. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='report_time')
  311. self.assertEqual(my_statistics_data['Stats']['report_time'], self.const_default_datetime)
  312. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='boot_time')
  313. self.assertEqual(my_statistics_data['Stats']['boot_time'], self.const_default_datetime)
  314. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='last_update_time')
  315. self.assertEqual(my_statistics_data['Stats']['last_update_time'], self.const_default_datetime)
  316. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='timestamp')
  317. self.assertEqual(my_statistics_data['Stats']['timestamp'], 0.0)
  318. my_statistics_data = self.stats.get_statistics_data(owner='Stats', name='lname')
  319. self.assertEqual(my_statistics_data, {'Stats': {'lname':''}})
  320. self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
  321. owner='Stats', name='Bar')
  322. self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
  323. owner='Foo', name='Bar')
  324. self.assertRaises(stats.StatsError, self.stats.get_statistics_data,
  325. name='Bar')
  326. def test_update_statistics_data(self):
  327. self.stats.update_statistics_data(owner='Stats', lname='foo@bar')
  328. self.assertTrue('Stats' in self.stats.statistics_data)
  329. my_statistics_data = self.stats.statistics_data['Stats']
  330. self.assertEqual(my_statistics_data['lname'], 'foo@bar')
  331. self.stats.update_statistics_data(owner='Stats', last_update_time=self.const_datetime)
  332. self.assertTrue('Stats' in self.stats.statistics_data)
  333. my_statistics_data = self.stats.statistics_data['Stats']
  334. self.assertEqual(my_statistics_data['last_update_time'], self.const_datetime)
  335. self.assertEqual(self.stats.update_statistics_data(owner='Stats', lname=0.0),
  336. ['0.0 should be a string'])
  337. self.assertEqual(self.stats.update_statistics_data(owner='Dummy', foo='bar'),
  338. ['unknown module name: Dummy'])
  339. def test_update_statistics_data_withmid(self):
  340. # one id of Auth
  341. self.stats.update_statistics_data(owner='Auth',
  342. mid="bar@foo",
  343. **{'queries.tcp':1001})
  344. self.assertTrue('Auth' in self.stats.statistics_data)
  345. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  346. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 1001)
  347. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  348. self.assertTrue('bar@foo' in self.stats.statistics_data_bymid['Auth'])
  349. self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid['Auth']['bar@foo'])
  350. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo']['queries.tcp'], 1001)
  351. self.assertEqual(self.stats.statistics_data_bymid,
  352. {'Auth': {'bar@foo': {'queries.tcp': 1001}}})
  353. # check consolidation of statistics data
  354. self.stats.update_statistics_data(owner='Auth',
  355. mid="bar2@foo",
  356. **{'queries.tcp':2001})
  357. self.assertTrue('Auth' in self.stats.statistics_data)
  358. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  359. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 3002)
  360. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  361. self.assertTrue('bar@foo' in self.stats.statistics_data_bymid['Auth'])
  362. self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid['Auth']['bar@foo'])
  363. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo']['queries.tcp'], 1001)
  364. self.assertEqual(self.stats.statistics_data_bymid,
  365. {'Auth': {'bar@foo': {'queries.tcp': 1001},
  366. 'bar2@foo': {'queries.tcp': 2001}}})
  367. # kill running Auth but the statistics data is preserved
  368. self.assertEqual(self.base.boss.server.pid_list[0][0], 9999)
  369. killed = self.base.boss.server.pid_list.pop(0)
  370. self.stats.update_statistics_data()
  371. self.assertTrue('Auth' in self.stats.statistics_data)
  372. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  373. self.assertTrue('queries.udp' in self.stats.statistics_data['Auth'])
  374. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 3002)
  375. self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'], 0)
  376. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  377. # restore statistics data of killed auth
  378. self.base.boss.server.pid_list = [ killed ] + self.base.boss.server.pid_list[:]
  379. self.stats.update_statistics_data(owner='Auth',
  380. mid="bar@foo",
  381. **{'queries.tcp':1001})
  382. # another mid of Auth
  383. self.stats.update_statistics_data(owner='Auth',
  384. mid="bar3@foo",
  385. **{'queries.tcp':1002,
  386. 'queries.udp':1003})
  387. self.assertTrue('Auth' in self.stats.statistics_data)
  388. self.assertTrue('queries.tcp' in self.stats.statistics_data['Auth'])
  389. self.assertTrue('queries.udp' in self.stats.statistics_data['Auth'])
  390. self.assertEqual(self.stats.statistics_data['Auth']['queries.tcp'], 4004)
  391. self.assertEqual(self.stats.statistics_data['Auth']['queries.udp'], 1003)
  392. self.assertTrue('Auth' in self.stats.statistics_data_bymid)
  393. self.assertTrue('bar@foo' in self.stats.statistics_data_bymid['Auth'])
  394. self.assertTrue('bar3@foo' in self.stats.statistics_data_bymid['Auth'])
  395. self.assertTrue('queries.tcp' in self.stats.statistics_data_bymid['Auth']['bar@foo'])
  396. self.assertTrue('queries.udp' in self.stats.statistics_data_bymid['Auth']['bar3@foo'])
  397. self.assertTrue('queries.udp' in self.stats.statistics_data_bymid['Auth']['bar3@foo'])
  398. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar@foo']['queries.tcp'], 1001)
  399. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar3@foo']['queries.tcp'], 1002)
  400. self.assertEqual(self.stats.statistics_data_bymid['Auth']['bar3@foo']['queries.udp'], 1003)
  401. def test_config(self):
  402. stats_server = ThreadingServerManager(MyStats)
  403. stats = stats_server.server
  404. # test updating poll-interval
  405. self.assertEqual(stats.config['poll-interval'], 60)
  406. self.assertEqual(stats.config_handler({'poll-interval': 120}),
  407. isc.config.create_answer(0))
  408. self.assertEqual(stats.config['poll-interval'], 120)
  409. self.assertEqual(stats.config_handler({'poll-interval': "foo"}),
  410. isc.config.create_answer(1, 'foo should be an integer'))
  411. self.assertEqual(stats.config_handler({'poll-interval': -1}),
  412. isc.config.create_answer(1, 'Negative integer ignored'))
  413. # unknown item
  414. self.assertEqual(
  415. stats.config_handler({'_UNKNOWN_KEY_': None}),
  416. isc.config.ccsession.create_answer(
  417. 1, "unknown item _UNKNOWN_KEY_"))
  418. # test no change if zero interval time
  419. self.assertEqual(stats.config_handler({'poll-interval': 0}),
  420. isc.config.create_answer(0))
  421. self.assertEqual(stats.config['poll-interval'], 0)
  422. stats_server.run()
  423. self.assertEqual(
  424. send_command(
  425. 'show', 'Stats',
  426. params={ 'owner' : 'Boss',
  427. 'name' : 'boot_time' }),
  428. (0, {'Boss': {'boot_time': '1970-01-01T00:00:00Z'}}))
  429. stats_server.shutdown()
  430. def test_commands(self):
  431. # status
  432. self.assertEqual(self.stats.command_status(),
  433. isc.config.create_answer(
  434. 0, "Stats is up. (PID " + str(os.getpid()) + ")"))
  435. # shutdown
  436. self.stats.running = True
  437. self.assertEqual(self.stats.command_shutdown(),
  438. isc.config.create_answer(0))
  439. self.assertFalse(self.stats.running)
  440. def test_command_show(self):
  441. self.assertEqual(self.stats.command_show(owner='Foo', name=None),
  442. isc.config.create_answer(
  443. 1, "specified arguments are incorrect: owner: Foo, name: None"))
  444. self.assertEqual(self.stats.command_show(owner='Foo', name='_bar_'),
  445. isc.config.create_answer(
  446. 1, "specified arguments are incorrect: owner: Foo, name: _bar_"))
  447. self.assertEqual(self.stats.command_show(owner='Foo', name='bar'),
  448. isc.config.create_answer(
  449. 1, "specified arguments are incorrect: owner: Foo, name: bar"))
  450. self.assertEqual(self.stats.command_show(owner='Auth'),
  451. isc.config.create_answer(
  452. 0, {'Auth':{ 'queries.udp': 0,
  453. 'queries.tcp': 0,
  454. 'queries.perzone': [{ 'zonename': 'test1.example',
  455. 'queries.udp': 1,
  456. 'queries.tcp': 2 },
  457. { 'zonename': 'test2.example',
  458. 'queries.udp': 3,
  459. 'queries.tcp': 4 }] }}))
  460. self.assertEqual(self.stats.command_show(owner='Auth', name='queries.udp'),
  461. isc.config.create_answer(
  462. 0, {'Auth': {'queries.udp':0}}))
  463. self.assertEqual(self.stats.command_show(owner='Auth', name='queries.perzone'),
  464. isc.config.create_answer(
  465. 0, {'Auth': {'queries.perzone': [{ 'zonename': 'test1.example',
  466. 'queries.udp': 1,
  467. 'queries.tcp': 2 },
  468. { 'zonename': 'test2.example',
  469. 'queries.udp': 3,
  470. 'queries.tcp': 4 }]}}))
  471. orig_get_timestamp = stats.get_timestamp
  472. orig_get_datetime = stats.get_datetime
  473. stats.get_timestamp = lambda : self.const_timestamp
  474. stats.get_datetime = lambda : self.const_datetime
  475. self.assertEqual(stats.get_timestamp(), self.const_timestamp)
  476. self.assertEqual(stats.get_datetime(), self.const_datetime)
  477. self.assertEqual(self.stats.command_show(owner='Stats', name='report_time'), \
  478. isc.config.create_answer(0, {'Stats': {'report_time':self.const_datetime}}))
  479. self.assertEqual(self.stats.statistics_data['Stats']['timestamp'], self.const_timestamp)
  480. self.assertEqual(self.stats.statistics_data['Stats']['boot_time'], self.const_default_datetime)
  481. stats.get_timestamp = orig_get_timestamp
  482. stats.get_datetime = orig_get_datetime
  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_statistics_data(self):
  710. stats_server = ThreadingServerManager(MyStats)
  711. stats = 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. self.assertEqual(
  718. stats.statistics_data_bymid['Boss']\
  719. [self.base.boss.server.cc_session.lname],
  720. {'boot_time': self.const_datetime})
  721. self.assertEqual(
  722. len(stats.statistics_data_bymid['Boss']), 1)
  723. self.assertEqual(
  724. stats.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. stats.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(stats.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. stats.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. stats_server.shutdown()
  752. class TestOSEnv(unittest.TestCase):
  753. def test_osenv(self):
  754. """
  755. test for the environ variable "B10_FROM_SOURCE"
  756. "B10_FROM_SOURCE" is set in Makefile
  757. """
  758. # test case having B10_FROM_SOURCE
  759. self.assertTrue("B10_FROM_SOURCE" in os.environ)
  760. self.assertEqual(stats.SPECFILE_LOCATION, \
  761. os.environ["B10_FROM_SOURCE"] + os.sep + \
  762. "src" + os.sep + "bin" + os.sep + "stats" + \
  763. os.sep + "stats.spec")
  764. # test case not having B10_FROM_SOURCE
  765. path = os.environ["B10_FROM_SOURCE"]
  766. os.environ.pop("B10_FROM_SOURCE")
  767. self.assertFalse("B10_FROM_SOURCE" in os.environ)
  768. # import stats again
  769. imp.reload(stats)
  770. # revert the changes
  771. os.environ["B10_FROM_SOURCE"] = path
  772. imp.reload(stats)
  773. def test_main():
  774. unittest.main()
  775. if __name__ == "__main__":
  776. test_main()