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 INSECURE_PORT: Port = 9000;
const SECURE_PORT: Port = 9001;
const GRPC_SCHEMA: &str = "grpc";
pub const GRPCBIN_IMAGE_NAME: &str = "moul/grpcbin";
#[derive(Clone)]
pub struct GrpcBinConfig {
hostname: String,
version: String,
image_name: String,
visibility: PortVisibility,
timeout: Duration,
}
impl GrpcBinConfig {
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: GRPCBIN_IMAGE_NAME.to_string(),
timeout: Duration::from_secs(30),
visibility: Default::default(),
}
}
pub fn builder() -> GrpcBinConfigBuilder {
GrpcBinConfigBuilder::new()
}
}
pub struct GrpcBinConfigBuilder {
config: GrpcBinConfig,
}
impl GrpcBinConfigBuilder {
fn new() -> Self {
Self {
config: GrpcBinConfig::new(),
}
}
pub fn hostname<T: Into<String>>(self, hostname: T) -> Self {
Self {
config: GrpcBinConfig {
hostname: hostname.into(),
..self.config
},
}
}
pub fn version<T: Into<String>>(self, version: T) -> Self {
Self {
config: GrpcBinConfig {
version: version.into(),
..self.config
},
}
}
pub fn visibility(self, visibility: PortVisibility) -> Self {
Self {
config: GrpcBinConfig {
visibility,
..self.config
},
}
}
pub fn image_name<T: Into<String>>(self, image_name: T) -> Self {
Self {
config: GrpcBinConfig {
image_name: image_name.into(),
..self.config
},
}
}
pub fn timeout(self, timeout: Duration) -> Self {
Self {
config: GrpcBinConfig {
timeout,
..self.config
},
}
}
pub fn build(self) -> GrpcBinConfig {
self.config
}
}
impl Default for GrpcBinConfig {
fn default() -> Self {
Self::new()
}
}
impl Config for GrpcBinConfig {
fn hostname(&self) -> &str {
&self.hostname
}
fn port(&self) -> Port {
SECURE_PORT
}
fn schema(&self) -> &str {
GRPC_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(INSECURE_PORT, self.visibility),
PortAccess::new(SECURE_PORT, self.visibility),
])
.readiness(
MessageProbe::builder("listening on :")
.times(2)
.timeout(Duration::from_secs(30))
.source(MessageSource::StdErr)
.build(),
)
.build())
}
}
pub struct GrpcBin {
socket: Option<String>,
address: Option<String>,
}
impl GrpcBin {
pub fn socket(&self) -> Option<&str> {
self.socket.as_deref()
}
pub fn address(&self) -> Option<&str> {
self.address.as_deref()
}
}
impl Service for GrpcBin {
type Config = GrpcBinConfig;
fn new(_config: &Self::Config, container: &Container) -> Self {
let socket = container.socket(INSECURE_PORT).map(String::from);
let address = socket.as_ref().map(|s| format!("{GRPC_SCHEMA}://{s}"));
Self { socket, address }
}
}