diff --git a/guide/samples/tests/driver.rs b/guide/samples/tests/driver.rs index 44432d1f02..2db934ec3e 100644 --- a/guide/samples/tests/driver.rs +++ b/guide/samples/tests/driver.rs @@ -14,13 +14,34 @@ #[cfg(all(test, feature = "run-integration-tests"))] mod driver { + use google_cloud_gax::error::rpc::{Code, StatusDetails}; use rand::{Rng, distr::Alphanumeric}; const SECRET_ID_LENGTH: usize = 32; #[tokio::test(flavor = "multi_thread")] async fn authentication() -> anyhow::Result<()> { - user_guide_samples::authentication::adc::sample().await?; + let Err(err) = user_guide_samples::authentication::adc::sample().await else { + return Ok(()); + }; + // When the credentials lack a quota project the service returns this + // error. + let Some(StatusDetails::ErrorInfo(_)) = err + .downcast_ref::() + .and_then(|s| s.status()) + .filter(|s| s.code == Code::PermissionDenied) + .and_then(|s| { + // Must have a StatusDetails::ErrorInfo(_) in the details. + s.details.iter().find( + // ErrorInfo.reason can be treated as an enum. Testing its + // value programmatically is fine. + |d| matches!(d, StatusDetails::ErrorInfo(i) if i.reason == "SERVICE_DISABLED"), + ) + }) + else { + return Err(err); + }; + eprintln!("ignoring error: {err:?}"); Ok(()) } @@ -28,15 +49,23 @@ mod driver { async fn id_token() -> anyhow::Result<()> { use google_cloud_auth::credentials::idtoken::Builder; use httptest::{Expectation, Server, matchers::*, responders::*}; + const AUDIENCE: &str = "https://my-service.a.run.app"; - let audience = "https://my-service.a.run.app"; - let id_token = - user_guide_samples::authentication::request_id_token::sample(audience).await?; - user_guide_samples::authentication::verify_id_token::sample(&id_token, audience).await?; + let credentials = match Builder::new(AUDIENCE).build() { + Ok(c) => c, + Err(e) if e.is_not_supported() => { + eprintln!("ADC credentials type not supported for idtoken credentials: {e:?}"); + return Ok(()); + } + Err(e) => return Err(e.into()), + }; - let credentials = Builder::new(audience).build()?; - let id_token = credentials.id_token().await?; + let id_token = + user_guide_samples::authentication::request_id_token::sample(AUDIENCE).await?; + user_guide_samples::authentication::verify_id_token::sample(&id_token, AUDIENCE).await?; + // Create a server so the `api_call_with_id_token()` example has + // a valid URL to call upon. let server = Server::run(); server.expect( Expectation::matching(all_of![ @@ -53,7 +82,6 @@ mod driver { &credentials, ) .await?; - Ok(()) } diff --git a/guide/samples/tests/storage.rs b/guide/samples/tests/storage.rs index 4ac1c4e928..3442919232 100644 --- a/guide/samples/tests/storage.rs +++ b/guide/samples/tests/storage.rs @@ -24,6 +24,7 @@ pub mod storage { use google_cloud_storage::client::StorageControl; pub use google_cloud_test_utils::resource_names::random_bucket_id; + use storage_samples::custom_project_billing; #[cfg(all(test, feature = "run-integration-tests"))] mod driver { @@ -70,8 +71,10 @@ pub mod storage { } println!("running terminate_uploads() test"); terminate_uploads::attempt_upload(bucket_name).await?; - println!("running lros() test"); - lros::test(client, bucket_name).await?; + if !custom_project_billing("the LRO operation used for testing").await? { + println!("running lros() test"); + lros::test(client, bucket_name).await?; + } println!("running polling_policies() test"); polling_policies::test(client, bucket_name).await?; Ok(()) diff --git a/guide/samples/tests/storage/polling_policies.rs b/guide/samples/tests/storage/polling_policies.rs index 32343561ba..d9f20a5424 100644 --- a/guide/samples/tests/storage/polling_policies.rs +++ b/guide/samples/tests/storage/polling_policies.rs @@ -17,6 +17,7 @@ use anyhow::{Result, anyhow}; // ANCHOR: use use google_cloud_storage::client::StorageControl; +use storage_samples::custom_project_billing; // ANCHOR_END: use // ANCHOR: client-backoff @@ -222,13 +223,15 @@ pub async fn test(control: &StorageControl, bucket: &str) -> Result<()> { let bucket_id = bucket.strip_prefix("projects/_/buckets/").ok_or(anyhow!( "bad bucket name format {bucket}, should start with `projects/_/buckets/`" ))?; - println!("running client_backoff example"); - client_backoff(bucket_id, "client-backoff", "client-backoff-renamed").await?; - println!("running rpc_backoff example"); - rpc_backoff(bucket_id, "rpc-backoff", "rpc-backoff-renamed").await?; - println!("running client_errors example"); - client_errors(bucket_id, "client-errors", "client-errors-renamed").await?; - println!("running rpc_errors example"); - rpc_errors(bucket_id, "rpc-errors", "rpc-errors-renamed").await?; + if !custom_project_billing("the operation used in the LRO examples").await? { + println!("running client_backoff example"); + client_backoff(bucket_id, "client-backoff", "client-backoff-renamed").await?; + println!("running rpc_backoff example"); + rpc_backoff(bucket_id, "rpc-backoff", "rpc-backoff-renamed").await?; + println!("running client_errors example"); + client_errors(bucket_id, "client-errors", "client-errors-renamed").await?; + println!("running rpc_errors example"); + rpc_errors(bucket_id, "rpc-errors", "rpc-errors-renamed").await?; + } Ok(()) }