Skip to content

Commit 4f0346e

Browse files
committed
basic integration tests
1 parent 7d1ed4c commit 4f0346e

File tree

4 files changed

+226
-1
lines changed

4 files changed

+226
-1
lines changed
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2018-2019 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
//
15+
// HTTP2ClientTests+XCTest.swift
16+
//
17+
import XCTest
18+
19+
///
20+
/// NOTE: This file was generated by generate_linux_tests.rb
21+
///
22+
/// Do NOT edit this file directly as it will be regenerated automatically when needed.
23+
///
24+
25+
extension HTTP2ClientTests {
26+
static var allTests: [(String, (HTTP2ClientTests) -> () throws -> Void)] {
27+
return [
28+
("testSimpleGet", testSimpleGet),
29+
("testConcurrentRequests", testConcurrentRequests),
30+
("testConcurrentRequestsFromDifferentThreads", testConcurrentRequestsFromDifferentThreads),
31+
("testConcurrentRequestsWorkWithRequiredEventLoop", testConcurrentRequestsWorkWithRequiredEventLoop),
32+
]
33+
}
34+
}

Diff for: Tests/AsyncHTTPClientTests/HTTP2ClientTests.swift

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the AsyncHTTPClient open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the AsyncHTTPClient project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of AsyncHTTPClient project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
// TODO: remove @testable once we officially support HTTP/2
16+
@testable import AsyncHTTPClient // Tests that really need @testable go into HTTP2ClientInternalTests.swift
17+
#if canImport(Network)
18+
import Network
19+
#endif
20+
import Logging
21+
import NIOCore
22+
import NIOPosix
23+
import NIOSSL
24+
import XCTest
25+
26+
class HTTP2ClientTests: XCTestCase {
27+
let bin = HTTPBin(.http2(compress: false))
28+
let client: HTTPClient = {
29+
var tlsConfig = TLSConfiguration.makeClientConfiguration()
30+
tlsConfig.certificateVerification = .none
31+
return HTTPClient(
32+
eventLoopGroupProvider: .createNew,
33+
configuration: HTTPClient.Configuration(
34+
tlsConfiguration: tlsConfig,
35+
httpVersion: .automatic
36+
),
37+
backgroundActivityLogger: Logger(label: "HTTPClient", factory: StreamLogHandler.standardOutput(label:))
38+
)
39+
}()
40+
41+
override func tearDown() {
42+
super.tearDown()
43+
XCTAssertNoThrow(try self.client.syncShutdown())
44+
XCTAssertNoThrow(try self.bin.shutdown())
45+
}
46+
47+
func testSimpleGet() {
48+
var response: HTTPClient.Response?
49+
XCTAssertNoThrow(response = try self.client.get(url: "https://localhost:\(self.bin.port)/get").wait())
50+
51+
XCTAssertEqual(.ok, response?.status)
52+
XCTAssertEqual(response?.version, .http2)
53+
}
54+
55+
func testConcurrentRequests() {
56+
let el = self.client.eventLoopGroup.next()
57+
let requestPromises = (0..<1000).map { _ in
58+
client.get(url: "https://localhost:\(bin.port)/get")
59+
.map { result -> Void in
60+
XCTAssertEqual(result.version, .http2)
61+
}
62+
}
63+
XCTAssertNoThrow(try EventLoopFuture.whenAllComplete(requestPromises, on: el).wait())
64+
}
65+
66+
func testConcurrentRequestsFromDifferentThreads() {
67+
let numberOfWorkers = 20
68+
let numberOfRequestsPerWorkers = 20
69+
let allWorkersReady = DispatchSemaphore(value: 0)
70+
let allWorkersGo = DispatchSemaphore(value: 0)
71+
let allDone = DispatchGroup()
72+
73+
let url = "https://localhost:\(bin.port)/get"
74+
75+
var response: HTTPClient.Response?
76+
XCTAssertNoThrow(response = try self.client.get(url: url).wait())
77+
78+
XCTAssertEqual(.ok, response?.status)
79+
XCTAssertEqual(response?.version, .http2)
80+
81+
for w in 0..<numberOfWorkers {
82+
let q = DispatchQueue(label: "worker \(w)")
83+
q.async(group: allDone) {
84+
func go() {
85+
allWorkersReady.signal() // tell the driver we're ready
86+
allWorkersGo.wait() // wait for the driver to let us go
87+
88+
for _ in 0..<numberOfRequestsPerWorkers {
89+
var response: HTTPClient.Response?
90+
XCTAssertNoThrow(response = try self.client.get(url: url).wait())
91+
92+
XCTAssertEqual(.ok, response?.status)
93+
XCTAssertEqual(response?.version, .http2)
94+
}
95+
}
96+
go()
97+
}
98+
}
99+
100+
for _ in 0..<numberOfWorkers {
101+
allWorkersReady.wait()
102+
}
103+
// now all workers should be waiting for the go signal
104+
105+
for _ in 0..<numberOfWorkers {
106+
allWorkersGo.signal()
107+
}
108+
// all workers should be running, let's wait for them to finish
109+
allDone.wait()
110+
}
111+
112+
func testConcurrentRequestsWorkWithRequiredEventLoop() {
113+
let numberOfWorkers = 20
114+
let numberOfRequestsPerWorkers = 20
115+
let allWorkersReady = DispatchSemaphore(value: 0)
116+
let allWorkersGo = DispatchSemaphore(value: 0)
117+
let allDone = DispatchGroup()
118+
119+
let localHTTPBin = HTTPBin(.http2(compress: false))
120+
let elg = MultiThreadedEventLoopGroup(numberOfThreads: numberOfWorkers)
121+
var tlsConfig = TLSConfiguration.makeClientConfiguration()
122+
tlsConfig.certificateVerification = .none
123+
let localClient = HTTPClient(
124+
eventLoopGroupProvider: .shared(elg),
125+
configuration: HTTPClient.Configuration(
126+
tlsConfiguration: tlsConfig,
127+
httpVersion: .automatic
128+
),
129+
backgroundActivityLogger: Logger(label: "HTTPClient", factory: StreamLogHandler.standardOutput(label:))
130+
)
131+
defer {
132+
XCTAssertNoThrow(try localClient.syncShutdown())
133+
XCTAssertNoThrow(try localHTTPBin.shutdown())
134+
}
135+
136+
let url = "https://localhost:\(localHTTPBin.port)/get"
137+
138+
var response: HTTPClient.Response?
139+
XCTAssertNoThrow(response = try localClient.get(url: url).wait())
140+
141+
XCTAssertEqual(.ok, response?.status)
142+
XCTAssertEqual(response?.version, .http2)
143+
144+
for w in 0..<numberOfWorkers {
145+
let q = DispatchQueue(label: "worker \(w)")
146+
let el = elg.next()
147+
q.async(group: allDone) {
148+
func go() {
149+
allWorkersReady.signal() // tell the driver we're ready
150+
allWorkersGo.wait() // wait for the driver to let us go
151+
152+
for _ in 0..<numberOfRequestsPerWorkers {
153+
var response: HTTPClient.Response?
154+
let request = try! HTTPClient.Request(url: url)
155+
let requestPromise = localClient
156+
.execute(
157+
request: request,
158+
eventLoop: .delegateAndChannel(on: el)
159+
)
160+
.map { response -> HTTPClient.Response in
161+
XCTAssertTrue(el.inEventLoop)
162+
return response
163+
}
164+
XCTAssertNoThrow(response = try requestPromise.wait())
165+
166+
XCTAssertEqual(.ok, response?.status)
167+
XCTAssertEqual(response?.version, .http2)
168+
}
169+
}
170+
go()
171+
}
172+
}
173+
174+
for _ in 0..<numberOfWorkers {
175+
allWorkersReady.wait()
176+
}
177+
// now all workers should be waiting for the go signal
178+
179+
for _ in 0..<numberOfWorkers {
180+
allWorkersGo.signal()
181+
}
182+
// all workers should be running, let's wait for them to finish
183+
allDone.wait()
184+
}
185+
}

