GRPCChannelHandlerResponseCapturingTestCase.swift 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import Foundation
  2. import NIO
  3. import NIOHTTP1
  4. @testable import SwiftGRPCNIO
  5. import XCTest
  6. class CollectingChannelHandler<OutboundIn>: ChannelOutboundHandler {
  7. var responses: [OutboundIn] = []
  8. func write(ctx: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
  9. responses.append(unwrapOutboundIn(data))
  10. }
  11. }
  12. class CollectingServerErrorDelegate: ServerErrorDelegate {
  13. var errors: [Error] = []
  14. var asGRPCErrors: [GRPCError]? {
  15. return self.errors as? [GRPCError]
  16. }
  17. var asGRPCServerErrors: [GRPCServerError]? {
  18. return (self.asGRPCErrors?.map { $0.error }) as? [GRPCServerError]
  19. }
  20. var asGRPCCommonErrors: [GRPCCommonError]? {
  21. return (self.asGRPCErrors?.map { $0.error }) as? [GRPCCommonError]
  22. }
  23. func observe(_ error: Error) {
  24. self.errors.append(error)
  25. }
  26. }
  27. class GRPCChannelHandlerResponseCapturingTestCase: XCTestCase {
  28. static let echoProvider: [String: CallHandlerProvider] = ["echo.Echo": EchoProviderNIO()]
  29. class var defaultServiceProvider: [String: CallHandlerProvider] {
  30. return echoProvider
  31. }
  32. func configureChannel(withHandlers handlers: [ChannelHandler]) -> EventLoopFuture<EmbeddedChannel> {
  33. let channel = EmbeddedChannel()
  34. return channel.pipeline.addHandlers(handlers, first: true)
  35. .map { _ in channel }
  36. }
  37. var errorCollector: CollectingServerErrorDelegate = CollectingServerErrorDelegate()
  38. /// Waits for `count` responses to be collected and then returns them. The test fails if the number
  39. /// of collected responses does not match the expected.
  40. ///
  41. /// - Parameters:
  42. /// - count: expected number of responses.
  43. /// - servicesByName: service providers keyed by their service name.
  44. /// - callback: a callback called after the channel has been setup, intended to "fill" the channel
  45. /// with messages. The callback is called before this function returns.
  46. /// - Returns: The responses collected from the pipeline.
  47. func waitForGRPCChannelHandlerResponses(
  48. count: Int,
  49. servicesByName: [String: CallHandlerProvider] = defaultServiceProvider,
  50. callback: @escaping (EmbeddedChannel) throws -> Void
  51. ) throws -> [RawGRPCServerResponsePart] {
  52. let collector = CollectingChannelHandler<RawGRPCServerResponsePart>()
  53. try configureChannel(withHandlers: [collector, GRPCChannelHandler(servicesByName: servicesByName, errorDelegate: errorCollector)])
  54. .thenThrowing(callback)
  55. .wait()
  56. XCTAssertEqual(count, collector.responses.count)
  57. return collector.responses
  58. }
  59. }