GRPCCustomPayloadTests.swift 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * Copyright 2020, 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 GRPC
  17. import NIO
  18. import XCTest
  19. // TODO: Fixup these tests when we support custom server payloads again.
  20. //// These tests demonstrate how to use gRPC to create a service provider using your own payload type,
  21. //// or alternatively, how to avoid deserialization and just extract the raw bytes from a payload.
  22. //class GRPCCustomPayloadTests: GRPCTestCase {
  23. // var group: EventLoopGroup!
  24. // var server: Server!
  25. // var client: AnyServiceClient!
  26. //
  27. // override func setUp() {
  28. // super.setUp()
  29. // self.group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
  30. //
  31. // self.server = try! Server.insecure(group: self.group)
  32. // .withServiceProviders([CustomPayloadProvider()])
  33. // .bind(host: "localhost", port: 0)
  34. // .wait()
  35. //
  36. // let channel = ClientConnection.insecure(group: self.group)
  37. // .connect(host: "localhost", port: server.channel.localAddress!.port!)
  38. //
  39. // self.client = AnyServiceClient(channel: channel)
  40. // }
  41. //
  42. // override func tearDown() {
  43. // XCTAssertNoThrow(try self.server.close().wait())
  44. // XCTAssertNoThrow(try self.client.channel.close().wait())
  45. // XCTAssertNoThrow(try self.group.syncShutdownGracefully())
  46. // }
  47. //
  48. // func testCustomPayload() throws {
  49. // // This test demonstrates how to call a manually created bidirectional RPC with custom payloads.
  50. // let statusExpectation = self.expectation(description: "status received")
  51. //
  52. // var responses: [CustomPayload] = []
  53. //
  54. // // Make a bidirectional stream using `CustomPayload` as the request and response type.
  55. // // The service defined below is called "CustomPayload", and the method we call on it
  56. // // is "AddOneAndReverseMessage"
  57. // let rpc: BidirectionalStreamingCall<CustomPayload, CustomPayload> = self.client.makeBidirectionalStreamingCall(
  58. // path: "/CustomPayload/AddOneAndReverseMessage",
  59. // handler: { responses.append($0) }
  60. // )
  61. //
  62. // // Make and send some requests:
  63. // let requests: [CustomPayload] = [
  64. // CustomPayload(message: "one", number: .random(in: Int64.min..<Int64.max)),
  65. // CustomPayload(message: "two", number: .random(in: Int64.min..<Int64.max)),
  66. // CustomPayload(message: "three", number: .random(in: Int64.min..<Int64.max))
  67. // ]
  68. // rpc.sendMessages(requests, promise: nil)
  69. // rpc.sendEnd(promise: nil)
  70. //
  71. // // Wait for the RPC to finish before comparing responses.
  72. // rpc.status.map { $0.code }.assertEqual(.ok, fulfill: statusExpectation)
  73. // self.wait(for: [statusExpectation], timeout: 1.0)
  74. //
  75. // // Are the responses as expected?
  76. // let expected = requests.map { request in
  77. // CustomPayload(message: String(request.message.reversed()), number: request.number + 1)
  78. // }
  79. // XCTAssertEqual(responses, expected)
  80. // }
  81. //
  82. // func testNoDeserializationOnTheClient() throws {
  83. // // This test demonstrates how to skip the deserialization step on the client. It isn't necessary
  84. // // to use a custom service provider to do this, although we do here.
  85. // let statusExpectation = self.expectation(description: "status received")
  86. //
  87. // var responses: [IdentityPayload] = []
  88. // // Here we use `IdentityPayload` for our response type: we define it below such that it does
  89. // // not deserialize the bytes provided to it by gRPC.
  90. // let rpc: BidirectionalStreamingCall<CustomPayload, IdentityPayload> = self.client.makeBidirectionalStreamingCall(
  91. // path: "/CustomPayload/AddOneAndReverseMessage",
  92. // handler: { responses.append($0) }
  93. // )
  94. //
  95. // let request = CustomPayload(message: "message", number: 42)
  96. // rpc.sendMessage(request, promise: nil)
  97. // rpc.sendEnd(promise: nil)
  98. //
  99. // // Wait for the RPC to finish before comparing responses.
  100. // rpc.status.map { $0.code }.assertEqual(.ok, fulfill: statusExpectation)
  101. // self.wait(for: [statusExpectation], timeout: 1.0)
  102. //
  103. // guard var response = responses.first?.buffer else {
  104. // XCTFail("RPC completed without a response")
  105. // return
  106. // }
  107. //
  108. // // We just took the raw bytes from the payload: we can still decode it because we know the
  109. // // server returned a serialized `CustomPayload`.
  110. // let actual = try CustomPayload(serializedByteBuffer: &response)
  111. // XCTAssertEqual(actual.message, "egassem")
  112. // XCTAssertEqual(actual.number, 43)
  113. // }
  114. //}
  115. //
  116. //// MARK: Custom Payload Service
  117. //
  118. //fileprivate class CustomPayloadProvider: CallHandlerProvider {
  119. // var serviceName: String = "CustomPayload"
  120. //
  121. // // Bidirectional RPC which returns a new `CustomPayload` for each `CustomPayload` received.
  122. // // The returned payloads have their `message` reversed and their `number` incremented by one.
  123. // fileprivate func addOneAndReverseMessage(
  124. // context: StreamingResponseCallContext<CustomPayload>
  125. // ) -> EventLoopFuture<(StreamEvent<CustomPayload>) -> Void> {
  126. // return context.eventLoop.makeSucceededFuture({ event in
  127. // switch event {
  128. // case .message(let payload):
  129. // let response = CustomPayload(
  130. // message: String(payload.message.reversed()),
  131. // number: payload.number + 1
  132. // )
  133. // _ = context.sendResponse(response)
  134. //
  135. // case .end:
  136. // context.statusPromise.succeed(.ok)
  137. // }
  138. // })
  139. // }
  140. //
  141. // func handleMethod(_ methodName: String, callHandlerContext: CallHandlerContext) -> GRPCCallHandler? {
  142. // switch methodName {
  143. // case "AddOneAndReverseMessage":
  144. // return BidirectionalStreamingCallHandler<CustomPayload, CustomPayload>(callHandlerContext: callHandlerContext) { context in
  145. // return self.addOneAndReverseMessage(context: context)
  146. // }
  147. //
  148. // default:
  149. // return nil
  150. // }
  151. // }
  152. //}
  153. //
  154. //fileprivate struct IdentityPayload: GRPCPayload {
  155. // var buffer: ByteBuffer
  156. //
  157. // init(serializedByteBuffer: inout ByteBuffer) throws {
  158. // self.buffer = serializedByteBuffer
  159. // }
  160. //
  161. // func serialize(into buffer: inout ByteBuffer) throws {
  162. // // This will never be called, however, it could be implemented as a direct copy of the bytes
  163. // // we hold, e.g.:
  164. // //
  165. // // var copy = self.buffer
  166. // // buffer.writeBuffer(&copy)
  167. // fatalError("Unimplemented")
  168. // }
  169. //}
  170. //
  171. ///// A toy custom payload which holds a `String` and an `Int64`.
  172. /////
  173. ///// The payload is serialized as:
  174. ///// - the `UInt32` encoded length of the message,
  175. ///// - the UTF-8 encoded bytes of the message, and
  176. ///// - the `Int64` bytes of the number.
  177. //fileprivate struct CustomPayload: GRPCPayload, Equatable {
  178. // var message: String
  179. // var number: Int64
  180. //
  181. // init(message: String, number: Int64) {
  182. // self.message = message
  183. // self.number = number
  184. // }
  185. //
  186. // init(serializedByteBuffer: inout ByteBuffer) throws {
  187. // guard let messageLength = serializedByteBuffer.readInteger(as: UInt32.self),
  188. // let message = serializedByteBuffer.readString(length: Int(messageLength)),
  189. // let number = serializedByteBuffer.readInteger(as: Int64.self) else {
  190. // throw GRPCError.DeserializationFailure()
  191. // }
  192. //
  193. // self.message = message
  194. // self.number = number
  195. // }
  196. //
  197. // func serialize(into buffer: inout ByteBuffer) throws {
  198. // buffer.writeInteger(UInt32(self.message.count))
  199. // buffer.writeString(self.message)
  200. // buffer.writeInteger(self.number)
  201. // }
  202. //}