LengthPrefixedMessageReaderTests.swift 9.0 KB

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