| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- import unittest
- from common import (
- FUNC_CODE_COIL,
- FUNC_CODE_DISCRETE_INPUT,
- FUNC_CODE_HOLDING_REGISTER,
- FUNC_CODE_INPUT_REGISTER,
- all_type_point_specs,
- assert_frame_format,
- assert_response_contract,
- parse_frame,
- point_read_payload,
- post_json,
- raw_read_payload,
- )
- def expected_device(payload):
- return {
- "device_type": payload["device_type"],
- "ip": payload["ip"],
- "port": payload["port"],
- "word_byte_order": payload["word_byte_order"],
- "address_base": payload["address_base"],
- "slave_id": payload["slave_id"],
- }
- class ModbusReadApiIntegrationTest(unittest.TestCase):
- def test_raw_read_returns_modbus_poll_style_communication(self):
- payload = raw_read_payload(FUNC_CODE_HOLDING_REGISTER, address=0, quantity=4)
- status, data = post_json(
- "/api/dc-gateway/modbus/read",
- payload,
- )
- assert_response_contract(self, status, data)
- self.assertEqual(0, data["code"], data)
- self.assertEqual("success", data["msg"])
- self.assertNotIn("values", data)
- self.assertNotIn("communication", data)
- self.assertNotIn("device", data)
- self.assertEqual(expected_device(payload), data["data"]["device"])
- communication = data["data"]["communication"]
- assert_frame_format(self, communication)
- tx_frames = [parse_frame(frame)[1] for frame in communication if frame.startswith("Tx:")]
- rx_frames = [parse_frame(frame)[1] for frame in communication if frame.startswith("Rx:")]
- self.assertTrue(tx_frames, data)
- self.assertTrue(rx_frames, data)
- tx = tx_frames[0]
- self.assertGreaterEqual(len(tx), 12)
- self.assertEqual(FUNC_CODE_HOLDING_REGISTER, tx[7])
- self.assertEqual([0x00, 0x00], tx[8:10])
- self.assertEqual([0x00, 0x04], tx[10:12])
- rx = rx_frames[0]
- self.assertGreaterEqual(len(rx), 9)
- self.assertEqual(FUNC_CODE_HOLDING_REGISTER, rx[7])
- self.assertEqual(8, rx[8])
- def test_read_points_returns_all_function_codes_and_types(self):
- payload = point_read_payload(all_type_point_specs())
- status, data = post_json("/api/dc-gateway/modbus/read_points", payload)
- assert_response_contract(self, status, data)
- self.assertEqual(0, data["code"], data)
- self.assertNotIn("communication", data)
- self.assertNotIn("device", data)
- self.assertEqual(expected_device(payload), data["data"]["device"])
- points = data["data"]["points"]
- self.assertEqual(len(payload["points"]), len(points))
- seen = {(point["function_code"], point["address"], point["type"], point.get("bit")) for point in points}
- expected = {(point["function_code"], point["address"], point["type"], point.get("bit")) for point in payload["points"]}
- self.assertEqual(expected, seen)
- self.assertTrue(any(point["function_code"] == FUNC_CODE_COIL for point in points))
- self.assertTrue(any(point["function_code"] == FUNC_CODE_DISCRETE_INPUT for point in points))
- self.assertTrue(any(point["function_code"] == FUNC_CODE_HOLDING_REGISTER for point in points))
- self.assertTrue(any(point["function_code"] == FUNC_CODE_INPUT_REGISTER for point in points))
- for point in points:
- self.assertIn("value", point)
- self.assertNotIn("address_base", point)
- self.assertNotIn("protocol_address", point)
- self.assertNotIn("raw_values", point)
- self.assertNotIn("communication", point)
- if point["type"] == "bool":
- self.assertIsInstance(point["value"], bool)
- elif point["type"].startswith("float"):
- self.assertIsInstance(point["value"], float)
- else:
- self.assertIsInstance(point["value"], int)
- def test_validation_error_returns_http_200_contract(self):
- status, data = post_json(
- "/api/dc-gateway/modbus/read",
- raw_read_payload(FUNC_CODE_HOLDING_REGISTER, address=0, quantity=126),
- )
- assert_response_contract(self, status, data)
- self.assertEqual(1, data["code"], data)
- self.assertIn("quantity", data["msg"])
- self.assertEqual([], data["data"]["communication"])
- if __name__ == "__main__":
- unittest.main()
|