From f0d0e291775fae9016dcac2b8df01f2856efa7ea Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Wed, 26 Jul 2023 19:51:36 -0400 Subject: [PATCH] Remove vestiges of the old TimeSource implementation & refactor (#2877) ## Motivation and Context When `TimeSource` was created, we didn't carefully track down all the places and left a bit of existing implementation to limit the scope of the change. ## Description This removes the public (doc hidden) Testing code from aws-credential-types and our other test time sources instead. ## Testing - IT/UT ## Checklist - [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._ --------- Co-authored-by: John DiSanti --- CHANGELOG.next.toml | 12 ++ aws/rust-runtime/aws-config/Cargo.toml | 1 + .../src/default_provider/credentials.rs | 17 +-- .../aws-config/src/imds/client.rs | 16 +- .../aws-config/src/imds/credentials.rs | 23 +-- aws/rust-runtime/aws-config/src/lib.rs | 5 +- .../aws-config/src/provider_config.rs | 10 +- .../aws-config/src/sts/assume_role.rs | 15 +- .../aws-credential-types/Cargo.toml | 2 +- .../src/cache/lazy_caching.rs | 90 ++++++----- .../aws-credential-types/src/lib.rs | 2 - .../aws-credential-types/src/time_source.rs | 142 ------------------ .../aws-smithy-async/src/test_util.rs | 34 ++++- 13 files changed, 131 insertions(+), 238 deletions(-) delete mode 100644 aws/rust-runtime/aws-credential-types/src/time_source.rs diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 741a4540940..0018f2deda7 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -686,3 +686,15 @@ x-amzn-errortype: InvalidRequestException references = ["smithy-rs#2866"] meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "server" } author = "david-perez" + +[[aws-sdk-rust]] +message = """The `doc(hidden)` `time_source` in `aws-credential-types` was removed. Use `aws_smithy_async::time` instead.""" +meta = { "breaking" = true, "tada" = false, "bug" = false } +author = "rcoh" +references = ["smithy-rs#2877"] + +[[aws-sdk-rust]] +message = """The `doc(hidden)` `with_env` in `ProviderConfig` was removed.""" +meta = { "breaking" = true, "tada" = false, "bug" = false } +author = "rcoh" +references = ["smithy-rs#2877"] diff --git a/aws/rust-runtime/aws-config/Cargo.toml b/aws/rust-runtime/aws-config/Cargo.toml index c19658d9c37..997f7b86eef 100644 --- a/aws/rust-runtime/aws-config/Cargo.toml +++ b/aws/rust-runtime/aws-config/Cargo.toml @@ -66,6 +66,7 @@ aws-smithy-client = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-client", fe # used for a usage example hyper-rustls = { version = "0.24", features = ["webpki-tokio", "http2", "http1"] } +aws-smithy-async = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-async", features = ["test-util"] } [package.metadata.docs.rs] all-features = true diff --git a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs index 115cafcab16..a5e1fb0dc5d 100644 --- a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs +++ b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs @@ -199,6 +199,8 @@ impl Builder { #[cfg(test)] mod test { use aws_credential_types::provider::ProvideCredentials; + use aws_smithy_async::time::StaticTimeSource; + use std::time::UNIX_EPOCH; use crate::default_provider::credentials::DefaultCredentialsChain; @@ -279,21 +281,15 @@ mod test { make_test!(imds_no_iam_role); make_test!(imds_default_chain_error); make_test!(imds_default_chain_success, builder: |config| { - config.with_time_source(aws_credential_types::time_source::TimeSource::testing( - &aws_credential_types::time_source::TestingTimeSource::new(std::time::UNIX_EPOCH), - )) + config.with_time_source(StaticTimeSource::new(UNIX_EPOCH)) }); make_test!(imds_assume_role); make_test!(imds_config_with_no_creds, builder: |config| { - config.with_time_source(aws_credential_types::time_source::TimeSource::testing( - &aws_credential_types::time_source::TestingTimeSource::new(std::time::UNIX_EPOCH), - )) + config.with_time_source(StaticTimeSource::new(UNIX_EPOCH)) }); make_test!(imds_disabled); make_test!(imds_default_chain_retries, builder: |config| { - config.with_time_source(aws_credential_types::time_source::TimeSource::testing( - &aws_credential_types::time_source::TestingTimeSource::new(std::time::UNIX_EPOCH), - )) + config.with_time_source(StaticTimeSource::new(UNIX_EPOCH)) }); make_test!(ecs_assume_role); make_test!(ecs_credentials); @@ -335,7 +331,6 @@ mod test { async fn no_providers_configured_err() { use crate::provider_config::ProviderConfig; use aws_credential_types::provider::error::CredentialsError; - use aws_credential_types::time_source::TimeSource; use aws_smithy_async::rt::sleep::TokioSleep; use aws_smithy_client::erase::boxclone::BoxCloneService; use aws_smithy_client::never::NeverConnected; @@ -343,7 +338,7 @@ mod test { tokio::time::pause(); let conf = ProviderConfig::no_configuration() .with_tcp_connector(BoxCloneService::new(NeverConnected::new())) - .with_time_source(TimeSource::default()) + .with_time_source(StaticTimeSource::new(UNIX_EPOCH)) .with_sleep(TokioSleep::new()); let provider = DefaultCredentialsChain::builder() .configure(conf) diff --git a/aws/rust-runtime/aws-config/src/imds/client.rs b/aws/rust-runtime/aws-config/src/imds/client.rs index cb77b0759d5..f084bc9a832 100644 --- a/aws/rust-runtime/aws-config/src/imds/client.rs +++ b/aws/rust-runtime/aws-config/src/imds/client.rs @@ -571,8 +571,8 @@ impl ClassifyRetry, SdkError> for ImdsResponseRetryClassi pub(crate) mod test { use crate::imds::client::{Client, EndpointMode, ImdsResponseRetryClassifier}; use crate::provider_config::ProviderConfig; - use aws_credential_types::time_source::{TestingTimeSource, TimeSource}; use aws_smithy_async::rt::sleep::TokioSleep; + use aws_smithy_async::test_util::instant_time_and_sleep; use aws_smithy_client::erase::DynConnector; use aws_smithy_client::test_connection::{capture_request, TestConnection}; use aws_smithy_client::{SdkError, SdkSuccess}; @@ -700,14 +700,13 @@ pub(crate) mod test { imds_response(r#"test-imds-output2"#), ), ]); - let mut time_source = TestingTimeSource::new(UNIX_EPOCH); - tokio::time::pause(); + let (time_source, sleep) = instant_time_and_sleep(UNIX_EPOCH); let client = super::Client::builder() .configure( &ProviderConfig::no_configuration() .with_http_connector(DynConnector::new(connection.clone())) - .with_time_source(TimeSource::testing(&time_source)) - .with_sleep(TokioSleep::new()), + .with_time_source(time_source.clone()) + .with_sleep(sleep), ) .endpoint_mode(EndpointMode::IpV6) .token_ttl(Duration::from_secs(600)) @@ -752,14 +751,13 @@ pub(crate) mod test { imds_response(r#"test-imds-output3"#), ), ]); - tokio::time::pause(); - let mut time_source = TestingTimeSource::new(UNIX_EPOCH); + let (time_source, sleep) = instant_time_and_sleep(UNIX_EPOCH); let client = super::Client::builder() .configure( &ProviderConfig::no_configuration() - .with_sleep(TokioSleep::new()) + .with_sleep(sleep) .with_http_connector(DynConnector::new(connection.clone())) - .with_time_source(TimeSource::testing(&time_source)), + .with_time_source(time_source.clone()), ) .endpoint_mode(EndpointMode::IpV6) .token_ttl(Duration::from_secs(600)) diff --git a/aws/rust-runtime/aws-config/src/imds/credentials.rs b/aws/rust-runtime/aws-config/src/imds/credentials.rs index c0c5707f24b..ccc65eaf992 100644 --- a/aws/rust-runtime/aws-config/src/imds/credentials.rs +++ b/aws/rust-runtime/aws-config/src/imds/credentials.rs @@ -306,8 +306,7 @@ mod test { }; use crate::provider_config::ProviderConfig; use aws_credential_types::provider::ProvideCredentials; - use aws_credential_types::time_source::{TestingTimeSource, TimeSource}; - use aws_smithy_async::rt::sleep::TokioSleep; + use aws_smithy_async::test_util::instant_time_and_sleep; use aws_smithy_client::erase::DynConnector; use aws_smithy_client::test_connection::TestConnection; use tracing_test::traced_test; @@ -369,16 +368,12 @@ mod test { // set to 2021-09-21T04:16:50Z that makes returned credentials' expiry (2021-09-21T04:16:53Z) // not stale let time_of_request_to_fetch_credentials = UNIX_EPOCH + Duration::from_secs(1632197810); - let time_source = TimeSource::testing(&TestingTimeSource::new( - time_of_request_to_fetch_credentials, - )); - - tokio::time::pause(); + let (time_source, sleep) = instant_time_and_sleep(time_of_request_to_fetch_credentials); let provider_config = ProviderConfig::no_configuration() .with_http_connector(DynConnector::new(connection.clone())) - .with_time_source(time_source) - .with_sleep(TokioSleep::new()); + .with_sleep(sleep) + .with_time_source(time_source); let client = crate::imds::Client::builder() .configure(&provider_config) .build() @@ -419,16 +414,12 @@ mod test { // set to 2021-09-21T17:41:25Z that renders fetched credentials already expired (2021-09-21T04:16:53Z) let time_of_request_to_fetch_credentials = UNIX_EPOCH + Duration::from_secs(1632246085); - let time_source = TimeSource::testing(&TestingTimeSource::new( - time_of_request_to_fetch_credentials, - )); - - tokio::time::pause(); + let (time_source, sleep) = instant_time_and_sleep(time_of_request_to_fetch_credentials); let provider_config = ProviderConfig::no_configuration() .with_http_connector(DynConnector::new(connection.clone())) - .with_time_source(time_source) - .with_sleep(TokioSleep::new()); + .with_sleep(sleep) + .with_time_source(time_source); let client = crate::imds::Client::builder() .configure(&provider_config) .build() diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 154659377fb..e7c035ea803 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -620,9 +620,8 @@ mod loader { let credentials_cache = if credentials_provider.is_some() { Some(self.credentials_cache.unwrap_or_else(|| { - let mut builder = CredentialsCache::lazy_builder().time_source( - aws_credential_types::time_source::TimeSource::shared(conf.time_source()), - ); + let mut builder = + CredentialsCache::lazy_builder().time_source(conf.time_source()); builder.set_sleep(conf.sleep()); builder.into_credentials_cache() })) diff --git a/aws/rust-runtime/aws-config/src/provider_config.rs b/aws/rust-runtime/aws-config/src/provider_config.rs index 27bc23108dd..3712376b425 100644 --- a/aws/rust-runtime/aws-config/src/provider_config.rs +++ b/aws/rust-runtime/aws-config/src/provider_config.rs @@ -5,7 +5,6 @@ //! Configuration Options for Credential Providers -use aws_credential_types::time_source::TimeSource; use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep}; use aws_smithy_async::time::SharedTimeSource; use aws_smithy_client::erase::DynConnector; @@ -282,7 +281,7 @@ impl ProviderConfig { } } - #[doc(hidden)] + #[cfg(test)] pub fn with_env(self, env: Env) -> Self { ProviderConfig { parsed_profile: Default::default(), @@ -291,8 +290,11 @@ impl ProviderConfig { } } - #[doc(hidden)] - pub fn with_time_source(self, time_source: TimeSource) -> Self { + /// Override the time source for this configuration + pub fn with_time_source( + self, + time_source: impl aws_smithy_async::time::TimeSource + 'static, + ) -> Self { ProviderConfig { time_source: SharedTimeSource::new(time_source), ..self diff --git a/aws/rust-runtime/aws-config/src/sts/assume_role.rs b/aws/rust-runtime/aws-config/src/sts/assume_role.rs index 50a83b4b6d3..90cd91195f8 100644 --- a/aws/rust-runtime/aws-config/src/sts/assume_role.rs +++ b/aws/rust-runtime/aws-config/src/sts/assume_role.rs @@ -291,9 +291,10 @@ mod test { use crate::sts::AssumeRoleProvider; use aws_credential_types::credential_fn::provide_credentials_fn; use aws_credential_types::provider::ProvideCredentials; - use aws_credential_types::time_source::{TestingTimeSource, TimeSource}; use aws_credential_types::Credentials; use aws_smithy_async::rt::sleep::TokioSleep; + use aws_smithy_async::test_util::instant_time_and_sleep; + use aws_smithy_async::time::StaticTimeSource; use aws_smithy_client::erase::DynConnector; use aws_smithy_client::test_connection::{capture_request, TestConnection}; use aws_smithy_http::body::SdkBody; @@ -305,9 +306,9 @@ mod test { let (server, request) = capture_request(None); let provider_conf = ProviderConfig::empty() .with_sleep(TokioSleep::new()) - .with_time_source(TimeSource::testing(&TestingTimeSource::new( + .with_time_source(StaticTimeSource::new( UNIX_EPOCH + Duration::from_secs(1234567890 - 120), - ))) + )) .with_http_connector(DynConnector::new(server)); let provider = AssumeRoleProvider::builder("myrole") .configure(&provider_conf) @@ -335,13 +336,13 @@ mod test { )).unwrap()), ]); - let mut testing_time_source = TestingTimeSource::new( + let (testing_time_source, sleep) = instant_time_and_sleep( UNIX_EPOCH + Duration::from_secs(1234567890 - 120), // 1234567890 since UNIX_EPOCH is 2009-02-13T23:31:30Z ); let provider_conf = ProviderConfig::empty() - .with_sleep(TokioSleep::new()) - .with_time_source(TimeSource::testing(&testing_time_source)) + .with_sleep(sleep) + .with_time_source(testing_time_source.clone()) .with_http_connector(DynConnector::new(conn)); let credentials_list = std::sync::Arc::new(std::sync::Mutex::new(vec![ Credentials::new( @@ -371,8 +372,6 @@ mod test { } })); - tokio::time::pause(); - let creds_first = provider .provide_credentials() .await diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index cbd1426fe2a..e109667525a 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -20,7 +20,7 @@ tracing = "0.1" zeroize = "1" [dev-dependencies] -aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async", features = ["rt-tokio"] } +aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async", features = ["rt-tokio", "test-util"] } # used to test compatibility async-trait = "0.1.51" diff --git a/aws/rust-runtime/aws-credential-types/src/cache/lazy_caching.rs b/aws/rust-runtime/aws-credential-types/src/cache/lazy_caching.rs index ae1a6e2d36e..6169c2b930b 100644 --- a/aws/rust-runtime/aws-credential-types/src/cache/lazy_caching.rs +++ b/aws/rust-runtime/aws-credential-types/src/cache/lazy_caching.rs @@ -5,16 +5,16 @@ //! Lazy, credentials cache implementation -use std::time::{Duration, Instant}; +use std::time::Duration; use aws_smithy_async::future::timeout::Timeout; use aws_smithy_async::rt::sleep::{AsyncSleep, SharedAsyncSleep}; +use aws_smithy_async::time::SharedTimeSource; use tracing::{debug, info, info_span, Instrument}; use crate::cache::{ExpiringCache, ProvideCachedCredentials}; use crate::provider::SharedCredentialsProvider; use crate::provider::{error::CredentialsError, future, ProvideCredentials}; -use crate::time_source::TimeSource; const DEFAULT_LOAD_TIMEOUT: Duration = Duration::from_secs(5); const DEFAULT_CREDENTIAL_EXPIRATION: Duration = Duration::from_secs(15 * 60); @@ -23,7 +23,7 @@ const DEFAULT_BUFFER_TIME_JITTER_FRACTION: fn() -> f64 = fastrand::f64; #[derive(Debug)] pub(crate) struct LazyCredentialsCache { - time: TimeSource, + time: SharedTimeSource, sleeper: SharedAsyncSleep, cache: ExpiringCache, provider: SharedCredentialsProvider, @@ -35,7 +35,7 @@ pub(crate) struct LazyCredentialsCache { impl LazyCredentialsCache { fn new( - time: TimeSource, + time: SharedTimeSource, sleeper: SharedAsyncSleep, provider: SharedCredentialsProvider, load_timeout: Duration, @@ -79,7 +79,7 @@ impl ProvideCachedCredentials for LazyCredentialsCache { // since the futures are not eagerly executed, and the cache will only run one // of them. let future = Timeout::new(provider.provide_credentials(), timeout_future); - let start_time = Instant::now(); + let start_time = self.time.now(); let result = cache .get_or_load(|| { let span = info_span!("lazy_load_credentials"); @@ -111,14 +111,14 @@ impl ProvideCachedCredentials for LazyCredentialsCache { // only once for the first thread that succeeds in populating a cache value. info!( "credentials cache miss occurred; added new AWS credentials (took {:?})", - start_time.elapsed() + self.time.now().duration_since(start_time) ); Ok((credentials, expiry + jitter)) } - // Only instrument the the actual load future so that no span - // is opened if the cache decides not to execute it. - .instrument(span) + // Only instrument the the actual load future so that no span + // is opened if the cache decides not to execute it. + .instrument(span) }) .await; debug!("loaded credentials"); @@ -137,8 +137,8 @@ mod builder { use crate::cache::{CredentialsCache, Inner}; use crate::provider::SharedCredentialsProvider; use aws_smithy_async::rt::sleep::{default_async_sleep, SharedAsyncSleep}; + use aws_smithy_async::time::SharedTimeSource; - use super::TimeSource; use super::{ LazyCredentialsCache, DEFAULT_BUFFER_TIME, DEFAULT_BUFFER_TIME_JITTER_FRACTION, DEFAULT_CREDENTIAL_EXPIRATION, DEFAULT_LOAD_TIMEOUT, @@ -159,7 +159,7 @@ mod builder { #[derive(Clone, Debug, Default)] pub struct Builder { sleep: Option, - time_source: Option, + time_source: Option, load_timeout: Option, buffer_time: Option, buffer_time_jitter_fraction: Option f64>, @@ -193,13 +193,13 @@ mod builder { } #[doc(hidden)] // because they only exist for tests - pub fn time_source(mut self, time_source: TimeSource) -> Self { + pub fn time_source(mut self, time_source: SharedTimeSource) -> Self { self.set_time_source(Some(time_source)); self } #[doc(hidden)] // because they only exist for tests - pub fn set_time_source(&mut self, time_source: Option) -> &mut Self { + pub fn set_time_source(&mut self, time_source: Option) -> &mut Self { self.time_source = time_source; self } @@ -346,37 +346,45 @@ mod tests { use std::time::{Duration, SystemTime, UNIX_EPOCH}; use aws_smithy_async::rt::sleep::{SharedAsyncSleep, TokioSleep}; + use aws_smithy_async::test_util::{instant_time_and_sleep, ManualTimeSource}; + use aws_smithy_async::time::{SharedTimeSource, TimeSource}; use tracing::info; use tracing_test::traced_test; use crate::provider::SharedCredentialsProvider; use crate::{ cache::ProvideCachedCredentials, credential_fn::provide_credentials_fn, - provider::error::CredentialsError, time_source::TestingTimeSource, Credentials, + provider::error::CredentialsError, Credentials, }; use super::{ - LazyCredentialsCache, TimeSource, DEFAULT_BUFFER_TIME, DEFAULT_CREDENTIAL_EXPIRATION, + LazyCredentialsCache, DEFAULT_BUFFER_TIME, DEFAULT_CREDENTIAL_EXPIRATION, DEFAULT_LOAD_TIMEOUT, }; const BUFFER_TIME_NO_JITTER: fn() -> f64 = || 0_f64; fn test_provider( - time: TimeSource, + time: impl TimeSource + 'static, buffer_time_jitter_fraction: fn() -> f64, load_list: Vec, ) -> LazyCredentialsCache { let load_list = Arc::new(Mutex::new(load_list)); LazyCredentialsCache::new( - time, + SharedTimeSource::new(time), SharedAsyncSleep::new(TokioSleep::new()), SharedCredentialsProvider::new(provide_credentials_fn(move || { let list = load_list.clone(); async move { - let next = list.lock().unwrap().remove(0); - info!("refreshing the credentials to {:?}", next); - next + let mut list = list.lock().unwrap(); + if list.len() > 0 { + let next = list.remove(0); + info!("refreshing the credentials to {:?}", next); + next + } else { + drop(list); + panic!("no more credentials") + } } })), DEFAULT_LOAD_TIMEOUT, @@ -405,13 +413,13 @@ mod tests { #[traced_test] #[tokio::test] async fn initial_populate_credentials() { - let time = TestingTimeSource::new(UNIX_EPOCH); + let time = ManualTimeSource::new(UNIX_EPOCH); let provider = SharedCredentialsProvider::new(provide_credentials_fn(|| async { info!("refreshing the credentials"); Ok(credentials(1000)) })); let credentials_cache = LazyCredentialsCache::new( - TimeSource::testing(&time), + SharedTimeSource::new(time), SharedAsyncSleep::new(TokioSleep::new()), provider, DEFAULT_LOAD_TIMEOUT, @@ -433,9 +441,9 @@ mod tests { #[traced_test] #[tokio::test] async fn reload_expired_credentials() { - let mut time = TestingTimeSource::new(epoch_secs(100)); + let time = ManualTimeSource::new(epoch_secs(100)); let credentials_cache = test_provider( - TimeSource::testing(&time), + time.clone(), BUFFER_TIME_NO_JITTER, vec![ Ok(credentials(1000)), @@ -457,9 +465,9 @@ mod tests { #[traced_test] #[tokio::test] async fn load_failed_error() { - let mut time = TestingTimeSource::new(epoch_secs(100)); + let time = ManualTimeSource::new(epoch_secs(100)); let credentials_cache = test_provider( - TimeSource::testing(&time), + time.clone(), BUFFER_TIME_NO_JITTER, vec![ Ok(credentials(1000)), @@ -484,9 +492,9 @@ mod tests { .build() .unwrap(); - let time = TestingTimeSource::new(epoch_secs(0)); + let time = ManualTimeSource::new(epoch_secs(0)); let credentials_cache = Arc::new(test_provider( - TimeSource::testing(&time), + time.clone(), BUFFER_TIME_NO_JITTER, vec![ Ok(credentials(500)), @@ -497,16 +505,15 @@ mod tests { ], )); - let locked_time = Arc::new(Mutex::new(time)); - - for i in 0..4 { + // credentials are available up until 4500 seconds after the unix epoch + // 4*50 = 200 tasks are launched => we can advance time 4500/20 => 225 seconds per advance + for _ in 0..4 { let mut tasks = Vec::new(); - for j in 0..50 { + for _ in 0..50 { let credentials_cache = credentials_cache.clone(); - let time = locked_time.clone(); + let time = time.clone(); tasks.push(rt.spawn(async move { - let now = epoch_secs(i * 1000 + (4 * j)); - time.lock().unwrap().set_time(now); + let now = time.advance(Duration::from_secs(22)); let creds = credentials_cache .provide_cached_credentials() @@ -529,15 +536,15 @@ mod tests { #[tokio::test] #[traced_test] async fn load_timeout() { - let time = TestingTimeSource::new(epoch_secs(100)); + let (time, sleep) = instant_time_and_sleep(epoch_secs(100)); let credentials_cache = LazyCredentialsCache::new( - TimeSource::testing(&time), - SharedAsyncSleep::new(TokioSleep::new()), + SharedTimeSource::new(time.clone()), + SharedAsyncSleep::new(sleep), SharedCredentialsProvider::new(provide_credentials_fn(|| async { aws_smithy_async::future::never::Never::new().await; Ok(credentials(1000)) })), - Duration::from_millis(5), + Duration::from_secs(5), DEFAULT_BUFFER_TIME, BUFFER_TIME_NO_JITTER, DEFAULT_CREDENTIAL_EXPIRATION, @@ -547,14 +554,15 @@ mod tests { credentials_cache.provide_cached_credentials().await, Err(CredentialsError::ProviderTimedOut { .. }) )); + assert_eq!(time.now(), epoch_secs(105)); } #[tokio::test] async fn buffer_time_jitter() { - let mut time = TestingTimeSource::new(epoch_secs(100)); + let time = ManualTimeSource::new(epoch_secs(100)); let buffer_time_jitter_fraction = || 0.5_f64; let credentials_cache = test_provider( - TimeSource::testing(&time), + time.clone(), buffer_time_jitter_fraction, vec![Ok(credentials(1000)), Ok(credentials(2000))], ); diff --git a/aws/rust-runtime/aws-credential-types/src/lib.rs b/aws/rust-runtime/aws-credential-types/src/lib.rs index b2f8330b589..de662f6a50d 100644 --- a/aws/rust-runtime/aws-credential-types/src/lib.rs +++ b/aws/rust-runtime/aws-credential-types/src/lib.rs @@ -21,7 +21,5 @@ pub mod cache; pub mod credential_fn; mod credentials_impl; pub mod provider; -#[doc(hidden)] -pub mod time_source; pub use credentials_impl::Credentials; diff --git a/aws/rust-runtime/aws-credential-types/src/time_source.rs b/aws/rust-runtime/aws-credential-types/src/time_source.rs deleted file mode 100644 index 212c7aa904a..00000000000 --- a/aws/rust-runtime/aws-credential-types/src/time_source.rs +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use aws_smithy_async::time::{SharedTimeSource, TimeSource as TimeSourceTrait}; -use std::ops::Deref; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, SystemTime}; - -impl TimeSourceTrait for TimeSource { - fn now(&self) -> SystemTime { - self.now() - } -} - -/// Time source abstraction -/// -/// Simple abstraction representing time either real-time or manually-specified for testing -#[derive(Debug, Clone)] -// TODO(breakingChangeWindow): Delete this struct -pub struct TimeSource(Inner); - -impl TimeSource { - /// Creates `TimeSource` from the manually specified `time_source`. - pub fn testing(time_source: &TestingTimeSource) -> Self { - TimeSource(Inner::Testing(time_source.clone())) - } - - /// Creates `TimeSource` from a shared time source - pub fn shared(time_source: SharedTimeSource) -> Self { - TimeSource(Inner::Shared(time_source)) - } - - /// Returns the current system time based on the mode. - pub fn now(&self) -> SystemTime { - match &self.0 { - Inner::Default => SystemTime::now(), - Inner::Testing(testing) => testing.now(), - Inner::Shared(ts) => ts.now(), - } - } -} - -impl Default for TimeSource { - /// Creates `TimeSource` from the current system time. - fn default() -> Self { - TimeSource(Inner::Default) - } -} - -/// Time Source that can be manually moved for tests -/// > This has been superseded by [`aws_smithy_async::time::TimeSource`] and will be removed in a -/// > future release. -/// -/// # Examples -/// -/// ```rust -/// # struct Client { -/// # // stub -/// # } -/// # -/// # impl Client { -/// # fn with_timesource(ts: TimeSource) -> Self { -/// # Client { } -/// # } -/// # } -/// use aws_credential_types::time_source::{TestingTimeSource, TimeSource}; -/// use std::time::{UNIX_EPOCH, Duration}; -/// let mut time = TestingTimeSource::new(UNIX_EPOCH); -/// let client = Client::with_timesource(TimeSource::testing(&time)); -/// time.advance(Duration::from_secs(100)); -/// ``` -#[derive(Clone, Debug)] -pub struct TestingTimeSource { - queries: Arc>>, - now: Arc>, -} - -impl TestingTimeSource { - /// Creates `TestingTimeSource` with `start_time`. - pub fn new(start_time: SystemTime) -> Self { - Self { - queries: Default::default(), - now: Arc::new(Mutex::new(start_time)), - } - } - - /// Sets time to the specified `time`. - pub fn set_time(&mut self, time: SystemTime) { - let mut now = self.now.lock().unwrap(); - *now = time; - } - - /// Advances time by `delta`. - pub fn advance(&mut self, delta: Duration) { - let mut now = self.now.lock().unwrap(); - *now += delta; - } - - /// Returns a `Vec` of queried times so far. - pub fn queries(&self) -> impl Deref> + '_ { - self.queries.lock().unwrap() - } - - /// Returns the current time understood by `TestingTimeSource`. - pub fn now(&self) -> SystemTime { - let ts = *self.now.lock().unwrap(); - self.queries.lock().unwrap().push(ts); - ts - } -} - -#[derive(Debug, Clone)] -enum Inner { - Default, - Testing(TestingTimeSource), - Shared(SharedTimeSource), -} - -#[cfg(test)] -mod test { - use super::{TestingTimeSource, TimeSource}; - - use std::time::{Duration, UNIX_EPOCH}; - - #[test] - fn default_time_source_should_not_panic_on_calling_now() { - let time_source = TimeSource::default(); - // no panics - let _ = time_source.now(); - } - - #[test] - fn testing_time_source_should_behave_as_expected() { - let mut testing = TestingTimeSource::new(UNIX_EPOCH); - let time_source = TimeSource::testing(&testing); - assert_eq!(time_source.now(), UNIX_EPOCH); - testing.advance(Duration::from_secs(10)); - assert_eq!(time_source.now(), UNIX_EPOCH + Duration::from_secs(10)); - } -} diff --git a/rust-runtime/aws-smithy-async/src/test_util.rs b/rust-runtime/aws-smithy-async/src/test_util.rs index fa1dfe300b5..e323478d846 100644 --- a/rust-runtime/aws-smithy-async/src/test_util.rs +++ b/rust-runtime/aws-smithy-async/src/test_util.rs @@ -35,11 +35,43 @@ impl ManualTimeSource { .unwrap() .as_secs_f64() } + + /// Creates a new [`ManualTimeSource`] + pub fn new(start_time: SystemTime) -> ManualTimeSource { + Self { + start_time, + log: Default::default(), + } + } + + /// Advances the time of this time source by `duration`. + pub fn advance(&self, duration: Duration) -> SystemTime { + let mut log = self.log.lock().unwrap(); + log.push(duration); + self._now(&log) + } + + fn _now(&self, log: &[Duration]) -> SystemTime { + self.start_time + log.iter().sum::() + } + + /// Sets the `time` of this manual time source. + /// + /// # Panics + /// This function panics if `time` < `now()` + pub fn set_time(&self, time: SystemTime) { + let mut log = self.log.lock().unwrap(); + let now = self._now(&log); + if time < now { + panic!("Cannot move time backwards!"); + } + log.push(time.duration_since(now).unwrap()); + } } impl TimeSource for ManualTimeSource { fn now(&self) -> SystemTime { - self.start_time + self.log.lock().unwrap().iter().sum::() + self._now(&self.log.lock().unwrap()) } }