LCOV - code coverage report
Current view: top level - libs/remote_storage/tests - test_real_azure.rs (source / functions) Coverage Total Hit
Test: 792183ae0ef4f1f8b22e9ac7e8748740ab73f873.info Lines: 79.4 % 126 100
Test Date: 2024-06-26 01:04:33 Functions: 92.9 % 14 13

            Line data    Source code
       1              : use std::env;
       2              : use std::num::NonZeroUsize;
       3              : use std::ops::ControlFlow;
       4              : use std::sync::Arc;
       5              : use std::time::UNIX_EPOCH;
       6              : use std::{collections::HashSet, time::Duration};
       7              : 
       8              : use anyhow::Context;
       9              : use remote_storage::{
      10              :     AzureConfig, GenericRemoteStorage, RemotePath, RemoteStorageConfig, RemoteStorageKind,
      11              : };
      12              : use test_context::AsyncTestContext;
      13              : use tracing::info;
      14              : 
      15              : mod common;
      16              : 
      17              : #[path = "common/tests.rs"]
      18              : mod tests_azure;
      19              : 
      20              : use common::{cleanup, ensure_logging_ready, upload_remote_data, upload_simple_remote_data};
      21              : 
      22              : const ENABLE_REAL_AZURE_REMOTE_STORAGE_ENV_VAR_NAME: &str = "ENABLE_REAL_AZURE_REMOTE_STORAGE";
      23              : 
      24              : const BASE_PREFIX: &str = "test";
      25              : 
      26              : struct EnabledAzure {
      27              :     client: Arc<GenericRemoteStorage>,
      28              :     base_prefix: &'static str,
      29              : }
      30              : 
      31              : impl EnabledAzure {
      32            6 :     async fn setup(max_keys_in_list_response: Option<i32>) -> Self {
      33            6 :         let client = create_azure_client(max_keys_in_list_response)
      34            6 :             .context("Azure client creation")
      35            6 :             .expect("Azure client creation failed");
      36            6 : 
      37            6 :         EnabledAzure {
      38            6 :             client,
      39            6 :             base_prefix: BASE_PREFIX,
      40            6 :         }
      41            6 :     }
      42              : 
      43              :     #[allow(unused)] // this will be needed when moving the timeout integration tests back
      44            0 :     fn configure_request_timeout(&mut self, timeout: Duration) {
      45            0 :         match Arc::get_mut(&mut self.client).expect("outer Arc::get_mut") {
      46            0 :             GenericRemoteStorage::AzureBlob(azure) => {
      47            0 :                 let azure = Arc::get_mut(azure).expect("inner Arc::get_mut");
      48            0 :                 azure.timeout = timeout;
      49            0 :             }
      50            0 :             _ => unreachable!(),
      51              :         }
      52            0 :     }
      53              : }
      54              : 
      55              : enum MaybeEnabledStorage {
      56              :     Enabled(EnabledAzure),
      57              :     Disabled,
      58              : }
      59              : 
      60              : impl AsyncTestContext for MaybeEnabledStorage {
      61           16 :     async fn setup() -> Self {
      62           16 :         ensure_logging_ready();
      63           16 : 
      64           16 :         if env::var(ENABLE_REAL_AZURE_REMOTE_STORAGE_ENV_VAR_NAME).is_err() {
      65           12 :             info!(
      66            0 :                 "`{}` env variable is not set, skipping the test",
      67              :                 ENABLE_REAL_AZURE_REMOTE_STORAGE_ENV_VAR_NAME
      68              :             );
      69           12 :             return Self::Disabled;
      70            4 :         }
      71            4 : 
      72            4 :         Self::Enabled(EnabledAzure::setup(None).await)
      73           16 :     }
      74              : }
      75              : 
      76              : enum MaybeEnabledStorageWithTestBlobs {
      77              :     Enabled(AzureWithTestBlobs),
      78              :     Disabled,
      79              :     UploadsFailed(anyhow::Error, AzureWithTestBlobs),
      80              : }
      81              : 
      82              : struct AzureWithTestBlobs {
      83              :     enabled: EnabledAzure,
      84              :     remote_prefixes: HashSet<RemotePath>,
      85              :     remote_blobs: HashSet<RemotePath>,
      86              : }
      87              : 
      88              : impl AsyncTestContext for MaybeEnabledStorageWithTestBlobs {
      89            4 :     async fn setup() -> Self {
      90            4 :         ensure_logging_ready();
      91            4 :         if env::var(ENABLE_REAL_AZURE_REMOTE_STORAGE_ENV_VAR_NAME).is_err() {
      92            3 :             info!(
      93            0 :                 "`{}` env variable is not set, skipping the test",
      94              :                 ENABLE_REAL_AZURE_REMOTE_STORAGE_ENV_VAR_NAME
      95              :             );
      96            3 :             return Self::Disabled;
      97            1 :         }
      98            1 : 
      99            1 :         let max_keys_in_list_response = 10;
     100            1 :         let upload_tasks_count = 1 + (2 * usize::try_from(max_keys_in_list_response).unwrap());
     101              : 
     102            1 :         let enabled = EnabledAzure::setup(Some(max_keys_in_list_response)).await;
     103              : 
     104           21 :         match upload_remote_data(&enabled.client, enabled.base_prefix, upload_tasks_count).await {
     105            1 :             ControlFlow::Continue(uploads) => {
     106            1 :                 info!("Remote objects created successfully");
     107              : 
     108            1 :                 Self::Enabled(AzureWithTestBlobs {
     109            1 :                     enabled,
     110            1 :                     remote_prefixes: uploads.prefixes,
     111            1 :                     remote_blobs: uploads.blobs,
     112            1 :                 })
     113              :             }
     114            0 :             ControlFlow::Break(uploads) => Self::UploadsFailed(
     115            0 :                 anyhow::anyhow!("One or multiple blobs failed to upload to Azure"),
     116            0 :                 AzureWithTestBlobs {
     117            0 :                     enabled,
     118            0 :                     remote_prefixes: uploads.prefixes,
     119            0 :                     remote_blobs: uploads.blobs,
     120            0 :                 },
     121            0 :             ),
     122              :         }
     123            4 :     }
     124              : 
     125            4 :     async fn teardown(self) {
     126            4 :         match self {
     127            3 :             Self::Disabled => {}
     128            1 :             Self::Enabled(ctx) | Self::UploadsFailed(_, ctx) => {
     129           21 :                 cleanup(&ctx.enabled.client, ctx.remote_blobs).await;
     130              :             }
     131              :         }
     132            4 :     }
     133              : }
     134              : 
     135              : enum MaybeEnabledStorageWithSimpleTestBlobs {
     136              :     Enabled(AzureWithSimpleTestBlobs),
     137              :     Disabled,
     138              :     UploadsFailed(anyhow::Error, AzureWithSimpleTestBlobs),
     139              : }
     140              : struct AzureWithSimpleTestBlobs {
     141              :     enabled: EnabledAzure,
     142              :     remote_blobs: HashSet<RemotePath>,
     143              : }
     144              : 
     145              : impl AsyncTestContext for MaybeEnabledStorageWithSimpleTestBlobs {
     146            4 :     async fn setup() -> Self {
     147            4 :         ensure_logging_ready();
     148            4 :         if env::var(ENABLE_REAL_AZURE_REMOTE_STORAGE_ENV_VAR_NAME).is_err() {
     149            3 :             info!(
     150            0 :                 "`{}` env variable is not set, skipping the test",
     151              :                 ENABLE_REAL_AZURE_REMOTE_STORAGE_ENV_VAR_NAME
     152              :             );
     153            3 :             return Self::Disabled;
     154            1 :         }
     155            1 : 
     156            1 :         let max_keys_in_list_response = 10;
     157            1 :         let upload_tasks_count = 1 + (2 * usize::try_from(max_keys_in_list_response).unwrap());
     158              : 
     159            1 :         let enabled = EnabledAzure::setup(Some(max_keys_in_list_response)).await;
     160              : 
     161           21 :         match upload_simple_remote_data(&enabled.client, upload_tasks_count).await {
     162            1 :             ControlFlow::Continue(uploads) => {
     163            1 :                 info!("Remote objects created successfully");
     164              : 
     165            1 :                 Self::Enabled(AzureWithSimpleTestBlobs {
     166            1 :                     enabled,
     167            1 :                     remote_blobs: uploads,
     168            1 :                 })
     169              :             }
     170            0 :             ControlFlow::Break(uploads) => Self::UploadsFailed(
     171            0 :                 anyhow::anyhow!("One or multiple blobs failed to upload to Azure"),
     172            0 :                 AzureWithSimpleTestBlobs {
     173            0 :                     enabled,
     174            0 :                     remote_blobs: uploads,
     175            0 :                 },
     176            0 :             ),
     177              :         }
     178            4 :     }
     179              : 
     180            4 :     async fn teardown(self) {
     181            4 :         match self {
     182            3 :             Self::Disabled => {}
     183            1 :             Self::Enabled(ctx) | Self::UploadsFailed(_, ctx) => {
     184           21 :                 cleanup(&ctx.enabled.client, ctx.remote_blobs).await;
     185              :             }
     186              :         }
     187            4 :     }
     188              : }
     189              : 
     190            6 : fn create_azure_client(
     191            6 :     max_keys_per_list_response: Option<i32>,
     192            6 : ) -> anyhow::Result<Arc<GenericRemoteStorage>> {
     193              :     use rand::Rng;
     194              : 
     195            6 :     let remote_storage_azure_container = env::var("REMOTE_STORAGE_AZURE_CONTAINER").context(
     196            6 :         "`REMOTE_STORAGE_AZURE_CONTAINER` env var is not set, but real Azure tests are enabled",
     197            6 :     )?;
     198            6 :     let remote_storage_azure_region = env::var("REMOTE_STORAGE_AZURE_REGION").context(
     199            6 :         "`REMOTE_STORAGE_AZURE_REGION` env var is not set, but real Azure tests are enabled",
     200            6 :     )?;
     201              : 
     202              :     // due to how time works, we've had test runners use the same nanos as bucket prefixes.
     203              :     // millis is just a debugging aid for easier finding the prefix later.
     204            6 :     let millis = std::time::SystemTime::now()
     205            6 :         .duration_since(UNIX_EPOCH)
     206            6 :         .context("random Azure test prefix part calculation")?
     207            6 :         .as_millis();
     208            6 : 
     209            6 :     // because nanos can be the same for two threads so can millis, add randomness
     210            6 :     let random = rand::thread_rng().gen::<u32>();
     211            6 : 
     212            6 :     let remote_storage_config = RemoteStorageConfig {
     213            6 :         storage: RemoteStorageKind::AzureContainer(AzureConfig {
     214            6 :             container_name: remote_storage_azure_container,
     215            6 :             storage_account: None,
     216            6 :             container_region: remote_storage_azure_region,
     217            6 :             prefix_in_container: Some(format!("test_{millis}_{random:08x}/")),
     218            6 :             concurrency_limit: NonZeroUsize::new(100).unwrap(),
     219            6 :             max_keys_per_list_response,
     220            6 :         }),
     221            6 :         timeout: Duration::from_secs(120),
     222            6 :     };
     223            6 :     Ok(Arc::new(
     224            6 :         GenericRemoteStorage::from_config(&remote_storage_config).context("remote storage init")?,
     225              :     ))
     226            6 : }
        

Generated by: LCOV version 2.1-beta