|
|
@@ -0,0 +1,147 @@
|
|
|
+/*
|
|
|
+ * Copyright 2020, gRPC Authors All rights reserved.
|
|
|
+ *
|
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
+ * you may not use this file except in compliance with the License.
|
|
|
+ * You may obtain a copy of the License at
|
|
|
+ *
|
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+ *
|
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+ * See the License for the specific language governing permissions and
|
|
|
+ * limitations under the License.
|
|
|
+ */
|
|
|
+import Foundation
|
|
|
+import XCTest
|
|
|
+import NIO
|
|
|
+import NIOHTTP1
|
|
|
+import GRPC
|
|
|
+import EchoModel
|
|
|
+import EchoImplementation
|
|
|
+import Logging
|
|
|
+
|
|
|
+private class ServerErrorDelegateMock: ServerErrorDelegate {
|
|
|
+ private let transformLibraryErrorHandler: ((Error) -> (GRPCStatusAndMetadata?))
|
|
|
+
|
|
|
+ init(transformLibraryErrorHandler: @escaping ((Error) -> (GRPCStatusAndMetadata?))) {
|
|
|
+ self.transformLibraryErrorHandler = transformLibraryErrorHandler
|
|
|
+ }
|
|
|
+
|
|
|
+ func transformLibraryError(_ error: Error) -> GRPCStatusAndMetadata? {
|
|
|
+ return self.transformLibraryErrorHandler(error)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class ServerErrorDelegateTests: GRPCTestCase {
|
|
|
+ private var channel: EmbeddedChannel!
|
|
|
+ private var errorDelegate: ServerErrorDelegate!
|
|
|
+
|
|
|
+ override func tearDown() {
|
|
|
+ XCTAssertNoThrow(try self.channel.finish())
|
|
|
+ super.tearDown()
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatus_unary() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatus(uri: "/echo.Echo/Get")
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatus_clientStreaming() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatus(uri: "/echo.Echo/Collect")
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatus_serverStreaming() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatus(uri: "/echo.Echo/Expand")
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatus_bidirectionalStreaming() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatus(uri: "/echo.Echo/Update")
|
|
|
+ }
|
|
|
+
|
|
|
+ private func testTransformLibraryError_whenTransformingErrorToStatus(uri: String) throws {
|
|
|
+ self.setupChannelAndDelegate { _ in
|
|
|
+ GRPCStatusAndMetadata(status: .init(code: .notFound, message: "some error"))
|
|
|
+ }
|
|
|
+ let requestHead = HTTPRequestHead(
|
|
|
+ version: .init(major: 2, minor: 0),
|
|
|
+ method: .POST,
|
|
|
+ uri: uri,
|
|
|
+ headers: ["content-type": "application/grpc"]
|
|
|
+ )
|
|
|
+
|
|
|
+ XCTAssertNoThrow(try self.channel.writeInbound(HTTPServerRequestPart.head(requestHead)))
|
|
|
+ self.channel.pipeline.fireErrorCaught(GRPCStatus(code: .aborted, message: nil))
|
|
|
+ // This is the head
|
|
|
+ XCTAssertNoThrow(try self.channel.readOutbound(as: HTTPServerResponsePart.self))
|
|
|
+ let end = try self.channel.readOutbound(as: HTTPServerResponsePart.self)
|
|
|
+
|
|
|
+ guard case let .some(.end(headers)) = end else {
|
|
|
+ XCTFail("Expected headers but got \(end.debugDescription)")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ XCTAssertEqual(headers?.first(name: "grpc-status"), "5")
|
|
|
+ XCTAssertEqual(headers?.first(name: "grpc-message"), "some error")
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatusAndMetadata_unary() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatusAndMetadata(uri: "/echo.Echo/Get")
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatusAndMetadata_clientStreaming() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatusAndMetadata(uri: "/echo.Echo/Collect")
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatusAndMetadata_serverStreaming() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatusAndMetadata(uri: "/echo.Echo/Expand")
|
|
|
+ }
|
|
|
+
|
|
|
+ func testTransformLibraryError_whenTransformingErrorToStatusAndMetadata_bidirectionalStreaming() throws {
|
|
|
+ try testTransformLibraryError_whenTransformingErrorToStatusAndMetadata(uri: "/echo.Echo/Update")
|
|
|
+ }
|
|
|
+
|
|
|
+ private func testTransformLibraryError_whenTransformingErrorToStatusAndMetadata(uri: String) throws {
|
|
|
+ self.setupChannelAndDelegate { _ in
|
|
|
+ GRPCStatusAndMetadata(
|
|
|
+ status: .init(code: .notFound, message: "some error"),
|
|
|
+ metadata: ["some-metadata": "test"]
|
|
|
+ )
|
|
|
+ }
|
|
|
+ let requestHead = HTTPRequestHead(
|
|
|
+ version: .init(major: 2, minor: 0),
|
|
|
+ method: .POST,
|
|
|
+ uri: uri,
|
|
|
+ headers: ["content-type": "application/grpc"]
|
|
|
+ )
|
|
|
+
|
|
|
+ XCTAssertNoThrow(try self.channel.writeInbound(HTTPServerRequestPart.head(requestHead)))
|
|
|
+ self.channel.pipeline.fireErrorCaught(GRPCStatus(code: .aborted, message: nil))
|
|
|
+ // This is the head
|
|
|
+ XCTAssertNoThrow(try self.channel.readOutbound(as: HTTPServerResponsePart.self))
|
|
|
+ let end = try self.channel.readOutbound(as: HTTPServerResponsePart.self)
|
|
|
+
|
|
|
+ guard case let .some(.end(headers)) = end else {
|
|
|
+ XCTFail("Expected headers but got \(end.debugDescription)")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ XCTAssertEqual(headers?.first(name: "grpc-status"), "5")
|
|
|
+ XCTAssertEqual(headers?.first(name: "grpc-message"), "some error")
|
|
|
+ XCTAssertEqual(headers?.first(name: "some-metadata"), "test")
|
|
|
+ }
|
|
|
+
|
|
|
+ private func setupChannelAndDelegate(transformLibraryErrorHandler: @escaping ((Error) -> (GRPCStatusAndMetadata?))) {
|
|
|
+ let provider = EchoProvider()
|
|
|
+ self.errorDelegate = ServerErrorDelegateMock(transformLibraryErrorHandler: transformLibraryErrorHandler)
|
|
|
+ let handler = GRPCServerRequestRoutingHandler(
|
|
|
+ servicesByName: [provider.serviceName: provider],
|
|
|
+ encoding: .disabled,
|
|
|
+ errorDelegate: self.errorDelegate,
|
|
|
+ logger: self.logger
|
|
|
+ )
|
|
|
+
|
|
|
+ self.channel = EmbeddedChannel(handler: handler)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|