Diff for: Tests/AsyncHTTPClientTests/HTTPClientTestUtils.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Foundation
1717
import Logging
1818
import NIOConcurrencyHelpers
1919
import NIOCore
20+
import NIOHPACK
2021
import NIOHTTP1
2122
import NIOHTTP2
2223
import NIOHTTPCompression
@@ -484,7 +485,11 @@ internal final class HTTPBin<RequestHandler: ChannelInboundHandler> where
484485
// Successful upgrade to HTTP/2. Let the user configure the pipeline.
485486
let http2Handler = NIOHTTP2Handler(
486487
mode: .server,
487-
initialSettings: NIOHTTP2.nioDefaultSettings
488+
initialSettings: [
489+
// TODO: make max concurrent streams configurable
490+
HTTP2Setting(parameter: .maxConcurrentStreams, value: 10),
491+
HTTP2Setting(parameter: .maxHeaderListSize, value: HPACKDecoder.defaultMaxHeaderListSize),
492+
]
488493
)
489494
let multiplexer = HTTP2StreamMultiplexer(
490495
mode: .server,

Diff for: Tests/LinuxMain.swift

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import XCTest
3131
testCase(HTTP1ConnectionTests.allTests),
3232
testCase(HTTP1ProxyConnectHandlerTests.allTests),
3333
testCase(HTTP2ClientRequestHandlerTests.allTests),
34+
testCase(HTTP2ClientTests.allTests),
3435
testCase(HTTP2ConnectionTests.allTests),
3536
testCase(HTTP2IdleHandlerTests.allTests),
3637
testCase(HTTPClientCookieTests.allTests),

0 commit comments

Comments
 (0)