15
15
@testable import AsyncHTTPClient
16
16
import Logging
17
17
import NIOConcurrencyHelpers
18
- import NIOCore
18
+ @ preconcurrency import NIOCore
19
19
import NIOEmbedded
20
20
import NIOHTTP1
21
21
import NIOPosix
@@ -41,23 +41,23 @@ final class TransactionTests: XCTestCase {
41
41
guard let preparedRequest = maybePreparedRequest else {
42
42
return XCTFail ( " Expected to have a request here. " )
43
43
}
44
- let ( transaction, responseTask) = Transaction . makeWithResultTask (
44
+
45
+ let queuer = MockTaskQueuer ( )
46
+
47
+ await XCTAssertThrowsError ( try await Transaction . awaitResponseWithTransaction (
45
48
request: preparedRequest,
46
49
preferredEventLoop: embeddedEventLoop
47
- )
50
+ ) { transaction in
51
+ transaction. requestWasQueued ( queuer)
48
52
49
- let queuer = MockTaskQueuer ( )
50
- transaction. requestWasQueued ( queuer)
53
+ Task . detached {
54
+ try await Task . sleep ( nanoseconds: 5 * 1000 * 1000 )
55
+ transaction. cancel ( )
56
+ }
51
57
52
- Task . detached {
53
- try await Task . sleep ( nanoseconds: 5 * 1000 * 1000 )
54
- transaction. cancel ( )
55
- }
58
+ XCTAssertEqual ( queuer. hitCancelCount, 0 )
59
+ } )
56
60
57
- XCTAssertEqual ( queuer. hitCancelCount, 0 )
58
- await XCTAssertThrowsError ( try await responseTask. value) {
59
- XCTAssertEqual ( $0 as? HTTPClientError , . cancelled)
60
- }
61
61
XCTAssertEqual ( queuer. hitCancelCount, 1 )
62
62
}
63
63
#endif
@@ -78,50 +78,54 @@ final class TransactionTests: XCTestCase {
78
78
guard let preparedRequest = maybePreparedRequest else {
79
79
return
80
80
}
81
- let ( transaction, responseTask) = Transaction . makeWithResultTask (
82
- request: preparedRequest,
83
- preferredEventLoop: embeddedEventLoop
84
- )
85
81
86
82
let executor = MockRequestExecutor (
87
83
pauseRequestBodyPartStreamAfterASingleWrite: true ,
88
84
eventLoop: embeddedEventLoop
89
85
)
90
86
91
- transaction. willExecuteRequest ( executor)
92
- transaction. requestHeadSent ( )
93
-
94
- let responseHead = HTTPResponseHead ( version: . http1_1, status: . ok, headers: [ " foo " : " bar " ] )
95
- XCTAssertFalse ( executor. signalledDemandForResponseBody)
96
- transaction. receiveResponseHead ( responseHead)
87
+ let response = try await Transaction . awaitResponseWithTransaction (
88
+ request: preparedRequest,
89
+ preferredEventLoop: embeddedEventLoop
90
+ ) { transaction in
97
91
98
- let response = try await responseTask. value
99
- XCTAssertEqual ( response. status, responseHead. status)
100
- XCTAssertEqual ( response. headers, responseHead. headers)
101
- XCTAssertEqual ( response. version, responseHead. version)
92
+ transaction. willExecuteRequest ( executor)
93
+ transaction. requestHeadSent ( )
102
94
103
- let iterator = SharedIterator ( response. body. filter { $0. readableBytes > 0 } . makeAsyncIterator ( ) )
95
+ let responseHead = HTTPResponseHead ( version: . http1_1, status: . ok, headers: [ " foo " : " bar " ] )
96
+ XCTAssertFalse ( executor. signalledDemandForResponseBody)
97
+ transaction. receiveResponseHead ( responseHead)
104
98
105
- for i in 0 ..< 100 {
106
- XCTAssertFalse ( executor. signalledDemandForResponseBody, " Demand was not signalled yet. " )
99
+ for i in 0 ..< 100 {
100
+ XCTAssertFalse ( executor. signalledDemandForResponseBody, " Demand was not signalled yet. " )
107
101
108
- async let part = iterator. next ( )
102
+ XCTAssertNoThrow ( try executor. receiveResponseDemand ( ) )
103
+ executor. resetResponseStreamDemandSignal ( )
104
+ transaction. receiveResponseBodyParts ( [ ByteBuffer ( integer: i) ] )
105
+ }
109
106
107
+ XCTAssertFalse ( executor. signalledDemandForResponseBody, " Demand was not signalled yet. " )
110
108
XCTAssertNoThrow ( try executor. receiveResponseDemand ( ) )
111
109
executor. resetResponseStreamDemandSignal ( )
112
- transaction. receiveResponseBodyParts ( [ ByteBuffer ( integer: i) ] )
110
+ transaction. succeedRequest ( [ ] )
111
+ }
113
112
114
- let result = try await part
113
+ let expectedResponse = HTTPResponseHead ( version: . http1_1, status: . ok, headers: [ " foo " : " bar " ] )
114
+
115
+ XCTAssertEqual ( response. status, expectedResponse. status)
116
+ XCTAssertEqual ( response. headers, expectedResponse. headers)
117
+ XCTAssertEqual ( response. version, expectedResponse. version)
118
+
119
+ var iterator = response. body. filter { $0. readableBytes > 0 } . makeAsyncIterator ( )
120
+
121
+ for i in 0 ..< 100 {
122
+ let result = try await iterator. next ( )
115
123
XCTAssertEqual ( result, ByteBuffer ( integer: i) )
116
124
}
117
125
118
- XCTAssertFalse ( executor. signalledDemandForResponseBody, " Demand was not signalled yet. " )
119
- async let part = iterator. next ( )
120
- XCTAssertNoThrow ( try executor. receiveResponseDemand ( ) )
121
- executor. resetResponseStreamDemandSignal ( )
122
- transaction. succeedRequest ( [ ] )
123
- let result = try await part
124
- XCTAssertNil ( result)
126
+ let final = try await iterator. next ( )
127
+ XCTAssertNil ( final)
128
+
125
129
}
126
130
#endif
127
131
}
@@ -581,5 +585,34 @@ extension Transaction {
581
585
582
586
return ( transaction, result)
583
587
}
588
+
589
+ fileprivate static func awaitResponseWithTransaction(
590
+ request: PreparedRequest ,
591
+ requestOptions: RequestOptions = . forTests( ) ,
592
+ logger: Logger = Logger ( label: " test " ) ,
593
+ connectionDeadline: NIODeadline = . distantFuture,
594
+ preferredEventLoop: EventLoop ,
595
+ _ closure: @Sendable @escaping ( Transaction) async throws -> ( )
596
+ ) async throws -> HTTPClientResponse {
597
+
598
+ try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < HTTPClientResponse , Error > ) in
599
+ let transaction = Transaction (
600
+ request: request,
601
+ requestOptions: requestOptions,
602
+ logger: logger,
603
+ connectionDeadline: connectionDeadline,
604
+ preferredEventLoop: preferredEventLoop,
605
+ responseContinuation: continuation
606
+ )
607
+
608
+ Task {
609
+ do {
610
+ try await closure ( transaction)
611
+ } catch {
612
+ XCTFail ( )
613
+ }
614
+ }
615
+ }
616
+ }
584
617
}
585
618
#endif
0 commit comments