@@ -23,6 +23,7 @@ public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived
23
23
private List < ChannelEventArgs > _channelEndOfDataRegister ;
24
24
private IList < ExceptionEventArgs > _channelExceptionRegister ;
25
25
private ManualResetEvent _channelClosedReceived ;
26
+ private Thread _raiseChannelCloseReceivedThread ;
26
27
27
28
private void SetupData ( )
28
29
{
@@ -38,6 +39,7 @@ private void SetupData()
38
39
_channelEndOfDataRegister = new List < ChannelEventArgs > ( ) ;
39
40
_channelExceptionRegister = new List < ExceptionEventArgs > ( ) ;
40
41
_channelClosedReceived = new ManualResetEvent ( false ) ;
42
+ _raiseChannelCloseReceivedThread = null ;
41
43
}
42
44
43
45
private void CreateMocks ( )
@@ -54,21 +56,29 @@ private void SetupMocks()
54
56
_sessionMock . InSequence ( sequence ) . Setup ( p => p . WaitOnHandle ( It . IsAny < EventWaitHandle > ( ) ) )
55
57
. Callback < WaitHandle > ( w =>
56
58
{
57
- new Thread ( ( ) =>
59
+ _raiseChannelCloseReceivedThread = new Thread ( ( ) =>
58
60
{
59
61
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
+ //
64
76
// we're mocking the wait on the ChannelCloseMessage, but we still want
65
77
// to get the channel in the state that it would have after actually receiving
66
78
// the ChannelCloseMessage
67
79
_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 ( ) ;
72
82
w . WaitOne ( ) ;
73
83
} ) ;
74
84
}
@@ -88,6 +98,14 @@ public void TearDown()
88
98
_channelClosedReceived . Dispose ( ) ;
89
99
_channelClosedReceived = null ;
90
100
}
101
+
102
+ if ( _raiseChannelCloseReceivedThread != null && _raiseChannelCloseReceivedThread . IsAlive )
103
+ {
104
+ if ( ! _raiseChannelCloseReceivedThread . Join ( 1000 ) )
105
+ {
106
+ _raiseChannelCloseReceivedThread . Abort ( ) ;
107
+ }
108
+ }
91
109
}
92
110
93
111
private void Arrange ( )
@@ -166,5 +184,11 @@ public void ExceptionShouldNeverHaveFired()
166
184
{
167
185
Assert . AreEqual ( 0 , _channelExceptionRegister . Count ) ;
168
186
}
187
+
188
+ [ TestMethod ]
189
+ public void ThreadThatRaisedChannelCloseReceivedShouldComplete ( )
190
+ {
191
+ _raiseChannelCloseReceivedThread . Join ( ) ;
192
+ }
169
193
}
170
194
}
0 commit comments