testcontainers_modules/localstack/
pro.rs1use std::borrow::Cow;
2
3use testcontainers::{core::WaitFor, Image};
4
5const NAME: &str = "localstack/localstack-pro";
6
7#[derive(Clone)]
29pub struct LocalStackPro {
30 auth_token: Option<String>,
33}
34
35impl LocalStackPro {
36 pub fn new(auth_token: impl Into<String>) -> Self {
39 Self::with_auth_token(Some(auth_token))
40 }
41
42 pub fn from_env() -> Self {
46 Self::with_auth_token(std::env::var("LOCALSTACK_AUTH_TOKEN").ok())
47 }
48
49 pub fn with_auth_token(auth_token: Option<impl Into<String>>) -> Self {
52 Self {
53 auth_token: auth_token.map(Into::into),
54 }
55 }
56}
57
58impl Default for LocalStackPro {
59 fn default() -> Self {
60 Self::from_env()
61 }
62}
63
64impl std::fmt::Debug for LocalStackPro {
65 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 formatter
67 .debug_struct("LocalStackPro")
68 .field("auth_token", &{
69 if self.auth_token.is_none() {
70 "[UNSET]"
71 } else {
72 "[REDACTED]"
73 }
74 })
75 .finish()
76 }
77}
78
79impl Image for LocalStackPro {
80 fn name(&self) -> &str {
81 NAME
82 }
83
84 fn tag(&self) -> &str {
85 super::TAG
86 }
87
88 fn ready_conditions(&self) -> Vec<WaitFor> {
89 vec![WaitFor::message_on_stdout("Ready."), WaitFor::healthcheck()]
90 }
91 fn env_vars(
92 &self,
93 ) -> impl IntoIterator<Item = (impl Into<Cow<'_, str>>, impl Into<Cow<'_, str>>)> {
94 if let Some(token) = self.auth_token.as_deref() {
95 vec![("LOCALSTACK_AUTH_TOKEN", token), ("ACTIVATE_PRO", "1")]
96 } else {
97 vec![("ACTIVATE_PRO", "0")]
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use testcontainers::runners::AsyncRunner;
105
106 use super::LocalStackPro;
107
108 #[tokio::test]
109 #[should_panic]
110 #[allow(clippy::result_large_err)]
111 async fn fails_on_invalid_token() {
112 LocalStackPro::new("not-a-real-auth-token")
113 .start()
114 .await
115 .unwrap();
116 }
117
118 #[tokio::test]
119 #[allow(clippy::result_large_err)]
120 async fn skips_pro_activation_without_token() {
121 let container = LocalStackPro::with_auth_token(Option::<&str>::None)
122 .start()
123 .await;
124
125 assert!(container.is_ok());
126
127 let stdout = container
128 .unwrap()
129 .stdout_to_vec()
130 .await
131 .map(|value| String::from_utf8_lossy(&value).to_string())
132 .unwrap_or_default();
133
134 assert!(
135 stdout.trim().ends_with("Ready."),
136 "expected a string ending with \"Ready.\" but got: {stdout}",
137 );
138 }
139}