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: introduce properties-config cargo feature #608

Merged
merged 2 commits into from
Apr 29, 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
3 changes: 2 additions & 1 deletion testcontainers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ futures = "0.3"
log = "0.4"
parse-display = "0.9.0"
serde = { version = "1", features = ["derive"] }
serde-java-properties = "0.1.1"
serde-java-properties = { version = "0.1.1", optional = true }
serde_json = "1"
serde_with = "3.7.0"
signal-hook = { version = "0.3", optional = true }
Expand All @@ -37,6 +37,7 @@ url = { version = "2", features = ["serde"] }
default = []
blocking = []
watchdog = ["signal-hook", "conquer-once"]
properties-config = ["serde-java-properties"]

[dev-dependencies]
pretty_env_logger = "0.5"
Expand Down
64 changes: 51 additions & 13 deletions testcontainers/src/core/env/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ use std::{
str::FromStr,
};

use serde::Deserialize;
use serde_with::serde_as;
use url::Url;

use crate::core::env::GetEnvValue;

#[cfg(feature = "properties-config")]
const TESTCONTAINERS_PROPERTIES: &str = ".testcontainers.properties";

/// The default `DOCKER_HOST` address that we will try to connect to.
Expand All @@ -28,8 +27,9 @@ pub(crate) struct Config {
command: Option<Command>,
}

#[serde_as]
#[derive(Debug, Default, Deserialize)]
#[cfg(feature = "properties-config")]
#[serde_with::serde_as]
#[derive(Debug, Default, serde::Deserialize)]
struct TestcontainersProperties {
#[serde(rename = "tc.host")]
tc_host: Option<Url>,
Expand All @@ -42,6 +42,7 @@ struct TestcontainersProperties {
cert_path: Option<PathBuf>,
}

#[cfg(feature = "properties-config")]
impl TestcontainersProperties {
async fn load() -> Option<Self> {
let home_dir = dirs::home_dir()?;
Expand All @@ -61,16 +62,22 @@ impl Config {
E: GetEnvValue,
{
let env_config = Self::load_from_env_config::<E>();
let properties = TestcontainersProperties::load().await.unwrap_or_default();

// Environment variables take precedence over properties
Self {
tc_host: env_config.tc_host.or(properties.tc_host),
host: env_config.host.or(properties.host),
tls_verify: env_config.tls_verify.or(properties.tls_verify),
cert_path: env_config.cert_path.or(properties.cert_path),
command: env_config.command,

#[cfg(feature = "properties-config")]
{
let properties = TestcontainersProperties::load().await.unwrap_or_default();

// Environment variables take precedence over properties
Self {
tc_host: env_config.tc_host.or(properties.tc_host),
host: env_config.host.or(properties.host),
tls_verify: env_config.tls_verify.or(properties.tls_verify),
cert_path: env_config.cert_path.or(properties.cert_path),
command: env_config.command,
}
}
#[cfg(not(feature = "properties-config"))]
env_config
}

fn load_from_env_config<E>() -> Self
Expand Down Expand Up @@ -142,3 +149,34 @@ impl FromStr for Command {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[cfg(feature = "properties-config")]
#[test]
fn deserialize_java_properties() {
let tc_host = Url::parse("http://tc-host").unwrap();
let docker_host = Url::parse("http://docker-host").unwrap();
let tls_verify = 1;
let cert_path = "/path/to/cert";

let file_content = format!(
r"
tc.host={tc_host}
docker.host={docker_host}
docker.tls.verify={tls_verify}
docker.cert.path={cert_path}
"
);
let properties: TestcontainersProperties =
serde_java_properties::from_slice(file_content.as_bytes())
.expect("Failed to parse properties");

assert_eq!(properties.tc_host, Some(tc_host));
assert_eq!(properties.host, Some(docker_host));
assert_eq!(properties.tls_verify, Some(tls_verify == 1));
assert_eq!(properties.cert_path, Some(PathBuf::from(cert_path)));
}
}
13 changes: 13 additions & 0 deletions testcontainers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@
//!
//! See examples in the corresponding runner ([`AsyncRunner`] and [`SyncRunner`])
//!
//! ### Docker host resolution
//!
//! You can change the configuration of the Docker host used by the client in two ways:
//! - environment variables
//! - `~/.testcontainers.properties` file (a Java properties file, enabled by the `properties-config` feature)
//!
//! ##### The host is resolved in the following order:
//!
//! 1. Docker host from the `tc.host` property in the `~/.testcontainers.properties` file.
//! 2. `DOCKER_HOST` environment variable.
//! 3. Docker host from the "docker.host" property in the `~/.testcontainers.properties` file.
//! 4. Else, the default Docker socket will be returned.
//!
//! # Ecosystem
//!
//! `testcontainers` is the core crate that provides an API for working with containers in a test environment.
Expand Down
Loading