/
ServerTests.swift
218 lines (180 loc) · 6.63 KB
/
ServerTests.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import Vapor
import XCTest
final class ServerTests: XCTestCase {
func testPortOverride() throws {
let env = Environment(
name: "testing",
arguments: ["vapor", "serve", "--port", "8123"]
)
let app = Application(env)
defer { app.shutdown() }
app.get("foo") { req in
return "bar"
}
try app.start()
let res = try app.client.get("http://127.0.0.1:8123/foo").wait()
XCTAssertEqual(res.body?.string, "bar")
}
func testConfigureHTTPDecompressionLimit() throws {
let app = Application(.testing)
defer { app.shutdown() }
let smallOrigString = "Hello, world!"
let smallBody = ByteBuffer(base64String: "H4sIAAAAAAAAE/NIzcnJ11Eozy/KSVEEAObG5usNAAA=")! // "Hello, world!"
let bigBody = ByteBuffer(base64String: "H4sIAAAAAAAAE/NIzcnJ11HILU3OgBBJmenpqUUK5flFOSkKJRmJeQpJqWn5RamKAICcGhUqAAAA")! // "Hello, much much bigger world than before!"
// Max out at the smaller payload (.size is of compressed data)
app.http.server.configuration.requestDecompression = .enabled(
limit: .size(smallBody.readableBytes)
)
app.post("gzip") { $0.body.string ?? "" }
try app.server.start()
defer { app.server.shutdown() }
// Small payload should just barely get through.
let res = try app.client.post("http://localhost:8080/gzip") { req in
req.headers.replaceOrAdd(name: .contentEncoding, value: "gzip")
req.body = smallBody
}.wait()
XCTAssertEqual(res.body?.string, smallOrigString)
// Big payload should be hard-rejected. We can't test for the raw NIOHTTPDecompression.DecompressionError.limit error here because
// protocol decoding errors are only ever logged and can't be directly caught.
do {
_ = try app.client.post("http://localhost:8080/gzip") { req in
req.headers.replaceOrAdd(name: .contentEncoding, value: "gzip")
req.body = bigBody
}.wait()
} catch let error as HTTPClientError {
XCTAssertEqual(error, HTTPClientError.remoteConnectionClosed)
} catch {
XCTFail("\(error)")
}
}
func testLiveServer() throws {
let app = Application(.testing)
defer { app.shutdown() }
app.routes.get("ping") { req -> String in
return "123"
}
try app.testable().test(.GET, "/ping") { res in
XCTAssertEqual(res.status, .ok)
XCTAssertEqual(res.body.string, "123")
}
}
func testCustomServer() throws {
let app = Application(.testing)
defer { app.shutdown() }
app.servers.use(.custom)
XCTAssertEqual(app.customServer.didStart, false)
XCTAssertEqual(app.customServer.didShutdown, false)
try app.server.start()
XCTAssertEqual(app.customServer.didStart, true)
XCTAssertEqual(app.customServer.didShutdown, false)
app.server.shutdown()
XCTAssertEqual(app.customServer.didStart, true)
XCTAssertEqual(app.customServer.didShutdown, true)
}
func testMultipleChunkBody() throws {
let app = Application(.testing)
defer { app.shutdown() }
let payload = [UInt8].random(count: 1 << 20)
app.on(.POST, "payload", body: .collect(maxSize: "1gb")) { req -> HTTPStatus in
guard let data = req.body.data else {
throw Abort(.internalServerError)
}
XCTAssertEqual(payload.count, data.readableBytes)
XCTAssertEqual([UInt8](data.readableBytesView), payload)
return .ok
}
var buffer = ByteBufferAllocator().buffer(capacity: payload.count)
buffer.writeBytes(payload)
try app.testable(method: .running).test(.POST, "payload", body: buffer) { res in
XCTAssertEqual(res.status, .ok)
}
}
func testCollectedResponseBodyEnd() throws {
let app = Application(.testing)
defer { app.shutdown() }
app.post("drain") { req -> EventLoopFuture<HTTPStatus> in
let promise = req.eventLoop.makePromise(of: HTTPStatus.self)
req.body.drain { result in
switch result {
case .buffer: break
case .error(let error):
promise.fail(error)
case .end:
promise.succeed(.ok)
}
return req.eventLoop.makeSucceededFuture(())
}
return promise.futureResult
}
try app.testable(method: .running).test(.POST, "drain", beforeRequest: { req in
try req.content.encode(["hello": "world"])
}, afterResponse: { res in
XCTAssertEqual(res.status, .ok)
})
}
// https://github.com/vapor/vapor/issues/1786
func testMissingBody() throws {
struct User: Content { }
let app = Application(.testing)
defer { app.shutdown() }
app.get("user") { req -> User in
return try req.content.decode(User.self)
}
try app.testable().test(.GET, "/user") { res in
XCTAssertEqual(res.status, .unsupportedMediaType)
}
}
// https://github.com/vapor/vapor/issues/2245
func testTooLargePort() throws {
let app = Application(.testing)
defer { app.shutdown() }
app.http.server.configuration.port = .max
XCTAssertThrowsError(try app.start())
}
}
extension Application.Servers.Provider {
static var custom: Self {
.init {
$0.servers.use { $0.customServer }
}
}
}
extension Application {
struct Key: StorageKey {
typealias Value = CustomServer
}
var customServer: CustomServer {
if let existing = self.storage[Key.self] {
return existing
} else {
let new = CustomServer()
self.storage[Key.self] = new
return new
}
}
}
final class CustomServer: Server {
var didStart: Bool
var didShutdown: Bool
var onShutdown: EventLoopFuture<Void> {
fatalError()
}
init() {
self.didStart = false
self.didShutdown = false
}
func start(hostname: String?, port: Int?) throws {
self.didStart = true
}
func shutdown() {
self.didShutdown = true
}
}
private extension ByteBuffer {
init?(base64String: String) {
guard let decoded = Data(base64Encoded: base64String) else { return nil }
var buffer = ByteBufferAllocator().buffer(capacity: decoded.count)
buffer.writeBytes(decoded)
self = buffer
}
}