ZeroLengthWriteTests.swift 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Copyright 2020, 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 Dispatch
  17. import Foundation
  18. import NIO
  19. import NIOSSL
  20. import NIOTransportServices
  21. import GRPC
  22. import GRPCSampleData
  23. import EchoModel
  24. import EchoImplementation
  25. import XCTest
  26. final class ZeroLengthWriteTests: GRPCTestCase {
  27. func clientBuilder(group: EventLoopGroup, secure: Bool, debugInitializer: @escaping (Channel) -> EventLoopFuture<Void>) -> ClientConnection.Builder {
  28. if secure {
  29. return ClientConnection.secure(group: group)
  30. .withTLS(trustRoots: .certificates([SampleCertificate.ca.certificate]))
  31. .withDebugChannelInitializer(debugInitializer)
  32. } else {
  33. return ClientConnection.insecure(group: group)
  34. .withDebugChannelInitializer(debugInitializer)
  35. }
  36. }
  37. func serverBuilder(group: EventLoopGroup, secure: Bool, debugInitializer: @escaping (Channel) -> EventLoopFuture<Void>) -> Server.Builder {
  38. if secure {
  39. return Server.secure(
  40. group: group,
  41. certificateChain: [SampleCertificate.server.certificate],
  42. privateKey: SamplePrivateKey.server
  43. ).withTLS(trustRoots: .certificates([SampleCertificate.ca.certificate]))
  44. .withDebugChannelInitializer(debugInitializer)
  45. } else {
  46. return Server.insecure(group: group)
  47. .withDebugChannelInitializer(debugInitializer)
  48. }
  49. }
  50. func makeServer(group: EventLoopGroup, secure: Bool, debugInitializer: @escaping (Channel) -> EventLoopFuture<Void>) throws -> Server {
  51. return try self.serverBuilder(group: group, secure: secure, debugInitializer: debugInitializer)
  52. .withServiceProviders([self.makeEchoProvider()])
  53. .withLogger(self.serverLogger)
  54. .bind(host: "localhost", port: 0)
  55. .wait()
  56. }
  57. func makeClientConnection(group: EventLoopGroup, secure: Bool, port: Int, debugInitializer: @escaping (Channel) -> EventLoopFuture<Void>) throws -> ClientConnection {
  58. return self.clientBuilder(group: group, secure: secure, debugInitializer: debugInitializer)
  59. .withBackgroundActivityLogger(self.clientLogger)
  60. .connect(host: "localhost", port: port)
  61. }
  62. func makeEchoProvider() -> Echo_EchoProvider { return EchoProvider() }
  63. func makeEchoClient(group: EventLoopGroup, secure: Bool, port: Int, debugInitializer: @escaping (Channel) -> EventLoopFuture<Void>) throws -> Echo_EchoClient {
  64. return Echo_EchoClient(
  65. channel: try self.makeClientConnection(group: group, secure: secure, port: port, debugInitializer: debugInitializer),
  66. defaultCallOptions: self.callOptionsWithLogger
  67. )
  68. }
  69. func zeroLengthWriteExpectation() -> XCTestExpectation {
  70. let expectation = self.expectation(description: "Expecting zero length write workaround")
  71. expectation.expectedFulfillmentCount = 1
  72. expectation.assertForOverFulfill = true
  73. return expectation
  74. }
  75. func noZeroLengthWriteExpectation() -> XCTestExpectation {
  76. let expectation = self.expectation(description: "Not expecting zero length write workaround")
  77. expectation.expectedFulfillmentCount = 1
  78. expectation.assertForOverFulfill = true
  79. return expectation
  80. }
  81. func debugPipelineExpectation(_ callback: @escaping (Result<NIOFilterEmptyWritesHandler, Error>) -> Void) -> (Channel) -> EventLoopFuture<Void> {
  82. return { channel in
  83. channel.pipeline.handler(type: NIOFilterEmptyWritesHandler.self).always { result in
  84. callback(result)
  85. }.map { _ in () }.recover { _ in () }
  86. }
  87. }
  88. private func _runTest(
  89. networkPreference: NetworkPreference,
  90. secure: Bool,
  91. clientHandlerCallback: @escaping (Result<NIOFilterEmptyWritesHandler, Error>) -> Void,
  92. serverHandlerCallback: @escaping (Result<NIOFilterEmptyWritesHandler, Error>) -> Void
  93. ) {
  94. // We can only run this test on platforms where the zero-length write workaround _could_ be added.
  95. #if canImport(Network)
  96. guard #available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) else { return }
  97. let group = PlatformSupport.makeEventLoopGroup(
  98. loopCount: 1,
  99. networkPreference: networkPreference)
  100. let server = try! self.makeServer(group: group, secure: secure, debugInitializer: self.debugPipelineExpectation(serverHandlerCallback))
  101. defer {
  102. XCTAssertNoThrow(try server.close().wait())
  103. XCTAssertNoThrow(try group.syncShutdownGracefully())
  104. }
  105. let port = server.channel.localAddress!.port!
  106. let client = try! self.makeEchoClient(group: group, secure: secure, port: port, debugInitializer: self.debugPipelineExpectation(clientHandlerCallback))
  107. defer {
  108. XCTAssertNoThrow(try client.channel.close().wait())
  109. }
  110. // We need to wait here to confirm that the RPC completes. All expectations should have completed by then.
  111. let call = client.get(Echo_EchoRequest(text: "foo bar baz"))
  112. XCTAssertNoThrow(try call.status.wait())
  113. self.waitForExpectations(timeout: 1.0)
  114. #endif
  115. }
  116. func testZeroLengthWriteTestPosixSecure() throws {
  117. // We can only run this test on platforms where the zero-length write workaround _could_ be added.
  118. #if canImport(Network)
  119. guard #available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) else { return }
  120. let serverExpectation = self.noZeroLengthWriteExpectation()
  121. let clientExpectation = self.noZeroLengthWriteExpectation()
  122. self._runTest(
  123. networkPreference: .userDefined(.posix),
  124. secure: true,
  125. clientHandlerCallback: { result in
  126. if case .failure = result {
  127. clientExpectation.fulfill()
  128. }
  129. },
  130. serverHandlerCallback: { result in
  131. if case .failure = result {
  132. serverExpectation.fulfill()
  133. }
  134. }
  135. )
  136. #endif
  137. }
  138. func testZeroLengthWriteTestPosixInsecure() throws {
  139. // We can only run this test on platforms where the zero-length write workaround _could_ be added.
  140. #if canImport(Network)
  141. guard #available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) else { return }
  142. let serverExpectation = self.noZeroLengthWriteExpectation()
  143. let clientExpectation = self.noZeroLengthWriteExpectation()
  144. self._runTest(
  145. networkPreference: .userDefined(.posix),
  146. secure: false,
  147. clientHandlerCallback: { result in
  148. if case .failure = result {
  149. clientExpectation.fulfill()
  150. }
  151. },
  152. serverHandlerCallback: { result in
  153. if case .failure = result {
  154. serverExpectation.fulfill()
  155. }
  156. }
  157. )
  158. #endif
  159. }
  160. func testZeroLengthWriteTestNetworkFrameworkSecure() throws {
  161. // We can only run this test on platforms where the zero-length write workaround _could_ be added.
  162. #if canImport(Network)
  163. guard #available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) else { return }
  164. let serverExpectation = self.noZeroLengthWriteExpectation()
  165. let clientExpectation = self.noZeroLengthWriteExpectation()
  166. self._runTest(
  167. networkPreference: .userDefined(.networkFramework),
  168. secure: true,
  169. clientHandlerCallback: { result in
  170. if case .failure = result {
  171. clientExpectation.fulfill()
  172. }
  173. },
  174. serverHandlerCallback: { result in
  175. if case .failure = result {
  176. serverExpectation.fulfill()
  177. }
  178. }
  179. )
  180. #endif
  181. }
  182. func testZeroLengthWriteTestNetworkFrameworkInsecure() throws {
  183. // We can only run this test on platforms where the zero-length write workaround _could_ be added.
  184. #if canImport(Network)
  185. guard #available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) else { return }
  186. let serverExpectation = self.zeroLengthWriteExpectation()
  187. let clientExpectation = self.zeroLengthWriteExpectation()
  188. self._runTest(
  189. networkPreference: .userDefined(.networkFramework),
  190. secure: false,
  191. clientHandlerCallback: { result in
  192. if case .success = result {
  193. clientExpectation.fulfill()
  194. }
  195. },
  196. serverHandlerCallback: { result in
  197. if case .success = result {
  198. serverExpectation.fulfill()
  199. }
  200. }
  201. )
  202. #endif
  203. }
  204. }