LCOV - code coverage report
Current view: top level - libs/remote_storage/tests - test_real_azure.rs (source / functions) Coverage Total Hit
Test: 32f4a56327bc9da697706839ed4836b2a00a408f.info Lines: 29.5 % 122 36
Test Date: 2024-02-07 07:37:29 Functions: 72.2 % 18 13

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

Generated by: LCOV version 2.1-beta