Skip to content

Commit

Permalink
Confirm RuntimeErrors to HTTPResponseConvertible
Browse files Browse the repository at this point in the history
  • Loading branch information
Gayathri Sairamkrishnan committed Dec 13, 2024
1 parent 7177b0c commit cd80496
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 1 deletion.
42 changes: 41 additions & 1 deletion Sources/OpenAPIRuntime/Errors/RuntimeError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//===----------------------------------------------------------------------===//
import protocol Foundation.LocalizedError
import struct Foundation.Data

import HTTPTypes
/// Error thrown by generated code.
internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, PrettyStringConvertible {

Expand Down Expand Up @@ -141,3 +141,43 @@ internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, Pret
@_spi(Generated) public func throwUnexpectedResponseBody(expectedContent: String, body: any Sendable) throws -> Never {
throw RuntimeError.unexpectedResponseBody(expectedContent: expectedContent, body: body)
}

/// HTTP Response status definition for ``RuntimeError``.
extension RuntimeError: HTTPResponseConvertible {
public var httpStatus: HTTPTypes.HTTPResponse.Status {
switch self {
case .invalidServerURL,
.invalidServerVariableValue:
.notFound
case .invalidExpectedContentType,
.missingCoderForCustomContentType,
.unexpectedContentTypeHeader:
.unsupportedMediaType
case .unexpectedAcceptHeader(_):
.notAcceptable
case .missingOrMalformedContentDispositionName:
.unprocessableContent
case .failedToDecodeStringConvertibleValue,
.invalidAcceptSubstring,
.invalidBase64String,
.invalidHeaderFieldName,
.malformedAcceptHeader,
.missingMultipartBoundaryContentTypeParameter,
.missingRequiredHeaderField,
.missingRequiredMultipartFormDataContentType,
.missingRequiredQueryParameter,
.missingRequiredPathParameter,
.missingRequiredRequestBody,
.pathUnset,
.unsupportedParameterStyle:
.badRequest
case .handlerFailed,
.middlewareFailed,
.missingRequiredResponseBody,
.transportFailed,
.unexpectedResponseStatus,
.unexpectedResponseBody:
.internalServerError
}
}
}
98 changes: 98 additions & 0 deletions Tests/OpenAPIRuntimeTests/Errors/Test_RuntimeError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftOpenAPIGenerator open source project
//
// Copyright (c) 2024 Apple Inc. and the SwiftOpenAPIGenerator project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import HTTPTypes
@_spi(Generated) @testable import OpenAPIRuntime
import XCTest

struct MockRuntimeErrorHandler: Sendable {
var failWithError: (any Error)? = nil
func greet(_ input: String) async throws -> String {
if failWithError != nil { throw failWithError! }
guard input == "hello" else { throw TestError() }
return "bye"
}

static let requestBody: HTTPBody = HTTPBody("hello")
static let responseBody: HTTPBody = HTTPBody("bye")
}

final class Test_RuntimeError: XCTestCase {
func testRuntimeError_returnsCorrectStatusCode() async throws {

let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: RuntimeError.invalidServerURL("Invalid server URL")),
middlewares: [ErrorHandlingMiddleware()])
let response = try await server.handle(
request: .init(soar_path: "/", method: .post),
requestBody: MockHandler.requestBody,
metadata: .init(),
forOperation: "op",
using: { MockRuntimeErrorHandler.greet($0) },
deserializer: { request, body, metadata in
let body = try XCTUnwrap(body)
return try await String(collecting: body, upTo: 10)
},
serializer: { output, _ in fatalError() }
)
XCTAssertEqual(response.0.status, .notFound)
}

func testRuntimeError_withUnderlyingErrorNotConfirming_returns500() async throws {

let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: RuntimeError.transportFailed(TestError())),
middlewares: [ErrorHandlingMiddleware()])
let response = try await server.handle(
request: .init(soar_path: "/", method: .post),
requestBody: MockHandler.requestBody,
metadata: .init(),
forOperation: "op",
using: { MockRuntimeErrorHandler.greet($0) },
deserializer: { request, body, metadata in
let body = try XCTUnwrap(body)
return try await String(collecting: body, upTo: 10)
},
serializer: { output, _ in fatalError() }
)
XCTAssertEqual(response.0.status, .internalServerError)
}

func testRuntimeError_withUnderlyingErrorConfirming_returns500() async throws {

let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: TestErrorConvertible.testError("Test Error")),
middlewares: [ErrorHandlingMiddleware()])
let response = try await server.handle(
request: .init(soar_path: "/", method: .post),
requestBody: MockHandler.requestBody,
metadata: .init(),
forOperation: "op",
using: { MockRuntimeErrorHandler.greet($0) },
deserializer: { request, body, metadata in
let body = try XCTUnwrap(body)
return try await String(collecting: body, upTo: 10)
},
serializer: { output, _ in fatalError() }
)
XCTAssertEqual(response.0.status, .badGateway)
}
}

enum TestErrorConvertible: Error, HTTPResponseConvertible {
case testError(String)

public var httpStatus: HTTPTypes.HTTPResponse.Status {
.badGateway
}
}


0 comments on commit cd80496

Please sign in to comment.