Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add consul module #104

Merged
merged 2 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rustdoc-args = ["--cfg", "docsrs"]

[features]
default = []
consul = []
dynamodb = []
elastic_search = []
elasticmq = []
Expand Down
114 changes: 114 additions & 0 deletions src/consul/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use std::collections::BTreeMap;

use testcontainers::core::WaitFor;
use testcontainers::Image;

const DEFAULT_IMAGE_NAME: &str = "hashicorp/consul";
const DEFAULT_IMAGE_TAG: &str = "1.16.1";
const CONSUL_LOCAL_CONFIG: &str = "CONSUL_LOCAL_CONFIG";

/// Module to work with [`Consul`] inside of tests.
///
/// This module is based on the official [`Consul docker image`].
///
/// # Example
/// ```
/// use testcontainers::clients;
/// use testcontainers_modules::consul;
///
/// let docker = clients::Cli::default();
/// let consul = docker.run(consul::Consul::default());
///
/// let http_port = consul.get_host_port_ipv4(8500);
///
/// // do something with the started consul instance..
/// ```
///
/// [`Consul`]: https://www.consul.io/
/// [`Consul docker image`]: https://hub.docker.com/r/hashicorp/consul
#[derive(Debug)]
pub struct Consul {
DDtKey marked this conversation as resolved.
Show resolved Hide resolved
name: String,
tag: String,
env_vars: BTreeMap<String, String>,
}

impl Default for Consul {
fn default() -> Self {
Consul::new(
DEFAULT_IMAGE_NAME.to_string(),
DEFAULT_IMAGE_TAG.to_string(),
)
}
}

impl Consul {
fn new(name: String, tag: String) -> Self {
Consul {
name,
tag,
env_vars: Default::default(),
}
}

pub fn with_local_config(self, config: String) -> Self {
let mut env_vars = self.env_vars;
env_vars.insert(CONSUL_LOCAL_CONFIG.to_owned(), config);
Self { env_vars, ..self }
}
}

impl Image for Consul {
type Args = ();

fn name(&self) -> String {
self.name.clone()
}

fn tag(&self) -> String {
self.tag.clone()
}

fn ready_conditions(&self) -> Vec<WaitFor> {
vec![WaitFor::message_on_stdout("agent: Consul agent running!")]
}

fn env_vars(&self) -> Box<dyn Iterator<Item = (&String, &String)> + '_> {
Box::new(self.env_vars.iter())
}
}

#[cfg(test)]
mod tests {
use serde_json::Value;
use testcontainers::clients;

use crate::consul::Consul;

#[tokio::test]
async fn consul_container() {
let docker = clients::Cli::default();

let consul = Consul::default().with_local_config("{\"datacenter\":\"dc-rust\"}".to_owned());
let node = docker.run(consul);
let port = node.get_host_port_ipv4(8500);

let response = reqwest::Client::new()
.get(format!("http://localhost:{}/v1/agent/self", port))
.send()
.await
.unwrap()
.json::<Value>()
.await
.unwrap();
let config = response.as_object().unwrap().get("Config").unwrap();
let dc = config
.as_object()
.unwrap()
.get("Datacenter")
.unwrap()
.as_str()
.unwrap();
assert_eq!("dc-rust", dc)
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#![doc = include_str!("../README.md")]
//! Please have a look at the documentation of the separate modules for examples on how to use the module.

#[cfg(feature = "consul")]
#[cfg_attr(docsrs, doc(cfg(feature = "consul")))]
pub mod consul;
#[cfg(feature = "dynamodb")]
#[cfg_attr(docsrs, doc(cfg(feature = "dynamodb")))]
pub mod dynamodb_local;
Expand Down
Loading