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:
Johannes Weiss 2019-05-28 11:28:59 +01:00 committed by GitHub
parent 3a9ddcaf3e
commit 66f9a509ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 131 additions and 29 deletions

View File

@ -25,7 +25,7 @@ var targets: [PackageDescription.Target] = [
linkerSettings: [
.linkedLibrary("z")
]),
.testTarget(name: "NIOExtrasTests", dependencies: ["NIOExtras"]),
.testTarget(name: "NIOExtrasTests", dependencies: ["NIOExtras", "NIOTestUtils"]),
.testTarget(name: "NIOHTTPCompressionTests", dependencies: ["NIOHTTPCompression"]),
]
@ -38,7 +38,7 @@ let package = Package(
.library(name: "NIOHTTPCompression", targets: ["NIOHTTPCompression"]),
],
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
)

View File

@ -43,8 +43,7 @@ public final class LengthFieldBasedFrameDecoder: ByteToMessageDecoder {
case four
case eight
fileprivate var length: Int {
var length: Int {
switch self {
case .one:
return 1

View File

@ -30,7 +30,7 @@ extension FixedLengthFrameDecoderTest {
("testDecodeIfMoreBytesAreSent", testDecodeIfMoreBytesAreSent),
("testRemoveHandlerWhenBufferIsNotEmpty", testRemoveHandlerWhenBufferIsNotEmpty),
("testRemoveHandlerWhenBufferIsEmpty", testRemoveHandlerWhenBufferIsEmpty),
("testCloseInChannelRead", testCloseInChannelRead),
("testBasicValidation", testBasicValidation),
]
}
}

View File

@ -15,6 +15,7 @@
import XCTest
import NIO
import NIOExtras
import NIOTestUtils
class FixedLengthFrameDecoderTest: XCTestCase {
public func testDecodeIfFewerBytesAreSent() throws {
@ -115,30 +116,22 @@ class FixedLengthFrameDecoderTest: XCTestCase {
XCTAssertTrue(try 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)")
func testBasicValidation() {
for length in 1 ... 20 {
let inputs = [
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),
String(decoding: Array(repeating: UInt8(ascii: "c"), count: length), as: Unicode.UTF8.self),
]
func byteBuffer(_ string: String) -> ByteBuffer {
var buffer = ByteBufferAllocator().buffer(capacity: string.utf8.count)
buffer.writeString(string)
return buffer
}
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()))
}
}

View File

@ -40,6 +40,8 @@ extension LengthFieldBasedFrameDecoderTest {
("testDecodeWithUInt16HeaderWithPartialBody", testDecodeWithUInt16HeaderWithPartialBody),
("testRemoveHandlerWhenBufferIsEmpty", testRemoveHandlerWhenBufferIsEmpty),
("testRemoveHandlerWhenBufferIsNotEmpty", testRemoveHandlerWhenBufferIsNotEmpty),
("testCloseInChannelRead", testCloseInChannelRead),
("testBasicVerification", testBasicVerification),
]
}
}

View File

@ -14,7 +14,8 @@
import XCTest
import NIO
import NIOExtras
@testable import NIOExtras
import NIOTestUtils
private let standardDataString = "abcde"
@ -375,4 +376,83 @@ class LengthFieldBasedFrameDecoderTest: XCTestCase {
}))
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)
})
}
}
}

View File

@ -34,6 +34,7 @@ extension LineBasedFrameDecoderTest {
("testChannelInactiveWithLeftOverBytes", testChannelInactiveWithLeftOverBytes),
("testMoreDataAvailableWhenChannelBecomesInactive", testMoreDataAvailableWhenChannelBecomesInactive),
("testDripFedCRLN", testDripFedCRLN),
("testBasicValidation", testBasicValidation),
]
}
}

View File

@ -15,6 +15,7 @@
import XCTest
@testable import NIO // to inspect the cumulationBuffer
import NIOExtras
import NIOTestUtils
class LineBasedFrameDecoderTest: XCTestCase {
private var channel: EmbeddedChannel!
@ -186,4 +187,30 @@ class LineBasedFrameDecoderTest: XCTestCase {
buffer.writeString("a")
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()
}
}
}