/nmodbus/NModbus/src/Modbus.UnitTests/IO/ModbusTransportFixture.cs

https://github.com/offlinehacker/Bastet-GUI · C# · 328 lines · 242 code · 69 blank · 17 comment · 0 complexity · d4bb31baf5d2c452a2f78b4534fb6f4f MD5 · raw file

  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Reflection;
  5. using MbUnit.Framework;
  6. using Modbus.Data;
  7. using Modbus.IO;
  8. using Modbus.Message;
  9. using Modbus.Utility;
  10. using Rhino.Mocks;
  11. using Unme.Common;
  12. using Unme.MbUnit.Framework.Extensions;
  13. namespace Modbus.UnitTests.IO
  14. {
  15. delegate ReadCoilsInputsResponse ThrowExceptionDelegate();
  16. [TestFixture]
  17. public class ModbusTransportFixture
  18. {
  19. [Test]
  20. public void UnicastMessage()
  21. {
  22. MockRepository mocks = new MockRepository();
  23. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  24. transport.Write(null);
  25. LastCall.IgnoreArguments();
  26. // read 4 coils from slave id 2
  27. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  28. .Return(new ReadCoilsInputsResponse(Modbus.ReadCoils, 2, 1, new DiscreteCollection(true, false, true, false, false, false, false, false)));
  29. transport.OnValidateResponse(null, null);
  30. LastCall.IgnoreArguments();
  31. mocks.ReplayAll();
  32. ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(Modbus.ReadCoils, 2, 3, 4);
  33. ReadCoilsInputsResponse expectedResponse = new ReadCoilsInputsResponse(Modbus.ReadCoils, 2, 1, new DiscreteCollection(true, false, true, false, false, false, false, false));
  34. ReadCoilsInputsResponse response = transport.UnicastMessage<ReadCoilsInputsResponse>(request);
  35. Assert.AreEqual(expectedResponse.MessageFrame, response.MessageFrame);
  36. mocks.VerifyAll();
  37. }
  38. [Test, ExpectedException(typeof(IOException))]
  39. public void UnicastMessage_WrongResponseFunctionCode()
  40. {
  41. MockRepository mocks = new MockRepository();
  42. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  43. transport.Write(null);
  44. LastCall.IgnoreArguments().Repeat.Times(Modbus.DefaultRetries + 1);
  45. // read 4 coils from slave id 2
  46. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  47. .Return(new ReadCoilsInputsResponse(Modbus.ReadCoils, 2, 0, new DiscreteCollection()))
  48. .Repeat.Times(Modbus.DefaultRetries + 1);
  49. mocks.ReplayAll();
  50. ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(Modbus.ReadInputs, 2, 3, 4);
  51. transport.UnicastMessage<ReadCoilsInputsResponse>(request);
  52. mocks.VerifyAll();
  53. }
  54. [Test, ExpectedException(typeof(SlaveException))]
  55. public void UnicastMessage_ErrorSlaveException()
  56. {
  57. MockRepository mocks = new MockRepository();
  58. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  59. transport.Write(null);
  60. LastCall.IgnoreArguments().Repeat.Times(Modbus.DefaultRetries + 1);
  61. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  62. .Do((ThrowExceptionDelegate) delegate { throw new SlaveException(); });
  63. mocks.ReplayAll();
  64. ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(Modbus.ReadInputs, 2, 3, 4);
  65. transport.UnicastMessage<ReadCoilsInputsResponse>(request);
  66. mocks.VerifyAll();
  67. }
  68. /// <summary>
  69. /// We should reread the response w/o retransmitting the request.
  70. /// </summary>
  71. [Test]
  72. public void UnicastMessage_AcknowlegeSlaveException()
  73. {
  74. MockRepository mocks = new MockRepository();
  75. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  76. // set the wait to retry property to a small value so the test completes quickly
  77. transport.WaitToRetryMilliseconds = 5;
  78. transport.Write(null);
  79. LastCall.IgnoreArguments();
  80. // return a slave exception a greater number of times than number of retries to make sure we aren't just retrying
  81. Expect.Call(transport.ReadResponse<ReadHoldingInputRegistersResponse>())
  82. .Return(new SlaveExceptionResponse(1, Modbus.ReadHoldingRegisters + Modbus.ExceptionOffset, Modbus.Acknowledge))
  83. .Repeat.Times(transport.Retries + 1);
  84. Expect.Call(transport.ReadResponse<ReadHoldingInputRegistersResponse>())
  85. .Return(new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection(1)));
  86. transport.OnValidateResponse(null, null);
  87. LastCall.IgnoreArguments();
  88. mocks.ReplayAll();
  89. ReadHoldingInputRegistersRequest request = new ReadHoldingInputRegistersRequest(Modbus.ReadHoldingRegisters, 1, 1, 1);
  90. ReadHoldingInputRegistersResponse expectedResponse = new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection(1));
  91. ReadHoldingInputRegistersResponse response = transport.UnicastMessage<ReadHoldingInputRegistersResponse>(request);
  92. Assert.AreEqual(expectedResponse.MessageFrame, response.MessageFrame);
  93. mocks.VerifyAll();
  94. }
  95. /// <summary>
  96. /// We should retransmit the request.
  97. /// </summary>
  98. [Test]
  99. public void UnicastMessage_SlaveDeviceBusySlaveException()
  100. {
  101. MockRepository mocks = new MockRepository();
  102. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  103. // set the wait to retry property to a small value so the test completes quickly
  104. transport.WaitToRetryMilliseconds = 5;
  105. transport.Write(null);
  106. LastCall.IgnoreArguments()
  107. .Repeat.Times(2);
  108. // return a slave exception a greater number of times than number of retries to make sure we aren't just retrying
  109. Expect.Call(transport.ReadResponse<ReadHoldingInputRegistersResponse>())
  110. .Return(new SlaveExceptionResponse(1, Modbus.ReadHoldingRegisters + Modbus.ExceptionOffset, Modbus.SlaveDeviceBusy));
  111. Expect.Call(transport.ReadResponse<ReadHoldingInputRegistersResponse>())
  112. .Return(new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection(1)));
  113. transport.OnValidateResponse(null, null);
  114. LastCall.IgnoreArguments();
  115. mocks.ReplayAll();
  116. ReadHoldingInputRegistersRequest request = new ReadHoldingInputRegistersRequest(Modbus.ReadHoldingRegisters, 1, 1, 1);
  117. ReadHoldingInputRegistersResponse expectedResponse = new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection(1));
  118. ReadHoldingInputRegistersResponse response = transport.UnicastMessage<ReadHoldingInputRegistersResponse>(request);
  119. Assert.AreEqual(expectedResponse.MessageFrame, response.MessageFrame);
  120. mocks.VerifyAll();
  121. }
  122. /// <summary>
  123. /// We should retransmit the request.
  124. /// </summary>
  125. [Test]
  126. public void UnicastMessage_SlaveDeviceBusySlaveExceptionDoesNotFailAfterExceedingRetries()
  127. {
  128. MockRepository mocks = new MockRepository();
  129. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  130. // set the wait to retry property to a small value so the test completes quickly
  131. transport.WaitToRetryMilliseconds = 5;
  132. transport.Write(null);
  133. LastCall.IgnoreArguments()
  134. .Repeat.Times(transport.Retries + 1);
  135. // return a slave exception a greater number of times than number of retries to make sure we aren't just retrying
  136. Expect.Call(transport.ReadResponse<ReadHoldingInputRegistersResponse>())
  137. .Return(new SlaveExceptionResponse(1, Modbus.ReadHoldingRegisters + Modbus.ExceptionOffset, Modbus.SlaveDeviceBusy))
  138. .Repeat.Times(transport.Retries);
  139. Expect.Call(transport.ReadResponse<ReadHoldingInputRegistersResponse>())
  140. .Return(new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection(1)));
  141. transport.OnValidateResponse(null, null);
  142. LastCall.IgnoreArguments();
  143. mocks.ReplayAll();
  144. ReadHoldingInputRegistersRequest request = new ReadHoldingInputRegistersRequest(Modbus.ReadHoldingRegisters, 1, 1, 1);
  145. ReadHoldingInputRegistersResponse expectedResponse = new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection(1));
  146. ReadHoldingInputRegistersResponse response = transport.UnicastMessage<ReadHoldingInputRegistersResponse>(request);
  147. Assert.AreEqual(expectedResponse.MessageFrame, response.MessageFrame);
  148. mocks.VerifyAll();
  149. }
  150. [RowTest,
  151. Row(typeof(TimeoutException)),
  152. Row(typeof(IOException)),
  153. Row(typeof(NotImplementedException)),
  154. Row(typeof(FormatException))]
  155. public void UnicastMessage_SingleFailingException(Type exceptionType)
  156. {
  157. MockRepository mocks = new MockRepository();
  158. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  159. transport.Retries = 1;
  160. transport.Write(null);
  161. LastCall.IgnoreArguments().Repeat.Times(2);
  162. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  163. .Do((ThrowExceptionDelegate) delegate { throw (Exception) Activator.CreateInstance(exceptionType); });
  164. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  165. .Return(new ReadCoilsInputsResponse(Modbus.ReadCoils, 2, 1, new DiscreteCollection(true, false, true, false, false, false, false, false)));
  166. transport.OnValidateResponse(null, null);
  167. LastCall.IgnoreArguments();
  168. mocks.ReplayAll();
  169. ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(Modbus.ReadCoils, 2, 3, 4);
  170. transport.UnicastMessage<ReadCoilsInputsResponse>(request);
  171. mocks.VerifyAll();
  172. }
  173. [RowTest,
  174. Row(typeof(TimeoutException)),
  175. Row(typeof(IOException)),
  176. Row(typeof(NotImplementedException)),
  177. Row(typeof(FormatException))]
  178. public void UnicastMessage_TooManyFailingExceptions(Type exceptionType)
  179. {
  180. MockRepository mocks = new MockRepository();
  181. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  182. transport.Write(null);
  183. LastCall.IgnoreArguments().Repeat.Times(transport.Retries + 1);
  184. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  185. .Do((ThrowExceptionDelegate) delegate { throw (Exception) Activator.CreateInstance(exceptionType); })
  186. .Repeat.Times(transport.Retries + 1);
  187. mocks.ReplayAll();
  188. ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(Modbus.ReadCoils, 2, 3, 4);
  189. Action action = () => transport.UnicastMessage<ReadCoilsInputsResponse>(request);
  190. typeof(AssertUtility).GetMethod("Throws", BindingFlags.Public | BindingFlags.Static).
  191. MakeGenericMethod(new Type[] { exceptionType }).
  192. Invoke(transport, new object[] { action });
  193. mocks.VerifyAll();
  194. }
  195. [Test, ExpectedException(typeof(TimeoutException))]
  196. public void UnicastMessage_TimeoutException()
  197. {
  198. MockRepository mocks = new MockRepository();
  199. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  200. transport.Write(null);
  201. LastCall.IgnoreArguments().Repeat.Times(Modbus.DefaultRetries + 1);
  202. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  203. .Do((ThrowExceptionDelegate) delegate { throw new TimeoutException(); })
  204. .Repeat.Times(Modbus.DefaultRetries + 1);
  205. mocks.ReplayAll();
  206. ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(Modbus.ReadInputs, 2, 3, 4);
  207. transport.UnicastMessage<ReadCoilsInputsResponse>(request);
  208. mocks.VerifyAll();
  209. }
  210. [Test, ExpectedException(typeof(TimeoutException))]
  211. public void UnicastMessage_Retries()
  212. {
  213. MockRepository mocks = new MockRepository();
  214. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  215. transport.Retries = 5;
  216. transport.Write(null);
  217. LastCall.IgnoreArguments().Repeat.Times(transport.Retries + 1);
  218. Expect.Call(transport.ReadResponse<ReadCoilsInputsResponse>())
  219. .Do((ThrowExceptionDelegate) delegate { throw new TimeoutException(); })
  220. .Repeat.Times(transport.Retries + 1);
  221. mocks.ReplayAll();
  222. ReadCoilsInputsRequest request = new ReadCoilsInputsRequest(Modbus.ReadInputs, 2, 3, 4);
  223. transport.UnicastMessage<ReadCoilsInputsResponse>(request);
  224. mocks.VerifyAll();
  225. }
  226. [Test]
  227. public void CreateResponse_SlaveException()
  228. {
  229. ModbusTransport transport = new ModbusAsciiTransport(MockRepository.GenerateStub<IStreamResource>());
  230. byte[] frame = { 2, 129, 2 };
  231. IModbusMessage message = transport.CreateResponse<ReadCoilsInputsResponse>(frame.Concat(SequenceUtility.ToSequence(ModbusUtility.CalculateLrc(frame))).ToArray());
  232. Assert.IsTrue(message is SlaveExceptionResponse);
  233. }
  234. [Test, ExpectedException(typeof(IOException))]
  235. public void ValidateResponse_MismatchingFunctionCodes()
  236. {
  237. MockRepository mocks = new MockRepository();
  238. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  239. IModbusMessage request = new ReadCoilsInputsRequest(Modbus.ReadCoils, 1, 1, 1);
  240. IModbusMessage response = new ReadHoldingInputRegistersResponse(Modbus.ReadHoldingRegisters, 1, new RegisterCollection());
  241. mocks.ReplayAll();
  242. transport.ValidateResponse(request, response);
  243. mocks.VerifyAll();
  244. }
  245. [Test]
  246. public void ValidateResponse()
  247. {
  248. MockRepository mocks = new MockRepository();
  249. ModbusTransport transport = mocks.PartialMock<ModbusTransport>();
  250. IModbusMessage request = new ReadCoilsInputsRequest(Modbus.ReadCoils, 1, 1, 1);
  251. IModbusMessage response = new ReadCoilsInputsResponse(Modbus.ReadCoils, 1, 1, null);
  252. transport.OnValidateResponse(null, null);
  253. LastCall.IgnoreArguments();
  254. mocks.ReplayAll();
  255. transport.ValidateResponse(request, response);
  256. mocks.VerifyAll();
  257. }
  258. }
  259. }