ReflectionServiceIntegrationTests.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*
  2. * Copyright 2023, 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 GRPC
  18. import GRPCReflectionService
  19. import NIOPosix
  20. import SwiftProtobuf
  21. import XCTest
  22. @testable import GRPCReflectionService
  23. final class ReflectionServiceIntegrationTests: GRPCTestCase {
  24. private var server: Server?
  25. private var channel: GRPCChannel?
  26. private let protos: [Google_Protobuf_FileDescriptorProto] = makeProtosWithDependencies()
  27. private let independentProto: Google_Protobuf_FileDescriptorProto = generateFileDescriptorProto(
  28. fileName: "independentBar",
  29. suffix: "5"
  30. )
  31. private func setUpServerAndChannel() throws {
  32. let reflectionServiceProvider = try ReflectionService(
  33. fileDescriptors: self.protos + [self.independentProto]
  34. )
  35. let server = try Server.insecure(group: MultiThreadedEventLoopGroup.singleton)
  36. .withServiceProviders([reflectionServiceProvider])
  37. .withLogger(self.serverLogger)
  38. .bind(host: "127.0.0.1", port: 0)
  39. .wait()
  40. self.server = server
  41. let channel = try GRPCChannelPool.with(
  42. target: .hostAndPort("127.0.0.1", server.channel.localAddress!.port!),
  43. transportSecurity: .plaintext,
  44. eventLoopGroup: MultiThreadedEventLoopGroup.singleton
  45. ) {
  46. $0.backgroundActivityLogger = self.clientLogger
  47. }
  48. self.channel = channel
  49. }
  50. override func tearDown() {
  51. if let channel = self.channel {
  52. XCTAssertNoThrow(try channel.close().wait())
  53. }
  54. if let server = self.server {
  55. XCTAssertNoThrow(try server.close().wait())
  56. }
  57. super.tearDown()
  58. }
  59. func testFileByFileName() async throws {
  60. try self.setUpServerAndChannel()
  61. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  62. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  63. try await serviceReflectionInfo.requestStream.send(
  64. .with {
  65. $0.host = "127.0.0.1"
  66. $0.fileByFilename = "bar1.proto"
  67. }
  68. )
  69. serviceReflectionInfo.requestStream.finish()
  70. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  71. guard let message = try await iterator.next() else {
  72. return XCTFail("Could not get a response message.")
  73. }
  74. let receivedFileDescriptorProto =
  75. try Google_Protobuf_FileDescriptorProto(
  76. serializedData: (message.fileDescriptorResponse
  77. .fileDescriptorProto[0])
  78. )
  79. XCTAssertEqual(receivedFileDescriptorProto.name, "bar1.proto")
  80. XCTAssertEqual(receivedFileDescriptorProto.service.count, 1)
  81. guard let service = receivedFileDescriptorProto.service.first else {
  82. return XCTFail("The received file descriptor proto doesn't have any services.")
  83. }
  84. guard let method = service.method.first else {
  85. return XCTFail("The service of the received file descriptor proto doesn't have any methods.")
  86. }
  87. XCTAssertEqual(method.name, "testMethod1")
  88. XCTAssertEqual(message.fileDescriptorResponse.fileDescriptorProto.count, 4)
  89. }
  90. func testListServices() async throws {
  91. try self.setUpServerAndChannel()
  92. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  93. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  94. try await serviceReflectionInfo.requestStream.send(
  95. .with {
  96. $0.host = "127.0.0.1"
  97. $0.listServices = "services"
  98. }
  99. )
  100. serviceReflectionInfo.requestStream.finish()
  101. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  102. guard let message = try await iterator.next() else {
  103. return XCTFail("Could not get a response message.")
  104. }
  105. let receivedServices = message.listServicesResponse.service.map { $0.name }.sorted()
  106. let servicesNames = (self.protos + [self.independentProto]).flatMap { $0.qualifiedServiceNames }
  107. .sorted()
  108. XCTAssertEqual(receivedServices, servicesNames)
  109. }
  110. func testFileBySymbol() async throws {
  111. try self.setUpServerAndChannel()
  112. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  113. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  114. try await serviceReflectionInfo.requestStream.send(
  115. .with {
  116. $0.host = "127.0.0.1"
  117. $0.fileContainingSymbol = "packagebar1.enumType1"
  118. }
  119. )
  120. serviceReflectionInfo.requestStream.finish()
  121. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  122. guard let message = try await iterator.next() else {
  123. return XCTFail("Could not get a response message.")
  124. }
  125. let receivedData: [Google_Protobuf_FileDescriptorProto]
  126. do {
  127. receivedData = try message.fileDescriptorResponse.fileDescriptorProto.map {
  128. try Google_Protobuf_FileDescriptorProto(serializedData: $0)
  129. }
  130. } catch {
  131. return XCTFail("Could not serialize data received as a message.")
  132. }
  133. let fileToFind = self.protos[0]
  134. let dependentProtos = self.protos[1...]
  135. for fileDescriptorProto in receivedData {
  136. if fileDescriptorProto == fileToFind {
  137. XCTAssert(
  138. fileDescriptorProto.enumType.names.contains("enumType1"),
  139. """
  140. The response doesn't contain the serialized file descriptor proto \
  141. containing the \"packagebar1.enumType1\" symbol.
  142. """
  143. )
  144. } else {
  145. XCTAssert(
  146. dependentProtos.contains(fileDescriptorProto),
  147. """
  148. The \(fileDescriptorProto.name) is not a dependency of the \
  149. proto file containing the \"packagebar1.enumType1\" symbol.
  150. """
  151. )
  152. }
  153. }
  154. }
  155. func testFileByExtension() async throws {
  156. try self.setUpServerAndChannel()
  157. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  158. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  159. try await serviceReflectionInfo.requestStream.send(
  160. .with {
  161. $0.host = "127.0.0.1"
  162. $0.fileContainingExtension = .with {
  163. $0.containingType = "packagebar1.inputMessage1"
  164. $0.extensionNumber = 2
  165. }
  166. }
  167. )
  168. serviceReflectionInfo.requestStream.finish()
  169. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  170. guard let message = try await iterator.next() else {
  171. return XCTFail("Could not get a response message.")
  172. }
  173. let receivedData: [Google_Protobuf_FileDescriptorProto]
  174. do {
  175. receivedData = try message.fileDescriptorResponse.fileDescriptorProto.map {
  176. try Google_Protobuf_FileDescriptorProto(serializedData: $0)
  177. }
  178. } catch {
  179. return XCTFail("Could not serialize data received as a message.")
  180. }
  181. let fileToFind = self.protos[0]
  182. let dependentProtos = self.protos[1...]
  183. var receivedProtoContainingExtension = 0
  184. var dependenciesCount = 0
  185. for fileDescriptorProto in receivedData {
  186. if fileDescriptorProto == fileToFind {
  187. receivedProtoContainingExtension += 1
  188. XCTAssert(
  189. fileDescriptorProto.extension.map { $0.name }.contains(
  190. "extension.packagebar1.inputMessage1-2"
  191. ),
  192. """
  193. The response doesn't contain the serialized file descriptor proto \
  194. containing the \"extensioninputMessage1-2\" extension.
  195. """
  196. )
  197. } else {
  198. dependenciesCount += 1
  199. XCTAssert(
  200. dependentProtos.contains(fileDescriptorProto),
  201. """
  202. The \(fileDescriptorProto.name) is not a dependency of the \
  203. proto file containing the \"extensioninputMessage1-2\" extension.
  204. """
  205. )
  206. }
  207. }
  208. XCTAssertEqual(
  209. receivedProtoContainingExtension,
  210. 1,
  211. "The file descriptor proto of the proto containing the extension was not received."
  212. )
  213. XCTAssertEqual(dependenciesCount, 3)
  214. }
  215. func testAllExtensionNumbersOfType() async throws {
  216. try self.setUpServerAndChannel()
  217. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  218. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  219. try await serviceReflectionInfo.requestStream.send(
  220. .with {
  221. $0.host = "127.0.0.1"
  222. $0.allExtensionNumbersOfType = "packagebar2.inputMessage2"
  223. }
  224. )
  225. serviceReflectionInfo.requestStream.finish()
  226. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  227. guard let message = try await iterator.next() else {
  228. return XCTFail("Could not get a response message.")
  229. }
  230. XCTAssertEqual(message.allExtensionNumbersResponse.baseTypeName, "packagebar2.inputMessage2")
  231. XCTAssertEqual(message.allExtensionNumbersResponse.extensionNumber, [1, 2, 3, 4, 5])
  232. }
  233. func testErrorResponseFileByFileNameRequest() async throws {
  234. try self.setUpServerAndChannel()
  235. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  236. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  237. try await serviceReflectionInfo.requestStream.send(
  238. .with {
  239. $0.host = "127.0.0.1"
  240. $0.fileByFilename = "invalidFileName.proto"
  241. }
  242. )
  243. serviceReflectionInfo.requestStream.finish()
  244. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  245. guard let message = try await iterator.next() else {
  246. return XCTFail("Could not get a response message.")
  247. }
  248. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.notFound.rawValue))
  249. XCTAssertEqual(
  250. message.errorResponse.errorMessage,
  251. "The provided file or a dependency of the provided file could not be found."
  252. )
  253. }
  254. func testErrorResponseFileBySymbolRequest() async throws {
  255. try self.setUpServerAndChannel()
  256. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  257. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  258. try await serviceReflectionInfo.requestStream.send(
  259. .with {
  260. $0.host = "127.0.0.1"
  261. $0.fileContainingSymbol = "packagebar1.invalidEnumType1"
  262. }
  263. )
  264. serviceReflectionInfo.requestStream.finish()
  265. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  266. guard let message = try await iterator.next() else {
  267. return XCTFail("Could not get a response message.")
  268. }
  269. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.notFound.rawValue))
  270. XCTAssertEqual(message.errorResponse.errorMessage, "The provided symbol could not be found.")
  271. }
  272. func testErrorResponseFileByExtensionRequest() async throws {
  273. try self.setUpServerAndChannel()
  274. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  275. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  276. try await serviceReflectionInfo.requestStream.send(
  277. .with {
  278. $0.host = "127.0.0.1"
  279. $0.fileContainingExtension = .with {
  280. $0.containingType = "packagebar1.invalidInputMessage1"
  281. $0.extensionNumber = 2
  282. }
  283. }
  284. )
  285. serviceReflectionInfo.requestStream.finish()
  286. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  287. guard let message = try await iterator.next() else {
  288. return XCTFail("Could not get a response message.")
  289. }
  290. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.notFound.rawValue))
  291. XCTAssertEqual(message.errorResponse.errorMessage, "The provided extension could not be found.")
  292. }
  293. func testErrorResponseAllExtensionNumbersOfTypeRequest() async throws {
  294. try self.setUpServerAndChannel()
  295. let client = Grpc_Reflection_V1_ServerReflectionAsyncClient(channel: self.channel!)
  296. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  297. try await serviceReflectionInfo.requestStream.send(
  298. .with {
  299. $0.host = "127.0.0.1"
  300. $0.allExtensionNumbersOfType = "packagebar2.invalidInputMessage2"
  301. }
  302. )
  303. serviceReflectionInfo.requestStream.finish()
  304. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  305. guard let message = try await iterator.next() else {
  306. return XCTFail("Could not get a response message.")
  307. }
  308. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.invalidArgument.rawValue))
  309. XCTAssertEqual(message.errorResponse.errorMessage, "The provided type is invalid.")
  310. }
  311. }