LengthPrefixedMessageReaderTests.swift 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import Foundation
  2. import XCTest
  3. import SwiftGRPCNIO
  4. import NIO
  5. class LengthPrefixedMessageReaderTests: XCTestCase {
  6. var reader = LengthPrefixedMessageReader(mode: .client, compressionMechanism: .none)
  7. var allocator = ByteBufferAllocator()
  8. func byteBuffer(withBytes bytes: [UInt8]) -> ByteBuffer {
  9. var buffer = allocator.buffer(capacity: bytes.count)
  10. buffer.writeBytes(bytes)
  11. return buffer
  12. }
  13. final let twoByteMessage: [UInt8] = [0x01, 0x02]
  14. func lengthPrefixedTwoByteMessage(withCompression compression: Bool = false) -> [UInt8] {
  15. return [
  16. compression ? 0x01 : 0x00, // 1-byte compression flag
  17. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  18. ] + twoByteMessage
  19. }
  20. func assertMessagesEqual(expected expectedBytes: [UInt8], actual buffer: ByteBuffer?, file: StaticString = #file, line: UInt = #line) {
  21. guard let buffer = buffer else {
  22. XCTFail("buffer is nil", file: file, line: line)
  23. return
  24. }
  25. guard let bytes = buffer.getBytes(at: buffer.readerIndex, length: expectedBytes.count) else {
  26. XCTFail("Expected \(expectedBytes.count) bytes, but only \(buffer.readableBytes) bytes are readable", file: file, line: line)
  27. return
  28. }
  29. XCTAssertEqual(expectedBytes, bytes, file: file, line: line)
  30. }
  31. func testNextMessageReturnsNilWhenNoBytesAppended() throws {
  32. XCTAssertNil(try reader.nextMessage())
  33. }
  34. func testNextMessageReturnsMessageIsAppendedInOneBuffer() throws {
  35. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage())
  36. reader.append(buffer: &buffer)
  37. self.assertMessagesEqual(expected: twoByteMessage, actual: try reader.nextMessage())
  38. }
  39. func testNextMessageReturnsMessageForZeroLengthMessage() throws {
  40. let bytes: [UInt8] = [
  41. 0x00, // 1-byte compression flag
  42. 0x00, 0x00, 0x00, 0x00, // 4-byte message length (0)
  43. // 0-byte message
  44. ]
  45. var buffer = byteBuffer(withBytes: bytes)
  46. reader.append(buffer: &buffer)
  47. self.assertMessagesEqual(expected: [], actual: try reader.nextMessage())
  48. }
  49. func testNextMessageDeliveredAcrossMultipleByteBuffers() throws {
  50. let firstBytes: [UInt8] = [
  51. 0x00, // 1-byte compression flag
  52. 0x00, 0x00, 0x00, // first 3 bytes of 4-byte message length
  53. ]
  54. let secondBytes: [UInt8] = [
  55. 0x02, // fourth byte of 4-byte message length (2)
  56. 0xf0, 0xba, // 2-byte message
  57. ]
  58. var firstBuffer = byteBuffer(withBytes: firstBytes)
  59. reader.append(buffer: &firstBuffer)
  60. var secondBuffer = byteBuffer(withBytes: secondBytes)
  61. reader.append(buffer: &secondBuffer)
  62. self.assertMessagesEqual(expected: [0xf0, 0xba], actual: try reader.nextMessage())
  63. }
  64. func testNextMessageWhenMultipleMessagesAreBuffered() throws {
  65. let bytes: [UInt8] = [
  66. // 1st message
  67. 0x00, // 1-byte compression flag
  68. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  69. 0x0f, 0x00, // 2-byte message
  70. // 2nd message
  71. 0x00, // 1-byte compression flag
  72. 0x00, 0x00, 0x00, 0x04, // 4-byte message length (4)
  73. 0xde, 0xad, 0xbe, 0xef, // 4-byte message
  74. // 3rd message
  75. 0x00, // 1-byte compression flag
  76. 0x00, 0x00, 0x00, 0x01, // 4-byte message length (1)
  77. 0x01, // 1-byte message
  78. ]
  79. var buffer = byteBuffer(withBytes: bytes)
  80. reader.append(buffer: &buffer)
  81. self.assertMessagesEqual(expected: [0x0f, 0x00], actual: try reader.nextMessage())
  82. self.assertMessagesEqual(expected: [0xde, 0xad, 0xbe, 0xef], actual: try reader.nextMessage())
  83. self.assertMessagesEqual(expected: [0x01], actual: try reader.nextMessage())
  84. }
  85. func testNextMessageReturnsNilWhenNoMessageLengthIsAvailable() throws {
  86. let bytes: [UInt8] = [
  87. 0x00, // 1-byte compression flag
  88. ]
  89. var buffer = byteBuffer(withBytes: bytes)
  90. reader.append(buffer: &buffer)
  91. XCTAssertNil(try reader.nextMessage())
  92. // Ensure we can read a message when the rest of the bytes are delivered
  93. let restOfBytes: [UInt8] = [
  94. 0x00, 0x00, 0x00, 0x01, // 4-byte message length (1)
  95. 0x00, // 1-byte message
  96. ]
  97. var secondBuffer = byteBuffer(withBytes: restOfBytes)
  98. reader.append(buffer: &secondBuffer)
  99. self.assertMessagesEqual(expected: [0x00], actual: try reader.nextMessage())
  100. }
  101. func testNextMessageReturnsNilWhenNotAllMessageLengthIsAvailable() throws {
  102. let bytes: [UInt8] = [
  103. 0x00, // 1-byte compression flag
  104. 0x00, 0x00, // 2-bytes of message length (should be 4)
  105. ]
  106. var buffer = byteBuffer(withBytes: bytes)
  107. reader.append(buffer: &buffer)
  108. XCTAssertNil(try reader.nextMessage())
  109. // Ensure we can read a message when the rest of the bytes are delivered
  110. let restOfBytes: [UInt8] = [
  111. 0x00, 0x01, // 4-byte message length (1)
  112. 0x00, // 1-byte message
  113. ]
  114. var secondBuffer = byteBuffer(withBytes: restOfBytes)
  115. reader.append(buffer: &secondBuffer)
  116. self.assertMessagesEqual(expected: [0x00], actual: try reader.nextMessage())
  117. }
  118. func testNextMessageReturnsNilWhenNoMessageBytesAreAvailable() throws {
  119. let bytes: [UInt8] = [
  120. 0x00, // 1-byte compression flag
  121. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  122. ]
  123. var buffer = byteBuffer(withBytes: bytes)
  124. reader.append(buffer: &buffer)
  125. XCTAssertNil(try reader.nextMessage())
  126. // Ensure we can read a message when the rest of the bytes are delivered
  127. var secondBuffer = byteBuffer(withBytes: twoByteMessage)
  128. reader.append(buffer: &secondBuffer)
  129. self.assertMessagesEqual(expected: twoByteMessage, actual: try reader.nextMessage())
  130. }
  131. func testNextMessageReturnsNilWhenNotAllMessageBytesAreAvailable() throws {
  132. let bytes: [UInt8] = [
  133. 0x00, // 1-byte compression flag
  134. 0x00, 0x00, 0x00, 0x02, // 4-byte message length (2)
  135. 0x00, // 1-byte of message
  136. ]
  137. var buffer = byteBuffer(withBytes: bytes)
  138. reader.append(buffer: &buffer)
  139. XCTAssertNil(try reader.nextMessage())
  140. // Ensure we can read a message when the rest of the bytes are delivered
  141. let restOfBytes: [UInt8] = [
  142. 0x01 // final byte of message
  143. ]
  144. var secondBuffer = byteBuffer(withBytes: restOfBytes)
  145. reader.append(buffer: &secondBuffer)
  146. self.assertMessagesEqual(expected: [0x00, 0x01], actual: try reader.nextMessage())
  147. }
  148. func testNextMessageThrowsWhenCompressionMechanismIsNotSupported() throws {
  149. // Unknown should never be supported.
  150. reader.compressionMechanism = .unknown
  151. XCTAssertFalse(reader.compressionMechanism.supported)
  152. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage(withCompression: true))
  153. reader.append(buffer: &buffer)
  154. XCTAssertThrowsError(try reader.nextMessage()) { error in
  155. XCTAssertEqual(.unsupportedCompressionMechanism("unknown"), (error as? GRPCError)?.error as? GRPCCommonError)
  156. }
  157. }
  158. func testNextMessageThrowsWhenCompressionFlagIsSetButNotExpected() throws {
  159. // Default compression mechanism is `.none` which requires that no
  160. // compression flag is set as it indicates a lack of message encoding header.
  161. XCTAssertFalse(reader.compressionMechanism.requiresFlag)
  162. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage(withCompression: true))
  163. reader.append(buffer: &buffer)
  164. XCTAssertThrowsError(try reader.nextMessage()) { error in
  165. XCTAssertEqual(.unexpectedCompression, (error as? GRPCError)?.error as? GRPCCommonError)
  166. }
  167. }
  168. func testNextMessageDoesNotThrowWhenCompressionFlagIsExpectedButNotSet() throws {
  169. // `.identity` should always be supported and requires a flag.
  170. reader.compressionMechanism = .identity
  171. XCTAssertTrue(reader.compressionMechanism.supported)
  172. XCTAssertTrue(reader.compressionMechanism.requiresFlag)
  173. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage())
  174. reader.append(buffer: &buffer)
  175. self.assertMessagesEqual(expected: twoByteMessage, actual: try reader.nextMessage())
  176. }
  177. func testAppendReadsAllBytes() throws {
  178. var buffer = byteBuffer(withBytes: lengthPrefixedTwoByteMessage())
  179. reader.append(buffer: &buffer)
  180. XCTAssertEqual(0, buffer.readableBytes)
  181. }
  182. }