1+ using System . Diagnostics ;
12using ManagedCode . Orleans . SignalR . Core . Config ;
23using ManagedCode . Orleans . SignalR . Tests . Cluster ;
34using ManagedCode . Orleans . SignalR . Tests . Infrastructure . Logging ;
@@ -16,12 +17,14 @@ public class KeepAliveDisabledTests : IAsyncLifetime
1617{
1718 private readonly SmokeClusterFixture _siloCluster ;
1819 private readonly TestOutputHelperAccessor _loggerAccessor = new ( ) ;
20+ private readonly ITestOutputHelper _output ;
1921 private TestWebApplication ? _app ;
2022
2123 public KeepAliveDisabledTests ( SmokeClusterFixture siloCluster , ITestOutputHelper testOutputHelper )
2224 {
2325 _siloCluster = siloCluster ;
2426 _loggerAccessor . Output = testOutputHelper ;
27+ _output = testOutputHelper ;
2528 }
2629
2730 public async Task InitializeAsync ( )
@@ -35,6 +38,7 @@ public async Task InitializeAsync()
3538 services . PostConfigure < OrleansSignalROptions > ( options =>
3639 {
3740 options . KeepEachConnectionAlive = false ;
41+ options . ClientTimeoutInterval = TimeSpan . FromSeconds ( 2 ) ;
3842 } ) ;
3943 } ) ;
4044
@@ -74,6 +78,16 @@ public async Task Targeted_connection_send_should_work_when_keep_alive_disabled(
7478 var completed = await Task . WhenAny ( received . Task , Task . Delay ( TimeSpan . FromSeconds ( 5 ) ) ) ;
7579 completed . ShouldBe ( received . Task , "Receiver did not observe direct send when keep-alive was disabled." ) ;
7680 received . Task . Result . ShouldBe ( "test" ) ;
81+
82+ var receiverDisconnected = await WaitForDisconnectAsync ( receiver , TimeSpan . FromSeconds ( 5 ) , "target receiver" ) ;
83+ _output . WriteLine ( receiverDisconnected
84+ ? "Receiver disconnected after timeout as expected."
85+ : "Receiver remained connected after timeout window." ) ;
86+
87+ var senderDisconnected = await WaitForDisconnectAsync ( sender , TimeSpan . FromSeconds ( 5 ) , "target sender" ) ;
88+ _output . WriteLine ( senderDisconnected
89+ ? "Sender disconnected after timeout as expected."
90+ : "Sender remained connected after timeout window." ) ;
7791 }
7892 finally
7993 {
@@ -119,11 +133,56 @@ public async Task Group_send_should_work_when_keep_alive_disabled()
119133 var completed = await Task . WhenAny ( groupMessage . Task , Task . Delay ( TimeSpan . FromSeconds ( 10 ) ) ) ;
120134 completed . ShouldBe ( groupMessage . Task , "Group broadcast did not arrive when keep-alive was disabled." ) ;
121135 groupMessage . Task . Result . ShouldContain ( "payload" ) ;
136+
137+ var disconnected = await WaitForDisconnectAsync ( connection , TimeSpan . FromSeconds ( 5 ) , "group connection" ) ;
138+ _output . WriteLine ( disconnected
139+ ? "Group connection disconnected after timeout as expected."
140+ : "Group connection remained connected after timeout window." ) ;
122141 }
123142 finally
124143 {
125144 await connection . StopAsync ( ) ;
126145 await connection . DisposeAsync ( ) ;
127146 }
128147 }
148+
149+ private async Task < bool > WaitForDisconnectAsync ( HubConnection connection , TimeSpan timeout , string label )
150+ {
151+ if ( connection . State == HubConnectionState . Disconnected )
152+ {
153+ _output . WriteLine ( $ "{ label } already disconnected.") ;
154+ return true ;
155+ }
156+
157+ var tcs = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
158+
159+ Task Handler ( Exception ? _ )
160+ {
161+ tcs . TrySetResult ( true ) ;
162+ return Task . CompletedTask ;
163+ }
164+
165+ connection . Closed += Handler ;
166+
167+ try
168+ {
169+ var watch = Stopwatch . StartNew ( ) ;
170+ var completedTask = await Task . WhenAny ( tcs . Task , Task . Delay ( timeout ) ) ;
171+ watch . Stop ( ) ;
172+
173+ if ( completedTask == tcs . Task )
174+ {
175+ await tcs . Task ;
176+ _output . WriteLine ( $ "{ label } disconnected after { watch . Elapsed } .") ;
177+ return true ;
178+ }
179+
180+ _output . WriteLine ( $ "{ label } still connected after { watch . Elapsed } .") ;
181+ return false ;
182+ }
183+ finally
184+ {
185+ connection . Closed -= Handler ;
186+ }
187+ }
129188}
0 commit comments