diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 3b30f2b379..5317cd5c7b 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -227,3 +227,15 @@ match client.some_operation().send().await { references = ["smithy-rs#2398"] meta = { "breaking" = false, "tada" = true, "bug" = false } author = "ysaito1001" + +[[aws-sdk-rust]] +message = "`SdkError` variants can now be constructed for easier unit testing." +references = ["smithy-rs#2428", "smithy-rs#2208"] +meta = { "breaking" = false, "tada" = true, "bug" = false } +author = "jdisanti" + +[[smithy-rs]] +message = "`SdkError` variants can now be constructed for easier unit testing." +references = ["smithy-rs#2428", "smithy-rs#2208"] +meta = { "breaking" = false, "tada" = true, "bug" = false, "target" = "client" } +author = "jdisanti" diff --git a/rust-runtime/aws-smithy-http/src/result.rs b/rust-runtime/aws-smithy-http/src/result.rs index b00667d2c9..f11dcc2d36 100644 --- a/rust-runtime/aws-smithy-http/src/result.rs +++ b/rust-runtime/aws-smithy-http/src/result.rs @@ -32,18 +32,183 @@ pub struct SdkSuccess { pub parsed: O, } +/// Builders for `SdkError` variant context. +pub mod builders { + use super::*; + + macro_rules! source_only_error_builder { + ($errorName:ident, $builderName:ident, $sourceType:ident) => { + #[doc = concat!("Builder for [`", stringify!($errorName), "`](super::", stringify!($errorName), ").")] + #[derive(Debug, Default)] + pub struct $builderName { + source: Option<$sourceType>, + } + + impl $builderName { + #[doc = "Creates a new builder."] + pub fn new() -> Self { Default::default() } + + #[doc = "Sets the error source."] + pub fn source(mut self, source: impl Into<$sourceType>) -> Self { + self.source = Some(source.into()); + self + } + + #[doc = "Sets the error source."] + pub fn set_source(&mut self, source: Option<$sourceType>) -> &mut Self { + self.source = source; + self + } + + #[doc = "Builds the error context."] + pub fn build(self) -> $errorName { + $errorName { source: self.source.expect("source is required") } + } + } + }; + } + + source_only_error_builder!(ConstructionFailure, ConstructionFailureBuilder, BoxError); + source_only_error_builder!(TimeoutError, TimeoutErrorBuilder, BoxError); + source_only_error_builder!(DispatchFailure, DispatchFailureBuilder, ConnectorError); + + /// Builder for [`ResponseError`](super::ResponseError). + #[derive(Debug)] + pub struct ResponseErrorBuilder { + source: Option, + raw: Option, + } + + impl Default for ResponseErrorBuilder { + fn default() -> Self { + Self { + source: None, + raw: None, + } + } + } + + impl ResponseErrorBuilder { + /// Creates a new builder. + pub fn new() -> Self { + Default::default() + } + + /// Sets the error source. + pub fn source(mut self, source: impl Into) -> Self { + self.source = Some(source.into()); + self + } + + /// Sets the error source. + pub fn set_source(&mut self, source: Option) -> &mut Self { + self.source = source; + self + } + + /// Sets the raw response. + pub fn raw(mut self, raw: R) -> Self { + self.raw = Some(raw); + self + } + + /// Sets the raw response. + pub fn set_raw(&mut self, raw: Option) -> &mut Self { + self.raw = raw; + self + } + + /// Builds the error context. + pub fn build(self) -> ResponseError { + ResponseError { + source: self.source.expect("source is required"), + raw: self.raw.expect("a raw response is required"), + } + } + } + + /// Builder for [`ServiceError`](super::ServiceError). + #[derive(Debug)] + pub struct ServiceErrorBuilder { + source: Option, + raw: Option, + } + + impl Default for ServiceErrorBuilder { + fn default() -> Self { + Self { + source: None, + raw: None, + } + } + } + + impl ServiceErrorBuilder { + /// Creates a new builder. + pub fn new() -> Self { + Default::default() + } + + /// Sets the error source. + pub fn source(mut self, source: impl Into) -> Self { + self.source = Some(source.into()); + self + } + + /// Sets the error source. + pub fn set_source(&mut self, source: Option) -> &mut Self { + self.source = source; + self + } + + /// Sets the raw response. + pub fn raw(mut self, raw: R) -> Self { + self.raw = Some(raw); + self + } + + /// Sets the raw response. + pub fn set_raw(&mut self, raw: Option) -> &mut Self { + self.raw = raw; + self + } + + /// Builds the error context. + pub fn build(self) -> ServiceError { + ServiceError { + source: self.source.expect("source is required"), + raw: self.raw.expect("a raw response is required"), + } + } + } +} + /// Error context for [`SdkError::ConstructionFailure`] #[derive(Debug)] pub struct ConstructionFailure { source: BoxError, } +impl ConstructionFailure { + /// Creates a builder for this error context type. + pub fn builder() -> builders::ConstructionFailureBuilder { + builders::ConstructionFailureBuilder::new() + } +} + /// Error context for [`SdkError::TimeoutError`] #[derive(Debug)] pub struct TimeoutError { source: BoxError, } +impl TimeoutError { + /// Creates a builder for this error context type. + pub fn builder() -> builders::TimeoutErrorBuilder { + builders::TimeoutErrorBuilder::new() + } +} + /// Error context for [`SdkError::DispatchFailure`] #[derive(Debug)] pub struct DispatchFailure { @@ -51,6 +216,11 @@ pub struct DispatchFailure { } impl DispatchFailure { + /// Creates a builder for this error context type. + pub fn builder() -> builders::DispatchFailureBuilder { + builders::DispatchFailureBuilder::new() + } + /// Returns true if the error is an IO error pub fn is_io(&self) -> bool { self.source.is_io() @@ -82,6 +252,11 @@ pub struct ResponseError { } impl ResponseError { + /// Creates a builder for this error context type. + pub fn builder() -> builders::ResponseErrorBuilder { + builders::ResponseErrorBuilder::new() + } + /// Returns a reference to the raw response pub fn raw(&self) -> &R { &self.raw @@ -103,6 +278,11 @@ pub struct ServiceError { } impl ServiceError { + /// Creates a builder for this error context type. + pub fn builder() -> builders::ServiceErrorBuilder { + builders::ServiceErrorBuilder::new() + } + /// Returns the underlying error of type `E` pub fn err(&self) -> &E { &self.source