From e7b2d004265ad77ecdd94d22df53767297569784 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sat, 1 Mar 2025 10:01:22 -0500 Subject: [PATCH] fix: Get rid of Docker login in CI to get dependabot working (#23) --- .github/workflows/rust.yml | 6 -- tests/integration.rs | 10 ++- tests/minio_testcontainer.rs | 155 +++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 tests/minio_testcontainer.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7d59dbe..aeebe5f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,12 +39,6 @@ jobs: with: toolchain: stable - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Install cargo-nextest uses: taiki-e/install-action@nextest diff --git a/tests/integration.rs b/tests/integration.rs index e7006ba..50cbda8 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -11,7 +11,10 @@ use testcontainers::core::logs::LogFrame; use testcontainers::core::logs::consumer::LogConsumer; use testcontainers::runners::AsyncRunner; use testcontainers::{ContainerAsync, ImageExt}; -use testcontainers_modules::minio::MinIO; + +mod minio_testcontainer; + +use minio_testcontainer::MinIO; #[rstest] #[case("prefix/2024-*/file*.txt", &[ @@ -415,8 +418,9 @@ async fn test_download_flatten() -> anyhow::Result<()> { // async fn minio_and_client() -> (ContainerAsync, u16, Client) { - let minio = - testcontainers_modules::minio::MinIO::default().with_log_consumer(LogPrinter::new()); + let minio = MinIO::default() + .with_name("quay.io/minio/minio") + .with_log_consumer(LogPrinter::new()); let node = match minio.start().await { Ok(node) => node, Err(e) => { diff --git a/tests/minio_testcontainer.rs b/tests/minio_testcontainer.rs new file mode 100644 index 0000000..e078f1f --- /dev/null +++ b/tests/minio_testcontainer.rs @@ -0,0 +1,155 @@ +use std::{borrow::Cow, collections::HashMap}; + +use testcontainers::{Image, core::WaitFor}; + +const NAME: &str = "minio/minio"; +const TAG: &str = "RELEASE.2025-02-28T09-55-16Z"; + +const DIR: &str = "/data"; +const CONSOLE_ADDRESS: &str = ":9001"; + +#[allow(missing_docs)] +// not having docs here is currently allowed to address the missing docs problem one place at a time. Helping us by documenting just one of these places helps other devs tremendously +#[derive(Debug, Clone)] +pub struct MinIO { + env_vars: HashMap, + cmd: MinIOServerCmd, +} + +impl Default for MinIO { + fn default() -> Self { + let mut env_vars = HashMap::new(); + env_vars.insert( + "MINIO_CONSOLE_ADDRESS".to_owned(), + CONSOLE_ADDRESS.to_owned(), + ); + + Self { + env_vars, + cmd: MinIOServerCmd::default(), + } + } +} + +#[allow(missing_docs)] +// not having docs here is currently allowed to address the missing docs problem one place at a time. Helping us by documenting just one of these places helps other devs tremendously +#[derive(Debug, Clone)] +pub struct MinIOServerCmd { + #[allow(missing_docs)] + // not having docs here is currently allowed to address the missing docs problem one place at a time. Helping us by documenting just one of these places helps other devs tremendously + pub dir: String, + #[allow(missing_docs)] + // not having docs here is currently allowed to address the missing docs problem one place at a time. Helping us by documenting just one of these places helps other devs tremendously + pub certs_dir: Option, + #[allow(missing_docs)] + // not having docs here is currently allowed to address the missing docs problem one place at a time. Helping us by documenting just one of these places helps other devs tremendously + pub json_log: bool, +} + +impl Default for MinIOServerCmd { + fn default() -> Self { + Self { + dir: DIR.to_owned(), + certs_dir: None, + json_log: false, + } + } +} + +impl IntoIterator for &MinIOServerCmd { + type Item = String; + type IntoIter = as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + let mut args = vec!["server".to_owned(), self.dir.to_owned()]; + + if let Some(ref certs_dir) = self.certs_dir { + args.push("--certs-dir".to_owned()); + args.push(certs_dir.to_owned()) + } + + if self.json_log { + args.push("--json".to_owned()); + } + + args.into_iter() + } +} + +impl Image for MinIO { + fn name(&self) -> &str { + NAME + } + + fn tag(&self) -> &str { + TAG + } + + fn ready_conditions(&self) -> Vec { + vec![WaitFor::message_on_stderr("API:")] + } + + fn env_vars( + &self, + ) -> impl IntoIterator>, impl Into>)> { + &self.env_vars + } + + fn cmd(&self) -> impl IntoIterator>> { + &self.cmd + } +} + +#[cfg(test)] +mod tests { + use aws_config::{BehaviorVersion, meta::region::RegionProviderChain}; + use aws_sdk_s3::{Client, config::Credentials}; + use testcontainers::runners::AsyncRunner; + + use super::MinIO; + + #[tokio::test] + async fn minio_buckets() -> Result<(), Box> { + let minio = MinIO::default(); + let node = minio.start().await?; + + let host_port = node.get_host_port_ipv4(9000).await?; + let client = build_s3_client(host_port).await; + + let bucket_name = "test-bucket"; + + client + .create_bucket() + .bucket(bucket_name) + .send() + .await + .expect("Failed to create test bucket"); + + let buckets = client + .list_buckets() + .send() + .await + .expect("Failed to get list of buckets") + .buckets + .unwrap(); + assert_eq!(1, buckets.len()); + assert_eq!(bucket_name, buckets[0].name.as_ref().unwrap()); + Ok(()) + } + + async fn build_s3_client(host_port: u16) -> Client { + let endpoint_uri = format!("http://127.0.0.1:{host_port}"); + let region_provider = RegionProviderChain::default_provider().or_else("us-east-1"); + let creds = Credentials::new("minioadmin", "minioadmin", None, None, "test"); + + // Default MinIO credentials (Can be overridden by ENV container variables) + let shared_config = aws_config::defaults(BehaviorVersion::latest()) + .region(region_provider) + .endpoint_url(endpoint_uri) + .credentials_provider(creds) + .load() + .await; + + Client::new(&shared_config) + } +}