@@ -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 Thread _raiseChannelCloseReceivedThread ;
2627
2728 private void SetupData ( )
2829 {
@@ -38,6 +39,7 @@ private void SetupData()
3839 _channelEndOfDataRegister = new List < ChannelEventArgs > ( ) ;
3940 _channelExceptionRegister = new List < ExceptionEventArgs > ( ) ;
4041 _channelClosedReceived = new ManualResetEvent ( false ) ;
42+ _raiseChannelCloseReceivedThread = null ;
4143 }
4244
4345 private void CreateMocks ( )
@@ -54,21 +56,29 @@ private void SetupMocks()
5456 _sessionMock . InSequence ( sequence ) . Setup ( p => p . WaitOnHandle ( It . IsAny < EventWaitHandle > ( ) ) )
5557 . Callback < WaitHandle > ( w =>
5658 {
57- new Thread ( ( ) =>
59+ _raiseChannelCloseReceivedThread = new Thread ( ( ) =>
5860 {
5961 Thread . Sleep ( 100 ) ;
60- // raise ChannelCloseReceived event to set waithandle for receiving
61- // SSH_MSG_CHANNEL_CLOSE message from server which is waited on after
62- // sending the SSH_MSG_CHANNEL_CLOSE message to the server
63- //
62+
63+ // signal that the ChannelCloseMessage was received; we use this to verify whether we've actually
64+ // waited on the EventWaitHandle to be set; this needs to be set before we raise the ChannelCloseReceived
65+ // to make sure the waithandle is signaled when the Dispose method completes (or else the assert that
66+ // checks whether the handle has been signaled, will sometimes fail)
67+ _channelClosedReceived . Set ( ) ;
68+
69+ // raise ChannelCloseReceived event to set waithandle for receiving SSH_MSG_CHANNEL_CLOSE message
70+ // from server which is waited on after sending the SSH_MSG_CHANNEL_CLOSE message to the server
71+ //
72+ // this will cause a new invocation of Close() that will block until the Close() that was invoked
73+ // as part of Dispose() has released the lock; as such, this thread cannot be joined until that
74+ // lock is released
75+ //
6476 // we're mocking the wait on the ChannelCloseMessage, but we still want
6577 // to get the channel in the state that it would have after actually receiving
6678 // the ChannelCloseMessage
6779 _sessionMock . Raise ( s => s . ChannelCloseReceived += null , new MessageEventArgs < ChannelCloseMessage > ( new ChannelCloseMessage ( _localChannelNumber ) ) ) ;
68- // signal that the ChannelCloseMessage was received; we use this to verify whether we've actually
69- // waited on the EventWaitHandle to be set
70- _channelClosedReceived . Set ( ) ;
71- } ) . Start ( ) ;
80+ } ) ;
81+ _raiseChannelCloseReceivedThread . Start ( ) ;
7282 w . WaitOne ( ) ;
7383 } ) ;
7484 }
@@ -88,6 +98,14 @@ public void TearDown()
8898 _channelClosedReceived . Dispose ( ) ;
8999 _channelClosedReceived = null ;
90100 }
101+
102+ if ( _raiseChannelCloseReceivedThread != null && _raiseChannelCloseReceivedThread . IsAlive )
103+ {
104+ if ( ! _raiseChannelCloseReceivedThread . Join ( 1000 ) )
105+ {
106+ _raiseChannelCloseReceivedThread . Abort ( ) ;
107+ }
108+ }
91109 }
92110
93111 private void Arrange ( )
@@ -166,5 +184,11 @@ public void ExceptionShouldNeverHaveFired()
166184 {
167185 Assert . AreEqual ( 0 , _channelExceptionRegister . Count ) ;
168186 }
187+
188+ [ TestMethod ]
189+ public void ThreadThatRaisedChannelCloseReceivedShouldComplete ( )
190+ {
191+ _raiseChannelCloseReceivedThread . Join ( ) ;
192+ }
169193 }
170194}
0 commit comments