mirror of https://github.com/smithy-lang/smithy-rs
Implement `StdError::source()` for Error enum (#2564)
## Motivation and Context This is an attempt at fixing https://github.com/awslabs/aws-sdk-rust/issues/784. The service-level `Error` enum implements `std::error::Error` but does not implement its `source()` method. This means that an error library like `anyhow` or `eyre` won't be able to display the root cause of an error, which is especially problematic for the `Unhandled` variant. ## Description I modified `ServiceErrorGenerator` in the `codegen-client` crate and replaced the line that output `impl std::error::Error for Error {}` with an impl block that implements the `source()` method by delegating to the inner error structure. ## Testing I've added a simple unit test to `ServiceErrorGeneratorTest`. ## Checklist <!--- If a checkbox below is not applicable, then please DELETE it rather than leaving it unchecked --> - [x] I have updated `CHANGELOG.next.toml` if I made changes to the smithy-rs codegen or runtime crates - [x] I have updated `CHANGELOG.next.toml` if I made changes to the AWS SDK, generated SDK code, or SDK runtime crates ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
This commit is contained in:
parent
35f2f27a83
commit
fc63800f6a
|
@ -11,6 +11,18 @@
|
|||
# meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client | server | all"}
|
||||
# author = "rcoh"
|
||||
|
||||
[[aws-sdk-rust]]
|
||||
message = "Implement std::error::Error#source() properly for the service meta Error enum"
|
||||
references = ["aws-sdk-rust#784"]
|
||||
meta = { "breaking" = false, "tada" = false, "bug" = false }
|
||||
author = "abusch"
|
||||
|
||||
[[smithy-rs]]
|
||||
message = "Implement std::error::Error#source() properly for the service meta Error enum"
|
||||
references = ["aws-sdk-rust#784"]
|
||||
meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client"}
|
||||
author = "abusch"
|
||||
|
||||
[[aws-sdk-rust]]
|
||||
message = "The outputs for event stream operations (for example, S3's SelectObjectContent) now implement the `Sync` auto-trait."
|
||||
references = ["smithy-rs#2496"]
|
||||
|
|
|
@ -80,7 +80,16 @@ class ServiceErrorGenerator(
|
|||
errors.map { it.id },
|
||||
)
|
||||
}
|
||||
rust("impl #T for Error {}", RuntimeType.StdError)
|
||||
rustBlock("impl #T for Error", RuntimeType.StdError) {
|
||||
rustBlock("fn source(&self) -> std::option::Option<&(dyn #T + 'static)>", RuntimeType.StdError) {
|
||||
rustBlock("match self") {
|
||||
allErrors.forEach {
|
||||
rust("Error::${symbolProvider.toSymbol(it).name}(inner) => inner.source(),")
|
||||
}
|
||||
rust("Error::Unhandled(inner) => inner.source()")
|
||||
}
|
||||
}
|
||||
}
|
||||
writeCustomizations(customizations, ErrorSection.ServiceErrorAdditionalTraitImpls(allErrors))
|
||||
}
|
||||
crate.lib { rust("pub use error_meta::Error;") }
|
||||
|
|
|
@ -6,45 +6,48 @@
|
|||
package software.amazon.smithy.rust.codegen.client.smithy.generators.error
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import software.amazon.smithy.model.shapes.StructureShape
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.integrationTest
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.unitTest
|
||||
import software.amazon.smithy.rust.codegen.core.util.lookup
|
||||
|
||||
internal class ServiceErrorGeneratorTest {
|
||||
private val model = """
|
||||
namespace com.example
|
||||
|
||||
use aws.protocols#restJson1
|
||||
|
||||
@restJson1
|
||||
service HelloService {
|
||||
operations: [SayHello],
|
||||
version: "1"
|
||||
}
|
||||
|
||||
@http(uri: "/", method: "POST")
|
||||
operation SayHello {
|
||||
input: EmptyStruct,
|
||||
output: EmptyStruct,
|
||||
errors: [SorryBusy, CanYouRepeatThat, MeDeprecated]
|
||||
}
|
||||
|
||||
structure EmptyStruct { }
|
||||
|
||||
@error("server")
|
||||
structure SorryBusy { }
|
||||
|
||||
@error("client")
|
||||
structure CanYouRepeatThat { }
|
||||
|
||||
@error("client")
|
||||
@deprecated
|
||||
structure MeDeprecated { }
|
||||
""".asSmithyModel()
|
||||
|
||||
@Test
|
||||
fun `top level errors are send + sync`() {
|
||||
val model = """
|
||||
namespace com.example
|
||||
|
||||
use aws.protocols#restJson1
|
||||
|
||||
@restJson1
|
||||
service HelloService {
|
||||
operations: [SayHello],
|
||||
version: "1"
|
||||
}
|
||||
|
||||
@http(uri: "/", method: "POST")
|
||||
operation SayHello {
|
||||
input: EmptyStruct,
|
||||
output: EmptyStruct,
|
||||
errors: [SorryBusy, CanYouRepeatThat, MeDeprecated]
|
||||
}
|
||||
|
||||
structure EmptyStruct { }
|
||||
|
||||
@error("server")
|
||||
structure SorryBusy { }
|
||||
|
||||
@error("client")
|
||||
structure CanYouRepeatThat { }
|
||||
|
||||
@error("client")
|
||||
@deprecated
|
||||
structure MeDeprecated { }
|
||||
""".asSmithyModel()
|
||||
|
||||
clientIntegrationTest(model) { codegenContext, rustCrate ->
|
||||
rustCrate.integrationTest("validate_errors") {
|
||||
rust(
|
||||
|
@ -60,4 +63,25 @@ internal class ServiceErrorGeneratorTest {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `generates combined error enums`() {
|
||||
clientIntegrationTest(model) { _, rustCrate ->
|
||||
rustCrate.moduleFor(model.lookup<StructureShape>("com.example#CanYouRepeatThat")) {
|
||||
unitTest(
|
||||
name = "generates_combined_error_enums",
|
||||
test = """
|
||||
use std::error::Error as StdError;
|
||||
use crate::Error;
|
||||
use crate::operation::say_hello::SayHelloError;
|
||||
|
||||
// Unhandled variants properly delegate source.
|
||||
let error = Error::from(SayHelloError::unhandled("some other error"));
|
||||
let source = error.source().expect("source should not be None");
|
||||
assert_eq!(format!("{}", source), "some other error");
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue