test_modbus_read_api.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import unittest
  2. from common import (
  3. FUNC_CODE_COIL,
  4. FUNC_CODE_DISCRETE_INPUT,
  5. FUNC_CODE_HOLDING_REGISTER,
  6. FUNC_CODE_INPUT_REGISTER,
  7. all_type_point_specs,
  8. assert_frame_format,
  9. assert_response_contract,
  10. parse_frame,
  11. point_read_payload,
  12. post_json,
  13. raw_read_payload,
  14. )
  15. def expected_device(payload):
  16. return {
  17. "device_type": payload["device_type"],
  18. "ip": payload["ip"],
  19. "port": payload["port"],
  20. "word_byte_order": payload["word_byte_order"],
  21. "address_base": payload["address_base"],
  22. "slave_id": payload["slave_id"],
  23. }
  24. class ModbusReadApiIntegrationTest(unittest.TestCase):
  25. def test_raw_read_returns_modbus_poll_style_communication(self):
  26. payload = raw_read_payload(FUNC_CODE_HOLDING_REGISTER, address=0, quantity=4)
  27. status, data = post_json(
  28. "/api/dc-gateway/modbus/read",
  29. payload,
  30. )
  31. assert_response_contract(self, status, data)
  32. self.assertEqual(0, data["code"], data)
  33. self.assertEqual("success", data["msg"])
  34. self.assertNotIn("values", data)
  35. self.assertNotIn("communication", data)
  36. self.assertNotIn("device", data)
  37. self.assertEqual(expected_device(payload), data["data"]["device"])
  38. communication = data["data"]["communication"]
  39. assert_frame_format(self, communication)
  40. tx_frames = [parse_frame(frame)[1] for frame in communication if frame.startswith("Tx:")]
  41. rx_frames = [parse_frame(frame)[1] for frame in communication if frame.startswith("Rx:")]
  42. self.assertTrue(tx_frames, data)
  43. self.assertTrue(rx_frames, data)
  44. tx = tx_frames[0]
  45. self.assertGreaterEqual(len(tx), 12)
  46. self.assertEqual(FUNC_CODE_HOLDING_REGISTER, tx[7])
  47. self.assertEqual([0x00, 0x00], tx[8:10])
  48. self.assertEqual([0x00, 0x04], tx[10:12])
  49. rx = rx_frames[0]
  50. self.assertGreaterEqual(len(rx), 9)
  51. self.assertEqual(FUNC_CODE_HOLDING_REGISTER, rx[7])
  52. self.assertEqual(8, rx[8])
  53. def test_read_points_returns_all_function_codes_and_types(self):
  54. payload = point_read_payload(all_type_point_specs())
  55. status, data = post_json("/api/dc-gateway/modbus/read_points", payload)
  56. assert_response_contract(self, status, data)
  57. self.assertEqual(0, data["code"], data)
  58. self.assertNotIn("communication", data)
  59. self.assertNotIn("device", data)
  60. self.assertEqual(expected_device(payload), data["data"]["device"])
  61. points = data["data"]["points"]
  62. self.assertEqual(len(payload["points"]), len(points))
  63. seen = {(point["function_code"], point["address"], point["type"], point.get("bit")) for point in points}
  64. expected = {(point["function_code"], point["address"], point["type"], point.get("bit")) for point in payload["points"]}
  65. self.assertEqual(expected, seen)
  66. self.assertTrue(any(point["function_code"] == FUNC_CODE_COIL for point in points))
  67. self.assertTrue(any(point["function_code"] == FUNC_CODE_DISCRETE_INPUT for point in points))
  68. self.assertTrue(any(point["function_code"] == FUNC_CODE_HOLDING_REGISTER for point in points))
  69. self.assertTrue(any(point["function_code"] == FUNC_CODE_INPUT_REGISTER for point in points))
  70. for point in points:
  71. self.assertIn("value", point)
  72. self.assertNotIn("address_base", point)
  73. self.assertNotIn("protocol_address", point)
  74. self.assertNotIn("raw_values", point)
  75. self.assertNotIn("communication", point)
  76. if point["type"] == "bool":
  77. self.assertIsInstance(point["value"], bool)
  78. elif point["type"].startswith("float"):
  79. self.assertIsInstance(point["value"], float)
  80. else:
  81. self.assertIsInstance(point["value"], int)
  82. def test_validation_error_returns_http_200_contract(self):
  83. status, data = post_json(
  84. "/api/dc-gateway/modbus/read",
  85. raw_read_payload(FUNC_CODE_HOLDING_REGISTER, address=0, quantity=126),
  86. )
  87. assert_response_contract(self, status, data)
  88. self.assertEqual(1, data["code"], data)
  89. self.assertIn("quantity", data["msg"])
  90. self.assertEqual([], data["data"]["communication"])
  91. if __name__ == "__main__":
  92. unittest.main()