1010using Microsoft . DotNet . RemoteExecutor ;
1111using Xunit ;
1212using Xunit . Abstractions ;
13+ using TestUtilities ;
1314
1415namespace System . Net . Http . Functional . Tests
1516{
@@ -18,6 +19,11 @@ public abstract class SocketsHttpHandler_Cancellation_Test : HttpClientHandler_C
1819 {
1920 protected SocketsHttpHandler_Cancellation_Test ( ITestOutputHelper output ) : base ( output ) { }
2021
22+ [ Fact ] public async Task ValidateConnectTimeout2 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
23+ [ Fact ] public async Task ValidateConnectTimeout3 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
24+ [ Fact ] [ OuterLoop ] public async Task ValidateConnectTimeout4 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
25+ [ Fact ] [ OuterLoop ] public async Task ValidateConnectTimeout5 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
26+
2127 private async Task ValidateConnectTimeout ( HttpMessageInvoker invoker , Uri uri , int minElapsed , int maxElapsed )
2228 {
2329 var sw = Stopwatch . StartNew ( ) ;
@@ -81,6 +87,11 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
8187 options : new GenericLoopbackOptions ( ) { UseSsl = useSsl } ) ;
8288 }
8389
90+ [ Fact ] public async Task ConnectTimeout_PlaintextStreamFilterTimesOut_Throws2 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
91+ [ Fact ] public async Task ConnectTimeout_PlaintextStreamFilterTimesOut_Throws3 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
92+ [ Fact ] [ OuterLoop ] public async Task ConnectTimeout_PlaintextStreamFilterTimesOut_Throws4 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
93+ [ Fact ] [ OuterLoop ] public async Task ConnectTimeout_PlaintextStreamFilterTimesOut_Throws5 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
94+
8495 [ OuterLoop ]
8596 [ Fact ]
8697 public async Task ConnectTimeout_PlaintextStreamFilterTimesOut_Throws ( )
@@ -107,36 +118,35 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
107118 options : new GenericLoopbackOptions ( ) { UseSsl = false } ) ;
108119 }
109120
110- [ OuterLoop ]
121+ [ Fact ] public async Task ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection2 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
122+ [ Fact ] public async Task ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection3 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
123+
124+ [ Fact ] [ OuterLoop ] public async Task ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection4 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
125+ [ Fact ] [ OuterLoop ] public async Task ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection5 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
126+
111127 [ Theory ]
112128 [ InlineData ( true ) ]
113129 [ InlineData ( false ) ]
114130 public async Task ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( bool useSsl )
115131 {
116- if ( UseVersion == HttpVersion . Version30 )
132+ if ( UseVersion . Major != 1 || ! TestAsync || ! useSsl )
117133 {
118- // HTTP3 does not support ConnectCallback
119134 return ;
120135 }
121136
122- if ( ! TestAsync )
123- {
124- // Test relies on ordering of async operations, so we can't test the sync case
125- return ;
126- }
137+ using var listener = new TestEventListener ( _output , TestEventListener . NetworkingEvents ) ;
127138
128139 await LoopbackServerFactory . CreateClientAndServerAsync ( async uri =>
129140 {
130141 int connectCount = 0 ;
131142
132- TaskCompletionSource tcsFirstConnectionInitiated = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
133- TaskCompletionSource tcsFirstRequestCanceled = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
143+ var tcsFirstConnectionInitiated = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
144+ var tcsFirstRequestCanceled = new TaskCompletionSource ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
134145
135- using ( var handler = CreateHttpClientHandler ( allowAllCertificates : true ) )
136- using ( var client = CreateHttpClient ( handler ) )
146+ using ( HttpClientHandler handler = CreateHttpClientHandler ( ) )
147+ using ( HttpClient client = CreateHttpClient ( handler ) )
137148 {
138- var socketsHandler = GetUnderlyingSocketsHttpHandler ( handler ) ;
139- socketsHandler . ConnectCallback = async ( context , token ) =>
149+ GetUnderlyingSocketsHttpHandler ( handler ) . ConnectCallback = async ( context , token ) =>
140150 {
141151 // Note we force serialization of connection creation by waiting on tcsFirstConnectionInitiated below,
142152 // so we don't need to worry about concurrent access to connectCount.
@@ -145,6 +155,8 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
145155
146156 Assert . True ( connectCount <= 2 ) ;
147157
158+ _output . WriteLine ( $ "Connection count { connectCount } ") ;
159+
148160 if ( isFirstConnection )
149161 {
150162 tcsFirstConnectionInitiated . SetResult ( ) ;
@@ -157,6 +169,8 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
157169 // Wait until first request is cancelled and has completed
158170 await tcsFirstRequestCanceled . Task ;
159171
172+ _output . WriteLine ( $ "After tcsFirstRequestCanceled { isFirstConnection } ") ;
173+
160174 if ( isFirstConnection )
161175 {
162176 // Fail the first connection attempt
@@ -170,27 +184,34 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
170184 } ;
171185
172186 using CancellationTokenSource cts = new CancellationTokenSource ( ) ;
173- Task < HttpResponseMessage > t1 = client . SendAsync ( new HttpRequestMessage ( HttpMethod . Get , uri ) { Version = UseVersion , VersionPolicy = HttpVersionPolicy . RequestVersionExact } , cts . Token ) ;
187+ Task < HttpResponseMessage > t1 = client . SendAsync ( CreateRequest ( HttpMethod . Get , uri , UseVersion , exactVersion : true ) , cts . Token ) ;
188+ _output . WriteLine ( "t1" ) ;
174189
175190 // Wait for the connection attempt to be initiated before we send the second request, to avoid races in connection creation
176191 await tcsFirstConnectionInitiated . Task ;
177- Task < HttpResponseMessage > t2 = client . SendAsync ( new HttpRequestMessage ( HttpMethod . Get , uri ) { Version = UseVersion , VersionPolicy = HttpVersionPolicy . RequestVersionExact } , default ) ;
192+ Task < HttpResponseMessage > t2 = client . SendAsync ( CreateRequest ( HttpMethod . Get , uri , UseVersion , exactVersion : true ) , CancellationToken . None ) ;
193+ _output . WriteLine ( "t2" ) ;
178194
179195 // Cancel the first message and wait for it to complete
180196 cts . Cancel ( ) ;
181197 await Assert . ThrowsAnyAsync < OperationCanceledException > ( ( ) => t1 ) ;
198+ _output . WriteLine ( "ThrowsAnyAsync" ) ;
182199
183200 // Signal connections to proceed
184201 tcsFirstRequestCanceled . SetResult ( ) ;
185202
186203 // Second request should succeed, even though the first connection failed
187204 HttpResponseMessage resp2 = await t2 ;
205+ _output . WriteLine ( "resp2" ) ;
188206 Assert . Equal ( HttpStatusCode . OK , resp2 . StatusCode ) ;
189207 Assert . Equal ( "Hello world" , await resp2 . Content . ReadAsStringAsync ( ) ) ;
208+
209+ Assert . True ( connectCount == 2 ) ;
190210 }
191211 } , async server =>
192212 {
193- await server . AcceptConnectionSendResponseAndCloseAsync ( content : "Hello world" ) ;
213+ await server . HandleRequestAsync ( content : "Hello world" ) ;
214+ _output . WriteLine ( "Server done" ) ;
194215 } ,
195216 options : new GenericLoopbackOptions ( ) { UseSsl = useSsl } ) ;
196217 }
@@ -393,6 +414,11 @@ await RemoteExecutor.Invoke(static async (versionString, timoutStr) =>
393414 } , UseVersion . ToString ( ) , timeout . ToString ( ) ) . DisposeAsync ( ) ;
394415 }
395416
417+ [ Fact ] public async Task PendingConnectionTimeout_HighValue_PendingConnectionIsNotCancelled2 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
418+ [ Fact ] public async Task PendingConnectionTimeout_HighValue_PendingConnectionIsNotCancelled3 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
419+ [ Fact ] [ OuterLoop ] public async Task PendingConnectionTimeout_HighValue_PendingConnectionIsNotCancelled4 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
420+ [ Fact ] [ OuterLoop ] public async Task PendingConnectionTimeout_HighValue_PendingConnectionIsNotCancelled5 ( ) => await ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( true ) ;
421+
396422 private sealed class SetTcsContent : StreamContent
397423 {
398424 private readonly TaskCompletionSource < bool > _tcs ;
0 commit comments