GRPCChannelHandlerResponseCapturingTestCase.swift 2.5 KB

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