Skip to content

Commit 95f0f22

Browse files
authored
Merge pull request #320 from sshnet/channel_closed
Channel: Raise the Closed event as part of the Close() method
2 parents 19167e7 + 93555c9 commit 95f0f22

10 files changed

+545
-29
lines changed

src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceiv
2121
private uint _remotePacketSize;
2222
private ChannelStub _channel;
2323
private Stopwatch _closeTimer;
24-
private ManualResetEvent _channelClosedWaitHandle;
24+
private ManualResetEvent _channelClosedEventHandlerCompleted;
2525
private List<ChannelEventArgs> _channelClosedRegister;
2626
private IList<ExceptionEventArgs> _channelExceptionRegister;
2727

@@ -43,7 +43,7 @@ private void Arrange()
4343
_remotePacketSize = (uint)random.Next(0, int.MaxValue);
4444
_closeTimer = new Stopwatch();
4545
_channelClosedRegister = new List<ChannelEventArgs>();
46-
_channelClosedWaitHandle = new ManualResetEvent(false);
46+
_channelClosedEventHandlerCompleted = new ManualResetEvent(false);
4747
_channelExceptionRegister = new List<ExceptionEventArgs>();
4848

4949
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
@@ -80,7 +80,8 @@ private void Arrange()
8080
_channel.Closed += (sender, args) =>
8181
{
8282
_channelClosedRegister.Add(args);
83-
_channelClosedWaitHandle.Set();
83+
Thread.Sleep(50);
84+
_channelClosedEventHandlerCompleted.Set();
8485
};
8586
_channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
8687
_channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
@@ -129,12 +130,16 @@ public void WaitOnHandleOnSessionShouldWaitForChannelCloseMessageToBeReceived()
129130
[TestMethod]
130131
public void ClosedEventShouldHaveFiredOnce()
131132
{
132-
_channelClosedWaitHandle.WaitOne(100);
133-
134133
Assert.AreEqual(1, _channelClosedRegister.Count);
135134
Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber);
136135
}
137136

