Move to the more modern and maintained object_store library to access generic buckets. We should be able also to do streaming of files now, and proceed by implementing paginated results for listings if we want. Fixes #1.
124 lines
4 KiB
Rust
124 lines
4 KiB
Rust
// SPDX-FileCopyrightText: © Matteo Settenvini <matteo.settenvini@montecristosoftware.eu>
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
mod minio;
|
|
|
|
use {
|
|
::minio::s3::{
|
|
client::Client as MinIOClient, creds::StaticProvider, http::BaseUrl, types::S3Api,
|
|
},
|
|
anyhow::{Result, anyhow},
|
|
object_store::{ObjectStore, aws::AmazonS3Builder},
|
|
reqwest::Url,
|
|
std::{ptr::null_mut, str::FromStr},
|
|
testcontainers::{ContainerAsync, runners::AsyncRunner},
|
|
tokio::io::AsyncBufReadExt as _,
|
|
};
|
|
|
|
pub struct Test {
|
|
pub base_url: Url,
|
|
pub bucket: Box<dyn ObjectStore>,
|
|
pub serves3: tokio::process::Child,
|
|
pub _minio: ContainerAsync<minio::MinIO>,
|
|
}
|
|
|
|
const MAXIMUM_SERVES3_INIT_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(5);
|
|
|
|
const BUCKET_NAME: &'static str = "integration-test-bucket";
|
|
const REGION: &'static str = "test-region";
|
|
const ACCESS_KEY: &'static str = "minioadmin";
|
|
const SECRET_KEY: &'static str = "minioadmin";
|
|
|
|
impl Test {
|
|
pub async fn new() -> Result<Self> {
|
|
// NOTE: this testsuite was setup to work
|
|
// against a recent version of podman,
|
|
// which correctly distinguishes between
|
|
// stdout and stderr of the running container.
|
|
|
|
let image = minio::MinIO::default();
|
|
let container = image.start().await?;
|
|
|
|
let endpoint = format!(
|
|
"http://{host}:{port}",
|
|
host = container.get_host().await?,
|
|
port = container.get_host_port_ipv4(9000).await?
|
|
);
|
|
|
|
// We need to create the bucket
|
|
let minio_client = MinIOClient::new(
|
|
BaseUrl::from_str(&endpoint).unwrap(),
|
|
Some(Box::new(StaticProvider::new(ACCESS_KEY, SECRET_KEY, None))),
|
|
None,
|
|
None,
|
|
)?;
|
|
minio_client.create_bucket(BUCKET_NAME).send().await?;
|
|
|
|
let bucket = AmazonS3Builder::new()
|
|
.with_endpoint(&endpoint)
|
|
.with_access_key_id(ACCESS_KEY)
|
|
.with_secret_access_key(SECRET_KEY)
|
|
.with_bucket_name(BUCKET_NAME)
|
|
.with_allow_http(true)
|
|
.build()?;
|
|
|
|
let bin = std::env!("CARGO_BIN_EXE_serves3");
|
|
let mut child = tokio::process::Command::new(bin)
|
|
.env("SERVES3_ADDRESS", "127.0.0.1")
|
|
.env("SERVES3_PORT", "0")
|
|
.env("SERVES3_LOG_LEVEL", "debug")
|
|
.env(
|
|
"SERVES3_S3_BUCKET",
|
|
format!(
|
|
r#"{{
|
|
name = "{name}",
|
|
endpoint = "{endpoint}",
|
|
region = "{region}",
|
|
access_key_id = "{user}",
|
|
secret_access_key = "{secret}",
|
|
path_style = true
|
|
}}"#,
|
|
name = BUCKET_NAME,
|
|
endpoint = endpoint,
|
|
region = ®ION,
|
|
user = ACCESS_KEY,
|
|
secret = SECRET_KEY
|
|
),
|
|
)
|
|
.stdout(std::process::Stdio::piped())
|
|
.spawn()?;
|
|
|
|
let base_url = tokio::time::timeout(MAXIMUM_SERVES3_INIT_TIMEOUT, async {
|
|
let stdout = child.stdout.as_mut().unwrap();
|
|
let mut lines = tokio::io::BufReader::new(stdout).lines();
|
|
let re = regex::Regex::new("^Rocket has launched from (http://.+)$").unwrap();
|
|
while let Some(line) = lines.next_line().await? {
|
|
println!("{}", &line);
|
|
if let Some(captures) = re.captures(&line) {
|
|
let url = captures.get(1).unwrap().as_str();
|
|
return Ok(Url::from_str(url)?);
|
|
}
|
|
}
|
|
|
|
Err(anyhow!("Rocket did not print that it has started"))
|
|
})
|
|
.await??;
|
|
|
|
Ok(Self {
|
|
base_url,
|
|
bucket: Box::new(bucket),
|
|
serves3: child,
|
|
_minio: container,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Drop for Test {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
let pid = self.serves3.id().unwrap() as i32;
|
|
libc::kill(pid, libc::SIGTERM);
|
|
libc::waitpid(pid, null_mut(), 0);
|
|
}
|
|
}
|
|
}
|