Skip to content

Commit cd80496

Browse files
author
Gayathri Sairamkrishnan
committed
Confirm RuntimeErrors to HTTPResponseConvertible
1 parent 7177b0c commit cd80496

File tree

2 files changed

+139
-1
lines changed

2 files changed

+139
-1
lines changed

Sources/OpenAPIRuntime/Errors/RuntimeError.swift

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414
import protocol Foundation.LocalizedError
1515
import struct Foundation.Data
16-
16+
import HTTPTypes
1717
/// Error thrown by generated code.
1818
internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, PrettyStringConvertible {
1919

@@ -141,3 +141,43 @@ internal enum RuntimeError: Error, CustomStringConvertible, LocalizedError, Pret
141141
@_spi(Generated) public func throwUnexpectedResponseBody(expectedContent: String, body: any Sendable) throws -> Never {
142142
throw RuntimeError.unexpectedResponseBody(expectedContent: expectedContent, body: body)
143143
}
144+
145+
/// HTTP Response status definition for ``RuntimeError``.
146+
extension RuntimeError: HTTPResponseConvertible {
147+
public var httpStatus: HTTPTypes.HTTPResponse.Status {
148+
switch self {
149+
case .invalidServerURL,
150+
.invalidServerVariableValue:
151+
.notFound
152+
case .invalidExpectedContentType,
153+
.missingCoderForCustomContentType,
154+
.unexpectedContentTypeHeader:
155+
.unsupportedMediaType
156+
case .unexpectedAcceptHeader(_):
157+
.notAcceptable
158+
case .missingOrMalformedContentDispositionName:
159+
.unprocessableContent
160+
case .failedToDecodeStringConvertibleValue,
161+
.invalidAcceptSubstring,
162+
.invalidBase64String,
163+
.invalidHeaderFieldName,
164+
.malformedAcceptHeader,
165+
.missingMultipartBoundaryContentTypeParameter,
166+
.missingRequiredHeaderField,
167+
.missingRequiredMultipartFormDataContentType,
168+
.missingRequiredQueryParameter,
169+
.missingRequiredPathParameter,
170+
.missingRequiredRequestBody,
171+
.pathUnset,
172+
.unsupportedParameterStyle:
173+
.badRequest
174+
case .handlerFailed,
175+
.middlewareFailed,
176+
.missingRequiredResponseBody,
177+
.transportFailed,
178+
.unexpectedResponseStatus,
179+
.unexpectedResponseBody:
180+
.internalServerError
181+
}
182+
}
183+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftOpenAPIGenerator open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the SwiftOpenAPIGenerator project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import HTTPTypes
16+
@_spi(Generated) @testable import OpenAPIRuntime
17+
import XCTest
18+
19+
struct MockRuntimeErrorHandler: Sendable {
20+
var failWithError: (any Error)? = nil
21+
func greet(_ input: String) async throws -> String {
22+
if failWithError != nil { throw failWithError! }
23+
guard input == "hello" else { throw TestError() }
24+
return "bye"
25+
}
26+
27+
static let requestBody: HTTPBody = HTTPBody("hello")
28+
static let responseBody: HTTPBody = HTTPBody("bye")
29+
}
30+
31+
final class Test_RuntimeError: XCTestCase {
32+
func testRuntimeError_returnsCorrectStatusCode() async throws {
33+
34+
let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: RuntimeError.invalidServerURL("Invalid server URL")),
35+
middlewares: [ErrorHandlingMiddleware()])
36+
let response = try await server.handle(
37+
request: .init(soar_path: "/", method: .post),
38+
requestBody: MockHandler.requestBody,
39+
metadata: .init(),
40+
forOperation: "op",
41+
using: { MockRuntimeErrorHandler.greet($0) },
42+
deserializer: { request, body, metadata in
43+
let body = try XCTUnwrap(body)
44+
return try await String(collecting: body, upTo: 10)
45+
},
46+
serializer: { output, _ in fatalError() }
47+
)
48+
XCTAssertEqual(response.0.status, .notFound)
49+
}
50+
51+
func testRuntimeError_withUnderlyingErrorNotConfirming_returns500() async throws {
52+
53+
let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: RuntimeError.transportFailed(TestError())),
54+
middlewares: [ErrorHandlingMiddleware()])
55+
let response = try await server.handle(
56+
request: .init(soar_path: "/", method: .post),
57+
requestBody: MockHandler.requestBody,
58+
metadata: .init(),
59+
forOperation: "op",
60+
using: { MockRuntimeErrorHandler.greet($0) },
61+
deserializer: { request, body, metadata in
62+
let body = try XCTUnwrap(body)
63+
return try await String(collecting: body, upTo: 10)
64+
},
65+
serializer: { output, _ in fatalError() }
66+
)
67+
XCTAssertEqual(response.0.status, .internalServerError)
68+
}
69+
70+
func testRuntimeError_withUnderlyingErrorConfirming_returns500() async throws {
71+
72+
let server = UniversalServer(handler: MockRuntimeErrorHandler(failWithError: TestErrorConvertible.testError("Test Error")),
73+
middlewares: [ErrorHandlingMiddleware()])
74+
let response = try await server.handle(
75+
request: .init(soar_path: "/", method: .post),
76+
requestBody: MockHandler.requestBody,
77+
metadata: .init(),
78+
forOperation: "op",
79+
using: { MockRuntimeErrorHandler.greet($0) },
80+
deserializer: { request, body, metadata in
81+
let body = try XCTUnwrap(body)
82+
return try await String(collecting: body, upTo: 10)
83+
},
84+
serializer: { output, _ in fatalError() }
85+
)
86+
XCTAssertEqual(response.0.status, .badGateway)
87+
}
88+
}
89+
90+
enum TestErrorConvertible: Error, HTTPResponseConvertible {
91+
case testError(String)
92+
93+
public var httpStatus: HTTPTypes.HTTPResponse.Status {
94+
.badGateway
95+
}
96+
}
97+
98+

0 commit comments

Comments
 (0)