PageRenderTime 63ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/test/test_datastore.py

http://github.com/bashwork/pymodbus
Python | 410 lines | 304 code | 74 blank | 32 comment | 15 complexity | c1170a32fa665e01664766aff4ba890a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, GPL-2.0
  1. #!/usr/bin/env python
  2. import unittest
  3. import mock
  4. from mock import MagicMock
  5. import redis
  6. import random
  7. from pymodbus.datastore import *
  8. from pymodbus.datastore.store import BaseModbusDataBlock
  9. from pymodbus.datastore.database import SqlSlaveContext
  10. from pymodbus.datastore.database import RedisSlaveContext
  11. from pymodbus.exceptions import NotImplementedException
  12. from pymodbus.exceptions import NoSuchSlaveException
  13. from pymodbus.exceptions import ParameterException
  14. from pymodbus.datastore.remote import RemoteSlaveContext
  15. class ModbusDataStoreTest(unittest.TestCase):
  16. '''
  17. This is the unittest for the pymodbus.datastore module
  18. '''
  19. def setUp(self):
  20. pass
  21. def tearDown(self):
  22. ''' Cleans up the test environment '''
  23. pass
  24. def testModbusDataBlock(self):
  25. ''' Test a base data block store '''
  26. block = BaseModbusDataBlock()
  27. block.default(10, True)
  28. self.assertNotEqual(str(block), None)
  29. self.assertEqual(block.default_value, True)
  30. self.assertEqual(block.values, [True]*10)
  31. block.default_value = False
  32. block.reset()
  33. self.assertEqual(block.values, [False]*10)
  34. def testModbusDataBlockIterate(self):
  35. ''' Test a base data block store '''
  36. block = BaseModbusDataBlock()
  37. block.default(10, False)
  38. for idx,value in block:
  39. self.assertEqual(value, False)
  40. block.values = {0 : False, 2 : False, 3 : False }
  41. for idx,value in block:
  42. self.assertEqual(value, False)
  43. def testModbusDataBlockOther(self):
  44. ''' Test a base data block store '''
  45. block = BaseModbusDataBlock()
  46. self.assertRaises(NotImplementedException, lambda: block.validate(1,1))
  47. self.assertRaises(NotImplementedException, lambda: block.getValues(1,1))
  48. self.assertRaises(NotImplementedException, lambda: block.setValues(1,1))
  49. def testModbusSequentialDataBlock(self):
  50. ''' Test a sequential data block store '''
  51. block = ModbusSequentialDataBlock(0x00, [False]*10)
  52. self.assertFalse(block.validate(-1, 0))
  53. self.assertFalse(block.validate(0, 20))
  54. self.assertFalse(block.validate(10, 1))
  55. self.assertTrue(block.validate(0x00, 10))
  56. block.setValues(0x00, True)
  57. self.assertEqual(block.getValues(0x00, 1), [True])
  58. block.setValues(0x00, [True]*10)
  59. self.assertEqual(block.getValues(0x00, 10), [True]*10)
  60. def testModbusSequentialDataBlockFactory(self):
  61. ''' Test the sequential data block store factory '''
  62. block = ModbusSequentialDataBlock.create()
  63. self.assertEqual(block.getValues(0x00, 65536), [False]*65536)
  64. block = ModbusSequentialDataBlock(0x00, 0x01)
  65. self.assertEqual(block.values, [0x01])
  66. def testModbusSparseDataBlock(self):
  67. ''' Test a sparse data block store '''
  68. values = dict(enumerate([True]*10))
  69. block = ModbusSparseDataBlock(values)
  70. self.assertFalse(block.validate(-1, 0))
  71. self.assertFalse(block.validate(0, 20))
  72. self.assertFalse(block.validate(10, 1))
  73. self.assertTrue(block.validate(0x00, 10))
  74. self.assertTrue(block.validate(0x00, 10))
  75. self.assertFalse(block.validate(0, 0))
  76. self.assertFalse(block.validate(5, 0))
  77. block.setValues(0x00, True)
  78. self.assertEqual(block.getValues(0x00, 1), [True])
  79. block.setValues(0x00, [True]*10)
  80. self.assertEqual(block.getValues(0x00, 10), [True]*10)
  81. block.setValues(0x00, dict(enumerate([False]*10)))
  82. self.assertEqual(block.getValues(0x00, 10), [False]*10)
  83. block = ModbusSparseDataBlock({3: [10, 11, 12], 10: 1, 15: [0] * 4})
  84. self.assertEqual(block.values, {3: 10, 4: 11, 5: 12, 10: 1,
  85. 15:0 , 16:0, 17:0, 18:0 })
  86. self.assertEqual(block.default_value, {3: 10, 4: 11, 5: 12, 10: 1,
  87. 15:0 , 16:0, 17:0, 18:0 })
  88. self.assertEqual(block.mutable, True)
  89. block.setValues(3, [20, 21, 22, 23], use_as_default=True)
  90. self.assertEqual(block.getValues(3, 4), [20, 21, 22, 23])
  91. self.assertEqual(block.default_value, {3: 20, 4: 21, 5: 22, 6:23, 10: 1,
  92. 15:0 , 16:0, 17:0, 18:0 })
  93. # check when values is a dict, address is ignored
  94. block.setValues(0, {5: 32, 7: 43})
  95. self.assertEqual(block.getValues(5, 3), [32, 23, 43])
  96. # assert value is empty dict when initialized without params
  97. block = ModbusSparseDataBlock()
  98. self.assertEqual(block.values, {})
  99. # mark block as unmutable and see if parameter exeception
  100. # is raised for invalid offset writes
  101. block = ModbusSparseDataBlock({1: 100}, mutable=False)
  102. self.assertRaises(ParameterException, block.setValues, 0, 1)
  103. self.assertRaises(ParameterException, block.setValues, 0, {2: 100})
  104. self.assertRaises(ParameterException, block.setValues, 0, [1] * 10)
  105. # Reset datablock
  106. block = ModbusSparseDataBlock({3: [10, 11, 12], 10: 1, 15: [0] * 4})
  107. block.setValues(0, {3: [20, 21, 22], 10: 11, 15: [10] * 4})
  108. self.assertEqual(block.values, {3: 20, 4: 21, 5: 22, 10: 11,
  109. 15: 10 ,16:10, 17:10, 18:10 })
  110. block.reset()
  111. self.assertEqual(block.values, {3: 10, 4: 11, 5: 12, 10: 1,
  112. 15: 0, 16: 0, 17: 0, 18: 0})
  113. def testModbusSparseDataBlockFactory(self):
  114. ''' Test the sparse data block store factory '''
  115. block = ModbusSparseDataBlock.create([0x00]*65536)
  116. self.assertEqual(block.getValues(0x00, 65536), [False]*65536)
  117. def testModbusSparseDataBlockOther(self):
  118. block = ModbusSparseDataBlock([True]*10)
  119. self.assertEqual(block.getValues(0x00, 10), [True]*10)
  120. self.assertRaises(ParameterException,
  121. lambda: ModbusSparseDataBlock(True))
  122. def testModbusSlaveContext(self):
  123. ''' Test a modbus slave context '''
  124. store = {
  125. 'di' : ModbusSequentialDataBlock(0, [False]*10),
  126. 'co' : ModbusSequentialDataBlock(0, [False]*10),
  127. 'ir' : ModbusSequentialDataBlock(0, [False]*10),
  128. 'hr' : ModbusSequentialDataBlock(0, [False]*10),
  129. }
  130. context = ModbusSlaveContext(**store)
  131. self.assertNotEqual(str(context), None)
  132. for fx in [1,2,3,4]:
  133. context.setValues(fx, 0, [True]*10)
  134. self.assertTrue(context.validate(fx, 0,10))
  135. self.assertEqual(context.getValues(fx, 0,10), [True]*10)
  136. context.reset()
  137. for fx in [1,2,3,4]:
  138. self.assertTrue(context.validate(fx, 0,10))
  139. self.assertEqual(context.getValues(fx, 0,10), [False]*10)
  140. def testModbusServerContext(self):
  141. ''' Test a modbus server context '''
  142. def _set(ctx):
  143. ctx[0xffff] = None
  144. context = ModbusServerContext(single=False)
  145. self.assertRaises(NoSuchSlaveException, lambda: _set(context))
  146. self.assertRaises(NoSuchSlaveException, lambda: context[0xffff])
  147. class RedisDataStoreTest(unittest.TestCase):
  148. '''
  149. This is the unittest for the pymodbus.datastore.database.redis module
  150. '''
  151. def setUp(self):
  152. self.slave = RedisSlaveContext()
  153. def tearDown(self):
  154. ''' Cleans up the test environment '''
  155. pass
  156. def testStr(self):
  157. # slave = RedisSlaveContext()
  158. self.assertEqual(str(self.slave), "Redis Slave Context %s" % self.slave.client)
  159. def testReset(self):
  160. assert isinstance(self.slave.client, redis.Redis)
  161. self.slave.client = MagicMock()
  162. self.slave.reset()
  163. self.slave.client.flushall.assert_called_once_with()
  164. def testValCallbacksSuccess(self):
  165. self.slave._build_mapping()
  166. mock_count = 3
  167. mock_offset = 0
  168. self.slave.client.mset = MagicMock()
  169. self.slave.client.mget = MagicMock(return_value=['11'])
  170. for key in ('d', 'c', 'h', 'i'):
  171. self.assertTrue(
  172. self.slave._val_callbacks[key](mock_offset, mock_count)
  173. )
  174. def testValCallbacksFailure(self):
  175. self.slave._build_mapping()
  176. mock_count = 3
  177. mock_offset = 0
  178. self.slave.client.mset = MagicMock()
  179. self.slave.client.mget = MagicMock(return_value=['11', None])
  180. for key in ('d', 'c', 'h', 'i'):
  181. self.assertFalse(
  182. self.slave._val_callbacks[key](mock_offset, mock_count)
  183. )
  184. def testGetCallbacks(self):
  185. self.slave._build_mapping()
  186. mock_count = 3
  187. mock_offset = 0
  188. self.slave.client.mget = MagicMock(return_value='11')
  189. for key in ('d', 'c'):
  190. resp = self.slave._get_callbacks[key](mock_offset, mock_count)
  191. self.assertEqual(resp, [True, False, False])
  192. for key in ('h', 'i'):
  193. resp = self.slave._get_callbacks[key](mock_offset, mock_count)
  194. self.assertEqual(resp, ['1', '1'])
  195. def testSetCallbacks(self):
  196. self.slave._build_mapping()
  197. mock_values = [3]
  198. mock_offset = 0
  199. self.slave.client.mset = MagicMock()
  200. self.slave.client.mget = MagicMock()
  201. for key in ['c', 'd']:
  202. self.slave._set_callbacks[key](mock_offset, [3])
  203. k = "pymodbus:{}:{}".format(key, mock_offset)
  204. self.slave.client.mset.assert_called_with(
  205. {k: '\x01'}
  206. )
  207. for key in ('h', 'i'):
  208. self.slave._set_callbacks[key](mock_offset, [3])
  209. k = "pymodbus:{}:{}".format(key, mock_offset)
  210. self.slave.client.mset.assert_called_with(
  211. {k: mock_values[0]}
  212. )
  213. def testValidate(self):
  214. self.slave.client.mget = MagicMock(return_value=[123])
  215. self.assertTrue(self.slave.validate(0x01, 3000))
  216. def testSetValue(self):
  217. self.slave.client.mset = MagicMock()
  218. self.slave.client.mget = MagicMock()
  219. self.assertEqual(self.slave.setValues(0x01, 1000, [12]), None)
  220. def testGetValue(self):
  221. self.slave.client.mget = MagicMock(return_value=["123"])
  222. self.assertEqual(self.slave.getValues(0x01, 23), [])
  223. class MockSqlResult(object):
  224. def __init__(self, rowcount=0, value=0):
  225. self.rowcount = rowcount
  226. self.value = value
  227. class SqlDataStoreTest(unittest.TestCase):
  228. '''
  229. This is the unittest for the pymodbus.datastore.database.SqlSlaveContesxt
  230. module
  231. '''
  232. def setUp(self):
  233. self.slave = SqlSlaveContext()
  234. self.slave._metadata.drop_all = MagicMock()
  235. self.slave._db_create = MagicMock()
  236. self.slave._table.select = MagicMock()
  237. self.slave._connection = MagicMock()
  238. self.mock_addr = random.randint(0, 65000)
  239. self.mock_values = random.sample(range(1, 100), 5)
  240. self.mock_function = 0x01
  241. self.mock_type = 'h'
  242. self.mock_offset = 0
  243. self.mock_count = 1
  244. self.function_map = {2: 'd', 4: 'i'}
  245. self.function_map.update([(i, 'h') for i in [3, 6, 16, 22, 23]])
  246. self.function_map.update([(i, 'c') for i in [1, 5, 15]])
  247. def tearDown(self):
  248. ''' Cleans up the test environment '''
  249. pass
  250. def testStr(self):
  251. self.assertEqual(str(self.slave), "Modbus Slave Context")
  252. def testReset(self):
  253. self.slave.reset()
  254. self.slave._metadata.drop_all.assert_called_once_with()
  255. self.slave._db_create.assert_called_once_with(
  256. self.slave.table, self.slave.database
  257. )
  258. def testValidateSuccess(self):
  259. self.slave._connection.execute.return_value.fetchall.return_value = self.mock_values
  260. self.assertTrue(self.slave.validate(
  261. self.mock_function, self.mock_addr, len(self.mock_values))
  262. )
  263. def testValidateFailure(self):
  264. wrong_count = 9
  265. self.slave._connection.execute.return_value.fetchall.return_value = self.mock_values
  266. self.assertFalse(self.slave.validate(
  267. self.mock_function, self.mock_addr, wrong_count)
  268. )
  269. def testBuildSet(self):
  270. mock_set = [
  271. {
  272. 'index': 0,
  273. 'type': 'h',
  274. 'value': 11
  275. },
  276. {
  277. 'index': 1,
  278. 'type': 'h',
  279. 'value': 12
  280. }
  281. ]
  282. self.assertListEqual(self.slave._build_set('h', 0, [11, 12]), mock_set)
  283. def testCheckSuccess(self):
  284. mock_success_results = [1, 2, 3]
  285. self.slave._get = MagicMock(return_value=mock_success_results)
  286. self.assertFalse(self.slave._check('h', 0, 1))
  287. def testCheckFailure(self):
  288. mock_success_results = []
  289. self.slave._get = MagicMock(return_value=mock_success_results)
  290. self.assertTrue(self.slave._check('h', 0, 1))
  291. def testGetValues(self):
  292. self.slave._get = MagicMock()
  293. for key, value in self.function_map.items():
  294. self.slave.getValues(key, self.mock_addr, self.mock_count)
  295. self.slave._get.assert_called_with(
  296. value, self.mock_addr + 1, self.mock_count
  297. )
  298. def testSetValues(self):
  299. self.slave._set = MagicMock()
  300. for key, value in self.function_map.items():
  301. self.slave.setValues(key, self.mock_addr,
  302. self.mock_values, update=False)
  303. self.slave._set.assert_called_with(
  304. value, self.mock_addr + 1, self.mock_values
  305. )
  306. def testSet(self):
  307. self.slave._check = MagicMock(return_value=True)
  308. self.slave._connection.execute = MagicMock(
  309. return_value=MockSqlResult(rowcount=len(self.mock_values))
  310. )
  311. self.assertTrue(self.slave._set(
  312. self.mock_type, self.mock_offset, self.mock_values)
  313. )
  314. self.slave._check = MagicMock(return_value=False)
  315. self.assertFalse(
  316. self.slave._set(self.mock_type, self.mock_offset, self.mock_values)
  317. )
  318. def testUpdateSuccess(self):
  319. self.slave._connection.execute = MagicMock(
  320. return_value=MockSqlResult(rowcount=len(self.mock_values))
  321. )
  322. self.assertTrue(
  323. self.slave._update(self.mock_type, self.mock_offset, self.mock_values)
  324. )
  325. def testUpdateFailure(self):
  326. self.slave._connection.execute = MagicMock(
  327. return_value=MockSqlResult(rowcount=100)
  328. )
  329. self.assertFalse(
  330. self.slave._update(self.mock_type, self.mock_offset, self.mock_values)
  331. )
  332. # --------------------------------------------------------------------------- #
  333. # Main
  334. # --------------------------------------------------------------------------- #
  335. if __name__ == "__main__":
  336. unittest.main()