| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /*
- * Copyright 2019, gRPC Authors All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- import Logging
- import NIOCore
- import XCTest
- @testable import GRPC
- class LengthPrefixedMessageReaderTests: GRPCTestCase {
- var reader: LengthPrefixedMessageReader!
- override func setUp() {
- super.setUp()
- self.reader = LengthPrefixedMessageReader()
- }
- var allocator = ByteBufferAllocator()
- func byteBuffer(withBytes bytes: [UInt8]) -> ByteBuffer {
- var buffer = self.allocator.buffer(capacity: bytes.count)
- buffer.writeBytes(bytes)
- return buffer
- }
- final let twoByteMessage: [UInt8] = [0x01, 0x02]
- func lengthPrefixedTwoByteMessage(withCompression compression: Bool = false) -> [UInt8] {
- return [
- compression ? 0x01 : 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
- ] + self.twoByteMessage
- }
- private func assertMessagesEqual(
- expected expectedBytes: [UInt8],
- actual buffer: ByteBuffer?,
- line: UInt = #line
- ) {
- guard let buffer = buffer else {
- XCTFail("buffer is nil", line: line)
- return
- }
- guard let bytes = buffer.getBytes(at: buffer.readerIndex, length: expectedBytes.count) else {
- XCTFail(
- "Expected \(expectedBytes.count) bytes, but only \(buffer.readableBytes) bytes are readable",
- line: line
- )
- return
- }
- XCTAssertEqual(expectedBytes, bytes, line: line)
- }
- func testNextMessageReturnsNilWhenNoBytesAppended() throws {
- XCTAssertNil(try self.reader.nextMessage())
- }
- func testNextMessageReturnsMessageIsAppendedInOneBuffer() throws {
- var buffer = self.byteBuffer(withBytes: self.lengthPrefixedTwoByteMessage())
- self.reader.append(buffer: &buffer)
- self.assertMessagesEqual(expected: self.twoByteMessage, actual: try self.reader.nextMessage())
- }
- func testNextMessageReturnsMessageForZeroLengthMessage() throws {
- let bytes: [UInt8] = [
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, 0x00, // 4-byte message length (0)
- // 0-byte message
- ]
- var buffer = self.byteBuffer(withBytes: bytes)
- self.reader.append(buffer: &buffer)
- self.assertMessagesEqual(expected: [], actual: try self.reader.nextMessage())
- }
- func testNextMessageDeliveredAcrossMultipleByteBuffers() throws {
- let firstBytes: [UInt8] = [
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, // first 3 bytes of 4-byte message length
- ]
- let secondBytes: [UInt8] = [
- 0x02, // fourth byte of 4-byte message length (2)
- 0xF0, 0xBA, // 2-byte message
- ]
- var firstBuffer = self.byteBuffer(withBytes: firstBytes)
- self.reader.append(buffer: &firstBuffer)
- var secondBuffer = self.byteBuffer(withBytes: secondBytes)
- self.reader.append(buffer: &secondBuffer)
- self.assertMessagesEqual(expected: [0xF0, 0xBA], actual: try self.reader.nextMessage())
- }
- func testNextMessageWhenMultipleMessagesAreBuffered() throws {
- let bytes: [UInt8] = [
- // 1st message
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
- 0x0F, 0x00, // 2-byte message
- // 2nd message
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, 0x04, // 4-byte message length (4)
- 0xDE, 0xAD, 0xBE, 0xEF, // 4-byte message
- // 3rd message
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, 0x01, // 4-byte message length (1)
- 0x01, // 1-byte message
- ]
- var buffer = self.byteBuffer(withBytes: bytes)
- self.reader.append(buffer: &buffer)
- self.assertMessagesEqual(expected: [0x0F, 0x00], actual: try self.reader.nextMessage())
- self.assertMessagesEqual(
- expected: [0xDE, 0xAD, 0xBE, 0xEF],
- actual: try self.reader.nextMessage()
- )
- self.assertMessagesEqual(expected: [0x01], actual: try self.reader.nextMessage())
- }
- func testNextMessageReturnsNilWhenNoMessageLengthIsAvailable() throws {
- let bytes: [UInt8] = [
- 0x00 // 1-byte compression flag
- ]
- var buffer = self.byteBuffer(withBytes: bytes)
- self.reader.append(buffer: &buffer)
- XCTAssertNil(try self.reader.nextMessage())
- // Ensure we can read a message when the rest of the bytes are delivered
- let restOfBytes: [UInt8] = [
- 0x00, 0x00, 0x00, 0x01, // 4-byte message length (1)
- 0x00, // 1-byte message
- ]
- var secondBuffer = self.byteBuffer(withBytes: restOfBytes)
- self.reader.append(buffer: &secondBuffer)
- self.assertMessagesEqual(expected: [0x00], actual: try self.reader.nextMessage())
- }
- func testNextMessageReturnsNilWhenNotAllMessageLengthIsAvailable() throws {
- let bytes: [UInt8] = [
- 0x00, // 1-byte compression flag
- 0x00, 0x00, // 2-bytes of message length (should be 4)
- ]
- var buffer = self.byteBuffer(withBytes: bytes)
- self.reader.append(buffer: &buffer)
- XCTAssertNil(try self.reader.nextMessage())
- // Ensure we can read a message when the rest of the bytes are delivered
- let restOfBytes: [UInt8] = [
- 0x00, 0x01, // 4-byte message length (1)
- 0x00, // 1-byte message
- ]
- var secondBuffer = self.byteBuffer(withBytes: restOfBytes)
- self.reader.append(buffer: &secondBuffer)
- self.assertMessagesEqual(expected: [0x00], actual: try self.reader.nextMessage())
- }
- func testNextMessageReturnsNilWhenNoMessageBytesAreAvailable() throws {
- let bytes: [UInt8] = [
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
- ]
- var buffer = self.byteBuffer(withBytes: bytes)
- self.reader.append(buffer: &buffer)
- XCTAssertNil(try self.reader.nextMessage())
- // Ensure we can read a message when the rest of the bytes are delivered
- var secondBuffer = self.byteBuffer(withBytes: self.twoByteMessage)
- self.reader.append(buffer: &secondBuffer)
- self.assertMessagesEqual(expected: self.twoByteMessage, actual: try self.reader.nextMessage())
- }
- func testNextMessageReturnsNilWhenNotAllMessageBytesAreAvailable() throws {
- let bytes: [UInt8] = [
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
- 0x00, // 1-byte of message
- ]
- var buffer = self.byteBuffer(withBytes: bytes)
- self.reader.append(buffer: &buffer)
- XCTAssertNil(try self.reader.nextMessage())
- // Ensure we can read a message when the rest of the bytes are delivered
- let restOfBytes: [UInt8] = [
- 0x01 // final byte of message
- ]
- var secondBuffer = self.byteBuffer(withBytes: restOfBytes)
- self.reader.append(buffer: &secondBuffer)
- self.assertMessagesEqual(expected: [0x00, 0x01], actual: try self.reader.nextMessage())
- }
- func testNextMessageThrowsWhenCompressionFlagIsSetButNotExpected() throws {
- // Default compression mechanism is `nil` which requires that no
- // compression flag is set as it indicates a lack of message encoding header.
- XCTAssertNil(self.reader.compression)
- var buffer =
- self
- .byteBuffer(withBytes: self.lengthPrefixedTwoByteMessage(withCompression: true))
- self.reader.append(buffer: &buffer)
- XCTAssertThrowsError(try self.reader.nextMessage()) { error in
- let errorWithContext = error as? GRPCError.WithContext
- XCTAssertTrue(errorWithContext?.error is GRPCError.CompressionUnsupported)
- }
- }
- func testNextMessageDoesNotThrowWhenCompressionFlagIsExpectedButNotSet() throws {
- // `.identity` should always be supported and requires a flag.
- self.reader = LengthPrefixedMessageReader(compression: .identity, decompressionLimit: .ratio(1))
- var buffer = self.byteBuffer(withBytes: self.lengthPrefixedTwoByteMessage())
- self.reader.append(buffer: &buffer)
- self.assertMessagesEqual(expected: self.twoByteMessage, actual: try self.reader.nextMessage())
- }
- func testAppendReadsAllBytes() throws {
- var buffer = self.byteBuffer(withBytes: self.lengthPrefixedTwoByteMessage())
- self.reader.append(buffer: &buffer)
- XCTAssertEqual(0, buffer.readableBytes)
- }
- func testExcessiveBytesAreDiscarded() throws {
- // We're going to use a 1kB message here for ease of testing.
- let message = Array(repeating: UInt8(0), count: 1024)
- let largeMessage: [UInt8] =
- [
- 0x00, // 1-byte compression flag
- 0x00, 0x00, 0x04, 0x00, // 4-byte message length (1024)
- ] + message
- var buffer = self.byteBuffer(withBytes: largeMessage)
- buffer.writeBytes(largeMessage)
- buffer.writeBytes(largeMessage)
- self.reader.append(buffer: &buffer)
- XCTAssertEqual(self.reader.unprocessedBytes, (1024 + 5) * 3)
- XCTAssertEqual(self.reader._consumedNonDiscardedBytes, 0)
- self.assertMessagesEqual(expected: message, actual: try self.reader.nextMessage())
- XCTAssertEqual(self.reader.unprocessedBytes, (1024 + 5) * 2)
- XCTAssertEqual(self.reader._consumedNonDiscardedBytes, 1024 + 5)
- self.assertMessagesEqual(expected: message, actual: try self.reader.nextMessage())
- XCTAssertEqual(self.reader.unprocessedBytes, 1024 + 5)
- XCTAssertEqual(self.reader._consumedNonDiscardedBytes, 0)
- }
- }
- extension LengthPrefixedMessageReader {
- fileprivate mutating func nextMessage() throws -> ByteBuffer? {
- return try self.nextMessage(maxLength: .max)
- }
- }
|