FakeResponseStreamTests.swift 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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 EchoModel
  17. @testable import GRPC
  18. import NIO
  19. import NIOHPACK
  20. import XCTest
  21. class FakeResponseStreamTests: GRPCTestCase {
  22. private typealias Request = Echo_EchoRequest
  23. private typealias Response = Echo_EchoResponse
  24. private typealias ResponsePart = _GRPCClientResponsePart<Response>
  25. func testUnarySendMessage() {
  26. let unary = FakeUnaryResponse<Request, Response>()
  27. unary.activate()
  28. XCTAssertNoThrow(try unary.sendMessage(.with { $0.text = "foo" }))
  29. unary.channel.verifyInbound(as: ResponsePart.self) { part in
  30. part.assertInitialMetadata()
  31. }
  32. unary.channel.verifyInbound(as: ResponsePart.self) { part in
  33. part.assertMessage {
  34. XCTAssertEqual($0, .with { $0.text = "foo" })
  35. }
  36. }
  37. unary.channel.verifyInbound(as: ResponsePart.self) { part in
  38. part.assertTrailingMetadata()
  39. }
  40. unary.channel.verifyInbound(as: ResponsePart.self) { part in
  41. part.assertStatus()
  42. }
  43. }
  44. func testUnarySendError() {
  45. let unary = FakeUnaryResponse<Request, Response>()
  46. unary.activate()
  47. XCTAssertNoThrow(try unary.sendError(GRPCError.RPCNotImplemented(rpc: "uh oh!")))
  48. // Expect trailers and then an error.
  49. unary.channel.verifyInbound(as: ResponsePart.self) { part in
  50. part.assertTrailingMetadata()
  51. }
  52. XCTAssertThrowsError(try unary.channel.throwIfErrorCaught())
  53. }
  54. func testUnaryIgnoresExtraMessages() {
  55. let unary = FakeUnaryResponse<Request, Response>()
  56. unary.activate()
  57. XCTAssertNoThrow(try unary.sendError(GRPCError.RPCNotImplemented(rpc: "uh oh!")))
  58. // Expected.
  59. unary.channel.verifyInbound(as: ResponsePart.self) { part in
  60. part.assertTrailingMetadata()
  61. }
  62. XCTAssertThrowsError(try unary.channel.throwIfErrorCaught())
  63. // Send another error; this should on-op.
  64. XCTAssertThrowsError(try unary.sendError(GRPCError.RPCCancelledByClient())) { error in
  65. XCTAssertTrue(error is FakeResponseProtocolViolation)
  66. }
  67. XCTAssertNil(try unary.channel.readInbound(as: ResponsePart.self))
  68. XCTAssertNoThrow(try unary.channel.throwIfErrorCaught())
  69. // Send a message; this should on-op.
  70. XCTAssertThrowsError(try unary.sendMessage(.with { $0.text = "ignored" })) { error in
  71. XCTAssertTrue(error is FakeResponseProtocolViolation)
  72. }
  73. XCTAssertNil(try unary.channel.readInbound(as: ResponsePart.self))
  74. XCTAssertNoThrow(try unary.channel.throwIfErrorCaught())
  75. }
  76. func testStreamingSendMessage() {
  77. let streaming = FakeStreamingResponse<Request, Response>()
  78. streaming.activate()
  79. XCTAssertNoThrow(try streaming.sendMessage(.with { $0.text = "1" }))
  80. XCTAssertNoThrow(try streaming.sendMessage(.with { $0.text = "2" }))
  81. XCTAssertNoThrow(try streaming.sendMessage(.with { $0.text = "3" }))
  82. XCTAssertNoThrow(try streaming.sendEnd())
  83. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  84. part.assertInitialMetadata()
  85. }
  86. for expected in ["1", "2", "3"] {
  87. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  88. part.assertMessage { message in
  89. XCTAssertEqual(message, .with { $0.text = expected })
  90. }
  91. }
  92. }
  93. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  94. part.assertTrailingMetadata()
  95. }
  96. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  97. part.assertStatus()
  98. }
  99. }
  100. func testStreamingSendInitialMetadata() {
  101. let streaming = FakeStreamingResponse<Request, Response>()
  102. streaming.activate()
  103. XCTAssertNoThrow(try streaming.sendInitialMetadata(["foo": "bar"]))
  104. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  105. part.assertInitialMetadata { metadata in
  106. XCTAssertEqual(metadata, ["foo": "bar"])
  107. }
  108. }
  109. // This should be dropped.
  110. XCTAssertThrowsError(try streaming.sendInitialMetadata(["bar": "baz"])) { error in
  111. XCTAssertTrue(error is FakeResponseProtocolViolation)
  112. }
  113. // Trailers and status.
  114. XCTAssertNoThrow(try streaming.sendEnd(trailingMetadata: ["bar": "foo"]))
  115. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  116. part.assertTrailingMetadata { metadata in
  117. XCTAssertEqual(metadata, ["bar": "foo"])
  118. }
  119. }
  120. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  121. part.assertStatus()
  122. }
  123. }
  124. func streamingSendError() {
  125. let streaming = FakeStreamingResponse<Request, Response>()
  126. streaming.activate()
  127. XCTAssertNoThrow(try streaming.sendMessage(.with { $0.text = "1" }))
  128. XCTAssertNoThrow(try streaming.sendError(GRPCError.RPCCancelledByClient()))
  129. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  130. part.assertInitialMetadata()
  131. }
  132. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  133. part.assertMessage { message in
  134. XCTAssertEqual(message, .with { $0.text = "1" })
  135. }
  136. }
  137. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  138. part.assertTrailingMetadata()
  139. }
  140. XCTAssertThrowsError(try streaming.channel.throwIfErrorCaught())
  141. }
  142. func testStreamingIgnoresExtraMessages() {
  143. let streaming = FakeStreamingResponse<Request, Response>()
  144. streaming.activate()
  145. XCTAssertNoThrow(try streaming.sendError(GRPCError.RPCNotImplemented(rpc: "uh oh!")))
  146. // Expected.
  147. streaming.channel.verifyInbound(as: ResponsePart.self) { part in
  148. part.assertTrailingMetadata()
  149. }
  150. XCTAssertThrowsError(try streaming.channel.throwIfErrorCaught())
  151. // Send another error; this should on-op.
  152. XCTAssertThrowsError(try streaming.sendError(GRPCError.RPCCancelledByClient())) { error in
  153. XCTAssertTrue(error is FakeResponseProtocolViolation)
  154. }
  155. XCTAssertNil(try streaming.channel.readInbound(as: ResponsePart.self))
  156. XCTAssertNoThrow(try streaming.channel.throwIfErrorCaught())
  157. // Send a message; this should on-op.
  158. XCTAssertThrowsError(try streaming.sendMessage(.with { $0.text = "ignored" })) { error in
  159. XCTAssertTrue(error is FakeResponseProtocolViolation)
  160. }
  161. XCTAssertNil(try streaming.channel.readInbound(as: ResponsePart.self))
  162. XCTAssertNoThrow(try streaming.channel.throwIfErrorCaught())
  163. }
  164. }
  165. private extension EmbeddedChannel {
  166. func verifyInbound<Inbound>(as: Inbound.Type = Inbound.self, _ verify: (Inbound) -> Void = { _ in
  167. }) {
  168. do {
  169. if let inbound = try self.readInbound(as: Inbound.self) {
  170. verify(inbound)
  171. } else {
  172. XCTFail("Nothing to read")
  173. }
  174. } catch {
  175. XCTFail("Unable to readInbound: \(error)")
  176. }
  177. }
  178. }
  179. private extension _GRPCClientResponsePart {
  180. func assertInitialMetadata(_ verify: (HPACKHeaders) -> Void = { _ in }) {
  181. switch self {
  182. case let .initialMetadata(headers):
  183. verify(headers)
  184. default:
  185. XCTFail("Expected initial metadata but got: \(self)")
  186. }
  187. }
  188. func assertMessage(_ verify: (Response) -> Void = { _ in }) {
  189. switch self {
  190. case let .message(context):
  191. verify(context.message)
  192. default:
  193. XCTFail("Expected message but got: \(self)")
  194. }
  195. }
  196. func assertTrailingMetadata(_ verify: (HPACKHeaders) -> Void = { _ in }) {
  197. switch self {
  198. case let .trailingMetadata(headers):
  199. verify(headers)
  200. default:
  201. XCTFail("Expected trailing metadata but got: \(self)")
  202. }
  203. }
  204. func assertStatus(_ verify: (GRPCStatus) -> Void = { _ in }) {
  205. switch self {
  206. case let .status(status):
  207. verify(status)
  208. default:
  209. XCTFail("Expected status but got: \(self)")
  210. }
  211. }
  212. }