Unverified Commit 7ce80320 authored by John DiSanti's avatar John DiSanti Committed by GitHub
Browse files

Make it possible to create `SdkError` context structs for tests (#2428)

parent 818343ee
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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"
+180 −0
Original line number Diff line number Diff line
@@ -32,18 +32,183 @@ pub struct SdkSuccess<O> {
    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<R> {
        source: Option<BoxError>,
        raw: Option<R>,
    }

    impl<R> Default for ResponseErrorBuilder<R> {
        fn default() -> Self {
            Self {
                source: None,
                raw: None,
            }
        }
    }

    impl<R> ResponseErrorBuilder<R> {
        /// Creates a new builder.
        pub fn new() -> Self {
            Default::default()
        }

        /// Sets the error source.
        pub fn source(mut self, source: impl Into<BoxError>) -> Self {
            self.source = Some(source.into());
            self
        }

        /// Sets the error source.
        pub fn set_source(&mut self, source: Option<BoxError>) -> &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<R>) -> &mut Self {
            self.raw = raw;
            self
        }

        /// Builds the error context.
        pub fn build(self) -> ResponseError<R> {
            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<E, R> {
        source: Option<E>,
        raw: Option<R>,
    }

    impl<E, R> Default for ServiceErrorBuilder<E, R> {
        fn default() -> Self {
            Self {
                source: None,
                raw: None,
            }
        }
    }

    impl<E, R> ServiceErrorBuilder<E, R> {
        /// Creates a new builder.
        pub fn new() -> Self {
            Default::default()
        }

        /// Sets the error source.
        pub fn source(mut self, source: impl Into<E>) -> Self {
            self.source = Some(source.into());
            self
        }

        /// Sets the error source.
        pub fn set_source(&mut self, source: Option<E>) -> &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<R>) -> &mut Self {
            self.raw = raw;
            self
        }

        /// Builds the error context.
        pub fn build(self) -> ServiceError<E, R> {
            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<R> {
}

impl<R> ResponseError<R> {
    /// Creates a builder for this error context type.
    pub fn builder() -> builders::ResponseErrorBuilder<R> {
        builders::ResponseErrorBuilder::new()
    }

    /// Returns a reference to the raw response
    pub fn raw(&self) -> &R {
        &self.raw
@@ -103,6 +278,11 @@ pub struct ServiceError<E, R> {
}

impl<E, R> ServiceError<E, R> {
    /// Creates a builder for this error context type.
    pub fn builder() -> builders::ServiceErrorBuilder<E, R> {
        builders::ServiceErrorBuilder::new()
    }

    /// Returns the underlying error of type `E`
    pub fn err(&self) -> &E {
        &self.source