56
56
//! }
57
57
//! ```
58
58
59
+ use std:: time:: Duration ;
59
60
use testcontainers:: {
60
61
core:: { IntoContainerPort , WaitFor } ,
61
62
runners:: SyncRunner ,
@@ -73,6 +74,33 @@ const DEFAULT_IMAGE_NAME: &str = "torrust-provisioned-instance";
73
74
/// Default Docker image tag for provisioned instances
74
75
const DEFAULT_IMAGE_TAG : & str = "latest" ;
75
76
77
+ /// Container timeout configurations for different operations
78
+ ///
79
+ /// This struct provides configurable timeouts for various container operations
80
+ /// to make the system more flexible and adaptable to different environments.
81
+ #[ derive( Debug , Clone ) ]
82
+ pub struct ContainerTimeouts {
83
+ /// Timeout for Docker image build operations
84
+ pub docker_build : Duration ,
85
+ /// Timeout for container startup operations
86
+ pub container_start : Duration ,
87
+ /// Timeout for SSH connectivity to become available
88
+ pub ssh_ready : Duration ,
89
+ /// Timeout for SSH key setup operations
90
+ pub ssh_setup : Duration ,
91
+ }
92
+
93
+ impl Default for ContainerTimeouts {
94
+ fn default ( ) -> Self {
95
+ Self {
96
+ docker_build : Duration :: from_secs ( 300 ) , // 5 minutes
97
+ container_start : Duration :: from_secs ( 60 ) , // 1 minute
98
+ ssh_ready : Duration :: from_secs ( 30 ) , // 30 seconds
99
+ ssh_setup : Duration :: from_secs ( 15 ) , // 15 seconds
100
+ }
101
+ }
102
+ }
103
+
76
104
/// Specific error types for provisioned container operations
77
105
#[ derive( Debug , thiserror:: Error ) ]
78
106
pub enum ProvisionedContainerError {
@@ -171,18 +199,76 @@ pub type Result<T> = std::result::Result<T, Box<ProvisionedContainerError>>;
171
199
/// Following the pattern from Torrust Tracker `MySQL` driver, where different states
172
200
/// have different capabilities enforced at compile time.
173
201
/// Initial state - container is stopped/not started yet
174
- #[ derive( Debug , Default ) ]
175
- pub struct StoppedProvisionedContainer { }
202
+ #[ derive( Debug ) ]
203
+ pub struct StoppedProvisionedContainer {
204
+ /// Timeout configurations for container operations
205
+ pub timeouts : ContainerTimeouts ,
206
+ }
207
+
208
+ #[ allow( clippy:: derivable_impls) ]
209
+ impl Default for StoppedProvisionedContainer {
210
+ fn default ( ) -> Self {
211
+ Self {
212
+ timeouts : ContainerTimeouts :: default ( ) ,
213
+ }
214
+ }
215
+ }
176
216
177
217
impl StoppedProvisionedContainer {
218
+ /// Create a new stopped container with custom timeout configurations
219
+ ///
220
+ /// # Arguments
221
+ /// * `timeouts` - Custom timeout configuration for container operations
222
+ ///
223
+ /// # Example
224
+ /// ```rust,no_run
225
+ /// use torrust_tracker_deploy::e2e::containers::{StoppedProvisionedContainer, ContainerTimeouts};
226
+ /// use std::time::Duration;
227
+ ///
228
+ /// let mut timeouts = ContainerTimeouts::default();
229
+ /// timeouts.ssh_ready = Duration::from_secs(60);
230
+ ///
231
+ /// let container = StoppedProvisionedContainer::with_timeouts(timeouts);
232
+ /// ```
233
+ #[ must_use]
234
+ pub fn with_timeouts ( timeouts : ContainerTimeouts ) -> Self {
235
+ Self { timeouts }
236
+ }
237
+
238
+ /// Create a new stopped container with custom SSH ready timeout
239
+ ///
240
+ /// This is a convenience method for the most commonly customized timeout.
241
+ ///
242
+ /// # Arguments
243
+ /// * `ssh_ready_timeout` - How long to wait for SSH to become available
244
+ ///
245
+ /// # Example
246
+ /// ```rust,no_run
247
+ /// use torrust_tracker_deploy::e2e::containers::StoppedProvisionedContainer;
248
+ /// use std::time::Duration;
249
+ ///
250
+ /// let container = StoppedProvisionedContainer::with_ssh_ready_timeout(
251
+ /// Duration::from_secs(60)
252
+ /// );
253
+ /// ```
254
+ #[ must_use]
255
+ pub fn with_ssh_ready_timeout ( ssh_ready_timeout : Duration ) -> Self {
256
+ let timeouts = ContainerTimeouts {
257
+ ssh_ready : ssh_ready_timeout,
258
+ ..ContainerTimeouts :: default ( )
259
+ } ;
260
+ Self { timeouts }
261
+ }
262
+
178
263
/// Build the Docker image if needed using the `ContainerImageBuilder`
179
- fn build_image ( ) -> Result < ( ) > {
264
+ fn build_image ( docker_build_timeout : Duration ) -> Result < ( ) > {
180
265
let builder = ContainerImageBuilder :: new ( )
181
266
. with_name ( DEFAULT_IMAGE_NAME )
182
267
. with_tag ( DEFAULT_IMAGE_TAG )
183
268
. with_dockerfile ( std:: path:: PathBuf :: from (
184
269
"docker/provisioned-instance/Dockerfile" ,
185
- ) ) ;
270
+ ) )
271
+ . with_build_timeout ( docker_build_timeout) ;
186
272
builder. build ( ) . map_err ( |e| {
187
273
Box :: new ( ProvisionedContainerError :: DockerImageBuildFailed { source : * e } )
188
274
} ) ?;
@@ -199,7 +285,7 @@ impl StoppedProvisionedContainer {
199
285
/// - Container networking setup fails
200
286
pub fn start ( self ) -> Result < RunningProvisionedContainer > {
201
287
// First build the Docker image if needed
202
- Self :: build_image ( ) ?;
288
+ Self :: build_image ( self . timeouts . docker_build ) ?;
203
289
204
290
info ! ( "Starting provisioned instance container" ) ;
205
291
0 commit comments