10
10
using Microsoft . DotNet . RemoteExecutor ;
11
11
using Xunit ;
12
12
using Xunit . Abstractions ;
13
+ using TestUtilities ;
13
14
14
15
namespace System . Net . Http . Functional . Tests
15
16
{
@@ -18,6 +19,11 @@ public abstract class SocketsHttpHandler_Cancellation_Test : HttpClientHandler_C
18
19
{
19
20
protected SocketsHttpHandler_Cancellation_Test ( ITestOutputHelper output ) : base ( output ) { }
20
21
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
+
21
27
private async Task ValidateConnectTimeout ( HttpMessageInvoker invoker , Uri uri , int minElapsed , int maxElapsed )
22
28
{
23
29
var sw = Stopwatch . StartNew ( ) ;
@@ -81,6 +87,11 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
81
87
options : new GenericLoopbackOptions ( ) { UseSsl = useSsl } ) ;
82
88
}
83
89
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
+
84
95
[ OuterLoop ]
85
96
[ Fact ]
86
97
public async Task ConnectTimeout_PlaintextStreamFilterTimesOut_Throws ( )
@@ -107,36 +118,35 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
107
118
options : new GenericLoopbackOptions ( ) { UseSsl = false } ) ;
108
119
}
109
120
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
+
111
127
[ Theory ]
112
128
[ InlineData ( true ) ]
113
129
[ InlineData ( false ) ]
114
130
public async Task ConnectionFailure_AfterInitialRequestCancelled_SecondRequestSucceedsOnNewConnection ( bool useSsl )
115
131
{
116
- if ( UseVersion == HttpVersion . Version30 )
132
+ if ( UseVersion . Major != 1 || ! TestAsync || ! useSsl )
117
133
{
118
- // HTTP3 does not support ConnectCallback
119
134
return ;
120
135
}
121
136
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 ) ;
127
138
128
139
await LoopbackServerFactory . CreateClientAndServerAsync ( async uri =>
129
140
{
130
141
int connectCount = 0 ;
131
142
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 ) ;
134
145
135
- using ( var handler = CreateHttpClientHandler ( allowAllCertificates : true ) )
136
- using ( var client = CreateHttpClient ( handler ) )
146
+ using ( HttpClientHandler handler = CreateHttpClientHandler ( ) )
147
+ using ( HttpClient client = CreateHttpClient ( handler ) )
137
148
{
138
- var socketsHandler = GetUnderlyingSocketsHttpHandler ( handler ) ;
139
- socketsHandler . ConnectCallback = async ( context , token ) =>
149
+ GetUnderlyingSocketsHttpHandler ( handler ) . ConnectCallback = async ( context , token ) =>
140
150
{
141
151
// Note we force serialization of connection creation by waiting on tcsFirstConnectionInitiated below,
142
152
// so we don't need to worry about concurrent access to connectCount.
@@ -145,6 +155,8 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
145
155
146
156
Assert . True ( connectCount <= 2 ) ;
147
157
158
+ _output . WriteLine ( $ "Connection count { connectCount } ") ;
159
+
148
160
if ( isFirstConnection )
149
161
{
150
162
tcsFirstConnectionInitiated . SetResult ( ) ;
@@ -157,6 +169,8 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
157
169
// Wait until first request is cancelled and has completed
158
170
await tcsFirstRequestCanceled . Task ;
159
171
172
+ _output . WriteLine ( $ "After tcsFirstRequestCanceled { isFirstConnection } ") ;
173
+
160
174
if ( isFirstConnection )
161
175
{
162
176
// Fail the first connection attempt
@@ -170,27 +184,34 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri =>
170
184
} ;
171
185
172
186
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" ) ;
174
189
175
190
// Wait for the connection attempt to be initiated before we send the second request, to avoid races in connection creation
176
191
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" ) ;
178
194
179
195
// Cancel the first message and wait for it to complete
180
196
cts . Cancel ( ) ;
181
197
await Assert . ThrowsAnyAsync < OperationCanceledException > ( ( ) => t1 ) ;
198
+ _output . WriteLine ( "ThrowsAnyAsync" ) ;
182
199
183
200
// Signal connections to proceed
184
201
tcsFirstRequestCanceled . SetResult ( ) ;
185
202
186
203
// Second request should succeed, even though the first connection failed
187
204
HttpResponseMessage resp2 = await t2 ;
205
+ _output . WriteLine ( "resp2" ) ;
188
206
Assert . Equal ( HttpStatusCode . OK , resp2 . StatusCode ) ;
189
207
Assert . Equal ( "Hello world" , await resp2 . Content . ReadAsStringAsync ( ) ) ;
208
+
209
+ Assert . True ( connectCount == 2 ) ;
190
210
}
191
211
} , async server =>
192
212
{
193
- await server . AcceptConnectionSendResponseAndCloseAsync ( content : "Hello world" ) ;
213
+ await server . HandleRequestAsync ( content : "Hello world" ) ;
214
+ _output . WriteLine ( "Server done" ) ;
194
215
} ,
195
216
options : new GenericLoopbackOptions ( ) { UseSsl = useSsl } ) ;
196
217
}
@@ -393,6 +414,11 @@ await RemoteExecutor.Invoke(static async (versionString, timoutStr) =>
393
414
} , UseVersion . ToString ( ) , timeout . ToString ( ) ) . DisposeAsync ( ) ;
394
415
}
395
416
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
+
396
422
private sealed class SetTcsContent : StreamContent
397
423
{
398
424
private readonly TaskCompletionSource < bool > _tcs ;
0 commit comments