ReflectionServiceIntegrationTests.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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 = Reflection_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 = Reflection_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]).serviceNames.sorted()
  107. XCTAssertEqual(receivedServices, servicesNames)
  108. }
  109. func testFileBySymbol() async throws {
  110. try self.setUpServerAndChannel()
  111. let client = Reflection_ServerReflectionAsyncClient(channel: self.channel!)
  112. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  113. try await serviceReflectionInfo.requestStream.send(
  114. .with {
  115. $0.host = "127.0.0.1"
  116. $0.fileContainingSymbol = "packagebar1.enumType1"
  117. }
  118. )
  119. serviceReflectionInfo.requestStream.finish()
  120. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  121. guard let message = try await iterator.next() else {
  122. return XCTFail("Could not get a response message.")
  123. }
  124. let receivedData: [Google_Protobuf_FileDescriptorProto]
  125. do {
  126. receivedData = try message.fileDescriptorResponse.fileDescriptorProto.map {
  127. try Google_Protobuf_FileDescriptorProto(serializedData: $0)
  128. }
  129. } catch {
  130. return XCTFail("Could not serialize data received as a message.")
  131. }
  132. let fileToFind = self.protos[0]
  133. let dependentProtos = self.protos[1...]
  134. for fileDescriptorProto in receivedData {
  135. if fileDescriptorProto == fileToFind {
  136. XCTAssert(
  137. fileDescriptorProto.enumType.names.contains("enumType1"),
  138. """
  139. The response doesn't contain the serialized file descriptor proto \
  140. containing the \"packagebar1.enumType1\" symbol.
  141. """
  142. )
  143. } else {
  144. XCTAssert(
  145. dependentProtos.contains(fileDescriptorProto),
  146. """
  147. The \(fileDescriptorProto.name) is not a dependency of the \
  148. proto file containing the \"packagebar1.enumType1\" symbol.
  149. """
  150. )
  151. }
  152. }
  153. }
  154. func testFileByExtension() async throws {
  155. try self.setUpServerAndChannel()
  156. let client = Reflection_ServerReflectionAsyncClient(channel: self.channel!)
  157. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  158. try await serviceReflectionInfo.requestStream.send(
  159. .with {
  160. $0.host = "127.0.0.1"
  161. $0.fileContainingExtension = .with {
  162. $0.containingType = "packagebar1.inputMessage1"
  163. $0.extensionNumber = 2
  164. }
  165. }
  166. )
  167. serviceReflectionInfo.requestStream.finish()
  168. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  169. guard let message = try await iterator.next() else {
  170. return XCTFail("Could not get a response message.")
  171. }
  172. let receivedData: [Google_Protobuf_FileDescriptorProto]
  173. do {
  174. receivedData = try message.fileDescriptorResponse.fileDescriptorProto.map {
  175. try Google_Protobuf_FileDescriptorProto(serializedData: $0)
  176. }
  177. } catch {
  178. return XCTFail("Could not serialize data received as a message.")
  179. }
  180. let fileToFind = self.protos[0]
  181. let dependentProtos = self.protos[1...]
  182. var receivedProtoContainingExtension = 0
  183. var dependenciesCount = 0
  184. for fileDescriptorProto in receivedData {
  185. if fileDescriptorProto == fileToFind {
  186. receivedProtoContainingExtension += 1
  187. XCTAssert(
  188. fileDescriptorProto.extension.map { $0.name }.contains(
  189. "extension.packagebar1.inputMessage1-2"
  190. ),
  191. """
  192. The response doesn't contain the serialized file descriptor proto \
  193. containing the \"extensioninputMessage1-2\" extension.
  194. """
  195. )
  196. } else {
  197. dependenciesCount += 1
  198. XCTAssert(
  199. dependentProtos.contains(fileDescriptorProto),
  200. """
  201. The \(fileDescriptorProto.name) is not a dependency of the \
  202. proto file containing the \"extensioninputMessage1-2\" extension.
  203. """
  204. )
  205. }
  206. }
  207. XCTAssertEqual(
  208. receivedProtoContainingExtension,
  209. 1,
  210. "The file descriptor proto of the proto containing the extension was not received."
  211. )
  212. XCTAssertEqual(dependenciesCount, 3)
  213. }
  214. func testAllExtensionNumbersOfType() async throws {
  215. try self.setUpServerAndChannel()
  216. let client = Reflection_ServerReflectionAsyncClient(channel: self.channel!)
  217. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  218. try await serviceReflectionInfo.requestStream.send(
  219. .with {
  220. $0.host = "127.0.0.1"
  221. $0.allExtensionNumbersOfType = "packagebar2.inputMessage2"
  222. }
  223. )
  224. serviceReflectionInfo.requestStream.finish()
  225. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  226. guard let message = try await iterator.next() else {
  227. return XCTFail("Could not get a response message.")
  228. }
  229. XCTAssertEqual(message.allExtensionNumbersResponse.baseTypeName, "packagebar2.inputMessage2")
  230. XCTAssertEqual(message.allExtensionNumbersResponse.extensionNumber, [1, 2, 3, 4, 5])
  231. }
  232. func testErrorResponseFileByFileNameRequest() async throws {
  233. try self.setUpServerAndChannel()
  234. let client = Reflection_ServerReflectionAsyncClient(channel: self.channel!)
  235. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  236. try await serviceReflectionInfo.requestStream.send(
  237. .with {
  238. $0.host = "127.0.0.1"
  239. $0.fileByFilename = "invalidFileName.proto"
  240. }
  241. )
  242. serviceReflectionInfo.requestStream.finish()
  243. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  244. guard let message = try await iterator.next() else {
  245. return XCTFail("Could not get a response message.")
  246. }
  247. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.notFound.rawValue))
  248. XCTAssertEqual(
  249. message.errorResponse.errorMessage,
  250. "The provided file or a dependency of the provided file could not be found."
  251. )
  252. }
  253. func testErrorResponseFileBySymbolRequest() async throws {
  254. try self.setUpServerAndChannel()
  255. let client = Reflection_ServerReflectionAsyncClient(channel: self.channel!)
  256. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  257. try await serviceReflectionInfo.requestStream.send(
  258. .with {
  259. $0.host = "127.0.0.1"
  260. $0.fileContainingSymbol = "packagebar1.invalidEnumType1"
  261. }
  262. )
  263. serviceReflectionInfo.requestStream.finish()
  264. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  265. guard let message = try await iterator.next() else {
  266. return XCTFail("Could not get a response message.")
  267. }
  268. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.notFound.rawValue))
  269. XCTAssertEqual(message.errorResponse.errorMessage, "The provided symbol could not be found.")
  270. }
  271. func testErrorResponseFileByExtensionRequest() async throws {
  272. try self.setUpServerAndChannel()
  273. let client = Reflection_ServerReflectionAsyncClient(channel: self.channel!)
  274. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  275. try await serviceReflectionInfo.requestStream.send(
  276. .with {
  277. $0.host = "127.0.0.1"
  278. $0.fileContainingExtension = .with {
  279. $0.containingType = "packagebar1.invalidInputMessage1"
  280. $0.extensionNumber = 2
  281. }
  282. }
  283. )
  284. serviceReflectionInfo.requestStream.finish()
  285. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  286. guard let message = try await iterator.next() else {
  287. return XCTFail("Could not get a response message.")
  288. }
  289. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.notFound.rawValue))
  290. XCTAssertEqual(message.errorResponse.errorMessage, "The provided extension could not be found.")
  291. }
  292. func testErrorResponseAllExtensionNumbersOfTypeRequest() async throws {
  293. try self.setUpServerAndChannel()
  294. let client = Reflection_ServerReflectionAsyncClient(channel: self.channel!)
  295. let serviceReflectionInfo = client.makeServerReflectionInfoCall()
  296. try await serviceReflectionInfo.requestStream.send(
  297. .with {
  298. $0.host = "127.0.0.1"
  299. $0.allExtensionNumbersOfType = "packagebar2.invalidInputMessage2"
  300. }
  301. )
  302. serviceReflectionInfo.requestStream.finish()
  303. var iterator = serviceReflectionInfo.responseStream.makeAsyncIterator()
  304. guard let message = try await iterator.next() else {
  305. return XCTFail("Could not get a response message.")
  306. }
  307. XCTAssertEqual(message.errorResponse.errorCode, Int32(GRPCStatus.Code.invalidArgument.rawValue))
  308. XCTAssertEqual(message.errorResponse.errorMessage, "The provided type is invalid.")
  309. }
  310. }