137+
[TestMethod]
138+
public void DisposeShouldBlockUntilClosedEventHandlerHasCompleted()
139+
{
140+
Assert.IsTrue(_channelClosedEventHandlerCompleted.WaitOne(0));
141+
}
142+
138143
[TestMethod]
139144
public void ExceptionShouldNeverHaveFired()
140145
{

src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Renci.SshNet.Tests.Classes.Channels
1111
{
1212
[TestClass]
13+
[Ignore]
1314
public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked
1415
{
1516
private Mock<ISession> _sessionMock;
@@ -21,7 +22,7 @@ public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceiv
2122
private uint _remotePacketSize;
2223
private ChannelStub _channel;
2324
private Stopwatch _closeTimer;
24-
private ManualResetEvent _channelClosedWaitHandle;
25+
private ManualResetEvent _channelClosedEventHandlerCompleted;
2526
private List<ChannelEventArgs> _channelClosedRegister;
2627
private IList<ExceptionEventArgs> _channelExceptionRegister;
2728

@@ -32,6 +33,16 @@ public void Initialize()
3233
Act();
3334
}
3435

36+
[TestCleanup]
37+
public void TearDown()
38+
{
39+
if (_channelClosedEventHandlerCompleted != null)
40+
{
41+
_channelClosedEventHandlerCompleted.Dispose();
42+
_channelClosedEventHandlerCompleted = null;
43+
}
44+
}
45+
3546
private void Arrange()
3647
{
3748
var random = new Random();
@@ -42,7 +53,7 @@ private void Arrange()
4253
_remoteWindowSize = (uint)random.Next(0, int.MaxValue);
4354
_remotePacketSize = (uint)random.Next(0, int.MaxValue);
4455
_closeTimer = new Stopwatch();
45-
_channelClosedWaitHandle = new ManualResetEvent(false);
56+
_channelClosedEventHandlerCompleted = new ManualResetEvent(false);
4657
_channelClosedRegister = new List<ChannelEventArgs>();
4758
_channelExceptionRegister = new List<ExceptionEventArgs>();
4859

@@ -80,12 +91,13 @@ private void Arrange()
8091
_channel.Closed += (sender, args) =>
8192
{
8293
_channelClosedRegister.Add(args);
83-
_channelClosedWaitHandle.Set();
94+
Thread.Sleep(50);
95+
_channelClosedEventHandlerCompleted.Set();
8496
};
8597
_channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
8698
_channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
8799
_channel.SetIsOpen(true);
88-
_channel.SendEof();
100+
//_channel.SendEof();
89101
}
90102

91103
private void Act()
@@ -130,12 +142,16 @@ public void WaitOnHandleOnSessionShouldWaitForChannelCloseMessageToBeReceived()
130142
[TestMethod]
131143
public void ClosedEventShouldHaveFiredOnce()
132144
{
133-
_channelClosedWaitHandle.WaitOne(100);
134-
135145
Assert.AreEqual(1, _channelClosedRegister.Count);
136146
Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber);
137147
}
138148

149+
[TestMethod]
150+
public void DisposeShouldBlockUntilClosedEventHandlerHasCompleted()
151+
{
152+
Assert.IsTrue(_channelClosedEventHandlerCompleted.WaitOne(0));
153+
}
154+
139155
[TestMethod]
140156
public void ExceptionShouldNeverHaveFired()
141157
{

src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived
2323
private List<ChannelEventArgs> _channelEndOfDataRegister;
2424
private IList<ExceptionEventArgs> _channelExceptionRegister;
2525
private ManualResetEvent _channelClosedReceived;
26+
private ManualResetEvent _channelClosedEventHandlerCompleted;
2627
private Thread _raiseChannelCloseReceivedThread;
2728

2829
private void SetupData()
@@ -39,6 +40,7 @@ private void SetupData()
3940
_channelEndOfDataRegister = new List<ChannelEventArgs>();
4041
_channelExceptionRegister = new List<ExceptionEventArgs>();
4142
_channelClosedReceived = new ManualResetEvent(false);
43+
_channelClosedEventHandlerCompleted = new ManualResetEvent(false);
4244
_raiseChannelCloseReceivedThread = null;
4345
}
4446

@@ -106,6 +108,12 @@ public void TearDown()
106108
_raiseChannelCloseReceivedThread.Abort();
107109
}
108110
}
111+
112+
if (_channelClosedEventHandlerCompleted != null)
113+
{
114+
_channelClosedEventHandlerCompleted.Dispose();
115+
_channelClosedEventHandlerCompleted = null;
116+
}
109117
}
110118

111119
private void Arrange()
@@ -115,7 +123,12 @@ private void Arrange()
115123
SetupMocks();
116124

117125
_channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize);
118-
_channel.Closed += (sender, args) => _channelClosedRegister.Add(args);
126+
_channel.Closed += (sender, args) =>
127+
{
128+
_channelClosedRegister.Add(args);
129+
Thread.Sleep(50);
130+
_channelClosedEventHandlerCompleted.Set();
131+
};
119132
_channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args);
120133
_channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
121134
_channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
@@ -173,7 +186,7 @@ public void ClosedEventShouldHaveFiredOnce()
173186
}
174187

