use std::time::Duration;
use crate::config::{Config, ContainerConfig};
use crate::container::Container;
use crate::error::TestError;
use crate::image::Image;
use crate::port::{Port, PortAccess, PortVisibility};
use crate::probe::{MessageProbe, MessageSource};
use crate::service::Service;
const PORT: Port = 80;
const SCHEMA: &str = "http";
const HTTPBIN_IMAGE_NAME: &str = "kennethreitz/httpbin";
#[derive(Clone)]
pub struct HttpBinConfig {
hostname: String,
version: String,
image_name: String,
visibility: PortVisibility,
timeout: Duration,
}
impl HttpBinConfig {
pub fn hostname(&self) -> &str {
&self.hostname
}
pub fn version(&self) -> &str {
&self.version
}
pub fn image_name(&self) -> &str {
&self.image_name
}
pub fn visibility(&self) -> PortVisibility {
self.visibility
}
pub fn timeout(&self) -> Duration {
self.timeout
}
pub fn new() -> Self {
Self {
hostname: "backend".to_string(),
version: "latest".to_string(),
image_name: HTTPBIN_IMAGE_NAME.to_string(),
timeout: Duration::from_secs(30),
visibility: Default::default(),
}
}
pub fn builder() -> HttpBinConfigBuilder {
HttpBinConfigBuilder::new()
}
}
pub struct HttpBinConfigBuilder {
config: HttpBinConfig,
}
impl HttpBinConfigBuilder {
fn new() -> Self {
Self {
config: HttpBinConfig::new(),
}
}
pub fn hostname<T: Into<String>>(self, hostname: T) -> Self {
Self {
config: HttpBinConfig {
hostname: hostname.into(),
..self.config
},
}
}
pub fn version<T: Into<String>>(self, version: T) -> Self {
Self {
config: HttpBinConfig {
version: version.into(),
..self.config
},
}
}
pub fn image_name<T: Into<String>>(self, image_name: T) -> Self {
Self {
config: HttpBinConfig {
image_name: image_name.into(),
..self.config
},
}
}
pub fn visibility(self, visibility: PortVisibility) -> Self {
Self {
config: HttpBinConfig {
visibility,
..self.config
},
}
}
pub fn timeout(self, timeout: Duration) -> Self {
Self {
config: HttpBinConfig {
timeout,
..self.config
},
}
}
pub fn build(self) -> HttpBinConfig {
self.config
}
}
impl Default for HttpBinConfig {
fn default() -> Self {
Self::new()
}
}
impl Config for HttpBinConfig {
fn hostname(&self) -> &str {
&self.hostname
}
fn port(&self) -> Port {
PORT
}
fn schema(&self) -> &str {
SCHEMA
}
fn to_container_config(&self) -> Result<ContainerConfig, TestError> {
Ok(ContainerConfig::builder(
self.hostname.clone(),
Image::from_repository(self.image_name()).with_version(self.version()),
)
.ports([PortAccess::new(PORT, self.visibility)])
.readiness(
MessageProbe::builder("Using worker: gevent")
.timeout(Duration::from_secs(30))
.source(MessageSource::StdErr)
.build(),
)
.build())
}
}
pub struct HttpBin {
socket: Option<String>,
address: Option<String>,
}
impl HttpBin {
pub fn socket(&self) -> Option<&str> {
self.socket.as_deref()
}
pub fn address(&self) -> Option<&str> {
self.address.as_deref()
}
}
impl Service for HttpBin {
type Config = HttpBinConfig;
fn new(_config: &Self::Config, container: &Container) -> Self {
let socket = container.socket(PORT).map(String::from);
let address = socket.as_ref().map(|s| format!("http://{s}"));
Self { socket, address }
}
}