LengthPrefixedMessageReaderTests.swift 8.8 KB

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