aptos_testcontainer/
test_utils.rs

1/// This module provides utility functions for testing the `AptosContainer` by:
2#[cfg(feature = "testing")]
3pub mod aptos_container_test_utils {
4    use std::future::Future;
5    use std::pin::Pin;
6    use std::sync::{Arc, OnceLock, Weak};
7
8    use anyhow::Result;
9    use tokio::sync::Mutex;
10
11    use crate::aptos_container::AptosContainer;
12
13    static APTOS_CONTAINER: OnceLock<Mutex<Weak<AptosContainer>>> = OnceLock::new();
14
15    /// Lazily initializes and retrieves an `Arc<AptosContainer>`.
16    ///
17    /// # Returns
18    ///
19    /// * `Result<Arc<AptosContainer>>` - Returns an `Arc` pointing to the initialized `AptosContainer`.
20    ///
21    /// # Example
22    /// ```rust
23    /// use aptos_testcontainer::test_utils::aptos_container_test_utils::lazy_aptos_container;
24    ///
25    /// #[tokio::main]
26    /// async fn main() {
27    ///     let aptos_container = lazy_aptos_container().await.unwrap();
28    /// }
29    /// ```
30    pub async fn lazy_aptos_container() -> Result<Arc<AptosContainer>> {
31        // Access the global `APTOS_CONTAINER`, initialize it with a new `Mutex<Weak<AptosContainer>>`
32        // if it's not already initialized. Lock the `Mutex` to safely access the weak reference.
33        let mut guard = APTOS_CONTAINER
34            .get_or_init(|| Mutex::new(Weak::new()))
35            .lock()
36            .await;
37
38        // Attempt to upgrade the weak reference to a strong `Arc<AptosContainer>`.
39        let maybe_client = guard.upgrade();
40
41        // If a valid container already exists, return the strong reference.
42        if let Some(client) = maybe_client {
43            Ok(client)
44        } else {
45            // Otherwise, initialize a new `AptosContainer`, store a weak reference to it,
46            // and return the strong `Arc<AptosContainer>`.
47            let client = Arc::new(AptosContainer::init().await?);
48            *guard = Arc::downgrade(&client);
49
50            Ok(client)
51        }
52    }
53
54    /// Asynchronously runs a process that involves managing Aptos accounts using a `AptopsContainer`.
55    ///
56    /// # Arguments
57    ///
58    /// * `number_of_accounts` - The number of accounts required to run the process.
59    /// * `runner` - A callback function that takes a vector of accounts (`Vec<String>`) and returns
60    ///   a `Future`. This function defines the operations to be performed
61    ///   once the accounts are initialized or retrieved.
62    ///
63    /// # Example
64    /// ```rust
65    /// use std::collections::HashMap;
66    /// use aptos_testcontainer::test_utils::aptos_container_test_utils::{lazy_aptos_container, run};
67    /// use aptos_testcontainer::utils::get_account_address;
68    ///
69    /// #[tokio::main]
70    /// async fn main() {
71    ///     run(2, |accounts| {
72    ///         Box::pin(async move {
73    ///             let aptos_container = lazy_aptos_container().await.unwrap();
74    ///             let module_account_private_key = accounts.first().unwrap();
75    ///             let module_account_address = get_account_address(module_account_private_key);
76    ///
77    ///             let mut named_addresses = HashMap::new();
78    ///             named_addresses.insert("verifier_addr".to_string(), module_account_address.clone());
79    ///             aptos_container
80    ///                 .upload_contract(
81    ///                     "./contract-samples/sample1",
82    ///                     module_account_private_key,
83    ///                     &named_addresses,
84    ///                     None,
85    ///                     false,
86    ///                 )
87    ///                 .await
88    ///                 .unwrap();
89    ///             Ok(())
90    ///         })
91    ///     })
92    ///     .await
93    ///     .unwrap();
94    /// }
95    /// ```
96    pub async fn run(
97        number_of_accounts: usize,
98        runner: impl FnOnce(Vec<String>) -> Pin<Box<dyn Future<Output = Result<()>>>>,
99    ) -> Result<()> {
100        let aptos_container = lazy_aptos_container().await?;
101        aptos_container.run(number_of_accounts, runner).await
102    }
103}