StructuredSwift+ServerTests.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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 Testing
  17. @testable import GRPCCodeGen
  18. extension StructuedSwiftTests {
  19. @Suite("Server")
  20. struct Server {
  21. @Test(
  22. "func <Method>(request:context:) async throws -> ...",
  23. arguments: AccessModifier.allCases,
  24. RPCKind.allCases
  25. )
  26. func serverMethodSignature(access: AccessModifier, kind: RPCKind) {
  27. let decl: FunctionSignatureDescription = .serverMethod(
  28. accessLevel: access,
  29. name: "foo",
  30. input: "Input",
  31. output: "Output",
  32. streamingInput: kind.streamsInput,
  33. streamingOutput: kind.streamsOutput
  34. )
  35. let expected: String
  36. switch kind {
  37. case .unary:
  38. expected = """
  39. \(access) func foo(
  40. request: GRPCCore.ServerRequest<Input>,
  41. context: GRPCCore.ServerContext
  42. ) async throws -> GRPCCore.ServerResponse<Output>
  43. """
  44. case .clientStreaming:
  45. expected = """
  46. \(access) func foo(
  47. request: GRPCCore.StreamingServerRequest<Input>,
  48. context: GRPCCore.ServerContext
  49. ) async throws -> GRPCCore.ServerResponse<Output>
  50. """
  51. case .serverStreaming:
  52. expected = """
  53. \(access) func foo(
  54. request: GRPCCore.ServerRequest<Input>,
  55. context: GRPCCore.ServerContext
  56. ) async throws -> GRPCCore.StreamingServerResponse<Output>
  57. """
  58. case .bidirectionalStreaming:
  59. expected = """
  60. \(access) func foo(
  61. request: GRPCCore.StreamingServerRequest<Input>,
  62. context: GRPCCore.ServerContext
  63. ) async throws -> GRPCCore.StreamingServerResponse<Output>
  64. """
  65. }
  66. #expect(render(.function(signature: decl)) == expected)
  67. }
  68. @Test("protocol StreamingServiceProtocol { ... }", arguments: AccessModifier.allCases)
  69. func serverStreamingServiceProtocol(access: AccessModifier) {
  70. let decl: ProtocolDescription = .streamingService(
  71. accessLevel: access,
  72. name: "FooService",
  73. methods: [
  74. .init(
  75. documentation: "/// Some docs",
  76. name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"),
  77. isInputStreaming: false,
  78. isOutputStreaming: false,
  79. inputType: "FooInput",
  80. outputType: "FooOutput"
  81. )
  82. ]
  83. )
  84. let expected = """
  85. \(access) protocol FooService: GRPCCore.RegistrableRPCService {
  86. /// Some docs
  87. func foo(
  88. request: GRPCCore.StreamingServerRequest<FooInput>,
  89. context: GRPCCore.ServerContext
  90. ) async throws -> GRPCCore.StreamingServerResponse<FooOutput>
  91. }
  92. """
  93. #expect(render(.protocol(decl)) == expected)
  94. }
  95. @Test("protocol ServiceProtocol { ... }", arguments: AccessModifier.allCases)
  96. func serverServiceProtocol(access: AccessModifier) {
  97. let decl: ProtocolDescription = .service(
  98. accessLevel: access,
  99. name: "FooService",
  100. streamingProtocol: "FooService_StreamingServiceProtocol",
  101. methods: [
  102. .init(
  103. documentation: "/// Some docs",
  104. name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"),
  105. isInputStreaming: false,
  106. isOutputStreaming: false,
  107. inputType: "FooInput",
  108. outputType: "FooOutput"
  109. )
  110. ]
  111. )
  112. let expected = """
  113. \(access) protocol FooService: FooService_StreamingServiceProtocol {
  114. /// Some docs
  115. func foo(
  116. request: GRPCCore.ServerRequest<FooInput>,
  117. context: GRPCCore.ServerContext
  118. ) async throws -> GRPCCore.ServerResponse<FooOutput>
  119. }
  120. """
  121. #expect(render(.protocol(decl)) == expected)
  122. }
  123. @Test("{ router, context in try await self.<Method>(...) }")
  124. func routerHandlerInvokingRPC() {
  125. let expression: ClosureInvocationDescription = .routerHandlerInvokingRPC(method: "foo")
  126. let expected = """
  127. { request, context in
  128. try await self.foo(
  129. request: request,
  130. context: context
  131. )
  132. }
  133. """
  134. #expect(render(.closureInvocation(expression)) == expected)
  135. }
  136. @Test("router.registerHandler(...) { ... }")
  137. func registerMethodsWithRouter() {
  138. let expression: FunctionCallDescription = .registerWithRouter(
  139. serviceNamespace: "FooService",
  140. methodNamespace: "Bar",
  141. methodName: "bar",
  142. inputDeserializer: "Deserialize<BarInput>()",
  143. outputSerializer: "Serialize<BarOutput>()"
  144. )
  145. let expected = """
  146. router.registerHandler(
  147. forMethod: FooService.Method.Bar.descriptor,
  148. deserializer: Deserialize<BarInput>(),
  149. serializer: Serialize<BarOutput>(),
  150. handler: { request, context in
  151. try await self.bar(
  152. request: request,
  153. context: context
  154. )
  155. }
  156. )
  157. """
  158. #expect(render(.functionCall(expression)) == expected)
  159. }
  160. @Test("func registerMethods(router:)", arguments: AccessModifier.allCases)
  161. func registerMethods(access: AccessModifier) {
  162. let expression: FunctionDescription = .registerMethods(
  163. accessLevel: access,
  164. serviceNamespace: "FooService",
  165. methods: [
  166. .init(
  167. documentation: "",
  168. name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"),
  169. isInputStreaming: false,
  170. isOutputStreaming: false,
  171. inputType: "BarInput",
  172. outputType: "BarOutput"
  173. )
  174. ]
  175. ) { type in
  176. "Serialize<\(type)>()"
  177. } deserializer: { type in
  178. "Deserialize<\(type)>()"
  179. }
  180. let expected = """
  181. \(access) func registerMethods(with router: inout GRPCCore.RPCRouter) {
  182. router.registerHandler(
  183. forMethod: FooService.Method.Bar.descriptor,
  184. deserializer: Deserialize<BarInput>(),
  185. serializer: Serialize<BarOutput>(),
  186. handler: { request, context in
  187. try await self.bar(
  188. request: request,
  189. context: context
  190. )
  191. }
  192. )
  193. }
  194. """
  195. #expect(render(.function(expression)) == expected)
  196. }
  197. @Test(
  198. "func <Method>(request:context:) async throw { ... (convert to/from single) ... }",
  199. arguments: AccessModifier.allCases,
  200. RPCKind.allCases
  201. )
  202. func serverStreamingMethodsCallingMethod(access: AccessModifier, kind: RPCKind) {
  203. let expression: FunctionDescription = .serverStreamingMethodsCallingMethod(
  204. accessLevel: access,
  205. name: "foo",
  206. input: "Input",
  207. output: "Output",
  208. streamingInput: kind.streamsInput,
  209. streamingOutput: kind.streamsOutput
  210. )
  211. let expected: String
  212. switch kind {
  213. case .unary:
  214. expected = """
  215. \(access) func foo(
  216. request: GRPCCore.StreamingServerRequest<Input>,
  217. context: GRPCCore.ServerContext
  218. ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  219. let response = try await self.foo(
  220. request: GRPCCore.ServerRequest(stream: request),
  221. context: context
  222. )
  223. return GRPCCore.StreamingServerResponse(single: response)
  224. }
  225. """
  226. case .serverStreaming:
  227. expected = """
  228. \(access) func foo(
  229. request: GRPCCore.StreamingServerRequest<Input>,
  230. context: GRPCCore.ServerContext
  231. ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  232. let response = try await self.foo(
  233. request: GRPCCore.ServerRequest(stream: request),
  234. context: context
  235. )
  236. return response
  237. }
  238. """
  239. case .clientStreaming:
  240. expected = """
  241. \(access) func foo(
  242. request: GRPCCore.StreamingServerRequest<Input>,
  243. context: GRPCCore.ServerContext
  244. ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  245. let response = try await self.foo(
  246. request: request,
  247. context: context
  248. )
  249. return GRPCCore.StreamingServerResponse(single: response)
  250. }
  251. """
  252. case .bidirectionalStreaming:
  253. expected = """
  254. \(access) func foo(
  255. request: GRPCCore.StreamingServerRequest<Input>,
  256. context: GRPCCore.ServerContext
  257. ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  258. let response = try await self.foo(
  259. request: request,
  260. context: context
  261. )
  262. return response
  263. }
  264. """
  265. }
  266. #expect(render(.function(expression)) == expected)
  267. }
  268. @Test("extension FooService_ServiceProtocol { ... }", arguments: AccessModifier.allCases)
  269. func streamingServiceProtocolDefaultImplementation(access: AccessModifier) {
  270. let decl: ExtensionDescription = .streamingServiceProtocolDefaultImplementation(
  271. accessModifier: access,
  272. on: "Foo_ServiceProtocol",
  273. methods: [
  274. .init(
  275. documentation: "",
  276. name: .init(base: "Foo", generatedUpperCase: "Foo", generatedLowerCase: "foo"),
  277. isInputStreaming: false,
  278. isOutputStreaming: false,
  279. inputType: "FooInput",
  280. outputType: "FooOutput"
  281. ),
  282. // Will be ignored as a bidirectional streaming method.
  283. .init(
  284. documentation: "",
  285. name: .init(base: "Bar", generatedUpperCase: "Bar", generatedLowerCase: "bar"),
  286. isInputStreaming: true,
  287. isOutputStreaming: true,
  288. inputType: "BarInput",
  289. outputType: "BarOutput"
  290. ),
  291. ]
  292. )
  293. let expected = """
  294. extension Foo_ServiceProtocol {
  295. \(access) func foo(
  296. request: GRPCCore.StreamingServerRequest<FooInput>,
  297. context: GRPCCore.ServerContext
  298. ) async throws -> GRPCCore.StreamingServerResponse<FooOutput> {
  299. let response = try await self.foo(
  300. request: GRPCCore.ServerRequest(stream: request),
  301. context: context
  302. )
  303. return GRPCCore.StreamingServerResponse(single: response)
  304. }
  305. }
  306. """
  307. #expect(render(.extension(decl)) == expected)
  308. }
  309. }
  310. }