123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- using System;
- using System.IO;
- using System.Linq;
- using System.Net.Sockets;
- using System.Reflection;
- using System.Threading;
- using System.Threading.Tasks;
- namespace S7.Net.UnitTest
- {
- /// <summary>
- /// Test stream which only gives 1 byte per read.
- /// </summary>
- class TestStreamConnectionClose : Stream
- {
- private readonly CancellationTokenSource _cancellationTokenSource;
- public TestStreamConnectionClose(CancellationTokenSource cancellationTokenSource)
- {
- _cancellationTokenSource = cancellationTokenSource;
- }
- public override bool CanRead => false;
- public override bool CanSeek => throw new NotImplementedException();
- public override bool CanWrite => true;
- public override long Length => throw new NotImplementedException();
- public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
- public override void Flush()
- {
- throw new NotImplementedException();
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- throw new NotImplementedException();
- }
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
- public override void Write(byte[] buffer, int offset, int count)
- {
- _cancellationTokenSource.Cancel();
- }
- }
- /// <summary>
- /// These tests are intended to test <see cref="StreamExtensions"/> functions and other stream-related special cases.
- /// </summary>
- [TestClass]
- public class ConnectionCloseTest
- {
- const short TestServerPort = 31122;
- const string TestServerIp = "127.0.0.1";
- [TestMethod]
- public async Task Test_CancellationDuringTransmission()
- {
- var plc = new Plc(CpuType.S7300, TestServerIp, TestServerPort, 0, 2);
- // Set up a shared cancellation source so we can let the stream
- // initiate cancel after some data has been written to it.
- var cancellationSource = new CancellationTokenSource();
- var cancellationToken = cancellationSource.Token;
- var stream = new TestStreamConnectionClose(cancellationSource);
- var requestData = new byte[100]; // empty data, it does not matter what is in there
- // Set up access to private method and field
- var dynMethod = plc.GetType().GetMethod("NoLockRequestTpduAsync",
- BindingFlags.NonPublic | BindingFlags.Instance);
- if (dynMethod == null)
- {
- throw new NullReferenceException("Could not find method 'NoLockRequestTpduAsync' on Plc object.");
- }
- var tcpClientField = plc.GetType().GetField("tcpClient", BindingFlags.NonPublic | BindingFlags.Instance);
- if (tcpClientField == null)
- {
- throw new NullReferenceException("Could not find field 'tcpClient' on Plc object.");
- }
- // Set a value to tcpClient field so we can later ensure that it has been closed.
- tcpClientField.SetValue(plc, new TcpClient());
- var tcpClientValue = tcpClientField.GetValue(plc);
- Assert.IsNotNull(tcpClientValue);
-
- try
- {
- var result = (Task<COTP.TPDU>) dynMethod.Invoke(plc, new object[] { stream, requestData, cancellationToken });
- await result;
- }
- catch (OperationCanceledException)
- {
- Console.WriteLine("Task was cancelled as expected.");
- // Ensure that the plc connection was closed since the task was cancelled
- // after data has been sent through the network. We expect that the tcpClient
- // object was set to NULL
- var tcpClientValueAfter = tcpClientField.GetValue(plc);
- Assert.IsNull(tcpClientValueAfter);
- return;
- }
- catch (Exception e)
- {
- Assert.Fail($"Wrong exception type received. Expected {typeof(OperationCanceledException)}, received {e.GetType()}.");
- }
- // Ensure test fails if cancellation did not occur.
- Assert.Fail("Task was not cancelled as expected.");
- }
- [TestMethod]
- public async Task Test_CancellationBeforeTransmission()
- {
- var plc = new Plc(CpuType.S7300, TestServerIp, TestServerPort, 0, 2);
- // Set up a cancellation source
- var cancellationSource = new CancellationTokenSource();
- var cancellationToken = cancellationSource.Token;
- var stream = new TestStreamConnectionClose(cancellationSource);
- var requestData = new byte[100]; // empty data, it does not matter what is in there
- // Set up access to private method and field
- var dynMethod = plc.GetType().GetMethod("NoLockRequestTpduAsync",
- BindingFlags.NonPublic | BindingFlags.Instance);
- if (dynMethod == null)
- {
- throw new NullReferenceException("Could not find method 'NoLockRequestTpduAsync' on Plc object.");
- }
- var tcpClientField = plc.GetType().GetField("tcpClient", BindingFlags.NonPublic | BindingFlags.Instance);
- if (tcpClientField == null)
- {
- throw new NullReferenceException("Could not find field 'tcpClient' on Plc object.");
- }
- // Set a value to tcpClient field so we can later ensure that it has been closed.
- tcpClientField.SetValue(plc, new TcpClient());
- var tcpClientValue = tcpClientField.GetValue(plc);
- Assert.IsNotNull(tcpClientValue);
- try
- {
- // cancel the task before we start transmitting data
- cancellationSource.Cancel();
- var result = (Task<COTP.TPDU>)dynMethod.Invoke(plc, new object[] { stream, requestData, cancellationToken });
- await result;
- }
- catch (OperationCanceledException)
- {
- Console.WriteLine("Task was cancelled as expected.");
- // Ensure that the plc connection was not closed, since we cancelled the task before
- // sending data through the network. We expect that the tcpClient
- // object was NOT set to NULL
- var tcpClientValueAfter = tcpClientField.GetValue(plc);
- Assert.IsNotNull(tcpClientValueAfter);
- return;
- }
- catch (Exception e)
- {
- Assert.Fail($"Wrong exception type received. Expected {typeof(OperationCanceledException)}, received {e.GetType()}.");
- }
- // Ensure test fails if cancellation did not occur.
- Assert.Fail("Task was not cancelled as expected.");
- }
- }
- }
|