@@ -150,10 +150,13 @@ pub fn default_retry_config_plugin(
150150/// Runtime plugin that sets the default retry strategy, config, and partition.
151151///
152152/// This version respects the behavior version to enable retries by default for newer versions.
153- /// For AWS SDK clients, retries are enabled by default.
153+ /// For AWS SDK clients with BehaviorVersion >= v2025_01_17 , retries are enabled by default.
154154pub fn default_retry_config_plugin_v2 ( params : & DefaultPluginParams ) -> Option < SharedRuntimePlugin > {
155155 let default_partition_name = params. retry_partition_name . as_ref ( ) ?. clone ( ) ;
156156 let is_aws_sdk = params. is_aws_sdk ;
157+ let behavior_version = params
158+ . behavior_version
159+ . unwrap_or_else ( BehaviorVersion :: latest) ;
157160 let retry_partition = RetryPartition :: new ( default_partition_name) ;
158161 Some (
159162 default_plugin ( "default_retry_config_plugin" , |components| {
@@ -165,11 +168,13 @@ pub fn default_retry_config_plugin_v2(params: &DefaultPluginParams) -> Option<Sh
165168 . with_interceptor ( TokenBucketProvider :: new ( retry_partition. clone ( ) ) )
166169 } )
167170 . with_config ( layer ( "default_retry_config" , |layer| {
168- let retry_config = if is_aws_sdk {
169- RetryConfig :: standard ( )
170- } else {
171- RetryConfig :: disabled ( )
172- } ;
171+ #[ allow( deprecated) ]
172+ let retry_config =
173+ if is_aws_sdk && behavior_version. is_at_least ( BehaviorVersion :: v2025_01_17 ( ) ) {
174+ RetryConfig :: standard ( )
175+ } else {
176+ RetryConfig :: disabled ( )
177+ } ;
173178 layer. store_put ( retry_config) ;
174179 layer. store_put ( retry_partition) ;
175180 } ) )
@@ -454,6 +459,7 @@ mod tests {
454459 fn test_retry_enabled_for_aws_sdk ( ) {
455460 let params = DefaultPluginParams :: new ( )
456461 . with_retry_partition_name ( "test-partition" )
462+ . with_behavior_version ( BehaviorVersion :: latest ( ) )
457463 . with_is_aws_sdk ( true ) ;
458464 let plugin = default_retry_config_plugin_v2 ( & params) . expect ( "plugin should be created" ) ;
459465
@@ -465,14 +471,59 @@ mod tests {
465471 assert_eq ! (
466472 retry_config. max_attempts( ) ,
467473 3 ,
468- "retries should be enabled with max_attempts=3 for AWS SDK"
474+ "retries should be enabled with max_attempts=3 for AWS SDK with latest behavior version"
475+ ) ;
476+ }
477+
478+ #[ test]
479+ #[ allow( deprecated) ]
480+ fn test_retry_disabled_for_aws_sdk_old_behavior_version ( ) {
481+ // Any version before v2025_01_17 should have retries disabled
482+ let params = DefaultPluginParams :: new ( )
483+ . with_retry_partition_name ( "test-partition" )
484+ . with_behavior_version ( BehaviorVersion :: v2024_03_28 ( ) )
485+ . with_is_aws_sdk ( true ) ;
486+ let plugin = default_retry_config_plugin_v2 ( & params) . expect ( "plugin should be created" ) ;
487+
488+ let config = plugin. config ( ) . expect ( "config should exist" ) ;
489+ let retry_config = config
490+ . load :: < RetryConfig > ( )
491+ . expect ( "retry config should exist" ) ;
492+
493+ assert_eq ! (
494+ retry_config. max_attempts( ) ,
495+ 1 ,
496+ "retries should be disabled for AWS SDK with behavior version < v2025_01_17"
497+ ) ;
498+ }
499+
500+ #[ test]
501+ #[ allow( deprecated) ]
502+ fn test_retry_enabled_at_cutoff_version ( ) {
503+ // v2025_01_17 is the cutoff - retries should be enabled from this version onwards
504+ let params = DefaultPluginParams :: new ( )
505+ . with_retry_partition_name ( "test-partition" )
506+ . with_behavior_version ( BehaviorVersion :: v2025_01_17 ( ) )
507+ . with_is_aws_sdk ( true ) ;
508+ let plugin = default_retry_config_plugin_v2 ( & params) . expect ( "plugin should be created" ) ;
509+
510+ let config = plugin. config ( ) . expect ( "config should exist" ) ;
511+ let retry_config = config
512+ . load :: < RetryConfig > ( )
513+ . expect ( "retry config should exist" ) ;
514+
515+ assert_eq ! (
516+ retry_config. max_attempts( ) ,
517+ 3 ,
518+ "retries should be enabled for AWS SDK starting from v2025_01_17"
469519 ) ;
470520 }
471521
472522 #[ test]
473523 fn test_retry_disabled_for_non_aws_sdk ( ) {
474524 let params = DefaultPluginParams :: new ( )
475525 . with_retry_partition_name ( "test-partition" )
526+ . with_behavior_version ( BehaviorVersion :: latest ( ) )
476527 . with_is_aws_sdk ( false ) ;
477528 let plugin = default_retry_config_plugin_v2 ( & params) . expect ( "plugin should be created" ) ;
478529
@@ -487,4 +538,112 @@ mod tests {
487538 "retries should be disabled for non-AWS SDK clients"
488539 ) ;
489540 }
541+
542+ #[ test]
543+ #[ allow( deprecated) ]
544+ fn test_behavior_version_gates_retry_for_aws_sdk ( ) {
545+ // This test demonstrates the complete behavior:
546+ // AWS SDK clients get retries enabled ONLY when BehaviorVersion >= v2025_01_17
547+
548+ // Test all behavior versions
549+ let test_cases = vec ! [
550+ ( BehaviorVersion :: v2023_11_09( ) , 1 , "v2023_11_09 (old)" ) ,
551+ ( BehaviorVersion :: v2024_03_28( ) , 1 , "v2024_03_28 (old)" ) ,
552+ ( BehaviorVersion :: v2025_01_17( ) , 3 , "v2025_01_17 (cutoff)" ) ,
553+ ( BehaviorVersion :: latest( ) , 3 , "latest" ) ,
554+ ] ;
555+
556+ for ( version, expected_attempts, version_name) in test_cases {
557+ let params = DefaultPluginParams :: new ( )
558+ . with_retry_partition_name ( "test-partition" )
559+ . with_behavior_version ( version)
560+ . with_is_aws_sdk ( true ) ;
561+
562+ let plugin = default_retry_config_plugin_v2 ( & params) . expect ( "plugin should be created" ) ;
563+ let config = plugin. config ( ) . expect ( "config should exist" ) ;
564+ let retry_config = config
565+ . load :: < RetryConfig > ( )
566+ . expect ( "retry config should exist" ) ;
567+
568+ assert_eq ! (
569+ retry_config. max_attempts( ) ,
570+ expected_attempts,
571+ "AWS SDK with {} should have {} max attempts" ,
572+ version_name,
573+ expected_attempts
574+ ) ;
575+ }
576+ }
577+
578+ #[ test]
579+ #[ allow( deprecated) ]
580+ fn test_complete_default_plugins_integration ( ) {
581+ // This test simulates the complete flow as it would happen in a real AWS SDK client
582+ // It verifies that default_plugins() correctly applies retry config based on
583+ // both is_aws_sdk flag and BehaviorVersion
584+
585+ // Scenario 1: AWS SDK with latest behavior version -> retries enabled
586+ let params_aws_latest = DefaultPluginParams :: new ( )
587+ . with_retry_partition_name ( "aws-s3" )
588+ . with_behavior_version ( BehaviorVersion :: latest ( ) )
589+ . with_is_aws_sdk ( true ) ;
590+
591+ let config_aws_latest = config_for ( default_plugins ( params_aws_latest) ) ;
592+ let retry_aws_latest = config_aws_latest
593+ . load :: < RetryConfig > ( )
594+ . expect ( "retry config should exist" ) ;
595+ assert_eq ! (
596+ retry_aws_latest. max_attempts( ) ,
597+ 3 ,
598+ "AWS SDK with latest behavior version should have retries enabled (3 attempts)"
599+ ) ;
600+
601+ // Scenario 2: AWS SDK with old behavior version -> retries disabled
602+ let params_aws_old = DefaultPluginParams :: new ( )
603+ . with_retry_partition_name ( "aws-s3" )
604+ . with_behavior_version ( BehaviorVersion :: v2024_03_28 ( ) )
605+ . with_is_aws_sdk ( true ) ;
606+
607+ let config_aws_old = config_for ( default_plugins ( params_aws_old) ) ;
608+ let retry_aws_old = config_aws_old
609+ . load :: < RetryConfig > ( )
610+ . expect ( "retry config should exist" ) ;
611+ assert_eq ! (
612+ retry_aws_old. max_attempts( ) ,
613+ 1 ,
614+ "AWS SDK with old behavior version should have retries disabled (1 attempt)"
615+ ) ;
616+
617+ // Scenario 3: Non-AWS SDK (generic Smithy client) -> retries always disabled
618+ let params_generic = DefaultPluginParams :: new ( )
619+ . with_retry_partition_name ( "my-service" )
620+ . with_behavior_version ( BehaviorVersion :: latest ( ) )
621+ . with_is_aws_sdk ( false ) ;
622+
623+ let config_generic = config_for ( default_plugins ( params_generic) ) ;
624+ let retry_generic = config_generic
625+ . load :: < RetryConfig > ( )
626+ . expect ( "retry config should exist" ) ;
627+ assert_eq ! (
628+ retry_generic. max_attempts( ) ,
629+ 1 ,
630+ "Non-AWS SDK clients should always have retries disabled (1 attempt)"
631+ ) ;
632+
633+ // Scenario 4: Verify the cutoff version v2025_01_17 is the exact boundary
634+ let params_cutoff = DefaultPluginParams :: new ( )
635+ . with_retry_partition_name ( "aws-s3" )
636+ . with_behavior_version ( BehaviorVersion :: v2025_01_17 ( ) )
637+ . with_is_aws_sdk ( true ) ;
638+
639+ let config_cutoff = config_for ( default_plugins ( params_cutoff) ) ;
640+ let retry_cutoff = config_cutoff
641+ . load :: < RetryConfig > ( )
642+ . expect ( "retry config should exist" ) ;
643+ assert_eq ! (
644+ retry_cutoff. max_attempts( ) ,
645+ 3 ,
646+ "AWS SDK with v2025_01_17 (the cutoff version) should have retries enabled (3 attempts)"
647+ ) ;
648+ }
490649}
0 commit comments