Skip to content

Commit

Permalink
feat: Add support for OperationContextParams (#1680)
Browse files Browse the repository at this point in the history
* Add OperationContextParams handling to endpoint params construction codegen.

* Update endpoint param and endpoint middleware codegen tests & test smithy model.

* Add the Smithy model provided by SEP for testing string array endpoint params.

* Add runtime test for the endpoint resolver generated for mock service, using existing protocol test structure, similar to how waiters used the existing protocol structure, except with endpoint the test gets generated as well.

* Tweak endpoint test generator to correctly generate endpoint params initializer for string array values.

* Add default value handling for operation context params value codegen.

* Fix ktlint

---------

Co-authored-by: Sichan Yoo <[email protected]>
  • Loading branch information
sichanyoo and Sichan Yoo authored Aug 21, 2024
1 parent ee75889 commit f135974
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 12 deletions.
1 change: 1 addition & 0 deletions codegen/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ func addProtocolTests() {
.init(name: "EventStream", sourcePath: "\(baseDirLocal)/EventStream", buildOnly: true),
.init(name: "RPCEventStream", sourcePath: "\(baseDirLocal)/RPCEventStream", buildOnly: true),
.init(name: "Waiters", sourcePath: "\(baseDirLocal)/Waiters", testPath: "../codegen/protocol-test-codegen-local/Tests"),
.init(name: "StringArrayEndpointParam", sourcePath: "\(baseDirLocal)/StringArrayEndpointParam")
]
for protocolTest in protocolTests {
let target = Target.target(
Expand Down
4 changes: 4 additions & 0 deletions codegen/protocol-test-codegen-local/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ val codegenTests = listOf(
CodegenTest(
"aws.protocoltests.eventstream#RPCTestService",
"RPCEventStream"
),
CodegenTest(
"aws.endpointtests.stringarray#EndpointStringArray",
"StringArrayEndpointParam"
)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
$version: "2.0"

namespace aws.endpointtests.stringarray

use smithy.rules#endpointRuleSet
use smithy.rules#endpointTests
use smithy.rules#staticContextParams
use smithy.rules#operationContextParams
use aws.api#service
use aws.protocols#restJson1

@endpointRuleSet({
version: "1.0",
parameters: {
stringArrayParam: {
type: "stringArray",
required: true,
default: ["defaultValue1", "defaultValue2"],
documentation: "docs"
}
},
rules: [
{
"documentation": "Template first array value into URI if set",
"conditions": [
{
"fn": "getAttr",
"argv": [
{
"ref": "stringArrayParam"
},
"[0]"
],
"assign": "arrayValue"
}
],
"endpoint": {
"url": "https://example.com/{arrayValue}"
},
"type": "endpoint"
},
{
"conditions": [],
"documentation": "error fallthrough",
"error": "no array values set",
"type": "error"
}
]
})
@endpointTests({
"version": "1.0",
"testCases": [
{
"documentation": "Default array values used"
"params": {}
"expect": {
"endpoint": {
"url": "https://example.com/defaultValue1"
}
},
"operationInputs": [
{
"operationName": "NoBindingsOperation",
}
]
},
{
"documentation": "Empty array",
"params": {
"stringArrayParam": []
}
"expect": {
"error": "no array values set"
},
"operationInputs": [
{
"operationName": "EmptyStaticContextOperation",
}
]
},
{
"documentation": "Static value",
"params": {
"stringArrayParam": ["staticValue1"]
}
"expect": {
"endpoint": {
"url": "https://example.com/staticValue1"
}
},
"operationInputs": [
{
"operationName": "StaticContextOperation",
}
]
},
{
"documentation": "bound value from input",
"params": {
"stringArrayParam": ["key1"]
}
"expect": {
"endpoint": {
"url": "https://example.com/key1"
}
},
"operationInputs": [
{
"operationName": "ListOfObjectsOperation",
"operationParams": {
"nested": {
"listOfObjects": [{"key": "key1"}]
}
},
},
{
"operationName": "MapOperation",
"operationParams": {
"map": {
"key1": "value1"
}
}
}
]
}
]
})
@service(sdkId: "EndpointStringArray")
@restJson1
service EndpointStringArray {
version: "2022-01-01",
operations: [
NoBindingsOperation,
EmptyStaticContextOperation,
StaticContextOperation,
ListOfObjectsOperation,
MapOperation
]
}

@http(uri: "/1", method: "POST")
operation NoBindingsOperation {
input:= {}
}

@staticContextParams(
"stringArrayParam": {value: []}
)
@http(uri: "/2", method: "POST")
operation EmptyStaticContextOperation {
input := {}
}

@staticContextParams(
"stringArrayParam": {value: ["staticValue1"]}
)
@http(uri: "/3", method: "POST")
operation StaticContextOperation {
input := {}
}

@operationContextParams(
"stringArrayParam": {path: "nested.listOfObjects[*].key"}
)
@http(uri: "/4", method: "POST")
operation ListOfObjectsOperation {
input:= {
nested: Nested
}
}

@operationContextParams(
"stringArrayParam": {path: "keys(map)"}
)
@http(uri: "/5", method: "POST")
operation MapOperation {
input:= {
map: Map
}
}

structure Nested {
listOfObjects: ListOfObjects
}

list ListOfObjects {
member: ObjectMember
}

structure ObjectMember {
key: String,
}

map Map {
key: String,
value: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class EndpointTestGenerator(
val value = Value.fromNode(pair.second)
writer.call {
generateValue(
writer, value, if (idx < applicableParams.count() - 1) "," else ""
writer, value, if (idx < applicableParams.count() - 1) "," else "", false
)
}
}
Expand Down Expand Up @@ -127,7 +127,7 @@ class EndpointTestGenerator(
val value = Value.fromNode(second)
writer.writeInline("\$S: ", first)
writer.call {
generateValue(writer, value, if (idx < properties.values.count() - 1) "," else "")
generateValue(writer, value, if (idx < properties.values.count() - 1) "," else "", true)
}
}
}
Expand All @@ -137,7 +137,7 @@ class EndpointTestGenerator(
/**
* Recursively traverse the value and render a JSON string literal.
*/
private fun generateValue(writer: SwiftWriter, value: Value, delimeter: String) {
private fun generateValue(writer: SwiftWriter, value: Value, delimeter: String, castToAnyHashable: Boolean) {
when (value) {
is StringValue -> {
writer.write("\$S$delimeter", value.toString())
Expand All @@ -156,10 +156,11 @@ class EndpointTestGenerator(
}

is ArrayValue -> {
writer.openBlock("[", "] as [AnyHashable]$delimeter") {
val castStmt = if (castToAnyHashable) " as [AnyHashable]$delimeter" else ""
writer.openBlock("[", "]$castStmt") {
value.values.forEachIndexed { idx, item ->
writer.call {
generateValue(writer, item, if (idx < value.values.count() - 1) "," else "")
generateValue(writer, item, if (idx < value.values.count() - 1) "," else "", castToAnyHashable)
}
}
}
Expand All @@ -173,7 +174,7 @@ class EndpointTestGenerator(
value.value.map { it.key to it.value }.forEachIndexed { idx, (first, second) ->
writer.writeInline("\$S: ", first.name)
writer.call {
generateValue(writer, second, if (idx < value.value.count() - 1) "," else "")
generateValue(writer, second, if (idx < value.value.count() - 1) "," else "", castToAnyHashable)
}
}
}
Expand Down
Loading

0 comments on commit f135974

Please sign in to comment.