using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { [TestClass] public class ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately { private Mock _sessionMock; private Mock _channelMock; private Mock _connectionInfoMock; private ForwardedPortDynamic _forwardedPort; private Socket _client; private IList _closingRegister; private IList _exceptionRegister; private TimeSpan _connectionTimeout; private ManualResetEvent _channelDisposed; private IPEndPoint _forwardedPortEndPoint; [TestInitialize] public void Initialize() { Arrange(); Act(); } [TestCleanup] public void Cleanup() { if (_forwardedPort != null && _forwardedPort.IsStarted) { _ = _sessionMock.Setup(p => p.ConnectionInfo) .Returns(_connectionInfoMock.Object); _ = _connectionInfoMock.Setup(p => p.Timeout) .Returns(TimeSpan.FromSeconds(5)); _forwardedPort.Stop(); } if (_client != null) { if (_client.Connected) { _client.Shutdown(SocketShutdown.Both); _client.Close(); _client = null; } } if (_channelDisposed != null) { _channelDisposed.Dispose(); _channelDisposed = null; } } private void SetupData() { _closingRegister = new List(); _exceptionRegister = new List(); _connectionTimeout = TimeSpan.FromSeconds(5); _channelDisposed = new ManualResetEvent(false); _forwardedPortEndPoint = new IPEndPoint(IPAddress.Loopback, 8122); _forwardedPort = new ForwardedPortDynamic((uint)_forwardedPortEndPoint.Port); _forwardedPort.Closing += (sender, args) => _closingRegister.Add(args); _forwardedPort.Exception += (sender, args) => _exceptionRegister.Add(args); _forwardedPort.Session = _sessionMock.Object; _client = new Socket(_forwardedPortEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); } private void CreateMocks() { _sessionMock = new Mock(MockBehavior.Strict); _channelMock = new Mock(MockBehavior.Strict); _connectionInfoMock = new Mock(MockBehavior.Strict); } private void SetupMocks() { var seq = new MockSequence(); _ = _sessionMock.InSequence(seq) .Setup(p => p.IsConnected) .Returns(true); _ = _sessionMock.InSequence(seq) .Setup(p => p.CreateChannelDirectTcpip()) .Returns(_channelMock.Object); _ = _sessionMock.InSequence(seq) .Setup(p => p.ConnectionInfo) .Returns(_connectionInfoMock.Object); _ = _connectionInfoMock.InSequence(seq) .Setup(p => p.Timeout) .Returns(_connectionTimeout); _ = _channelMock.InSequence(seq) .Setup(p => p.Dispose()) .Callback(() => _channelDisposed.Set()); } private void Arrange() { CreateMocks(); SetupData(); SetupMocks(); _forwardedPort.Start(); _client.Connect(_forwardedPortEndPoint); } private void Act() { _client.Shutdown(SocketShutdown.Send); // wait for channel to be disposed _ = _channelDisposed.WaitOne(TimeSpan.FromMilliseconds(200)); } [TestMethod] public void SocketShouldNotBeConnected() { Assert.IsFalse(_client.Connected); } [TestMethod] public void ForwardedPortShouldShutdownSendOnSocket() { var buffer = new byte[1]; var bytesReceived = _client.Receive(buffer, 0, buffer.Length, SocketFlags.None); Assert.AreEqual(0, bytesReceived); } [TestMethod] public void ClosingShouldNotHaveFired() { Assert.AreEqual(0, _closingRegister.Count); } [TestMethod] public void ExceptionShouldNeverBeFired() { Assert.AreEqual(0, _exceptionRegister.Count, _exceptionRegister.AsString()); } [TestMethod] public void CreateChannelDirectTcpipOnSessionShouldBeInvokedOnce() { _sessionMock.Verify(p => p.CreateChannelDirectTcpip(), Times.Once); } [TestMethod] public void DisposeOnChannelShouldBeInvokedOnce() { _channelMock.Verify(p => p.Dispose(), Times.Once); } } }