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}