#![cfg(feature = "client")]
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::interceptors::context::{
AfterDeserializationInterceptorContextRef, BeforeDeserializationInterceptorContextMut,
BeforeDeserializationInterceptorContextRef, BeforeSerializationInterceptorContextMut,
BeforeSerializationInterceptorContextRef, BeforeTransmitInterceptorContextMut,
BeforeTransmitInterceptorContextRef, FinalizerInterceptorContextMut,
FinalizerInterceptorContextRef,
};
use aws_smithy_runtime_api::client::interceptors::{dyn_dispatch_hint, Intercept, OverriddenHooks};
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
use aws_smithy_types::config_bag::ConfigBag;
#[derive(Debug)]
struct SingleHook;
#[dyn_dispatch_hint]
impl Intercept for SingleHook {
fn name(&self) -> &'static str {
"SingleHook"
}
fn modify_before_signing(
&self,
_context: &mut BeforeTransmitInterceptorContextMut<'_>,
_runtime_components: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
}
#[test]
fn single_hook_sets_one_flag() {
assert_eq!(
SingleHook.overridden_hooks(),
OverriddenHooks::MODIFY_BEFORE_SIGNING,
);
}
#[derive(Debug)]
struct MultipleHooks;
#[dyn_dispatch_hint]
impl Intercept for MultipleHooks {
fn name(&self) -> &'static str {
"MultipleHooks"
}
fn read_before_execution(
&self,
_context: &BeforeSerializationInterceptorContextRef<'_>,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_after_execution(
&self,
_context: &FinalizerInterceptorContextRef<'_>,
_runtime_components: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
}
#[test]
fn multiple_hooks_or_flags_together() {
let flags = MultipleHooks.overridden_hooks();
let expected = OverriddenHooks::READ_BEFORE_EXECUTION | OverriddenHooks::READ_AFTER_EXECUTION;
assert_eq!(
flags, expected,
"should contain exactly the two overridden hooks and nothing else"
);
}
#[derive(Debug)]
struct NoHooks;
#[dyn_dispatch_hint]
impl Intercept for NoHooks {
fn name(&self) -> &'static str {
"NoHooks"
}
}
#[test]
fn no_hooks_returns_none() {
assert_eq!(NoHooks.overridden_hooks(), OverriddenHooks::none());
}
#[derive(Debug)]
struct NoMacro;
impl Intercept for NoMacro {
fn name(&self) -> &'static str {
"NoMacro"
}
}
#[test]
fn without_macro_returns_all() {
assert_eq!(NoMacro.overridden_hooks(), OverriddenHooks::all());
}
macro_rules! generate_hook {
($name:ident) => {
fn $name(
&self,
_context: &mut BeforeTransmitInterceptorContextMut<'_>,
_runtime_components: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
};
}
#[derive(Debug)]
struct MacroGeneratedHook;
#[dyn_dispatch_hint]
impl Intercept for MacroGeneratedHook {
fn name(&self) -> &'static str {
"MacroGeneratedHook"
}
generate_hook!(modify_before_signing);
}
#[test]
fn macro_generated_hook_is_not_detected() {
assert_eq!(
MacroGeneratedHook.overridden_hooks(),
OverriddenHooks::none(),
"a macro-generated hook is invisible to the attribute; write hooks longhand"
);
}
#[derive(Debug)]
struct AllHooks;
#[dyn_dispatch_hint]
impl Intercept for AllHooks {
fn name(&self) -> &'static str {
"AllHooks"
}
fn read_before_execution(
&self,
_c: &BeforeSerializationInterceptorContextRef<'_>,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn modify_before_serialization(
&self,
_c: &mut BeforeSerializationInterceptorContextMut<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_before_serialization(
&self,
_c: &BeforeSerializationInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_after_serialization(
&self,
_c: &BeforeTransmitInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn modify_before_retry_loop(
&self,
_c: &mut BeforeTransmitInterceptorContextMut<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_before_attempt(
&self,
_c: &BeforeTransmitInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn modify_before_signing(
&self,
_c: &mut BeforeTransmitInterceptorContextMut<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_before_signing(
&self,
_c: &BeforeTransmitInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_after_signing(
&self,
_c: &BeforeTransmitInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn modify_before_transmit(
&self,
_c: &mut BeforeTransmitInterceptorContextMut<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_before_transmit(
&self,
_c: &BeforeTransmitInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_after_transmit(
&self,
_c: &BeforeDeserializationInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn modify_before_deserialization(
&self,
_c: &mut BeforeDeserializationInterceptorContextMut<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_before_deserialization(
&self,
_c: &BeforeDeserializationInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_after_deserialization(
&self,
_c: &AfterDeserializationInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn modify_before_attempt_completion(
&self,
_c: &mut FinalizerInterceptorContextMut<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_after_attempt(
&self,
_c: &FinalizerInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn modify_before_completion(
&self,
_c: &mut FinalizerInterceptorContextMut<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
fn read_after_execution(
&self,
_c: &FinalizerInterceptorContextRef<'_>,
_rc: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
Ok(())
}
}
#[test]
fn every_longhand_hook_is_detected() {
let mask = AllHooks.overridden_hooks();
for (hook, flag) in [
(
"read_before_execution",
OverriddenHooks::READ_BEFORE_EXECUTION,
),
(
"modify_before_serialization",
OverriddenHooks::MODIFY_BEFORE_SERIALIZATION,
),
(
"read_before_serialization",
OverriddenHooks::READ_BEFORE_SERIALIZATION,
),
(
"read_after_serialization",
OverriddenHooks::READ_AFTER_SERIALIZATION,
),
(
"modify_before_retry_loop",
OverriddenHooks::MODIFY_BEFORE_RETRY_LOOP,
),
("read_before_attempt", OverriddenHooks::READ_BEFORE_ATTEMPT),
(
"modify_before_signing",
OverriddenHooks::MODIFY_BEFORE_SIGNING,
),
("read_before_signing", OverriddenHooks::READ_BEFORE_SIGNING),
("read_after_signing", OverriddenHooks::READ_AFTER_SIGNING),
(
"modify_before_transmit",
OverriddenHooks::MODIFY_BEFORE_TRANSMIT,
),
(
"read_before_transmit",
OverriddenHooks::READ_BEFORE_TRANSMIT,
),
("read_after_transmit", OverriddenHooks::READ_AFTER_TRANSMIT),
(
"modify_before_deserialization",
OverriddenHooks::MODIFY_BEFORE_DESERIALIZATION,
),
(
"read_before_deserialization",
OverriddenHooks::READ_BEFORE_DESERIALIZATION,
),
(
"read_after_deserialization",
OverriddenHooks::READ_AFTER_DESERIALIZATION,
),
(
"modify_before_attempt_completion",
OverriddenHooks::MODIFY_BEFORE_ATTEMPT_COMPLETION,
),
("read_after_attempt", OverriddenHooks::READ_AFTER_ATTEMPT),
(
"modify_before_completion",
OverriddenHooks::MODIFY_BEFORE_COMPLETION,
),
(
"read_after_execution",
OverriddenHooks::READ_AFTER_EXECUTION,
),
] {
assert!(
mask.contains(flag),
"`{hook}` is implemented longhand but the attribute did not detect it, \
so it would never be dispatched"
);
}
}