TestService.swift 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright 2024, 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 GRPCCore
  18. @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  19. internal struct TestService: Grpc_Testing_TestService.ServiceProtocol {
  20. internal func unimplementedCall(
  21. request: ServerRequest.Single<Grpc_Testing_TestService.Method.UnimplementedCall.Input>
  22. ) async throws
  23. -> ServerResponse.Single<Grpc_Testing_TestService.Method.UnimplementedCall.Output>
  24. {
  25. throw RPCError(code: .unimplemented, message: "The RPC is not implemented.")
  26. }
  27. /// Server implements `emptyCall` which immediately returns the empty message.
  28. internal func emptyCall(
  29. request: ServerRequest.Single<Grpc_Testing_TestService.Method.EmptyCall.Input>
  30. ) async throws -> ServerResponse.Single<Grpc_Testing_TestService.Method.EmptyCall.Output> {
  31. let message = Grpc_Testing_TestService.Method.EmptyCall.Output()
  32. return ServerResponse.Single(message: message)
  33. }
  34. /// Server implements `unaryCall` which immediately returns a `SimpleResponse` with a payload
  35. /// body of size `SimpleRequest.responseSize` bytes and type as appropriate for the
  36. /// `SimpleRequest.responseType`.
  37. ///
  38. /// If the server does not support the `responseType`, then it should fail the RPC with
  39. /// `INVALID_ARGUMENT`.
  40. internal func unaryCall(
  41. request: ServerRequest.Single<Grpc_Testing_TestService.Method.UnaryCall.Input>
  42. ) async throws -> ServerResponse.Single<Grpc_Testing_TestService.Method.UnaryCall.Output> {
  43. // If the request has a responseStatus set, the server should return that status.
  44. // If the code is an error code, the server will throw an error containing that code
  45. // and the message set in the responseStatus.
  46. // If the code is `ok`, the server will automatically send back an `ok` status.
  47. if request.message.responseStatus.isInitialized {
  48. guard let code = Status.Code(rawValue: Int(request.message.responseStatus.code)) else {
  49. throw RPCError(code: .invalidArgument, message: "The response status code is invalid.")
  50. }
  51. let status = Status(
  52. code: code,
  53. message: request.message.responseStatus.message
  54. )
  55. if let error = RPCError(status: status) {
  56. throw error
  57. }
  58. }
  59. if case .UNRECOGNIZED = request.message.responseType {
  60. throw RPCError(code: .invalidArgument, message: "The response type is not recognized.")
  61. }
  62. let responseMessage = Grpc_Testing_TestService.Method.UnaryCall.Output.with { response in
  63. response.payload = Grpc_Testing_Payload.with { payload in
  64. payload.body = Data(repeating: 0, count: Int(request.message.responseSize))
  65. payload.type = request.message.responseType
  66. }
  67. }
  68. return ServerResponse.Single(message: responseMessage)
  69. }
  70. /// Server gets the default `SimpleRequest` proto as the request. The content of the request is
  71. /// ignored. It returns the `SimpleResponse` proto with the payload set to current timestamp.
  72. /// The timestamp is an integer representing current time with nanosecond resolution. This
  73. /// integer is formated as ASCII decimal in the response. The format is not really important as
  74. /// long as the response payload is different for each request. In addition it adds cache control
  75. /// headers such that the response can be cached by proxies in the response path. Server should
  76. /// be behind a caching proxy for this test to pass. Currently we set the max-age to 60 seconds.
  77. internal func cacheableUnaryCall(
  78. request: ServerRequest.Single<Grpc_Testing_TestService.Method.CacheableUnaryCall.Input>
  79. ) async throws
  80. -> ServerResponse.Single<Grpc_Testing_TestService.Method.CacheableUnaryCall.Output>
  81. {
  82. throw RPCError(code: .unimplemented, message: "The RPC is not implemented.")
  83. }
  84. /// Server implements `streamingOutputCall` by replying, in order, with one
  85. /// `StreamingOutputCallResponse` for each `ResponseParameter`s in `StreamingOutputCallRequest`.
  86. /// Each `StreamingOutputCallResponse` should have a payload body of size `ResponseParameter.size`
  87. /// bytes, as specified by its respective `ResponseParameter`. After sending all responses, it
  88. /// closes with OK.
  89. internal func streamingOutputCall(
  90. request: ServerRequest.Single<
  91. Grpc_Testing_TestService.Method.StreamingOutputCall.Input
  92. >
  93. ) async throws
  94. -> ServerResponse.Stream<Grpc_Testing_TestService.Method.StreamingOutputCall.Output>
  95. {
  96. return ServerResponse.Stream { writer in
  97. for responseParameter in request.message.responseParameters {
  98. let response = Grpc_Testing_StreamingOutputCallResponse.with { response in
  99. response.payload = Grpc_Testing_Payload.with { payload in
  100. payload.body = Data(repeating: 0, count: Int(responseParameter.size))
  101. }
  102. }
  103. try await writer.write(response)
  104. // We convert the `intervalUs` value from microseconds to nanoseconds.
  105. try await Task.sleep(nanoseconds: UInt64(responseParameter.intervalUs) * 1000)
  106. }
  107. return [:]
  108. }
  109. }
  110. /// Server implements `streamingInputCall` which upon half close immediately returns a
  111. /// `StreamingInputCallResponse` where `aggregatedPayloadSize` is the sum of all request payload
  112. /// bodies received.
  113. internal func streamingInputCall(
  114. request: ServerRequest.Stream<Grpc_Testing_TestService.Method.StreamingInputCall.Input>
  115. ) async throws
  116. -> ServerResponse.Single<Grpc_Testing_TestService.Method.StreamingInputCall.Output>
  117. {
  118. var aggregatedPayloadSize = 0
  119. for try await message in request.messages {
  120. aggregatedPayloadSize += message.payload.body.count
  121. }
  122. let responseMessage = Grpc_Testing_TestService.Method.StreamingInputCall.Output.with {
  123. $0.aggregatedPayloadSize = Int32(aggregatedPayloadSize)
  124. }
  125. return ServerResponse.Single(message: responseMessage)
  126. }
  127. /// Server implements `fullDuplexCall` by replying, in order, with one
  128. /// `StreamingOutputCallResponse` for each `ResponseParameter`s in each
  129. /// `StreamingOutputCallRequest`. Each `StreamingOutputCallResponse` should have a payload body
  130. /// of size `ResponseParameter.size` bytes, as specified by its respective `ResponseParameter`s.
  131. /// After receiving half close and sending all responses, it closes with OK.
  132. internal func fullDuplexCall(
  133. request: ServerRequest.Stream<Grpc_Testing_TestService.Method.FullDuplexCall.Input>
  134. ) async throws
  135. -> ServerResponse.Stream<Grpc_Testing_TestService.Method.FullDuplexCall.Output>
  136. {
  137. return ServerResponse.Stream { writer in
  138. for try await message in request.messages {
  139. // If a request message has a responseStatus set, the server should return that status.
  140. // If the code is an error code, the server will throw an error containing that code
  141. // and the message set in the responseStatus.
  142. // If the code is `ok`, the server will automatically send back an `ok` status with the response.
  143. if message.responseStatus.isInitialized {
  144. guard let code = Status.Code(rawValue: Int(message.responseStatus.code)) else {
  145. throw RPCError(code: .invalidArgument, message: "The response status code is invalid.")
  146. }
  147. let status = Status(code: code, message: message.responseStatus.message)
  148. if let error = RPCError(status: status) {
  149. throw error
  150. }
  151. }
  152. for responseParameter in message.responseParameters {
  153. let response = Grpc_Testing_StreamingOutputCallResponse.with { response in
  154. response.payload = Grpc_Testing_Payload.with {
  155. $0.body = Data(count: Int(responseParameter.size))
  156. }
  157. }
  158. try await writer.write(response)
  159. }
  160. }
  161. return [:]
  162. }
  163. }
  164. /// This is not implemented as it is not described in the specification.
  165. ///
  166. /// See: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
  167. internal func halfDuplexCall(
  168. request: ServerRequest.Stream<Grpc_Testing_TestService.Method.HalfDuplexCall.Input>
  169. ) async throws
  170. -> ServerResponse.Stream<Grpc_Testing_TestService.Method.HalfDuplexCall.Output>
  171. {
  172. throw RPCError(code: .unimplemented, message: "The RPC is not implemented.")
  173. }
  174. }