Skip to content

Commit 2bbfa3f

Browse files
committed
refactor: errors
1 parent 229d9d9 commit 2bbfa3f

File tree

8 files changed

+56
-49
lines changed

8 files changed

+56
-49
lines changed

testcontainers/src/compose/client.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::{fmt, path::PathBuf};
22

3+
use crate::compose::error::{ComposeError, Result};
4+
35
pub(super) mod containerised;
46
pub(super) mod local;
57

@@ -13,10 +15,10 @@ impl ComposeClient {
1315
ComposeClient::Local(local::LocalComposeCli::new(compose_files))
1416
}
1517

16-
pub(super) async fn new_containerised(compose_files: Vec<PathBuf>) -> Self {
17-
ComposeClient::Containerised(
18-
containerised::ContainerisedComposeCli::new(compose_files).await,
19-
)
18+
pub(super) async fn new_containerised(compose_files: Vec<PathBuf>) -> Result<Self> {
19+
Ok(ComposeClient::Containerised(
20+
containerised::ContainerisedComposeCli::new(compose_files).await?,
21+
))
2022
}
2123
}
2224

@@ -35,19 +37,19 @@ pub(super) struct DownCommand {
3537
}
3638

3739
pub(super) trait ComposeInterface {
38-
async fn up(&self, command: UpCommand) -> Result<(), std::io::Error>;
39-
async fn down(&self, command: DownCommand) -> Result<(), std::io::Error>;
40+
async fn up(&self, command: UpCommand) -> Result<()>;
41+
async fn down(&self, command: DownCommand) -> Result<()>;
4042
}
4143

