Skip to content

Commit

Permalink
chore: Add aws_json error code tests (#1798)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbelkins authored Oct 23, 2024
1 parent 14c9760 commit 17d6f19
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import SmithyTestUtil
import SmithyHTTPAPI
import Smithy
@_spi(SmithyReadWrite) import class SmithyJSON.Reader
@_spi(SmithyReadWrite) import struct AWSClientRuntime.AWSJSONError
@_spi(SmithyReadWrite) import enum ClientRuntime.BaseErrorDecodeError
import XCTest

class AWSJSONErrorTests: HttpResponseTestBase {
// These error codes are taken from the examples in
// https://smithy.io/2.0/aws/protocols/aws-json-1_0-protocol.html#operation-error-serialization
// (one extra case with leading & trailing whitespace is added)
let errorCodes = [
"FooError",
" FooError ",
"FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/",
"aws.protocoltests.restjson#FooError",
"aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/"
]

// MARK: - error code decoding & sanitization

func test_errorInitThrowsIfNoCode() async throws {
let httpResponse = try httpResponseWithNoErrorCode()
let reader = try await Reader.from(data: httpResponse.body.readData() ?? Data())
XCTAssertThrowsError(try AWSJSONError(httpResponse: httpResponse, responseReader: reader, noErrorWrapping: true)) { error in
XCTAssertTrue((error as? BaseErrorDecodeError) == BaseErrorDecodeError.missingRequiredData)
}
}

func test_sanitizeErrorCodeInHeader() async throws {
for errorCode in errorCodes {
let httpResponse = try httpResponseWithHeaderErrorCode(errorCode: errorCode)
let reader = try await Reader.from(data: httpResponse.body.readData() ?? Data())
let awsJSONError = try AWSJSONError(httpResponse: httpResponse, responseReader: reader, noErrorWrapping: true)
XCTAssertEqual(awsJSONError.code, "FooError", "Error code '\(errorCode)' was not sanitized correctly, result was '\(awsJSONError.code)'")
}
}

func test_sanitizeErrorCodeInCodeField() async throws {
for errorCode in errorCodes {
let httpResponse = try httpResponseWithCodeFieldErrorCode(errorCode: errorCode)
let reader = try await Reader.from(data: httpResponse.body.readData() ?? Data())
let awsJSONError = try AWSJSONError(httpResponse: httpResponse, responseReader: reader, noErrorWrapping: true)
XCTAssertEqual(awsJSONError.code, "FooError", "Error code '\(errorCode)' was not sanitized correctly, result was '\(awsJSONError.code)'")
}
}

func test_sanitizeErrorCodeInTypeField() async throws {
for errorCode in errorCodes {
let httpResponse = try httpResponseWithTypeFieldErrorCode(errorCode: errorCode)
let reader = try await Reader.from(data: httpResponse.body.readData() ?? Data())
let awsJSONError = try AWSJSONError(httpResponse: httpResponse, responseReader: reader, noErrorWrapping: true)
XCTAssertEqual(awsJSONError.code, "FooError", "Error code '\(errorCode)' was not sanitized correctly, result was '\(awsJSONError.code)'")
}
}

// MARK: - Private methods

private func httpResponseWithNoErrorCode() throws -> HTTPResponse {
guard let response = buildHttpResponse(
code: 400,
headers: [
"Content-Type": "application/json",
],
content: ByteStream.data(Data("{}".utf8))
) else {
throw TestError("Something is wrong with the created http response")
}
return response
}

private func httpResponseWithHeaderErrorCode(errorCode: String) throws -> HTTPResponse {
guard let response = buildHttpResponse(
code: 400,
headers: [
"Content-Type": "application/json",
"X-Amzn-Errortype": errorCode,
],
content: ByteStream.data(Data("{}".utf8))
) else {
throw TestError("Something is wrong with the created http response")
}
return response
}

private func httpResponseWithCodeFieldErrorCode(errorCode: String) throws -> HTTPResponse {
guard let response = buildHttpResponse(
code: 400,
headers: [
"Content-Type": "application/json",
],
content: ByteStream.data(Data("{\"code\":\"\(errorCode)\"}".utf8))
) else {
throw TestError("Something is wrong with the created http response")
}
return response
}

private func httpResponseWithTypeFieldErrorCode(errorCode: String) throws -> HTTPResponse {
guard let response = buildHttpResponse(
code: 400,
headers: [
"Content-Type": "application/json",
],
content: ByteStream.data(Data("{\"__type\":\"\(errorCode)\"}".utf8))
) else {
throw TestError("Something is wrong with the created http response")
}
return response
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,7 @@ class RestJSONErrorTests: HttpResponseTestBase {
let host = "myapi.host.com"

func testRestJsonComplexError() async throws {
guard let httpResponse = buildHttpResponse(
code: 400,
headers: [
"Content-Type": "application/json",
"X-Header": "Header",
"X-Amzn-Errortype": "ComplexError"
],
content: ByteStream.data("""
{\"TopLevel\": \"Top level\"}
""".data(using: .utf8))
) else {
XCTFail("Something is wrong with the created http response")
return
}
let httpResponse = try httpResponse(errorCode: "my.protocoltests.restjson#ComplexError:http://my.fake.com")

let greetingWithErrorsError = try await GreetingWithErrorsError.httpError(from:)(httpResponse)

Expand All @@ -47,16 +34,35 @@ class RestJSONErrorTests: HttpResponseTestBase {
}
}

func testSanitizeErrorName() {
let errorNames = [
private func httpResponse(errorCode: String) throws -> HTTPResponse {
guard let response = buildHttpResponse(
code: 400,
headers: [
"Content-Type": "application/json",
"X-Header": "Header",
"X-Amzn-Errortype": errorCode,
],
content: ByteStream.data(Data("{\"TopLevel\": \"Top level\"}".utf8))
) else {
throw TestError("Something is wrong with the created http response")
}
return response
}

func testSanitizeErrorName() async throws {
let errorCodes = [
"FooError",
" FooError ",
"FooError:http://my.fake.com/",
"my.protocoltests.restjson#FooError",
"my.protocoltests.restjson#FooError:http://my.fake.com"
"FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/",
"aws.protocoltests.restjson#FooError",
"aws.protocoltests.restjson#FooError:http://internal.amazon.com/coral/com.amazon.coral.validate/"
]

for errorName in errorNames {
XCTAssertEqual(sanitizeErrorType(errorName), "FooError")
for errorCode in errorCodes {
let httpResponse = try httpResponse(errorCode: errorCode)
let reader = try await Reader.from(data: httpResponse.body.readData() ?? Data())
let restJSONError = try RestJSONError(httpResponse: httpResponse, responseReader: reader, noErrorWrapping: true)
XCTAssertEqual(restJSONError.code, "FooError", "Error code '\(errorCode)' was not sanitized correctly, result was '\(restJSONError.code)'")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

struct TestError: Error {
let description: String

init(_ description: String) { self.description = description }
}

0 comments on commit 17d6f19

Please sign in to comment.