pdk_test/services/
httpbin.rs1use std::time::Duration;
13
14use crate::config::{Config, ContainerConfig};
15use crate::container::Container;
16use crate::error::TestError;
17use crate::image::Image;
18use crate::port::{Port, PortAccess, PortVisibility};
19use crate::probe::{MessageProbe, MessageSource};
20use crate::service::Service;
21
22const PORT: Port = 80;
23const SCHEMA: &str = "http";
24const HTTPBIN_IMAGE_NAME: &str = "kennethreitz/httpbin";
25
26#[derive(Clone)]
28pub struct HttpBinConfig {
29 hostname: String,
30 version: String,
31 image_name: String,
32 visibility: PortVisibility,
33 timeout: Duration,
34}
35
36impl HttpBinConfig {
37 pub fn hostname(&self) -> &str {
39 &self.hostname
40 }
41
42 pub fn version(&self) -> &str {
44 &self.version
45 }
46
47 pub fn image_name(&self) -> &str {
49 &self.image_name
50 }
51
52 pub fn visibility(&self) -> PortVisibility {
54 self.visibility
55 }
56
57 pub fn timeout(&self) -> Duration {
59 self.timeout
60 }
61
62 pub fn new() -> Self {
64 Self {
65 hostname: "backend".to_string(),
66 version: "latest".to_string(),
67 image_name: HTTPBIN_IMAGE_NAME.to_string(),
68 timeout: Duration::from_secs(30),
69 visibility: Default::default(),
70 }
71 }
72
73 pub fn builder() -> HttpBinConfigBuilder {
75 HttpBinConfigBuilder::new()
76 }
77}
78
79pub struct HttpBinConfigBuilder {
81 config: HttpBinConfig,
82}
83
84impl HttpBinConfigBuilder {
85 fn new() -> Self {
86 Self {
87 config: HttpBinConfig::new(),
88 }
89 }
90
91 pub fn hostname<T: Into<String>>(self, hostname: T) -> Self {
93 Self {
94 config: HttpBinConfig {
95 hostname: hostname.into(),
96 ..self.config
97 },
98 }
99 }
100
101 pub fn version<T: Into<String>>(self, version: T) -> Self {
103 Self {
104 config: HttpBinConfig {
105 version: version.into(),
106 ..self.config
107 },
108 }
109 }
110
111 pub fn image_name<T: Into<String>>(self, image_name: T) -> Self {
113 Self {
114 config: HttpBinConfig {
115 image_name: image_name.into(),
116 ..self.config
117 },
118 }
119 }
120
121 pub fn visibility(self, visibility: PortVisibility) -> Self {
123 Self {
124 config: HttpBinConfig {
125 visibility,
126 ..self.config
127 },
128 }
129 }
130
131 pub fn timeout(self, timeout: Duration) -> Self {
133 Self {
134 config: HttpBinConfig {
135 timeout,
136 ..self.config
137 },
138 }
139 }
140
141 pub fn build(self) -> HttpBinConfig {
143 self.config
144 }
145}
146
147impl Default for HttpBinConfig {
148 fn default() -> Self {
149 Self::new()
150 }
151}
152
153impl Config for HttpBinConfig {
154 fn hostname(&self) -> &str {
155 &self.hostname
156 }
157
158 fn port(&self) -> Port {
159 PORT
160 }
161
162 fn schema(&self) -> &str {
163 SCHEMA
164 }
165
166 fn to_container_config(&self) -> Result<ContainerConfig, TestError> {
167 Ok(ContainerConfig::builder(
168 self.hostname.clone(),
169 Image::from_repository(self.image_name()).with_version(self.version()),
170 )
171 .ports([PortAccess::new(PORT, self.visibility)])
172 .readiness(
173 MessageProbe::builder("Using worker: gevent")
174 .timeout(Duration::from_secs(30))
175 .source(MessageSource::StdErr)
176 .build(),
177 )
178 .build())
179 }
180}
181
182pub struct HttpBin {
184 socket: Option<String>,
185 address: Option<String>,
186}
187
188impl HttpBin {
189 pub fn socket(&self) -> Option<&str> {
191 self.socket.as_deref()
192 }
193
194 pub fn address(&self) -> Option<&str> {
196 self.address.as_deref()
197 }
198}
199
200impl Service for HttpBin {
201 type Config = HttpBinConfig;
202
203 fn new(_config: &Self::Config, container: &Container) -> Self {
204 let socket = container.socket(PORT).map(String::from);
205 let address = socket.as_ref().map(|s| format!("http://{s}"));
206 Self { socket, address }
207 }
208}