4244
impl ComposeInterface for ComposeClient {
43-
async fn up(&self, command: UpCommand) -> Result<(), std::io::Error> {
45+
async fn up(&self, command: UpCommand) -> Result<()> {
4446
match self {
4547
ComposeClient::Local(client) => client.up(command).await,
4648
ComposeClient::Containerised(client) => client.up(command).await,
4749
}
4850
}
4951

50-
async fn down(&self, command: DownCommand) -> Result<(), std::io::Error> {
52+
async fn down(&self, command: DownCommand) -> Result<()> {
5153
match self {
5254
ComposeClient::Local(client) => client.down(command).await,
5355
ComposeClient::Containerised(client) => client.down(command).await,

testcontainers/src/compose/client/containerised.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use std::{io::Error, path::PathBuf};
1+
use std::path::PathBuf;
22

33
use crate::{
4-
compose::client::{ComposeInterface, DownCommand, UpCommand},
4+
compose::{
5+
client::{ComposeInterface, DownCommand, UpCommand},
6+
error::Result,
7+
},
58
core::{CmdWaitFor, ExecCommand, Mount},
69
images::docker_cli::DockerCli,
710
runners::AsyncRunner,
@@ -14,7 +17,7 @@ pub(crate) struct ContainerisedComposeCli {
1417
}
1518

1619
impl ContainerisedComposeCli {
17-
pub(super) async fn new(compose_files: Vec<PathBuf>) -> Self {
20+
pub(super) async fn new(compose_files: Vec<PathBuf>) -> Result<Self> {
1821
let mut image = ContainerRequest::from(DockerCli::new("/var/run/docker.sock"));
1922

2023
let compose_files_in_container: Vec<String> = compose_files
@@ -25,24 +28,24 @@ impl ContainerisedComposeCli {
2528
let mounts: Vec<_> = compose_files
2629
.iter()
2730
.zip(compose_files_in_container.iter())
28-
.map(|(path, file_name)| Mount::bind_mount(path.to_str().unwrap(), file_name))
31+
.filter_map(|(path, file_name)| path.to_str().map(|p| Mount::bind_mount(p, file_name)))
2932
.collect();
3033

3134
for mount in mounts {
3235
image = image.with_mount(mount);
3336
}
3437

35-
let container = image.start().await.expect("TODO: Handle error");
38+
let container = image.start().await?;
3639

37-
Self {
40+
Ok(Self {
3841
container,
3942
compose_files_in_container,
40-
}
43+
})
4144
}
4245
}
4346

4447
impl ComposeInterface for ContainerisedComposeCli {
45-
async fn up(&self, command: UpCommand) -> Result<(), Error> {
48+
async fn up(&self, command: UpCommand) -> Result<()> {
4649
let mut cmd = vec![
4750
"docker".to_string(),
4851
"compose".to_string(),
@@ -71,13 +74,12 @@ impl ComposeInterface for ContainerisedComposeCli {
7174
cmd.push(command.wait_timeout.as_secs().to_string());
7275

7376
let exec = ExecCommand::new(cmd);
74-
// todo: error handling
75-
self.container.exec(exec).await.map_err(Error::other)?;
77+
self.container.exec(exec).await?;
7678

7779
Ok(())
7880
}
7981

80-
async fn down(&self, command: DownCommand) -> Result<(), Error> {
82+
async fn down(&self, command: DownCommand) -> Result<()> {
8183
let mut cmd = vec![
8284
"docker".to_string(),
8385
"compose".to_string(),
@@ -94,7 +96,7 @@ impl ComposeInterface for ContainerisedComposeCli {
9496
}
9597

9698
let exec = ExecCommand::new(cmd).with_cmd_ready_condition(CmdWaitFor::exit_code(0));
97-
self.container.exec(exec).await.map_err(Error::other)?;
99+
self.container.exec(exec).await?;
98100
Ok(())
99101
}
100102
}

testcontainers/src/compose/client/local.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use std::{
2-
io::Error,
3-
path::{Path, PathBuf},
4-
};
1+
use std::path::{Path, PathBuf};
52

6-
use crate::compose::client::{ComposeInterface, DownCommand, UpCommand};
3+
use crate::compose::{
4+
client::{ComposeInterface, DownCommand, UpCommand},
5+
error::{ComposeError, Result},
6+
};
77

88
#[derive(Debug)]
99
pub(crate) struct LocalComposeCli {
@@ -22,17 +22,15 @@ impl LocalComposeCli {
2222
}
2323

2424
fn extract_current_dir(compose_files: &[PathBuf]) -> &Path {
25-
// TODO: error handling
2625
compose_files
2726
.first()
28-
.expect("At least one compose file is required")
29-
.parent()
30-
.expect("Compose file path must be absolute")
27+
.and_then(|p| p.parent())
28+
.unwrap_or_else(|| Path::new("."))
3129
}
3230
}
3331

3432
impl ComposeInterface for LocalComposeCli {
35-
async fn up(&self, command: UpCommand) -> Result<(), Error> {
33+
async fn up(&self, command: UpCommand) -> Result<()> {
3634
let mut cmd = tokio::process::Command::new("docker");
3735
cmd.current_dir(self.working_dir.as_path())
3836
.arg("compose")
@@ -61,12 +59,14 @@ impl ComposeInterface for LocalComposeCli {
6159
cmd.env(key, value);
6260
}
6361

64-
cmd.output().await?;
62+
cmd.output()
63+
.await
64+
.map_err(|e| ComposeError::Testcontainers(e.into()))?;
6565

6666
Ok(())
6767
}
6868

69-
async fn down(&self, command: DownCommand) -> Result<(), Error> {
69+
async fn down(&self, command: DownCommand) -> Result<()> {
7070
let mut cmd = tokio::process::Command::new("docker");
7171
cmd.current_dir(self.working_dir.as_path())
7272
.arg("compose")
@@ -81,7 +81,9 @@ impl ComposeInterface for LocalComposeCli {
8181
cmd.arg("--rmi");
8282
}
8383

84-
cmd.output().await?;
84+
cmd.output()
85+
.await
86+
.map_err(|e| ComposeError::Testcontainers(e.into()))?;
8587

8688
Ok(())
8789
}

testcontainers/src/compose/error.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,14 @@ use crate::core::{client::ClientError, error::TestcontainersError};
55
pub enum ComposeError {
66
#[error("Service '{0}' not found in compose stack")]
77
ServiceNotFound(String),
8-
9-
#[error("Failed to execute docker compose command: {0}")]
10-
CommandFailed(#[from] std::io::Error),
11-
12-
#[error("Docker compose stack not started - call up() first")]
13-
NotStarted,
14-
15-
#[error("Failed to parse compose file: {0}")]
16-
ParseError(String),
17-
18-
#[error("Docker client error: {0}")]
19-
Client(#[from] ClientError),
20-
218
#[error("Testcontainers error: {0}")]
229
Testcontainers(#[from] TestcontainersError),
2310
}
2411

2512
pub type Result<T> = std::result::Result<T, ComposeError>;
13+
14+
impl From<ClientError> for ComposeError {
15+
fn from(err: ClientError) -> Self {
16+
ComposeError::Testcontainers(TestcontainersError::from(err))
17+
}
18+
}

testcontainers/src/compose/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ impl DockerCompose {
5858
}
5959

6060
/// Create a new docker compose with a containerised client (doesn't require docker-cli installed locally)
61-
pub async fn with_containerised_client(compose_files: &[impl AsRef<Path>]) -> Self {
61+
pub async fn with_containerised_client(compose_files: &[impl AsRef<Path>]) -> Result<Self> {
6262
let compose_files = compose_files
6363
.iter()
6464
.map(|p| p.as_ref().to_path_buf())
6565
.collect();
6666

67-
let client = Arc::new(client::ComposeClient::new_containerised(compose_files).await);
67+
let client = Arc::new(client::ComposeClient::new_containerised(compose_files).await?);
6868

69-
Self::new(client)
69+
Ok(Self::new(client))
7070
}
7171

7272
/// Start the docker compose and discover all services

testcontainers/src/core/client.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ impl Client {
185185
.map_err(ClientError::InspectContainer)
186186
}
187187

188+
// It's used under a feature, but feature gate doesn't make a lot of sense here.
189+
#[allow(dead_code)]
188190
pub(crate) async fn list_containers_by_label(
189191
&self,
190192
label_key: &str,

testcontainers/src/core/ports.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,14 @@ impl Ports {
7777
self.ipv6_mapping.get(&container_port.into()).cloned()
7878
}
7979

80+
// It's used under a feature, but feature gate doesn't make a lot of sense here.
81+
#[allow(dead_code)]
8082
pub(crate) fn ipv4_mapping(&self) -> &HashMap<ContainerPort, u16> {
8183
&self.ipv4_mapping
8284
}
8385

86+
// It's used under a feature, but feature gate doesn't make a lot of sense here.
87+
#[allow(dead_code)]
8488
pub(crate) fn ipv6_mapping(&self) -> &HashMap<ContainerPort, u16> {
8589
&self.ipv6_mapping
8690
}

testcontainers/src/images/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(feature = "docker-compose")]
12
pub(crate) mod docker_cli;
23
pub mod generic;
4+
#[cfg(feature = "docker-compose")]
35
pub(crate) mod socat;

0 commit comments

Comments
 (0)