LengthPrefixedMessageReaderTests.swift 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright 2019, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import XCTest
  17. @testable import GRPC
  18. import NIO
  19. import Logging
  20. class LengthPrefixedMessageReaderTests: GRPCTestCase {
  21. var reader: LengthPrefixedMessageReader!
  22. override func setUp() {
  23. super.setUp()
  24. self.reader = LengthPrefixedMessageReader(mode: .client, compressionMechanism: .none)
  25. }
  26. var allocator = ByteBufferAllocator()
  27. func byteBuffer(withBytes bytes: [UInt8]) -> ByteBuffer {
  28. var buffer = allocator.buffer(capacity: bytes.count)
  29. buffer.writeBytes(bytes)
  30. return buffer
  31. }
  32. final let twoByteMessage: [UInt8] = [0x01, 0x02]
  33. func lengthPrefixedTwoByteMessage(withCompression compression: Bool = false) -> [UInt8] {
  34. return [
  35. compression ? 0x01 : 0x00, // 1-byte compression flag
  36. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  37. ] + twoByteMessage
  38. }
  39. func assertMessagesEqual(expected expectedBytes: [UInt8], actual buffer: ByteBuffer?, file: StaticString = #file, line: UInt = #line) {
  40. guard let buffer = buffer else {
  41. XCTFail("buffer is nil", file: file, line: line)
  42. return
  43. }
  44. guard let bytes = buffer.getBytes(at: buffer.readerIndex, length: expectedBytes.count) else {
  45. XCTFail("Expected \(expectedBytes.count) bytes, but only \(buffer.readableBytes) bytes are readable", file: file, line: line)
  46. return
  47. }
  48. XCTAssertEqual(expectedBytes, bytes, file: file, line: line)
  49. }
  50. func testNextMessageReturnsNilWhenNoBytesAppended() throws {
  51. XCTAssertNil(try reader.nextMessage())
  52. }
  53. func testNextMessageReturnsMessageIsAppendedInOneBuffer() throws {
  54. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage())
  55. reader.append(buffer: &buffer)
  56. self.assertMessagesEqual(expected: twoByteMessage, actual: try reader.nextMessage())
  57. }
  58. func testNextMessageReturnsMessageForZeroLengthMessage() throws {
  59. let bytes: [UInt8] = [
  60. 0x00, // 1-byte compression flag
  61. 0x00, 0x00, 0x00, 0x00, // 4-byte message length (0)
  62. // 0-byte message
  63. ]
  64. var buffer = byteBuffer(withBytes: bytes)
  65. reader.append(buffer: &buffer)
  66. self.assertMessagesEqual(expected: [], actual: try reader.nextMessage())
  67. }
  68. func testNextMessageDeliveredAcrossMultipleByteBuffers() throws {
  69. let firstBytes: [UInt8] = [
  70. 0x00, // 1-byte compression flag
  71. 0x00, 0x00, 0x00, // first 3 bytes of 4-byte message length
  72. ]
  73. let secondBytes: [UInt8] = [
  74. 0x02, // fourth byte of 4-byte message length (2)
  75. 0xf0, 0xba, // 2-byte message
  76. ]
  77. var firstBuffer = byteBuffer(withBytes: firstBytes)
  78. reader.append(buffer: &firstBuffer)
  79. var secondBuffer = byteBuffer(withBytes: secondBytes)
  80. reader.append(buffer: &secondBuffer)
  81. self.assertMessagesEqual(expected: [0xf0, 0xba], actual: try reader.nextMessage())
  82. }
  83. func testNextMessageWhenMultipleMessagesAreBuffered() throws {
  84. let bytes: [UInt8] = [
  85. // 1st message
  86. 0x00, // 1-byte compression flag
  87. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  88. 0x0f, 0x00, // 2-byte message
  89. // 2nd message
  90. 0x00, // 1-byte compression flag
  91. 0x00, 0x00, 0x00, 0x04, // 4-byte message length (4)
  92. 0xde, 0xad, 0xbe, 0xef, // 4-byte message
  93. // 3rd message
  94. 0x00, // 1-byte compression flag
  95. 0x00, 0x00, 0x00, 0x01, // 4-byte message length (1)
  96. 0x01, // 1-byte message
  97. ]
  98. var buffer = byteBuffer(withBytes: bytes)
  99. reader.append(buffer: &buffer)
  100. self.assertMessagesEqual(expected: [0x0f, 0x00], actual: try reader.nextMessage())
  101. self.assertMessagesEqual(expected: [0xde, 0xad, 0xbe, 0xef], actual: try reader.nextMessage())
  102. self.assertMessagesEqual(expected: [0x01], actual: try reader.nextMessage())
  103. }
  104. func testNextMessageReturnsNilWhenNoMessageLengthIsAvailable() throws {
  105. let bytes: [UInt8] = [
  106. 0x00, // 1-byte compression flag
  107. ]
  108. var buffer = byteBuffer(withBytes: bytes)
  109. reader.append(buffer: &buffer)
  110. XCTAssertNil(try reader.nextMessage())
  111. // Ensure we can read a message when the rest of the bytes are delivered
  112. let restOfBytes: [UInt8] = [
  113. 0x00, 0x00, 0x00, 0x01, // 4-byte message length (1)
  114. 0x00, // 1-byte message
  115. ]
  116. var secondBuffer = byteBuffer(withBytes: restOfBytes)
  117. reader.append(buffer: &secondBuffer)
  118. self.assertMessagesEqual(expected: [0x00], actual: try reader.nextMessage())
  119. }
  120. func testNextMessageReturnsNilWhenNotAllMessageLengthIsAvailable() throws {
  121. let bytes: [UInt8] = [
  122. 0x00, // 1-byte compression flag
  123. 0x00, 0x00, // 2-bytes of message length (should be 4)
  124. ]
  125. var buffer = byteBuffer(withBytes: bytes)
  126. reader.append(buffer: &buffer)
  127. XCTAssertNil(try reader.nextMessage())
  128. // Ensure we can read a message when the rest of the bytes are delivered
  129. let restOfBytes: [UInt8] = [
  130. 0x00, 0x01, // 4-byte message length (1)
  131. 0x00, // 1-byte message
  132. ]
  133. var secondBuffer = byteBuffer(withBytes: restOfBytes)
  134. reader.append(buffer: &secondBuffer)
  135. self.assertMessagesEqual(expected: [0x00], actual: try reader.nextMessage())
  136. }
  137. func testNextMessageReturnsNilWhenNoMessageBytesAreAvailable() throws {
  138. let bytes: [UInt8] = [
  139. 0x00, // 1-byte compression flag
  140. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  141. ]
  142. var buffer = byteBuffer(withBytes: bytes)
  143. reader.append(buffer: &buffer)
  144. XCTAssertNil(try reader.nextMessage())
  145. // Ensure we can read a message when the rest of the bytes are delivered
  146. var secondBuffer = byteBuffer(withBytes: twoByteMessage)
  147. reader.append(buffer: &secondBuffer)
  148. self.assertMessagesEqual(expected: twoByteMessage, actual: try reader.nextMessage())
  149. }
  150. func testNextMessageReturnsNilWhenNotAllMessageBytesAreAvailable() throws {
  151. let bytes: [UInt8] = [
  152. 0x00, // 1-byte compression flag
  153. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  154. 0x00, // 1-byte of message
  155. ]
  156. var buffer = byteBuffer(withBytes: bytes)
  157. reader.append(buffer: &buffer)
  158. XCTAssertNil(try reader.nextMessage())
  159. // Ensure we can read a message when the rest of the bytes are delivered
  160. let restOfBytes: [UInt8] = [
  161. 0x01 // final byte of message
  162. ]
  163. var secondBuffer = byteBuffer(withBytes: restOfBytes)
  164. reader.append(buffer: &secondBuffer)
  165. self.assertMessagesEqual(expected: [0x00, 0x01], actual: try reader.nextMessage())
  166. }
  167. func testNextMessageThrowsWhenCompressionMechanismIsNotSupported() throws {
  168. // Unknown should never be supported.
  169. reader.compressionMechanism = .unknown
  170. XCTAssertFalse(reader.compressionMechanism.supported)
  171. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage(withCompression: true))
  172. reader.append(buffer: &buffer)
  173. XCTAssertThrowsError(try reader.nextMessage()) { error in
  174. XCTAssertEqual(.unsupportedCompressionMechanism("unknown"), (error as? GRPCError)?.wrappedError as? GRPCCommonError)
  175. }
  176. }
  177. func testNextMessageThrowsWhenCompressionFlagIsSetButNotExpected() throws {
  178. // Default compression mechanism is `.none` which requires that no
  179. // compression flag is set as it indicates a lack of message encoding header.
  180. XCTAssertFalse(reader.compressionMechanism.requiresFlag)
  181. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage(withCompression: true))
  182. reader.append(buffer: &buffer)
  183. XCTAssertThrowsError(try reader.nextMessage()) { error in
  184. XCTAssertEqual(.unexpectedCompression, (error as? GRPCError)?.wrappedError as? GRPCCommonError)
  185. }
  186. }
  187. func testNextMessageDoesNotThrowWhenCompressionFlagIsExpectedButNotSet() throws {
  188. // `.identity` should always be supported and requires a flag.
  189. reader.compressionMechanism = .identity
  190. XCTAssertTrue(reader.compressionMechanism.supported)
  191. XCTAssertTrue(reader.compressionMechanism.requiresFlag)
  192. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage())
  193. reader.append(buffer: &buffer)
  194. self.assertMessagesEqual(expected: twoByteMessage, actual: try reader.nextMessage())
  195. }
  196. func testAppendReadsAllBytes() throws {
  197. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage())
  198. reader.append(buffer: &buffer)
  199. XCTAssertEqual(0, buffer.readableBytes)
  200. }
  201. }