pdk_test/services/
grpcbin.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 INSECURE_PORT: Port = 9000;
23const SECURE_PORT: Port = 9001;
24const GRPC_SCHEMA: &str = "grpc";
25
26pub const GRPCBIN_IMAGE_NAME: &str = "moul/grpcbin";
28
29#[derive(Clone)]
31pub struct GrpcBinConfig {
32 hostname: String,
33 version: String,
34 image_name: String,
35 visibility: PortVisibility,
36 timeout: Duration,
37}
38
39impl GrpcBinConfig {
40 pub fn hostname(&self) -> &str {
42 &self.hostname
43 }
44
45 pub fn version(&self) -> &str {
47 &self.version
48 }
49
50 pub fn image_name(&self) -> &str {
52 &self.image_name
53 }
54
55 pub fn visibility(&self) -> PortVisibility {
57 self.visibility
58 }
59
60 pub fn timeout(&self) -> Duration {
62 self.timeout
63 }
64
65 pub fn new() -> Self {
67 Self {
68 hostname: "backend".to_string(),
69 version: "latest".to_string(),
70 image_name: GRPCBIN_IMAGE_NAME.to_string(),
71 timeout: Duration::from_secs(30),
72 visibility: Default::default(),
73 }
74 }
75
76 pub fn builder() -> GrpcBinConfigBuilder {
78 GrpcBinConfigBuilder::new()
79 }
80}
81
82pub struct GrpcBinConfigBuilder {
84 config: GrpcBinConfig,
85}
86
87impl GrpcBinConfigBuilder {
88 fn new() -> Self {
89 Self {
90 config: GrpcBinConfig::new(),
91 }
92 }
93
94 pub fn hostname<T: Into<String>>(self, hostname: T) -> Self {
97 Self {
98 config: GrpcBinConfig {
99 hostname: hostname.into(),
100 ..self.config
101 },
102 }
103 }
104
105 pub fn version<T: Into<String>>(self, version: T) -> Self {
108 Self {
109 config: GrpcBinConfig {
110 version: version.into(),
111 ..self.config
112 },
113 }
114 }
115
116 pub fn visibility(self, visibility: PortVisibility) -> Self {
119 Self {
120 config: GrpcBinConfig {
121 visibility,
122 ..self.config
123 },
124 }
125 }
126
127 pub fn image_name<T: Into<String>>(self, image_name: T) -> Self {
130 Self {
131 config: GrpcBinConfig {
132 image_name: image_name.into(),
133 ..self.config
134 },
135 }
136 }
137
138 pub fn timeout(self, timeout: Duration) -> Self {
140 Self {
141 config: GrpcBinConfig {
142 timeout,
143 ..self.config
144 },
145 }
146 }
147
148 pub fn build(self) -> GrpcBinConfig {
150 self.config
151 }
152}
153
154impl Default for GrpcBinConfig {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159
160impl Config for GrpcBinConfig {
161 fn hostname(&self) -> &str {
162 &self.hostname
163 }
164
165 fn port(&self) -> Port {
166 SECURE_PORT
167 }
168
169 fn schema(&self) -> &str {
170 GRPC_SCHEMA
171 }
172
173 fn to_container_config(&self) -> Result<ContainerConfig, TestError> {
174 Ok(ContainerConfig::builder(
175 self.hostname.clone(),
176 Image::from_repository(self.image_name()).with_version(self.version()),
177 )
178 .ports([
179 PortAccess::new(INSECURE_PORT, self.visibility),
180 PortAccess::new(SECURE_PORT, self.visibility),
181 ])
182 .readiness(
183 MessageProbe::builder("listening on :")
184 .times(2)
185 .timeout(Duration::from_secs(30))
186 .source(MessageSource::StdErr)
187 .build(),
188 )
189 .build())
190 }
191}
192
193pub struct GrpcBin {
195 socket: Option<String>,
196 address: Option<String>,
197}
198
199impl GrpcBin {
200 pub fn socket(&self) -> Option<&str> {
202 self.socket.as_deref()
203 }
204
205 pub fn address(&self) -> Option<&str> {
207 self.address.as_deref()
208 }
209}
210
211impl Service for GrpcBin {
212 type Config = GrpcBinConfig;
213
214 fn new(_config: &Self::Config, container: &Container) -> Self {
215 let socket = container.socket(INSECURE_PORT).map(String::from);
216 let address = socket.as_ref().map(|s| format!("{GRPC_SCHEMA}://{s}"));
217
218 Self { socket, address }
219 }
220}