175188
[TestMethod]
176-
public void EndOfDataEventShouldHaveFiredOnce()
189+
public void EndOfDataEventShouldNotHaveFired()
177190
{
178191
Assert.AreEqual(1, _channelEndOfDataRegister.Count);
179192
Assert.AreEqual(_localChannelNumber, _channelEndOfDataRegister[0].ChannelNumber);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Common;
7+
using Renci.SshNet.Messages.Connection;
8+
9+
namespace Renci.SshNet.Tests.Classes.Channels
10+
{
11+
[TestClass]
12+
public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_ConnectionExceptionWaitingForChannelCloseMessage
13+
{
14+
private Mock<ISession> _sessionMock;
15+
private uint _localChannelNumber;
16+
private uint _localWindowSize;
17+
private uint _localPacketSize;
18+
private uint _remoteChannelNumber;
19+
private uint _remoteWindowSize;
20+
private uint _remotePacketSize;
21+
private ChannelStub _channel;
22+
private List<ChannelEventArgs> _channelClosedRegister;
23+
private List<ChannelEventArgs> _channelEndOfDataRegister;
24+
private IList<ExceptionEventArgs> _channelExceptionRegister;
25+
private SshConnectionException _connectionException;
26+
27+
private void SetupData()
28+
{
29+
var random = new Random();
30+
31+
_localChannelNumber = (uint)random.Next(0, int.MaxValue);
32+
_localWindowSize = (uint)random.Next(0, int.MaxValue);
33+
_localPacketSize = (uint)random.Next(0, int.MaxValue);
34+
_remoteChannelNumber = (uint)random.Next(0, int.MaxValue);
35+
_remoteWindowSize = (uint)random.Next(0, int.MaxValue);
36+
_remotePacketSize = (uint)random.Next(0, int.MaxValue);
37+
_channelClosedRegister = new List<ChannelEventArgs>();
38+
_channelEndOfDataRegister = new List<ChannelEventArgs>();
39+
_channelExceptionRegister = new List<ExceptionEventArgs>();
40+
_connectionException = new SshConnectionException();
41+
}
42+
43+
private void CreateMocks()
44+
{
45+
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
46+
}
47+
48+
private void SetupMocks()
49+
{
50+
var sequence = new MockSequence();
51+
52+
_sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
53+
_sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is<ChannelCloseMessage>(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true);
54+
_sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()))
55+
.Callback<WaitHandle>(w =>
56+
{
57+
throw _connectionException;
58+
});
59+
}
60+
61+
[TestInitialize]
62+
public void Initialize()
63+
{
64+
Arrange();
65+
Act();
66+
}
67+
68+
private void Arrange()
69+
{
70+
SetupData();
71+
CreateMocks();
72+
SetupMocks();
73+
74+
_channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize);
75+
_channel.Closed += (sender, args) =>
76+
{
77+
_channelClosedRegister.Add(args);
78+
};
79+
_channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args);
80+
_channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
81+
_channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
82+
_channel.SetIsOpen(true);
83+
84+
_sessionMock.Raise(
85+
s => s.ChannelEofReceived += null,
86+
new MessageEventArgs<ChannelEofMessage>(new ChannelEofMessage(_localChannelNumber)));
87+
}
88+
89+
private void Act()
90+
{
91+
_channel.Dispose();
92+
}
93+
94+
[TestMethod]
95+
public void IsOpenShouldReturnFalse()
96+
{
97+
Assert.IsFalse(_channel.IsOpen);
98+
}
99+
100+
[TestMethod]
101+
public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage()
102+
{
103+
_sessionMock.Verify(
104+
p => p.TrySendMessage(It.Is<ChannelCloseMessage>(c => c.LocalChannelNumber == _remoteChannelNumber)),
105+
Times.Once);
106+
}
107+
108+
[TestMethod]
109+
public void TrySendMessageOnSessionShouldNeverBeInvokedForChannelEofMessage()
110+
{
111+
_sessionMock.Verify(
112+
p => p.TrySendMessage(It.Is<ChannelEofMessage>(c => c.LocalChannelNumber == _remoteChannelNumber)),
113+
Times.Never);
114+
}
115+
116+
[TestMethod]
117+
public void WaitOnHandleOnSessionShouldBeInvokedOnce()
118+
{
119+
_sessionMock.Verify(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()), Times.Once);
120+
}
121+
122+
[TestMethod]
123+
public void ClosedEventShouldNotHaveFired()
124+
{
125+
Assert.AreEqual(0, _channelClosedRegister.Count);
126+
}
127+
128+
[TestMethod]
129+
public void EndOfDataEventShouldNotHaveFired()
130+
{
131+
Assert.AreEqual(1, _channelEndOfDataRegister.Count);
132+
Assert.AreEqual(_localChannelNumber, _channelEndOfDataRegister[0].ChannelNumber);
133+
}
134+
135+
[TestMethod]
136+
public void ExceptionShouldNeverHaveFired()
137+
{
138+
Assert.AreEqual(0, _channelExceptionRegister.Count);
139+
}
140+
}
141+
}

0 commit comments

Comments
 (0)