mirror of
https://github.com/apple/swift-nio-extras.git
synced 2025-06-01 18:53:35 +08:00
use B2MD verifier (#52)
Motivation: Use B2MDVerifier for the B2MDs in NIOExtras. Already found one bug, separetely fixed in #51. Modifications: Write a basic validation test for all B2MDs. Result: Better test coverage.
This commit is contained in:
parent
3a9ddcaf3e
commit
66f9a509ed
@ -25,7 +25,7 @@ var targets: [PackageDescription.Target] = [
|
|||||||
linkerSettings: [
|
linkerSettings: [
|
||||||
.linkedLibrary("z")
|
.linkedLibrary("z")
|
||||||
]),
|
]),
|
||||||
.testTarget(name: "NIOExtrasTests", dependencies: ["NIOExtras"]),
|
.testTarget(name: "NIOExtrasTests", dependencies: ["NIOExtras", "NIOTestUtils"]),
|
||||||
.testTarget(name: "NIOHTTPCompressionTests", dependencies: ["NIOHTTPCompression"]),
|
.testTarget(name: "NIOHTTPCompressionTests", dependencies: ["NIOHTTPCompression"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ let package = Package(
|
|||||||
.library(name: "NIOHTTPCompression", targets: ["NIOHTTPCompression"]),
|
.library(name: "NIOHTTPCompression", targets: ["NIOHTTPCompression"]),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
|
.package(url: "https://github.com/apple/swift-nio.git", from: "2.2.0"),
|
||||||
],
|
],
|
||||||
targets: targets
|
targets: targets
|
||||||
)
|
)
|
||||||
|
@ -43,8 +43,7 @@ public final class LengthFieldBasedFrameDecoder: ByteToMessageDecoder {
|
|||||||
case four
|
case four
|
||||||
case eight
|
case eight
|
||||||
|
|
||||||
fileprivate var length: Int {
|
var length: Int {
|
||||||
|
|
||||||
switch self {
|
switch self {
|
||||||
case .one:
|
case .one:
|
||||||
return 1
|
return 1
|
||||||
|
@ -30,7 +30,7 @@ extension FixedLengthFrameDecoderTest {
|
|||||||
("testDecodeIfMoreBytesAreSent", testDecodeIfMoreBytesAreSent),
|
("testDecodeIfMoreBytesAreSent", testDecodeIfMoreBytesAreSent),
|
||||||
("testRemoveHandlerWhenBufferIsNotEmpty", testRemoveHandlerWhenBufferIsNotEmpty),
|
("testRemoveHandlerWhenBufferIsNotEmpty", testRemoveHandlerWhenBufferIsNotEmpty),
|
||||||
("testRemoveHandlerWhenBufferIsEmpty", testRemoveHandlerWhenBufferIsEmpty),
|
("testRemoveHandlerWhenBufferIsEmpty", testRemoveHandlerWhenBufferIsEmpty),
|
||||||
("testCloseInChannelRead", testCloseInChannelRead),
|
("testBasicValidation", testBasicValidation),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
import NIO
|
import NIO
|
||||||
import NIOExtras
|
import NIOExtras
|
||||||
|
import NIOTestUtils
|
||||||
|
|
||||||
class FixedLengthFrameDecoderTest: XCTestCase {
|
class FixedLengthFrameDecoderTest: XCTestCase {
|
||||||
public func testDecodeIfFewerBytesAreSent() throws {
|
public func testDecodeIfFewerBytesAreSent() throws {
|
||||||
@ -115,30 +116,22 @@ class FixedLengthFrameDecoderTest: XCTestCase {
|
|||||||
XCTAssertTrue(try channel.finish().isClean)
|
XCTAssertTrue(try channel.finish().isClean)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCloseInChannelRead() {
|
func testBasicValidation() {
|
||||||
let channel = EmbeddedChannel(handler: ByteToMessageHandler(LengthFieldBasedFrameDecoder(lengthFieldLength: .four)))
|
for length in 1 ... 20 {
|
||||||
class CloseInReadHandler: ChannelInboundHandler {
|
let inputs = [
|
||||||
typealias InboundIn = ByteBuffer
|
String(decoding: Array(repeating: UInt8(ascii: "a"), count: length), as: Unicode.UTF8.self),
|
||||||
|
String(decoding: Array(repeating: UInt8(ascii: "b"), count: length), as: Unicode.UTF8.self),
|
||||||
private var numberOfReads = 0
|
String(decoding: Array(repeating: UInt8(ascii: "c"), count: length), as: Unicode.UTF8.self),
|
||||||
|
]
|
||||||
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
|
func byteBuffer(_ string: String) -> ByteBuffer {
|
||||||
self.numberOfReads += 1
|
var buffer = ByteBufferAllocator().buffer(capacity: string.utf8.count)
|
||||||
XCTAssertEqual(1, self.numberOfReads)
|
buffer.writeString(string)
|
||||||
XCTAssertEqual([UInt8(100)], Array(self.unwrapInboundIn(data).readableBytesView))
|
return buffer
|
||||||
context.close().whenFailure { error in
|
|
||||||
XCTFail("unexpected error: \(error)")
|
|
||||||
}
|
|
||||||
context.fireChannelRead(data)
|
|
||||||
}
|
}
|
||||||
|
let inputOutputPairs: [(String, [ByteBuffer])] = inputs.map { ($0, [byteBuffer($0)]) }
|
||||||
|
XCTAssertNoThrow(try ByteToMessageDecoderVerifier.verifyDecoder(stringInputOutputPairs: inputOutputPairs) {
|
||||||
|
FixedLengthFrameDecoder(frameLength: length)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
XCTAssertNoThrow(try channel.pipeline.addHandler(CloseInReadHandler()).wait())
|
|
||||||
|
|
||||||
var buf = channel.allocator.buffer(capacity: 1024)
|
|
||||||
buf.writeBytes([UInt8(0), 0, 0, 1, 100])
|
|
||||||
XCTAssertNoThrow(try channel.writeInbound(buf))
|
|
||||||
XCTAssertNoThrow(XCTAssertEqual([100], Array((try channel.readInbound() as ByteBuffer?)!.readableBytesView)))
|
|
||||||
XCTAssertNoThrow(XCTAssertNil(try channel.readInbound()))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,8 @@ extension LengthFieldBasedFrameDecoderTest {
|
|||||||
("testDecodeWithUInt16HeaderWithPartialBody", testDecodeWithUInt16HeaderWithPartialBody),
|
("testDecodeWithUInt16HeaderWithPartialBody", testDecodeWithUInt16HeaderWithPartialBody),
|
||||||
("testRemoveHandlerWhenBufferIsEmpty", testRemoveHandlerWhenBufferIsEmpty),
|
("testRemoveHandlerWhenBufferIsEmpty", testRemoveHandlerWhenBufferIsEmpty),
|
||||||
("testRemoveHandlerWhenBufferIsNotEmpty", testRemoveHandlerWhenBufferIsNotEmpty),
|
("testRemoveHandlerWhenBufferIsNotEmpty", testRemoveHandlerWhenBufferIsNotEmpty),
|
||||||
|
("testCloseInChannelRead", testCloseInChannelRead),
|
||||||
|
("testBasicVerification", testBasicVerification),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
import NIO
|
import NIO
|
||||||
import NIOExtras
|
@testable import NIOExtras
|
||||||
|
import NIOTestUtils
|
||||||
|
|
||||||
private let standardDataString = "abcde"
|
private let standardDataString = "abcde"
|
||||||
|
|
||||||
@ -375,4 +376,83 @@ class LengthFieldBasedFrameDecoderTest: XCTestCase {
|
|||||||
}))
|
}))
|
||||||
XCTAssertTrue(try self.channel.finish().isClean)
|
XCTAssertTrue(try self.channel.finish().isClean)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCloseInChannelRead() {
|
||||||
|
let channel = EmbeddedChannel(handler: ByteToMessageHandler(LengthFieldBasedFrameDecoder(lengthFieldLength: .four)))
|
||||||
|
class CloseInReadHandler: ChannelInboundHandler {
|
||||||
|
typealias InboundIn = ByteBuffer
|
||||||
|
|
||||||
|
private var numberOfReads = 0
|
||||||
|
|
||||||
|
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
|
||||||
|
self.numberOfReads += 1
|
||||||
|
XCTAssertEqual(1, self.numberOfReads)
|
||||||
|
XCTAssertEqual([UInt8(100)], Array(self.unwrapInboundIn(data).readableBytesView))
|
||||||
|
context.close().whenFailure { error in
|
||||||
|
XCTFail("unexpected error: \(error)")
|
||||||
|
}
|
||||||
|
context.fireChannelRead(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XCTAssertNoThrow(try channel.pipeline.addHandler(CloseInReadHandler()).wait())
|
||||||
|
|
||||||
|
var buf = channel.allocator.buffer(capacity: 1024)
|
||||||
|
buf.writeBytes([UInt8(0), 0, 0, 1, 100])
|
||||||
|
XCTAssertNoThrow(try channel.writeInbound(buf))
|
||||||
|
XCTAssertNoThrow(XCTAssertEqual([100], Array((try channel.readInbound() as ByteBuffer?)!.readableBytesView)))
|
||||||
|
XCTAssertNoThrow(XCTAssertNil(try channel.readInbound()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testBasicVerification() {
|
||||||
|
let inputs: [(LengthFieldBasedFrameDecoder.ByteLength, [(Int, String)])] = [
|
||||||
|
(.one, [
|
||||||
|
(6, "abcdef"),
|
||||||
|
(0, ""),
|
||||||
|
(9, "123456789"),
|
||||||
|
(Int(UInt8.max),
|
||||||
|
String(decoding: Array(repeating: UInt8(ascii: "X"), count: Int(UInt8.max)), as: Unicode.UTF8.self)),
|
||||||
|
]),
|
||||||
|
(.two, [
|
||||||
|
(1, "a"),
|
||||||
|
(0, ""),
|
||||||
|
(9, "123456789"),
|
||||||
|
(307,
|
||||||
|
String(decoding: Array(repeating: UInt8(ascii: "X"), count: 307), as: Unicode.UTF8.self)),
|
||||||
|
]),
|
||||||
|
(.four, [
|
||||||
|
(1, "a"),
|
||||||
|
(0, ""),
|
||||||
|
(3, "333"),
|
||||||
|
(307,
|
||||||
|
String(decoding: Array(repeating: UInt8(ascii: "X"), count: 307), as: Unicode.UTF8.self)),
|
||||||
|
]),
|
||||||
|
(.eight, [
|
||||||
|
(1, "a"),
|
||||||
|
(0, ""),
|
||||||
|
(4, "aaaa"),
|
||||||
|
(307,
|
||||||
|
String(decoding: Array(repeating: UInt8(ascii: "X"), count: 307), as: Unicode.UTF8.self)),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
|
||||||
|
for input in inputs {
|
||||||
|
let (lenBytes, inputData) = input
|
||||||
|
|
||||||
|
func byteBuffer(length: Int, string: String) -> ByteBuffer {
|
||||||
|
var buf = self.channel.allocator.buffer(capacity: string.utf8.count + 8)
|
||||||
|
buf.writeInteger(length)
|
||||||
|
buf.moveReaderIndex(forwardBy: 8 - lenBytes.length)
|
||||||
|
buf.writeString(string)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
let inputOutputPairs = inputData.map { (input: (Int, String)) -> (ByteBuffer, [ByteBuffer]) in
|
||||||
|
let bytes = byteBuffer(length: input.0, string: input.1)
|
||||||
|
return (bytes, [bytes.getSlice(at: bytes.readerIndex + lenBytes.length, length: input.0)!])
|
||||||
|
}
|
||||||
|
XCTAssertNoThrow(try ByteToMessageDecoderVerifier.verifyDecoder(inputOutputPairs: inputOutputPairs) {
|
||||||
|
LengthFieldBasedFrameDecoder(lengthFieldLength: lenBytes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ extension LineBasedFrameDecoderTest {
|
|||||||
("testChannelInactiveWithLeftOverBytes", testChannelInactiveWithLeftOverBytes),
|
("testChannelInactiveWithLeftOverBytes", testChannelInactiveWithLeftOverBytes),
|
||||||
("testMoreDataAvailableWhenChannelBecomesInactive", testMoreDataAvailableWhenChannelBecomesInactive),
|
("testMoreDataAvailableWhenChannelBecomesInactive", testMoreDataAvailableWhenChannelBecomesInactive),
|
||||||
("testDripFedCRLN", testDripFedCRLN),
|
("testDripFedCRLN", testDripFedCRLN),
|
||||||
|
("testBasicValidation", testBasicValidation),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
@testable import NIO // to inspect the cumulationBuffer
|
@testable import NIO // to inspect the cumulationBuffer
|
||||||
import NIOExtras
|
import NIOExtras
|
||||||
|
import NIOTestUtils
|
||||||
|
|
||||||
class LineBasedFrameDecoderTest: XCTestCase {
|
class LineBasedFrameDecoderTest: XCTestCase {
|
||||||
private var channel: EmbeddedChannel!
|
private var channel: EmbeddedChannel!
|
||||||
@ -186,4 +187,30 @@ class LineBasedFrameDecoderTest: XCTestCase {
|
|||||||
buffer.writeString("a")
|
buffer.writeString("a")
|
||||||
XCTAssertNoThrow(XCTAssertEqual(buffer, try self.channel.readInbound()))
|
XCTAssertNoThrow(XCTAssertEqual(buffer, try self.channel.readInbound()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testBasicValidation() {
|
||||||
|
func byteBuffer(_ string: String) -> ByteBuffer {
|
||||||
|
var buffer = self.channel.allocator.buffer(capacity: string.utf8.count)
|
||||||
|
buffer.writeString(string)
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try ByteToMessageDecoderVerifier.verifyDecoder(stringInputOutputPairs: [
|
||||||
|
("\n", [byteBuffer("")]),
|
||||||
|
("\r\n", [byteBuffer("")]),
|
||||||
|
("a\r\n", [byteBuffer("a")]),
|
||||||
|
("a\n", [byteBuffer("a")]),
|
||||||
|
("a\rb\n", [byteBuffer("a\rb")]),
|
||||||
|
("Content-Length: 17\r\nConnection: close\r\n\r\n", [byteBuffer("Content-Length: 17"),
|
||||||
|
byteBuffer("Connection: close"),
|
||||||
|
byteBuffer("")])
|
||||||
|
]) {
|
||||||
|
return LineBasedFrameDecoder()
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
XCTFail()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user