Skip to content

Commit

Permalink
Add volume reaping tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dmartin committed Jun 5, 2024
1 parent 589782b commit a04a090
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 4 deletions.
41 changes: 38 additions & 3 deletions tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use bollard::container::{Config, NetworkingConfig};
use bollard::image::CreateImageOptions;
use bollard::network::CreateNetworkOptions;
use bollard::secret::{ContainerCreateResponse, EndpointSettings};
use bollard::volume::CreateVolumeOptions;
use bollard::Docker;
use chrono::Utc;
use docker_reaper::{
Expand Down Expand Up @@ -127,6 +128,26 @@ pub(crate) async fn create_network(extra_labels: Option<HashMap<String, String>>
name
}

/// Create a volume on the local Docker daemon. Returns the name of the created volume.
/// The label [TEST_LABEL] will always be set. Additional labels may also be specified.
pub(crate) async fn create_volume(extra_labels: Option<HashMap<String, String>>) -> String {
let client = docker_client();
let mut labels = HashMap::from([(TEST_LABEL.to_string(), "true".to_string())]);
if let Some(extra_labels) = extra_labels {
labels.extend(extra_labels.into_iter())
}
let name = Utc::now().timestamp_millis().to_string(); // volume names must be unique
client
.create_volume(CreateVolumeOptions {
name: name.clone(),
labels,
..Default::default()
})
.await
.expect("failed to create volume");
name
}

/// Check whether a container with the given ID exists.
pub(crate) async fn container_exists(id: &str) -> bool {
let client = docker_client();
Expand All @@ -141,10 +162,24 @@ pub(crate) async fn container_exists(id: &str) -> bool {
}
}

/// Check whether a network with the given ID exists.
pub(crate) async fn network_exists(id: &str) -> bool {
/// Check whether a network with the given name exists.
pub(crate) async fn network_exists(name: &str) -> bool {
let client = docker_client();
match client.inspect_network::<&str>(name, None).await {
Ok(_) => return true,
Err(err) => match err {
bollard::errors::Error::DockerResponseServerError {
status_code: 404, ..
} => return false,
_ => panic!("unexpected error: {err}"),
},
}
}

/// Check whether a volume with the given name exists.
pub(crate) async fn volume_exists(name: &str) -> bool {
let client = docker_client();
match client.inspect_network::<&str>(id, None).await {
match client.inspect_volume(name).await {
Ok(_) => return true,
Err(err) => match err {
bollard::errors::Error::DockerResponseServerError {
Expand Down
2 changes: 1 addition & 1 deletion tests/networks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async fn max_age() {
cleanup().await;
}

/// Test that only containers matching the specified filters are reaped.
/// Test that only networks matching the specified filters are reaped.
#[tokio::test]
#[serial]
async fn filters() {
Expand Down
119 changes: 119 additions & 0 deletions tests/volumes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//! Volume reaping tests.
//!
//! These are run serially because all test-related resources are cleaned up after each test.
mod common;

use std::collections::HashMap;

use common::{cleanup, create_volume, docker_client, volume_exists, TEST_LABEL};
use docker_reaper::{
reap_volumes, Filter, ReapVolumesConfig, RemovalStatus, Resource, ResourceType,
};
use serial_test::serial;
use tokio::time::{sleep, Duration};

/// Test that only volumes older than the `min_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn min_age() {
let old_volume_id = create_volume(None).await;
sleep(Duration::from_secs(2)).await;
let new_volume_id = create_volume(None).await;
reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: false,
min_age: Some(Duration::from_secs(2)),
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap volumes");
assert_eq!(volume_exists(&old_volume_id).await, false);
assert_eq!(volume_exists(&new_volume_id).await, true);
cleanup().await;
}

/// Test that only volumes younger than the `max_age` threshold are reaped.
#[tokio::test]
#[serial]
async fn max_age() {
let old_volume_id = create_volume(None).await;
sleep(Duration::from_secs(2)).await;
let new_volume_id = create_volume(None).await;
reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: false,
min_age: None,
max_age: Some(Duration::from_secs(2)),
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap volumes");
assert_eq!(volume_exists(&old_volume_id).await, true);
assert_eq!(volume_exists(&new_volume_id).await, false);
cleanup().await;
}

/// Test that only volumes matching the specified filters are reaped.
#[tokio::test]
#[serial]
async fn filters() {
let purple_volume_id = create_volume(Some(HashMap::from([(
"color".to_string(),
"purple".to_string(),
)])))
.await;
let orange_volume_id = create_volume(Some(HashMap::from([(
"color".to_string(),
"orange".to_string(),
)])))
.await;
reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: false,
min_age: None,
max_age: None,
filters: &vec![
Filter::new("label", TEST_LABEL),
Filter::new("label", "color=orange"),
],
},
)
.await
.expect("failed to reap volumes");
assert_eq!(volume_exists(&purple_volume_id).await, true);
assert_eq!(volume_exists(&orange_volume_id).await, false);
cleanup().await;
}

/// Test that resources are identified but not removed if `dry_run` is set.
#[tokio::test]
#[serial]
async fn dry_run() {
let volume_id = create_volume(None).await;
let result = reap_volumes(
docker_client(),
&ReapVolumesConfig {
dry_run: true,
min_age: None,
max_age: None,
filters: &vec![Filter::new("label", TEST_LABEL)],
},
)
.await
.expect("failed to reap volumes");
assert!(result.contains(&Resource {
resource_type: ResourceType::Volume,
id: volume_id.clone(),
name: String::new(),
status: RemovalStatus::Eligible
}));
assert_eq!(volume_exists(&volume_id).await, true);
cleanup().await;
}

0 comments on commit a04a090

Please sign in to comment.