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