@@ -125,6 +125,57 @@ final class RequestBagTests: XCTestCase {
125
125
126
126
XCTAssertNoThrow ( try bag. task. futureResult. wait ( ) , " The request has succeeded " )
127
127
}
128
+
129
+ func testTaskIsFailedIfWritingFails( ) {
130
+ struct TestError : Error , Equatable { }
131
+
132
+ let embeddedEventLoop = EmbeddedEventLoop ( )
133
+ defer { XCTAssertNoThrow ( try embeddedEventLoop. syncShutdownGracefully ( ) ) }
134
+ let logger = Logger ( label: " test " )
135
+
136
+ let requestBody : HTTPClient . Body = . stream( length: 12 ) { writer -> EventLoopFuture < Void > in
137
+
138
+ writer. write ( . byteBuffer( ByteBuffer ( bytes: 0 ... 3 ) ) ) . flatMap { _ -> EventLoopFuture < Void > in
139
+ embeddedEventLoop. makeFailedFuture ( TestError ( ) )
140
+ }
141
+ }
142
+
143
+ var maybeRequest : HTTPClient . Request ?
144
+ XCTAssertNoThrow ( maybeRequest = try HTTPClient . Request ( url: " https://swift.org " , method: . POST, body: requestBody) )
145
+ guard let request = maybeRequest else { return XCTFail ( " Expected to have a request " ) }
146
+
147
+ let delegate = UploadCountingDelegate ( eventLoop: embeddedEventLoop)
148
+ let bag = RequestBag (
149
+ request: request,
150
+ eventLoopPreference: . delegate( on: embeddedEventLoop) ,
151
+ task: . init( eventLoop: embeddedEventLoop, logger: logger) ,
152
+ redirectHandler: nil ,
153
+ connectionDeadline: . now( ) + . seconds( 30 ) ,
154
+ idleReadTimeout: nil ,
155
+ delegate: delegate
156
+ )
157
+ XCTAssert ( bag. task. eventLoop === embeddedEventLoop)
158
+
159
+ let executor = MockRequestExecutor ( )
160
+
161
+ XCTAssertTrue ( bag. willExecuteRequest ( executor) , " false indicates request is cancelled " )
162
+
163
+ XCTAssertEqual ( delegate. hitDidSendRequestHead, 0 )
164
+ bag. requestHeadSent ( bag. requestHead)
165
+ XCTAssertEqual ( delegate. hitDidSendRequestHead, 1 )
166
+ XCTAssertEqual ( delegate. hitDidSendRequestPart, 0 )
167
+ bag. resumeRequestBodyStream ( )
168
+ XCTAssertEqual ( delegate. hitDidSendRequestPart, 1 )
169
+ XCTAssertEqual ( delegate. hitDidReceiveError, 1 )
170
+ XCTAssertEqual ( delegate. lastError as? TestError , TestError ( ) )
171
+
172
+ XCTAssertTrue ( executor. isCancelled)
173
+
174
+ XCTAssertThrowsError ( try bag. task. futureResult. wait ( ) ) {
175
+ XCTAssertEqual ( $0 as? TestError , TestError ( ) )
176
+ }
177
+ }
178
+
128
179
129
180
func testCancelFailsTaskBeforeRequestIsSent( ) {
130
181
let embeddedEventLoop = EmbeddedEventLoop ( )
@@ -280,10 +331,12 @@ class UploadCountingDelegate: HTTPClientResponseDelegate {
280
331
private( set) var hitDidSendRequestPart = 0
281
332
private( set) var hitDidSendRequest = 0
282
333
private( set) var hitDidReceiveResponse = 0
334
+ private( set) var hitDidReceiveError = 0
283
335
284
336
private( set) var receivedHead : HTTPResponseHead ?
285
337
private( set) var lastBodyPart : ByteBuffer ?
286
338
private( set) var backpressurePromise : EventLoopPromise < Void > ?
339
+ private( set) var lastError : Error ?
287
340
288
341
init ( eventLoop: EventLoop ) {
289
342
self . eventLoop = eventLoop
@@ -315,6 +368,11 @@ class UploadCountingDelegate: HTTPClientResponseDelegate {
315
368
func didFinishRequest( task: HTTPClient . Task < Void > ) throws {
316
369
self . hitDidReceiveResponse += 1
317
370
}
371
+
372
+ func didReceiveError( task: HTTPClient . Task < Void > , _ error: Error ) {
373
+ self . hitDidReceiveError += 1
374
+ self . lastError = error
375
+ }
318
376
319
377
private func createBackpressurePromise( ) -> EventLoopFuture < Void > {
320
378
assert ( self . backpressurePromise == nil )
0 commit comments