Skip to content

Commit ef18a81

Browse files
authored
fix: compare path in protocol tests (#358)
1 parent 98e4305 commit ef18a81

File tree

18 files changed

+297
-87
lines changed

18 files changed

+297
-87
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
public extension Float {
7+
func encoded() -> String {
8+
if self.isNaN {
9+
return "NaN"
10+
} else if self.isInfinite {
11+
let signed = self < 0 ? "-" : ""
12+
return "\(signed)Infinity"
13+
} else {
14+
return "\(self)"
15+
}
16+
}
17+
}
18+
19+
public extension Double {
20+
func encoded() -> String {
21+
if self.isNaN {
22+
return "NaN"
23+
} else if self.isInfinite {
24+
let signed = self < 0 ? "-" : ""
25+
return "\(signed)Infinity"
26+
} else {
27+
return "\(self)"
28+
}
29+
}
30+
}
31+
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
import XCTest
7+
@testable import ClientRuntime
8+
9+
class NumberExtensionsTests: XCTestCase {
10+
func testEncodeDouble() {
11+
let regularDouble: Double = 6.0
12+
XCTAssertEqual(regularDouble.encoded(), "6.0")
13+
}
14+
15+
func testEncodeDoubleInteger() {
16+
let regularIntAsDouble: Double = 6
17+
XCTAssertEqual(regularIntAsDouble.encoded(), "6.0")
18+
}
19+
20+
func testEncodeDoubleNan() {
21+
let nanDouble = Double.nan
22+
XCTAssertEqual(nanDouble.encoded(), "NaN")
23+
}
24+
25+
func testEncodeDoubleInfinity() {
26+
let doubleInfinity = Double.infinity
27+
XCTAssertEqual(doubleInfinity.encoded(), "Infinity")
28+
}
29+
30+
func testEncodeDoubleInfinityNegative() {
31+
let doubleInfinityNegative = -Double.infinity
32+
XCTAssertEqual(doubleInfinityNegative.encoded(), "-Infinity")
33+
}
34+
35+
func testEncodeFloat() {
36+
let regularFloat: Float = 6.0
37+
XCTAssertEqual(regularFloat.encoded(), "6.0")
38+
}
39+
40+
func testEncodeFloatInteger() {
41+
let regularFloatAsInt: Float = 6
42+
XCTAssertEqual(regularFloatAsInt.encoded(), "6.0")
43+
}
44+
45+
func testEncodeFloatNan() {
46+
let nanFloat = Float.nan
47+
XCTAssertEqual(nanFloat.encoded(), "NaN")
48+
}
49+
50+
func testEncodeFloatInfinity() {
51+
let floatInfinity = Float.infinity
52+
XCTAssertEqual(floatInfinity.encoded(), "Infinity")
53+
}
54+
55+
func testEncodeFloatInfinityNegative() {
56+
let floatInfinityNegative = -Float.infinity
57+
XCTAssertEqual(floatInfinityNegative.encoded(), "-Infinity")
58+
}
59+
}

Packages/SmithyTestUtil/Sources/RequestTestUtil/HttpRequestTestBase.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ open class HttpRequestTestBase: XCTestCase {
3535
host: String) -> ExpectedSdkHttpRequest {
3636
let builder = ExpectedSdkHttpRequestBuilder()
3737

38+
builder.withPath(path)
39+
3840
if let queryParams = queryParams {
3941
addQueryItems(queryParams: queryParams, builder: builder)
4042
}
@@ -180,6 +182,8 @@ open class HttpRequestTestBase: XCTestCase {
180182

181183
assertQueryItems(expected.queryItems, actual.queryItems)
182184

185+
XCTAssertEqual(expected.endpoint.path, actual.endpoint.path)
186+
183187
assertForbiddenQueryItems(expected.forbiddenQueryItems, actual.queryItems)
184188

185189
assertRequiredQueryItems(expected.requiredQueryItems, actual.queryItems)

Packages/SmithyTestUtil/Sources/ResponseTestUtil/HttpResponseTestBase.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ open class HttpResponseTestBase: XCTestCase {
1818
public func buildHttpResponse(code: Int,
1919
path: String? = nil,
2020
headers: [String: String]? = nil,
21-
content: HttpBody = HttpBody.empty,
22-
host: String) -> HttpResponse? {
21+
content: HttpBody = HttpBody.empty) -> HttpResponse? {
2322

2423
var internalHeaders: Headers = Headers()
2524
if let headers = headers {

Packages/SmithyTestUtil/Tests/SmithyTestUtilTests/ResponseTestUtilTests/HttpResponseTestBaseTests.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ import XCTest
99
import AwsCommonRuntimeKit
1010

1111
class HttpResponseTestBaseTests: HttpResponseTestBase {
12-
let host = "myapi.host.com"
1312

1413
func testBuildHttpResponse() {
1514
let statusCode = 200
1615
let headers = ["headerKey1": "headerValue1", "headerKey2": "headerValue2"]
1716
let bodyData = "{\"greeting\": \"Hello There\"}".data(using: .utf8)!
1817
let content = HttpBody.data(bodyData)
1918

20-
guard let httpResponse = buildHttpResponse(code: statusCode, headers: headers, content: content, host: host) else {
19+
guard let httpResponse = buildHttpResponse(code: statusCode, headers: headers, content: content) else {
2120
XCTFail("Failed to build Http Response")
2221
return
2322
}

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpBindingProtocolGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fun formatHeaderOrQueryValue(
8888
return when (val shape = ctx.model.expectShape(memberShape.target)) {
8989
is TimestampShape -> {
9090
val timestampFormat = bindingIndex.determineTimestampFormat(memberShape, location, defaultTimestampFormat)
91-
Pair(ProtocolGenerator.getFormattedDateString(timestampFormat, memberName, isInHeaderOrQuery = true), false)
91+
Pair(ProtocolGenerator.getFormattedDateString(timestampFormat, memberName, roundEpoch = true), false)
9292
}
9393
is BlobShape -> {
9494
Pair("try $memberName.base64EncodedString()", true)

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpProtocolTestGenerator.kt

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ import software.amazon.smithy.protocoltests.traits.HttpRequestTestsTrait
1515
import software.amazon.smithy.protocoltests.traits.HttpResponseTestsTrait
1616
import software.amazon.smithy.swift.codegen.SwiftDependency
1717
import software.amazon.smithy.swift.codegen.getOrNull
18+
import software.amazon.smithy.swift.codegen.integration.middlewares.RequestTestEndpointResolverMiddleware
19+
import software.amazon.smithy.swift.codegen.middleware.MiddlewareStep
1820
import software.amazon.smithy.swift.codegen.middleware.OperationMiddleware
1921
import software.amazon.smithy.swift.codegen.model.capitalizedName
22+
import software.amazon.smithy.swift.codegen.model.hasTrait
2023
import java.util.TreeSet
2124
import java.util.logging.Logger
2225

@@ -42,16 +45,39 @@ class HttpProtocolTestGenerator(
4245
fun generateProtocolTests(): Int {
4346
val topDownIndex: TopDownIndex = TopDownIndex.of(ctx.model)
4447
val serviceSymbol = ctx.symbolProvider.toSymbol(ctx.service)
48+
val operationMiddleware = updateRequestTestMiddleware()
4549
var numTests = 0
4650
for (operation in TreeSet(topDownIndex.getContainedOperations(ctx.service).filterNot(::serverOnly))) {
47-
numTests += renderRequestTests(operation, serviceSymbol)
51+
numTests += renderRequestTests(operation, serviceSymbol, operationMiddleware)
4852
numTests += renderResponseTests(operation, serviceSymbol)
4953
numTests += renderErrorTestCases(operation, serviceSymbol)
5054
}
5155
return numTests
5256
}
5357

54-
private fun renderRequestTests(operation: OperationShape, serviceSymbol: Symbol): Int {
58+
private fun updateRequestTestMiddleware(): OperationMiddleware {
59+
val topDownIndex: TopDownIndex = TopDownIndex.of(ctx.model)
60+
val requestTestOperations = TreeSet(
61+
topDownIndex.getContainedOperations(ctx.service)
62+
.filter { it.hasTrait<HttpRequestTestsTrait>() }
63+
.filterNot(::serverOnly)
64+
)
65+
val cloned = operationMiddleware.clone()
66+
67+
for (operation in requestTestOperations) {
68+
cloned.removeMiddleware(operation, MiddlewareStep.BUILDSTEP, "EndpointResolverMiddleware")
69+
cloned.removeMiddleware(operation, MiddlewareStep.BUILDSTEP, "UserAgentMiddleware")
70+
cloned.removeMiddleware(operation, MiddlewareStep.FINALIZESTEP, "RetryMiddleware")
71+
cloned.removeMiddleware(operation, MiddlewareStep.FINALIZESTEP, "AWSSigningMiddleware") // causes tests to halt :(
72+
cloned.removeMiddleware(operation, MiddlewareStep.DESERIALIZESTEP, "DeserializeMiddleware")
73+
cloned.removeMiddleware(operation, MiddlewareStep.DESERIALIZESTEP, "LoggingMiddleware")
74+
75+
cloned.appendMiddleware(operation, RequestTestEndpointResolverMiddleware(ctx.model, ctx.symbolProvider))
76+
}
77+
return cloned
78+
}
79+
80+
private fun renderRequestTests(operation: OperationShape, serviceSymbol: Symbol, operationMiddleware: OperationMiddleware): Int {
5581
val tempTestCases = operation.getTrait(HttpRequestTestsTrait::class.java)
5682
.getOrNull()
5783
?.getTestCasesFor(AppliesTo.CLIENT)

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpProtocolUnitTestGenerator.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ protected constructor(builder: Builder<T>) {
3737
fun renderTestClass(testClassName: String) {
3838
writer.write("")
3939
.openBlock("class $testClassName: $baseTestClassName {")
40-
// TODO:: Replace host appropriately
41-
.write("let host = \"my-api.us-east-2.amazonaws.com\"")
4240
.call {
4341
for (test in testCases) {
4442
renderTestFunction(test)

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpProtocolUnitTestRequestGenerator.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ open class HttpProtocolUnitTestRequestGenerator protected constructor(builder: B
3030
}
3131

3232
private fun renderExpectedBlock(test: HttpRequestTestCase) {
33+
writer.write("let host = \$S", test.host)
3334
writer.openBlock("let expected = buildExpectedHttpRequest(")
3435
.write("method: .${test.method.toLowerCase()},")
3536
.write("path: \$S,", test.uri)
@@ -86,6 +87,7 @@ open class HttpProtocolUnitTestRequestGenerator protected constructor(builder: B
8687
val hasIdempotencyTokenTrait = idempotentMember != null
8788
writer.swiftFunctionParameterIndent {
8889
writer.write(" .withEncoder(value: encoder)")
90+
writer.write(" .withHost(value: host)")
8991
if (hasIdempotencyTokenTrait) {
9092
writer.write(" .withIdempotencyTokenGenerator(value: QueryIdempotencyTestTokenGenerator())")
9193
}
@@ -94,18 +96,12 @@ open class HttpProtocolUnitTestRequestGenerator protected constructor(builder: B
9496
val operationStack = "operationStack"
9597
writer.write("var $operationStack = OperationStack<$inputSymbol, $outputSymbol, $outputErrorName>(id: \"${test.id}\")")
9698

97-
operationMiddleware.removeMiddleware(operation, MiddlewareStep.BUILDSTEP, "EndpointResolverMiddleware")
98-
operationMiddleware.removeMiddleware(operation, MiddlewareStep.BUILDSTEP, "UserAgentMiddleware")
99-
operationMiddleware.removeMiddleware(operation, MiddlewareStep.FINALIZESTEP, "RetryMiddleware")
100-
operationMiddleware.removeMiddleware(operation, MiddlewareStep.FINALIZESTEP, "AWSSigningMiddleware") // causes tests to halt :(
101-
operationMiddleware.removeMiddleware(operation, MiddlewareStep.DESERIALIZESTEP, "DeserializeMiddleware")
102-
operationMiddleware.removeMiddleware(operation, MiddlewareStep.DESERIALIZESTEP, "LoggingMiddleware")
103-
10499
operationMiddleware.renderMiddleware(writer, operation, operationStack, MiddlewareStep.INITIALIZESTEP)
105100
operationMiddleware.renderMiddleware(writer, operation, operationStack, MiddlewareStep.BUILDSTEP)
106101
operationMiddleware.renderMiddleware(writer, operation, operationStack, MiddlewareStep.SERIALIZESTEP)
107102
operationMiddleware.renderMiddleware(writer, operation, operationStack, MiddlewareStep.FINALIZESTEP)
108103
operationMiddleware.renderMiddleware(writer, operation, operationStack, MiddlewareStep.DESERIALIZESTEP)
104+
109105
renderMockDeserializeMiddleware(test, operationStack, inputSymbol, outputSymbol, outputErrorName, inputShape)
110106

111107
writer.openBlock("_ = operationStack.handleMiddleware(context: context, input: input, next: MockHandler(){ (context, request) in ", "})") {

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpProtocolUnitTestResponseGenerator.kt

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,7 @@ open class HttpProtocolUnitTestResponseGenerator protected constructor(builder:
4848

4949
protected fun renderBuildHttpResponse(test: HttpResponseTestCase) {
5050
writer.openBlock("guard let httpResponse = buildHttpResponse(", ") else {") {
51-
writer.write("code: ${test.code},")
52-
renderHeadersInHttpResponse(test)
53-
test.body.ifPresent { body ->
54-
if (body.isNotBlank() && body.isNotEmpty()) {
55-
writer.write(
56-
"content: HttpBody.stream(ByteStream.from(data: \"\"\"\n\$L\n\"\"\".data(using: .utf8)!)),",
57-
body.replace(".000", "")
58-
)
59-
}
60-
}
61-
writer.write("host: host")
51+
renderBuildHttpResponseParams(test)
6252
}
6353
writer.indent()
6454
writer.write("XCTFail(\"Something is wrong with the created http response\")")
@@ -67,6 +57,28 @@ open class HttpProtocolUnitTestResponseGenerator protected constructor(builder:
6757
writer.write("}")
6858
}
6959

60+
private fun renderBuildHttpResponseParams(test: HttpResponseTestCase) {
61+
val params = mutableListOf<String>()
62+
params.add("code: ${test.code}")
63+
if (test.headers.isNotEmpty()) {
64+
params.add(renderBuildHttpResponseHeaderParams(test))
65+
}
66+
test.body.ifPresent { body ->
67+
if (body.isNotBlank() && body.isNotEmpty()) {
68+
params.add("content: HttpBody.stream(ByteStream.from(data: \"\"\"\n${body.replace(".000", "")}\n\"\"\".data(using: .utf8)!))")
69+
}
70+
}
71+
writer.write(params.joinToString(",\n"))
72+
}
73+
74+
private fun renderBuildHttpResponseHeaderParams(test: HttpResponseTestCase): String {
75+
var headers = mutableListOf<String>()
76+
for (hdr in test.headers.entries) {
77+
headers.add(" \"${hdr.key}\": \"${hdr.value}\"")
78+
}
79+
return "headers: [\n${headers.joinToString(",\n")}\n]"
80+
}
81+
7082
protected fun needsResponseDecoder(test: HttpResponseTestCase): Boolean {
7183
var needsDecoder = false
7284
test.body.ifPresent { body ->
@@ -107,19 +119,6 @@ open class HttpProtocolUnitTestResponseGenerator protected constructor(builder:
107119
renderMemberAssertions(writer, test, members, model, symbolProvider, "expected", "actual")
108120
}
109121

110-
private fun renderHeadersInHttpResponse(test: HttpResponseTestCase) {
111-
if (test.headers.isNotEmpty()) {
112-
writer.openBlock("headers: [")
113-
.call {
114-
for ((idx, hdr) in test.headers.entries.withIndex()) {
115-
val suffix = if (idx < test.headers.size - 1) "," else ""
116-
writer.write("\$S: \$S$suffix", hdr.key, hdr.value)
117-
}
118-
}
119-
.closeBlock("],")
120-
}
121-
}
122-
123122
open class Builder : HttpProtocolUnitTestGenerator.Builder<HttpResponseTestCase>() {
124123
override fun build(): HttpProtocolUnitTestGenerator<HttpResponseTestCase> {
125124
return HttpProtocolUnitTestResponseGenerator(this)

0 commit comments

Comments
 (0)