testcontainers_modules/localstack/
mod.rs

1pub use pro::LocalStackPro;
2use testcontainers::{core::WaitFor, Image};
3
4/// LocalStack Pro
5pub mod pro;
6
7const NAME: &str = "localstack/localstack";
8const TAG: &str = "3.0";
9const DEFAULT_WAIT: u64 = 3000;
10
11/// This module provides [LocalStack](https://www.localstack.cloud/) (Community Edition).
12///
13/// Currently pinned to [version `3.0`](https://hub.docker.com/layers/localstack/localstack/3.0/images/sha256-73698e485240939490134aadd7e429ac87ff068cd5ad09f5de8ccb76727c13e1?context=explore)
14///
15/// # Configuration
16///
17/// For configuration, LocalStack uses environment variables. You can go [here](https://docs.localstack.cloud/references/configuration/)
18/// for the full list.
19///
20/// Testcontainers support setting environment variables with the method
21/// `RunnableImage::with_env_var((impl Into<String>, impl Into<String>))`. You will have to convert
22/// the Image into a RunnableImage first.
23///
24/// ```
25/// use testcontainers_modules::{localstack::LocalStack, testcontainers::ImageExt};
26///
27/// let container_request = LocalStack::default().with_env_var("SERVICES", "s3");
28/// ```
29///
30/// No environment variables are required.
31#[derive(Default, Debug, Clone)]
32pub struct LocalStack {
33    /// (remove if there is another variable)
34    /// Field is included to prevent this struct to be a unit struct.
35    /// This allows extending functionality (and thus further variables) without breaking changes
36    _priv: (),
37}
38
39impl Image for LocalStack {
40    fn name(&self) -> &str {
41        NAME
42    }
43
44    fn tag(&self) -> &str {
45        TAG
46    }
47
48    fn ready_conditions(&self) -> Vec<WaitFor> {
49        vec![
50            WaitFor::message_on_stdout("Ready."),
51            WaitFor::millis(DEFAULT_WAIT),
52        ]
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use aws_config::{meta::region::RegionProviderChain, BehaviorVersion};
59    use aws_sdk_sqs as sqs;
60    use testcontainers::runners::AsyncRunner;
61
62    use super::LocalStack;
63
64    #[tokio::test]
65    #[allow(clippy::result_large_err)]
66    async fn create_and_list_queue() -> Result<(), Box<dyn std::error::Error + 'static>> {
67        let node = LocalStack::default().start().await?;
68        let host_ip = node.get_host().await?;
69        let host_port = node.get_host_port_ipv4(4566).await?;
70
71        let region_provider = RegionProviderChain::default_provider().or_else("us-east-1");
72        let creds = sqs::config::Credentials::new("fake", "fake", None, None, "test");
73        let config = aws_config::defaults(BehaviorVersion::v2025_01_17())
74            .region(region_provider)
75            .credentials_provider(creds)
76            .endpoint_url(format!("http://{host_ip}:{host_port}"))
77            .load()
78            .await;
79        let client = sqs::Client::new(&config);
80
81        client
82            .create_queue()
83            .queue_name("example-queue")
84            .send()
85            .await?;
86
87        let list_result = client.list_queues().send().await?;
88        assert_eq!(list_result.queue_urls().len(), 1);
89
90        Ok(())
91    }
92}