HTTP2TransportNIOPosixTests.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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. private import GRPCCore
  17. private import GRPCHTTP2Core
  18. private import GRPCHTTP2TransportNIOPosix
  19. internal import XCTest
  20. #if canImport(NIOSSL)
  21. private import NIOSSL
  22. #endif
  23. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  24. final class HTTP2TransportNIOPosixTests: XCTestCase {
  25. func testGetListeningAddress_IPv4() async throws {
  26. let transport = GRPCHTTP2Core.HTTP2ServerTransport.Posix(
  27. address: .ipv4(host: "0.0.0.0", port: 0),
  28. config: .defaults(transportSecurity: .plaintext)
  29. )
  30. try await withThrowingDiscardingTaskGroup { group in
  31. group.addTask {
  32. try await transport.listen { _ in }
  33. }
  34. group.addTask {
  35. let address = try await transport.listeningAddress
  36. let ipv4Address = try XCTUnwrap(address.ipv4)
  37. XCTAssertNotEqual(ipv4Address.port, 0)
  38. transport.beginGracefulShutdown()
  39. }
  40. }
  41. }
  42. func testGetListeningAddress_IPv6() async throws {
  43. let transport = GRPCHTTP2Core.HTTP2ServerTransport.Posix(
  44. address: .ipv6(host: "::1", port: 0),
  45. config: .defaults(transportSecurity: .plaintext)
  46. )
  47. try await withThrowingDiscardingTaskGroup { group in
  48. group.addTask {
  49. try await transport.listen { _ in }
  50. }
  51. group.addTask {
  52. let address = try await transport.listeningAddress
  53. let ipv6Address = try XCTUnwrap(address.ipv6)
  54. XCTAssertNotEqual(ipv6Address.port, 0)
  55. transport.beginGracefulShutdown()
  56. }
  57. }
  58. }
  59. func testGetListeningAddress_UnixDomainSocket() async throws {
  60. let transport = GRPCHTTP2Core.HTTP2ServerTransport.Posix(
  61. address: .unixDomainSocket(path: "/tmp/posix-uds-test"),
  62. config: .defaults(transportSecurity: .plaintext)
  63. )
  64. try await withThrowingDiscardingTaskGroup { group in
  65. group.addTask {
  66. try await transport.listen { _ in }
  67. }
  68. group.addTask {
  69. let address = try await transport.listeningAddress
  70. XCTAssertEqual(
  71. address.unixDomainSocket,
  72. GRPCHTTP2Core.SocketAddress.UnixDomainSocket(path: "/tmp/posix-uds-test")
  73. )
  74. transport.beginGracefulShutdown()
  75. }
  76. }
  77. }
  78. func testGetListeningAddress_Vsock() async throws {
  79. try XCTSkipUnless(self.vsockAvailable(), "Vsock unavailable")
  80. let transport = GRPCHTTP2Core.HTTP2ServerTransport.Posix(
  81. address: .vsock(contextID: .any, port: .any),
  82. config: .defaults(transportSecurity: .plaintext)
  83. )
  84. try await withThrowingDiscardingTaskGroup { group in
  85. group.addTask {
  86. try await transport.listen { _ in }
  87. }
  88. group.addTask {
  89. let address = try await transport.listeningAddress
  90. XCTAssertNotNil(address.virtualSocket)
  91. transport.beginGracefulShutdown()
  92. }
  93. }
  94. }
  95. func testGetListeningAddress_InvalidAddress() async {
  96. let transport = GRPCHTTP2Core.HTTP2ServerTransport.Posix(
  97. address: .unixDomainSocket(path: "/this/should/be/an/invalid/path"),
  98. config: .defaults(transportSecurity: .plaintext)
  99. )
  100. try? await withThrowingDiscardingTaskGroup { group in
  101. group.addTask {
  102. try await transport.listen { _ in }
  103. }
  104. group.addTask {
  105. do {
  106. _ = try await transport.listeningAddress
  107. XCTFail("Should have thrown a RuntimeError")
  108. } catch let error as RuntimeError {
  109. XCTAssertEqual(error.code, .serverIsStopped)
  110. XCTAssertEqual(
  111. error.message,
  112. """
  113. There is no listening address bound for this server: there may have \
  114. been an error which caused the transport to close, or it may have shut down.
  115. """
  116. )
  117. }
  118. }
  119. }
  120. }
  121. func testGetListeningAddress_StoppedListening() async throws {
  122. let transport = GRPCHTTP2Core.HTTP2ServerTransport.Posix(
  123. address: .ipv4(host: "0.0.0.0", port: 0),
  124. config: .defaults(transportSecurity: .plaintext)
  125. )
  126. try? await withThrowingDiscardingTaskGroup { group in
  127. group.addTask {
  128. try await transport.listen { _ in }
  129. do {
  130. _ = try await transport.listeningAddress
  131. XCTFail("Should have thrown a RuntimeError")
  132. } catch let error as RuntimeError {
  133. XCTAssertEqual(error.code, .serverIsStopped)
  134. XCTAssertEqual(
  135. error.message,
  136. """
  137. There is no listening address bound for this server: there may have \
  138. been an error which caused the transport to close, or it may have shut down.
  139. """
  140. )
  141. }
  142. }
  143. group.addTask {
  144. let address = try await transport.listeningAddress
  145. XCTAssertNotNil(address.ipv4)
  146. transport.beginGracefulShutdown()
  147. }
  148. }
  149. }
  150. #if canImport(NIOSSL)
  151. static let samplePemCert = """
  152. -----BEGIN CERTIFICATE-----
  153. MIIGGzCCBAOgAwIBAgIJAJ/X0Fo0ynmEMA0GCSqGSIb3DQEBCwUAMIGjMQswCQYD
  154. VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5z
  155. b2t5bzEuMCwGA1UECgwlU2FuIEZyYW5zb2t5byBJbnN0aXR1dGUgb2YgVGVjaG5v
  156. bG9neTEVMBMGA1UECwwMUm9ib3RpY3MgTGFiMSAwHgYDVQQDDBdyb2JvdHMuc2Fu
  157. ZnJhbnNva3lvLmVkdTAeFw0xNzEwMTYyMTAxMDJaFw00NzEwMDkyMTAxMDJaMIGj
  158. MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu
  159. IEZyYW5zb2t5bzEuMCwGA1UECgwlU2FuIEZyYW5zb2t5byBJbnN0aXR1dGUgb2Yg
  160. VGVjaG5vbG9neTEVMBMGA1UECwwMUm9ib3RpY3MgTGFiMSAwHgYDVQQDDBdyb2Jv
  161. dHMuc2FuZnJhbnNva3lvLmVkdTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
  162. ggIBAO9rzJOOE8cmsIqAJMCrHDxkBAMgZhMsJ863MnWtVz5JIJK6CKI/Nu26tEzo
  163. kHy3EI9565RwikvauheMsWaTFA4PD/P+s1DtxRCGIcK5x+SoTN7Drn5ZueoJNZRf
  164. TYuN+gwyhprzrZrYjXpvEVPYuSIeUqK5XGrTyFA2uGj9wY3f9IF4rd7JT0ewRb1U
  165. 8OcR7xQbXKGjkY4iJE1TyfmIsBZboKaG/aYa9KbnWyTkDssaELWUIKrjwwuPgVgS
  166. vlAYmo12MlsGEzkO9z78jvFmhUOsaEldM8Ua2AhOKW0oSYgauVuro/Ap/o5zn8PD
  167. IDapl9g+5vjN2LucqX2a9utoFvxSKXT4NvfpL9fJvzdBNMM4xpqtHIkV0fkiMbWk
  168. EW2FFlOXKnIJV8wT4a9iduuIDMg8O7oc+gt9pG9MHTWthXm4S29DARTqfZ48bW77
  169. z8RrEURV03o05b/twuAJSRyyOCUi61yMo3YNytebjY2W3Pxqpq+YmT5qhqBZDLlT
  170. LMptuFdISv6SQgg7JoFHGMWRXUavMj/sn5qZD4pQyZToHJ2Vtg5W/MI1pKwc3oKD
  171. 6M3/7Gf35r92V/ox6XT7+fnEsAH8AtQiZJkEbvzJ5lpUihSIaV3a/S+jnk7Lw8Tp
  172. vjtpfjOg+wBblc38Oa9tk2WdXwYDbnvbeL26WmyHwQTUBi1jAgMBAAGjUDBOMB0G
  173. A1UdDgQWBBToPRmTBQEF5F5LcPiUI5qBNPBU+DAfBgNVHSMEGDAWgBToPRmTBQEF
  174. 5F5LcPiUI5qBNPBU+DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCY
  175. gxM5lufF2lTB9sH0s1E1VTERv37qoapNP+aw06oZkAD67QOTXFzbsM3JU1diY6rV
  176. Y0g9CLzRO7gZY+kmi1WWnsYiMMSIGjIfsB8S+ot43LME+AJXPVeDZQnoZ6KQ/9r+
  177. 71Umi4AKLoZ9dInyUIM3EHg9pg5B0eEINrh4J+OPGtlC3NMiWxdmIkZwzfXa+64Z
  178. 8k5aX5piMTI+9BQSMWw5l7tFT/PISuI8b/Ln4IUBXKA0xkONXVnjPOmS0h7MBoc2
  179. EipChDKnK+Mtm9GQewOCKdS2nsrCndGkIBnUix4ConUYIoywVzWGMD+9OzKNg76d
  180. O6A7MxdjEdKhf1JDvklxInntDUDTlSFL4iEFELwyRseoTzj8vJE+cL6h6ClasYQ6
  181. p0EeL3UpICYerfIvPhohftCivCH3k7Q1BSf0fq73cQ55nrFAHrqqYjD7HBeBS9hn
  182. 3L6bz9Eo6U9cuxX42k3l1N44BmgcDPin0+CRTirEmahUMb3gmvoSZqQ3Cz86GkIg
  183. 7cNJosc9NyevQlU9SX3ptEbv33tZtlB5GwgZ2hiGBTY0C3HaVFjLpQiSS5ygZLgI
  184. /+AKtah7sTHIAtpUH1ZZEgKPl1Hg6J4x/dBkuk3wxPommNHaYaHREXF+fHMhBrSi
  185. yH8agBmmECpa21SVnr7vrL+KSqfuF+GxwjSNsSR4SA==
  186. -----END CERTIFICATE-----
  187. """
  188. static let samplePemKey = """
  189. -----BEGIN RSA PRIVATE KEY-----
  190. MIIJKAIBAAKCAgEA72vMk44TxyawioAkwKscPGQEAyBmEywnzrcyda1XPkkgkroI
  191. oj827bq0TOiQfLcQj3nrlHCKS9q6F4yxZpMUDg8P8/6zUO3FEIYhwrnH5KhM3sOu
  192. flm56gk1lF9Ni436DDKGmvOtmtiNem8RU9i5Ih5SorlcatPIUDa4aP3Bjd/0gXit
  193. 3slPR7BFvVTw5xHvFBtcoaORjiIkTVPJ+YiwFlugpob9phr0pudbJOQOyxoQtZQg
  194. quPDC4+BWBK+UBiajXYyWwYTOQ73PvyO8WaFQ6xoSV0zxRrYCE4pbShJiBq5W6uj
  195. 8Cn+jnOfw8MgNqmX2D7m+M3Yu5ypfZr262gW/FIpdPg29+kv18m/N0E0wzjGmq0c
  196. iRXR+SIxtaQRbYUWU5cqcglXzBPhr2J264gMyDw7uhz6C32kb0wdNa2FebhLb0MB
  197. FOp9njxtbvvPxGsRRFXTejTlv+3C4AlJHLI4JSLrXIyjdg3K15uNjZbc/Gqmr5iZ
  198. PmqGoFkMuVMsym24V0hK/pJCCDsmgUcYxZFdRq8yP+yfmpkPilDJlOgcnZW2Dlb8
  199. wjWkrBzegoPozf/sZ/fmv3ZX+jHpdPv5+cSwAfwC1CJkmQRu/MnmWlSKFIhpXdr9
  200. L6OeTsvDxOm+O2l+M6D7AFuVzfw5r22TZZ1fBgNue9t4vbpabIfBBNQGLWMCAwEA
  201. AQKCAgArWV9PEBhwpIaubQk6gUC5hnpbfpA8xG/os67FM79qHZ9yMZDCn6N4Y6el
  202. jS4sBpFPCQoodD/2AAJVpTmxksu8x+lhiio5avOVTFPsh+qzce2JH/EGG4TX5Rb4
  203. aFEIBYrSjotknt49/RuQoW+HuOO8U7UulVUwWmwYae/1wow6/eOtVYZVoilil33p
  204. C+oaTFr3TwT0l0MRcwkTnyogrikDw09RF3vxiUvmtFkCUvCCwZNo7QsFJfv4qeEH
  205. a01d/zZsiowPgwgT+qu1kdDn0GIsoJi5P9DRzUx0JILHqtW1ePE6sdca8t+ON00k
  206. Cr5YZ1iA5NK5Fbw6K+FcRqSSduRCLYXAnI5GH1zWMki5TUdl+psvCnpdZK5wysGe
  207. tYfIbrVHXIlg7J3R4BrbMF4q3HwOppTHMrqsGyRVCCSjDwXjreugInV0CRzlapDs
  208. JNEVyrbt6Ild6ie7c1AJqTpibJ9lVYRVpG35Dni9RJy5Uk5m89uWnF9PCjCRCHOf
  209. 4UATY+qie6wlu0E8y43LcTvDi8ROXQQoCnys2ES8DmS+GKJ1uzG1l8jx3jF9BMAJ
  210. kyzZfSmPwuS2NUk8sftYQ8neJSgk4DOV4h7x5ghaBWYzseomy3uo3gD4IyuiO56K
  211. y7IYZnXSt2s8LfzhVcB5I4IZbSIvP/MAEkGMC09SV+dEcEJSQQKCAQEA/uJex1ef
  212. g+q4gb/C4/biPr+ZRFheVuHu49ES0DXxoxmTbosGRDPRFBLwtPxCLuzHXa1Du2Vc
  213. c0E12zLy8wNczv5bGAxynPo57twJCyeptFNFJkb+0uxRrCi+CZ56Qertg2jr460Q
  214. cg+TMYxauDleLzR7uwL6VnOhTSq3CVTA2TrQ+kjIHgVqmmpwgk5bPBRDj2EuqdyD
  215. dEQmt4z/0fFFBmW6iBcXS9y8Q1rCnAHKjDUEoXKyJYL85szupjUuerOt6iTIe7CJ
  216. pH0REwQO4djwM4Ju/PEGfBs+RqgNXoHmBMcFdf9RdogCuFit7lX0+LlRT/KJitan
  217. LaaFgY1TXTVkcwKCAQEA8HgZuPGVHQTMHCOfNesXxnCY9Dwqa9ZVukqDLMaZ0TVy
  218. PIqXhdNeVCWpP+VXWhj9JRLNuW8VWYMxk+poRmsZgbdwSbq30ljsGlfoupCpXfhd
  219. AIhUeRwLVl4XnaHW+MjAmY/rqO156/LvNbV5e0YsqObzynlTczmhhYwi48x1tdf0
  220. iuCn8o3+Ikv8xM7MuMnv5QmGp2l8Q3BhwxLN1x4MXfbG+4BGsqavudIkt71RVbSb
  221. Sp7U4Khq3UEnCekrceRLQpJykRFu11/ntPsJ0Q+fLuvuRUMg/wsq8WTuVlwLrw46
  222. hlRcq6S99jc9j2TbidxHyps6j8SDnEsEFHMHH8THUQKCAQAd03WN1CYZdL0UidEP
  223. hhNhjmAsDD814Yhn5k5SSQ22rUaAWApqrrmXpMPAGgjQnuqRfrX/VtQjtIzN0r91
  224. Sn5wxnj4bnR3BB0FY4A3avPD4z6jRQmKuxavk7DxRTc/QXN7vipkYRscjdAGq0ru
  225. ZeAsm/Kipq2Oskc81XPHxsAua2CK+TtZr/6ShUQXK34noKNrQs8IF4LWdycksX46
  226. Hgaawgq65CDYwsLRCuzc/qSqFYYuMlLAavyXMYH3tx9yQlZmoNlJCBaDRhNaa04m
  227. hZFOJcRBGx9MJI/8CqxN09uL0ZJFBZSNz0qqMc5gpnRdKqpmNZZ8xbOYdvUGfPg1
  228. XwsbAoIBAGdH7iRU/mp8SP48/oC1/HwqmEcuIDo40JE2t6hflGkav3npPLMp2XXi
  229. xxK+egokeXWW4e0nHNBZXM3e+/JixY3FL+E65QDfWGjoIPkgcN3/clJsO3vY47Ww
  230. rAv0GtS3xKEwA1OGy7rfmIZE72xW84+HwmXQPltbAVjOm52jj1sO6eVMIFY5TlGE
  231. uYf+Gkez0+lXchItaEW+2v5h8S7XpRAmkcgrjDHnDcqNy19vXKOm8pvWJDBppZxq
  232. A05qa1J7byekprhP+H9gnbBJsimsv/3zL19oOZ/ROBx98S/+ULZbMh/H1BWUqFI7
  233. 36Da/L/1cJBAo6JkEPLr9VCjJwgqCEECggEBAI6+35Lf4jDwRPvZV7kE+FQuFp1G
  234. /tKxIJtPOZU3sbOVlsFsOoyEfV6+HbpeWxlWnrOnKRFOLoC3s5MVTjPglu1rC0ZX
  235. 4b0wMetvun5S1MGadB808rvu5EsEB1vznz1vOXV8oDdkdgBiiUcKewSeCrG1IrXy
  236. B9ux859S3JjELzeuNdz+xHqu2AqR22gtqN72tJUEQ95qLGZ8vo+ytY9MDVDqoSWJ
  237. 9pqHXFUVLmwHTM0/pciXN4Kx1IL9FZ3fjXgME0vdYpWYQkcvSKLsswXN+LnYcpoQ
  238. h33H/Kz4yji7jPN6Uk9wMyG7XGqpjYAuKCd6V3HEHUiGJZzho/VBgb3TVnw=
  239. -----END RSA PRIVATE KEY-----
  240. """
  241. func testTLSConfig_Defaults() throws {
  242. let grpcTLSConfig = HTTP2ServerTransport.Posix.Config.TLS.defaults(
  243. certificateChain: [
  244. .bytes(Array(Self.samplePemCert.utf8), format: .pem)
  245. ],
  246. privateKey: .bytes(Array(Self.samplePemKey.utf8), format: .pem)
  247. )
  248. let nioSSLTLSConfig = try TLSConfiguration(grpcTLSConfig)
  249. XCTAssertEqual(
  250. nioSSLTLSConfig.certificateChain,
  251. [
  252. .certificate(
  253. try NIOSSLCertificate(
  254. bytes: Array(Self.samplePemCert.utf8),
  255. format: .pem
  256. )
  257. )
  258. ]
  259. )
  260. XCTAssertEqual(
  261. nioSSLTLSConfig.privateKey,
  262. .privateKey(try NIOSSLPrivateKey(bytes: Array(Self.samplePemKey.utf8), format: .pem))
  263. )
  264. XCTAssertEqual(nioSSLTLSConfig.minimumTLSVersion, .tlsv12)
  265. XCTAssertEqual(nioSSLTLSConfig.certificateVerification, .none)
  266. XCTAssertEqual(nioSSLTLSConfig.trustRoots, .default)
  267. XCTAssertEqual(nioSSLTLSConfig.applicationProtocols, ["grpc-exp", "h2"])
  268. }
  269. func testTLSConfig_mTLS() throws {
  270. let grpcTLSConfig = HTTP2ServerTransport.Posix.Config.TLS.mTLS(
  271. certificateChain: [
  272. .bytes(Array(Self.samplePemCert.utf8), format: .pem)
  273. ],
  274. privateKey: .bytes(Array(Self.samplePemKey.utf8), format: .pem)
  275. )
  276. let nioSSLTLSConfig = try TLSConfiguration(grpcTLSConfig)
  277. XCTAssertEqual(
  278. nioSSLTLSConfig.certificateChain,
  279. [
  280. .certificate(
  281. try NIOSSLCertificate(
  282. bytes: Array(Self.samplePemCert.utf8),
  283. format: .pem
  284. )
  285. )
  286. ]
  287. )
  288. XCTAssertEqual(
  289. nioSSLTLSConfig.privateKey,
  290. .privateKey(try NIOSSLPrivateKey(bytes: Array(Self.samplePemKey.utf8), format: .pem))
  291. )
  292. XCTAssertEqual(nioSSLTLSConfig.minimumTLSVersion, .tlsv12)
  293. XCTAssertEqual(nioSSLTLSConfig.certificateVerification, .noHostnameVerification)
  294. XCTAssertEqual(nioSSLTLSConfig.trustRoots, .default)
  295. XCTAssertEqual(nioSSLTLSConfig.applicationProtocols, ["grpc-exp", "h2"])
  296. }
  297. func testTLSConfig_FullVerifyClient() throws {
  298. var grpcTLSConfig = HTTP2ServerTransport.Posix.Config.TLS.defaults(
  299. certificateChain: [
  300. .bytes(Array(Self.samplePemCert.utf8), format: .pem)
  301. ],
  302. privateKey: .bytes(Array(Self.samplePemKey.utf8), format: .pem)
  303. )
  304. grpcTLSConfig.clientCertificateVerification = .fullVerification
  305. let nioSSLTLSConfig = try TLSConfiguration(grpcTLSConfig)
  306. XCTAssertEqual(
  307. nioSSLTLSConfig.certificateChain,
  308. [
  309. .certificate(
  310. try NIOSSLCertificate(
  311. bytes: Array(Self.samplePemCert.utf8),
  312. format: .pem
  313. )
  314. )
  315. ]
  316. )
  317. XCTAssertEqual(
  318. nioSSLTLSConfig.privateKey,
  319. .privateKey(try NIOSSLPrivateKey(bytes: Array(Self.samplePemKey.utf8), format: .pem))
  320. )
  321. XCTAssertEqual(nioSSLTLSConfig.minimumTLSVersion, .tlsv12)
  322. XCTAssertEqual(nioSSLTLSConfig.certificateVerification, .fullVerification)
  323. XCTAssertEqual(nioSSLTLSConfig.trustRoots, .default)
  324. XCTAssertEqual(nioSSLTLSConfig.applicationProtocols, ["grpc-exp", "h2"])
  325. }
  326. func testTLSConfig_CustomTrustRoots() throws {
  327. var grpcTLSConfig = HTTP2ServerTransport.Posix.Config.TLS.defaults(
  328. certificateChain: [
  329. .bytes(Array(Self.samplePemCert.utf8), format: .pem)
  330. ],
  331. privateKey: .bytes(Array(Self.samplePemKey.utf8), format: .pem)
  332. )
  333. grpcTLSConfig.trustRoots = .certificates([.bytes(Array(Self.samplePemCert.utf8), format: .pem)])
  334. let nioSSLTLSConfig = try TLSConfiguration(grpcTLSConfig)
  335. XCTAssertEqual(
  336. nioSSLTLSConfig.certificateChain,
  337. [
  338. .certificate(
  339. try NIOSSLCertificate(
  340. bytes: Array(Self.samplePemCert.utf8),
  341. format: .pem
  342. )
  343. )
  344. ]
  345. )
  346. XCTAssertEqual(
  347. nioSSLTLSConfig.privateKey,
  348. .privateKey(try NIOSSLPrivateKey(bytes: Array(Self.samplePemKey.utf8), format: .pem))
  349. )
  350. XCTAssertEqual(nioSSLTLSConfig.minimumTLSVersion, .tlsv12)
  351. XCTAssertEqual(nioSSLTLSConfig.certificateVerification, .none)
  352. XCTAssertEqual(
  353. nioSSLTLSConfig.trustRoots,
  354. .certificates(try NIOSSLCertificate.fromPEMBytes(Array(Self.samplePemCert.utf8)))
  355. )
  356. XCTAssertEqual(nioSSLTLSConfig.applicationProtocols, ["grpc-exp", "h2"])
  357. }
  358. #endif
  359. }