helper_test.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. # -*- coding: utf-8 -*-
  2. """Set of series helper functions for test."""
  3. from __future__ import absolute_import
  4. from __future__ import division
  5. from __future__ import print_function
  6. from __future__ import unicode_literals
  7. from datetime import datetime, timedelta
  8. import unittest
  9. import warnings
  10. import mock
  11. from influxdb import SeriesHelper, InfluxDBClient
  12. from requests.exceptions import ConnectionError
  13. class TestSeriesHelper(unittest.TestCase):
  14. """Define the SeriesHelper test object."""
  15. @classmethod
  16. def setUpClass(cls):
  17. """Set up the TestSeriesHelper object."""
  18. super(TestSeriesHelper, cls).setUpClass()
  19. TestSeriesHelper.client = InfluxDBClient(
  20. 'host',
  21. 8086,
  22. 'username',
  23. 'password',
  24. 'database'
  25. )
  26. class MySeriesHelper(SeriesHelper):
  27. """Define a SeriesHelper object."""
  28. class Meta:
  29. """Define metadata for the SeriesHelper object."""
  30. client = TestSeriesHelper.client
  31. series_name = 'events.stats.{server_name}'
  32. fields = ['some_stat']
  33. tags = ['server_name', 'other_tag']
  34. bulk_size = 5
  35. autocommit = True
  36. TestSeriesHelper.MySeriesHelper = MySeriesHelper
  37. def setUp(self):
  38. """Check that MySeriesHelper has empty datapoints."""
  39. super(TestSeriesHelper, self).setUp()
  40. self.assertEqual(
  41. TestSeriesHelper.MySeriesHelper._json_body_(),
  42. [],
  43. 'Resetting helper in teardown did not empty datapoints.')
  44. def tearDown(self):
  45. """Deconstruct the TestSeriesHelper object."""
  46. super(TestSeriesHelper, self).tearDown()
  47. TestSeriesHelper.MySeriesHelper._reset_()
  48. self.assertEqual(
  49. TestSeriesHelper.MySeriesHelper._json_body_(),
  50. [],
  51. 'Resetting helper did not empty datapoints.')
  52. def test_auto_commit(self):
  53. """Test write_points called after valid number of events."""
  54. class AutoCommitTest(SeriesHelper):
  55. """Define a SeriesHelper instance to test autocommit."""
  56. class Meta:
  57. """Define metadata for AutoCommitTest."""
  58. series_name = 'events.stats.{server_name}'
  59. fields = ['some_stat']
  60. tags = ['server_name', 'other_tag']
  61. bulk_size = 5
  62. client = InfluxDBClient()
  63. autocommit = True
  64. fake_write_points = mock.MagicMock()
  65. AutoCommitTest(server_name='us.east-1', some_stat=159, other_tag='gg')
  66. AutoCommitTest._client.write_points = fake_write_points
  67. AutoCommitTest(server_name='us.east-1', some_stat=158, other_tag='gg')
  68. AutoCommitTest(server_name='us.east-1', some_stat=157, other_tag='gg')
  69. AutoCommitTest(server_name='us.east-1', some_stat=156, other_tag='gg')
  70. self.assertFalse(fake_write_points.called)
  71. AutoCommitTest(server_name='us.east-1', some_stat=3443, other_tag='gg')
  72. self.assertTrue(fake_write_points.called)
  73. @mock.patch('influxdb.helper.SeriesHelper._current_timestamp')
  74. def testSingleSeriesName(self, current_timestamp):
  75. """Test JSON conversion when there is only one series name."""
  76. current_timestamp.return_value = current_date = datetime.today()
  77. TestSeriesHelper.MySeriesHelper(
  78. server_name='us.east-1', other_tag='ello', some_stat=159)
  79. TestSeriesHelper.MySeriesHelper(
  80. server_name='us.east-1', other_tag='ello', some_stat=158)
  81. TestSeriesHelper.MySeriesHelper(
  82. server_name='us.east-1', other_tag='ello', some_stat=157)
  83. TestSeriesHelper.MySeriesHelper(
  84. server_name='us.east-1', other_tag='ello', some_stat=156)
  85. expectation = [
  86. {
  87. "measurement": "events.stats.us.east-1",
  88. "tags": {
  89. "other_tag": "ello",
  90. "server_name": "us.east-1"
  91. },
  92. "fields": {
  93. "some_stat": 159
  94. },
  95. "time": current_date,
  96. },
  97. {
  98. "measurement": "events.stats.us.east-1",
  99. "tags": {
  100. "other_tag": "ello",
  101. "server_name": "us.east-1"
  102. },
  103. "fields": {
  104. "some_stat": 158
  105. },
  106. "time": current_date,
  107. },
  108. {
  109. "measurement": "events.stats.us.east-1",
  110. "tags": {
  111. "other_tag": "ello",
  112. "server_name": "us.east-1"
  113. },
  114. "fields": {
  115. "some_stat": 157
  116. },
  117. "time": current_date,
  118. },
  119. {
  120. "measurement": "events.stats.us.east-1",
  121. "tags": {
  122. "other_tag": "ello",
  123. "server_name": "us.east-1"
  124. },
  125. "fields": {
  126. "some_stat": 156
  127. },
  128. "time": current_date,
  129. }
  130. ]
  131. rcvd = TestSeriesHelper.MySeriesHelper._json_body_()
  132. self.assertTrue(all([el in expectation for el in rcvd]) and
  133. all([el in rcvd for el in expectation]),
  134. 'Invalid JSON body of time series returned from '
  135. '_json_body_ for one series name: {0}.'.format(rcvd))
  136. @mock.patch('influxdb.helper.SeriesHelper._current_timestamp')
  137. def testSeveralSeriesNames(self, current_timestamp):
  138. """Test JSON conversion when there are multiple series names."""
  139. current_timestamp.return_value = current_date = datetime.today()
  140. TestSeriesHelper.MySeriesHelper(
  141. server_name='us.east-1', some_stat=159, other_tag='ello')
  142. TestSeriesHelper.MySeriesHelper(
  143. server_name='fr.paris-10', some_stat=158, other_tag='ello')
  144. TestSeriesHelper.MySeriesHelper(
  145. server_name='lu.lux', some_stat=157, other_tag='ello')
  146. TestSeriesHelper.MySeriesHelper(
  147. server_name='uk.london', some_stat=156, other_tag='ello')
  148. expectation = [
  149. {
  150. 'fields': {
  151. 'some_stat': 157
  152. },
  153. 'measurement': 'events.stats.lu.lux',
  154. 'tags': {
  155. 'other_tag': 'ello',
  156. 'server_name': 'lu.lux'
  157. },
  158. "time": current_date,
  159. },
  160. {
  161. 'fields': {
  162. 'some_stat': 156
  163. },
  164. 'measurement': 'events.stats.uk.london',
  165. 'tags': {
  166. 'other_tag': 'ello',
  167. 'server_name': 'uk.london'
  168. },
  169. "time": current_date,
  170. },
  171. {
  172. 'fields': {
  173. 'some_stat': 158
  174. },
  175. 'measurement': 'events.stats.fr.paris-10',
  176. 'tags': {
  177. 'other_tag': 'ello',
  178. 'server_name': 'fr.paris-10'
  179. },
  180. "time": current_date,
  181. },
  182. {
  183. 'fields': {
  184. 'some_stat': 159
  185. },
  186. 'measurement': 'events.stats.us.east-1',
  187. 'tags': {
  188. 'other_tag': 'ello',
  189. 'server_name': 'us.east-1'
  190. },
  191. "time": current_date,
  192. }
  193. ]
  194. rcvd = TestSeriesHelper.MySeriesHelper._json_body_()
  195. self.assertTrue(all([el in expectation for el in rcvd]) and
  196. all([el in rcvd for el in expectation]),
  197. 'Invalid JSON body of time series returned from '
  198. '_json_body_ for several series names: {0}.'
  199. .format(rcvd))
  200. @mock.patch('influxdb.helper.SeriesHelper._current_timestamp')
  201. def testSeriesWithoutTimeField(self, current_timestamp):
  202. """Test that time is optional on a series without a time field."""
  203. current_date = datetime.today()
  204. yesterday = current_date - timedelta(days=1)
  205. current_timestamp.return_value = yesterday
  206. TestSeriesHelper.MySeriesHelper(
  207. server_name='us.east-1', other_tag='ello',
  208. some_stat=159, time=current_date
  209. )
  210. TestSeriesHelper.MySeriesHelper(
  211. server_name='us.east-1', other_tag='ello',
  212. some_stat=158,
  213. )
  214. point1, point2 = TestSeriesHelper.MySeriesHelper._json_body_()
  215. self.assertTrue('time' in point1 and 'time' in point2)
  216. self.assertEqual(point1['time'], current_date)
  217. self.assertEqual(point2['time'], yesterday)
  218. def testSeriesWithoutAllTags(self):
  219. """Test that creating a data point without a tag throws an error."""
  220. class MyTimeFieldSeriesHelper(SeriesHelper):
  221. class Meta:
  222. client = TestSeriesHelper.client
  223. series_name = 'events.stats.{server_name}'
  224. fields = ['some_stat', 'time']
  225. tags = ['server_name', 'other_tag']
  226. bulk_size = 5
  227. autocommit = True
  228. self.assertRaises(NameError, MyTimeFieldSeriesHelper,
  229. **{"server_name": 'us.east-1',
  230. "some_stat": 158})
  231. @mock.patch('influxdb.helper.SeriesHelper._current_timestamp')
  232. def testSeriesWithTimeField(self, current_timestamp):
  233. """Test that time is optional on a series with a time field."""
  234. current_date = datetime.today()
  235. yesterday = current_date - timedelta(days=1)
  236. current_timestamp.return_value = yesterday
  237. class MyTimeFieldSeriesHelper(SeriesHelper):
  238. class Meta:
  239. client = TestSeriesHelper.client
  240. series_name = 'events.stats.{server_name}'
  241. fields = ['some_stat', 'time']
  242. tags = ['server_name', 'other_tag']
  243. bulk_size = 5
  244. autocommit = True
  245. MyTimeFieldSeriesHelper(
  246. server_name='us.east-1', other_tag='ello',
  247. some_stat=159, time=current_date
  248. )
  249. MyTimeFieldSeriesHelper(
  250. server_name='us.east-1', other_tag='ello',
  251. some_stat=158,
  252. )
  253. point1, point2 = MyTimeFieldSeriesHelper._json_body_()
  254. self.assertTrue('time' in point1 and 'time' in point2)
  255. self.assertEqual(point1['time'], current_date)
  256. self.assertEqual(point2['time'], yesterday)
  257. def testInvalidHelpers(self):
  258. """Test errors in invalid helpers."""
  259. class MissingMeta(SeriesHelper):
  260. """Define instance of SeriesHelper for missing meta."""
  261. pass
  262. class MissingClient(SeriesHelper):
  263. """Define SeriesHelper for missing client data."""
  264. class Meta:
  265. """Define metadat for MissingClient."""
  266. series_name = 'events.stats.{server_name}'
  267. fields = ['time', 'server_name']
  268. autocommit = True
  269. class MissingSeriesName(SeriesHelper):
  270. """Define instance of SeriesHelper for missing series."""
  271. class Meta:
  272. """Define metadata for MissingSeriesName."""
  273. fields = ['time', 'server_name']
  274. class MissingFields(SeriesHelper):
  275. """Define instance of SeriesHelper for missing fields."""
  276. class Meta:
  277. """Define metadata for MissingFields."""
  278. series_name = 'events.stats.{server_name}'
  279. class InvalidTimePrecision(SeriesHelper):
  280. """Define instance of SeriesHelper for invalid time precision."""
  281. class Meta:
  282. """Define metadata for InvalidTimePrecision."""
  283. series_name = 'events.stats.{server_name}'
  284. time_precision = "ks"
  285. fields = ['time', 'server_name']
  286. autocommit = True
  287. for cls in [MissingMeta, MissingClient, MissingFields,
  288. MissingSeriesName, InvalidTimePrecision]:
  289. self.assertRaises(
  290. AttributeError, cls, **{'time': 159,
  291. 'server_name': 'us.east-1'})
  292. @unittest.skip("Fails on py32")
  293. def testWarnBulkSizeZero(self):
  294. """Test warning for an invalid bulk size."""
  295. class WarnBulkSizeZero(SeriesHelper):
  296. class Meta:
  297. client = TestSeriesHelper.client
  298. series_name = 'events.stats.{server_name}'
  299. fields = ['time', 'server_name']
  300. tags = []
  301. bulk_size = 0
  302. autocommit = True
  303. with warnings.catch_warnings(record=True) as w:
  304. warnings.simplefilter("always")
  305. try:
  306. WarnBulkSizeZero(time=159, server_name='us.east-1')
  307. except ConnectionError:
  308. # Server defined in the client is invalid, we're testing
  309. # the warning only.
  310. pass
  311. self.assertEqual(len(w), 1,
  312. '{0} call should have generated one warning.'
  313. .format(WarnBulkSizeZero))
  314. self.assertIn('forced to 1', str(w[-1].message),
  315. 'Warning message did not contain "forced to 1".')
  316. def testWarnBulkSizeNoEffect(self):
  317. """Test warning for a set bulk size but autocommit False."""
  318. class WarnBulkSizeNoEffect(SeriesHelper):
  319. """Define SeriesHelper for warning on bulk size."""
  320. class Meta:
  321. """Define metadat for WarnBulkSizeNoEffect."""
  322. series_name = 'events.stats.{server_name}'
  323. fields = ['time', 'server_name']
  324. bulk_size = 5
  325. tags = []
  326. autocommit = False
  327. with warnings.catch_warnings(record=True) as w:
  328. warnings.simplefilter("always")
  329. WarnBulkSizeNoEffect(time=159, server_name='us.east-1')
  330. self.assertEqual(len(w), 1,
  331. '{0} call should have generated one warning.'
  332. .format(WarnBulkSizeNoEffect))
  333. self.assertIn('has no affect', str(w[-1].message),
  334. 'Warning message did not contain "has not affect".')
  335. def testSeriesWithRetentionPolicy(self):
  336. """Test that the data is saved with the specified retention policy."""
  337. my_policy = 'my_policy'
  338. class RetentionPolicySeriesHelper(SeriesHelper):
  339. class Meta:
  340. client = InfluxDBClient()
  341. series_name = 'events.stats.{server_name}'
  342. fields = ['some_stat', 'time']
  343. tags = ['server_name', 'other_tag']
  344. bulk_size = 2
  345. autocommit = True
  346. retention_policy = my_policy
  347. fake_write_points = mock.MagicMock()
  348. RetentionPolicySeriesHelper(
  349. server_name='us.east-1', some_stat=159, other_tag='gg')
  350. RetentionPolicySeriesHelper._client.write_points = fake_write_points
  351. RetentionPolicySeriesHelper(
  352. server_name='us.east-1', some_stat=158, other_tag='aa')
  353. kall = fake_write_points.call_args
  354. args, kwargs = kall
  355. self.assertTrue('retention_policy' in kwargs)
  356. self.assertEqual(kwargs['retention_policy'], my_policy)
  357. def testSeriesWithoutRetentionPolicy(self):
  358. """Test that the data is saved without any retention policy."""
  359. class NoRetentionPolicySeriesHelper(SeriesHelper):
  360. class Meta:
  361. client = InfluxDBClient()
  362. series_name = 'events.stats.{server_name}'
  363. fields = ['some_stat', 'time']
  364. tags = ['server_name', 'other_tag']
  365. bulk_size = 2
  366. autocommit = True
  367. fake_write_points = mock.MagicMock()
  368. NoRetentionPolicySeriesHelper(
  369. server_name='us.east-1', some_stat=159, other_tag='gg')
  370. NoRetentionPolicySeriesHelper._client.write_points = fake_write_points
  371. NoRetentionPolicySeriesHelper(
  372. server_name='us.east-1', some_stat=158, other_tag='aa')
  373. kall = fake_write_points.call_args
  374. args, kwargs = kall
  375. self.assertTrue('retention_policy' in kwargs)
  376. self.assertEqual(kwargs['retention_policy'], None)