-
Notifications
You must be signed in to change notification settings - Fork 193
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move converters from constraint violations into
ValidationException
…
… to decorators This allows "easily" converting to other custom validation exception shapes by implementing a decorator. As a simple example, this PR adds a `CustomValidationExceptionWithReasonDecorator` decorator that is able to convert into a shape that is very similar to `smithy.framework#ValidationException`, but that has an additional `reason` field. The decorator can be enabled via the newly added `experimentalCustomValidationExceptionWithReasonPleaseDoNotUse` codegen config flag. This effectively provides a way for users to use custom validation exceptions without having to wait for the full implementation of #2053, provided they're interested enough to write a decorator in a JVM language. This mechanism is _experimental_ and will be removed once full support for custom validation exceptions as described in #2053 lands, hence why the configuration key is strongly worded in this respect. This commit also ports the mechanism to run codegen integration tests within Kotlin unit tests for client SDKs to the server. See #1956 for details. The custom validation exception decorator is tested this way.
- Loading branch information
1 parent
7bf9251
commit aa4eebc
Showing
51 changed files
with
1,279 additions
and
362 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
...otlin/software/amazon/smithy/rust/codegen/client/testutil/ClientCodegenIntegrationTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.rust.codegen.client.testutil | ||
|
||
import software.amazon.smithy.build.PluginContext | ||
import software.amazon.smithy.build.SmithyBuildPlugin | ||
import software.amazon.smithy.model.Model | ||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext | ||
import software.amazon.smithy.rust.codegen.client.smithy.RustClientCodegenPlugin | ||
import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator | ||
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate | ||
import software.amazon.smithy.rust.codegen.core.testutil.IntegrationTestParams | ||
import software.amazon.smithy.rust.codegen.core.testutil.codegenIntegrationTest | ||
import java.nio.file.Path | ||
|
||
fun clientIntegrationTest( | ||
model: Model, | ||
params: IntegrationTestParams = IntegrationTestParams(), | ||
additionalDecorators: List<ClientCodegenDecorator> = listOf(), | ||
test: (ClientCodegenContext, RustCrate) -> Unit = { _, _ -> }, | ||
): Path { | ||
fun invokeRustCodegenPlugin(ctx: PluginContext) { | ||
val codegenDecorator = object : ClientCodegenDecorator { | ||
override val name: String = "Add tests" | ||
override val order: Byte = 0 | ||
|
||
override fun classpathDiscoverable(): Boolean = false | ||
|
||
override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { | ||
test(codegenContext, rustCrate) | ||
} | ||
} | ||
RustClientCodegenPlugin().executeWithDecorator(ctx, codegenDecorator, *additionalDecorators.toTypedArray()) | ||
} | ||
return codegenIntegrationTest(model, params, invokePlugin = ::invokeRustCodegenPlugin) | ||
} | ||
|
||
/** | ||
* A `SmithyBuildPlugin` that accepts an additional decorator. | ||
* | ||
* This exists to allow tests to easily customize the _real_ build without needing to list out customizations | ||
* or attempt to manually discover them from the path. | ||
*/ | ||
abstract class ClientDecoratableBuildPlugin : SmithyBuildPlugin { | ||
abstract fun executeWithDecorator( | ||
context: PluginContext, | ||
vararg decorator: ClientCodegenDecorator, | ||
) | ||
|
||
override fun execute(context: PluginContext) { | ||
executeWithDecorator(context) | ||
} | ||
} |
103 changes: 0 additions & 103 deletions
103
...main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/CodegenIntegrationTest.kt
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
codegen-core/common-test-models/custom-validation-exceptions-experimental.smithy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
$version: "2.0" | ||
|
||
namespace com.amazonaws.constraints | ||
|
||
use aws.protocols#restJson1 | ||
|
||
enum ValidationExceptionFieldReason { | ||
LENGTH_NOT_VALID = "LengthNotValid" | ||
PATTERN_NOT_VALID = "PatternNotValid" | ||
SYNTAX_NOT_VALID = "SyntaxNotValid" | ||
VALUE_NOT_VALID = "ValueNotValid" | ||
OTHER = "Other" | ||
} | ||
|
||
/// Stores information about a field passed inside a request that resulted in an exception. | ||
structure ValidationExceptionField { | ||
/// The field name. | ||
@required | ||
Name: String | ||
|
||
@required | ||
Reason: ValidationExceptionFieldReason | ||
|
||
/// Message describing why the field failed validation. | ||
@required | ||
Message: String | ||
} | ||
|
||
/// A list of fields. | ||
list ValidationExceptionFieldList { | ||
member: ValidationExceptionField | ||
} | ||
|
||
enum ValidationExceptionReason { | ||
FIELD_VALIDATION_FAILED = "FieldValidationFailed" | ||
UNKNOWN_OPERATION = "UnknownOperation" | ||
CANNOT_PARSE = "CannotParse" | ||
OTHER = "Other" | ||
} | ||
|
||
/// The input fails to satisfy the constraints specified by an AWS service. | ||
@error("client") | ||
@httpError(400) | ||
structure ValidationException { | ||
/// Description of the error. | ||
@required | ||
Message: String | ||
|
||
/// Reason the request failed validation. | ||
@required | ||
Reason: ValidationExceptionReason | ||
|
||
/// The field that caused the error, if applicable. If more than one field | ||
/// caused the error, pick one and elaborate in the message. | ||
Fields: ValidationExceptionFieldList | ||
} | ||
|
||
/// A service to test (experimental support for) custom validation exceptions. | ||
@restJson1 | ||
@title("CustomValidationExceptionsExperimental") | ||
service CustomValidationExceptionsExperimental { | ||
operations: [ | ||
ConstrainedShapesOperation, | ||
], | ||
} | ||
|
||
@http(uri: "/constrained-shapes-operation", method: "POST") | ||
operation ConstrainedShapesOperation { | ||
input: ConstrainedShapesOperationInputOutput, | ||
output: ConstrainedShapesOperationInputOutput, | ||
errors: [ValidationException] | ||
} | ||
|
||
structure ConstrainedShapesOperationInputOutput { | ||
@required | ||
lengthString: LengthString, | ||
} | ||
|
||
@length(min: 2, max: 69) | ||
string LengthString |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
...c/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/CodegenIntegrationTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package software.amazon.smithy.rust.codegen.core.testutil | ||
|
||
import software.amazon.smithy.build.PluginContext | ||
import software.amazon.smithy.model.Model | ||
import software.amazon.smithy.model.node.ObjectNode | ||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig | ||
import software.amazon.smithy.rust.codegen.core.util.runCommand | ||
import java.io.File | ||
import java.nio.file.Path | ||
|
||
/** | ||
* A helper class holding common data with defaults that is threaded through several functions, to make their | ||
* signatures shorter. | ||
*/ | ||
data class IntegrationTestParams( | ||
val addModuleToEventStreamAllowList: Boolean = false, | ||
val service: String? = null, | ||
val runtimeConfig: RuntimeConfig? = null, | ||
val additionalSettings: ObjectNode = ObjectNode.builder().build(), | ||
val overrideTestDir: File? = null, | ||
val command: ((Path) -> Unit)? = null, | ||
) | ||
|
||
/** | ||
* Run cargo test on a true, end-to-end, codegen product of a given model. | ||
*/ | ||
fun codegenIntegrationTest(model: Model, params: IntegrationTestParams, invokePlugin: (PluginContext) -> Unit): Path { | ||
val (ctx, testDir) = generatePluginContext( | ||
model, | ||
params.additionalSettings, | ||
params.addModuleToEventStreamAllowList, | ||
params.service, | ||
params.runtimeConfig, | ||
params.overrideTestDir, | ||
) | ||
invokePlugin(ctx) | ||
ctx.fileManifest.printGeneratedFiles() | ||
params.command?.invoke(testDir) ?: "cargo test".runCommand(testDir, environment = mapOf("RUSTFLAGS" to "-D warnings")) | ||
return testDir | ||
} |
Oops, something went wrong.