testcontainers_modules/consul/
mod.rs1use std::{borrow::Cow, collections::BTreeMap};
2
3use testcontainers::{core::WaitFor, Image};
4
5const DEFAULT_IMAGE_NAME: &str = "hashicorp/consul";
6const DEFAULT_IMAGE_TAG: &str = "1.16.1";
7const CONSUL_LOCAL_CONFIG: &str = "CONSUL_LOCAL_CONFIG";
8
9#[derive(Debug, Default, Clone)]
26pub struct Consul {
27 env_vars: BTreeMap<String, String>,
28}
29
30impl Consul {
31 #[allow(missing_docs)]
33 pub fn with_local_config(self, config: String) -> Self {
34 let mut env_vars = self.env_vars;
35 env_vars.insert(CONSUL_LOCAL_CONFIG.to_owned(), config);
36 Self { env_vars }
37 }
38}
39
40impl Image for Consul {
41 fn name(&self) -> &str {
42 DEFAULT_IMAGE_NAME
43 }
44
45 fn tag(&self) -> &str {
46 DEFAULT_IMAGE_TAG
47 }
48
49 fn ready_conditions(&self) -> Vec<WaitFor> {
50 vec![WaitFor::message_on_stdout("agent: Consul agent running!")]
51 }
52
53 fn env_vars(
54 &self,
55 ) -> impl IntoIterator<Item = (impl Into<Cow<'_, str>>, impl Into<Cow<'_, str>>)> {
56 &self.env_vars
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use serde_json::Value;
63
64 use crate::{consul::Consul, testcontainers::runners::AsyncRunner};
65
66 #[tokio::test]
67 async fn consul_container() -> Result<(), Box<dyn std::error::Error + 'static>> {
68 let consul = Consul::default().with_local_config("{\"datacenter\":\"dc-rust\"}".to_owned());
69 let node = consul.start().await?;
70 let port = node.get_host_port_ipv4(8500).await?;
71
72 let response = reqwest::Client::new()
73 .get(format!("http://localhost:{}/v1/agent/self", port))
74 .send()
75 .await
76 .unwrap()
77 .json::<Value>()
78 .await
79 .unwrap();
80 let config = response.as_object().unwrap().get("Config").unwrap();
81 let dc = config
82 .as_object()
83 .unwrap()
84 .get("Datacenter")
85 .unwrap()
86 .as_str()
87 .unwrap();
88 assert_eq!("dc-rust", dc);
89 Ok(())
90 }
91}