minio-rs/tests/s3/client_config.rs
Henk-Jan Lebbink c450081b2e
Refactor string parameters to typed wrapper structs (#200)
- Replaced raw string parameters with validated wrapper types (BucketName, ObjectName, Region, VersionId, etc.) following the "parse, don't validate" pattern
- Bucket and object names are now validated at construction time, ensuring compile-time correctness
- Added both relaxed (MinIO-compatible) and strict (AWS S3-compliant) validation modes for bucket names
2026-01-27 14:12:49 +01:00

205 lines
6.3 KiB
Rust

// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
// Copyright 2025 MinIO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Tests for client configuration options like skip_region_lookup.
use bytes::Bytes;
use minio::s3::MinioClient;
use minio::s3::client::MinioClientBuilder;
use minio::s3::creds::StaticProvider;
use minio::s3::response::{GetObjectResponse, PutObjectContentResponse};
use minio::s3::response_traits::{HasBucket, HasObject};
use minio::s3::types::{BucketName, ObjectKey, S3Api, ToStream};
use minio_common::test_context::TestContext;
use minio_common::utils::rand_object_name;
/// Helper to create a client with skip_region_lookup enabled.
fn create_client_with_skip_region_lookup(ctx: &TestContext) -> MinioClient {
let mut builder = MinioClientBuilder::new(ctx.base_url.clone())
.provider(Some(StaticProvider::new(
&ctx.access_key,
&ctx.secret_key,
None,
)))
.skip_region_lookup(true);
if let Some(ignore_cert) = ctx.ignore_cert_check {
builder = builder.ignore_cert_check(Some(ignore_cert));
}
if let Some(ref ssl_cert_file) = ctx.ssl_cert_file {
builder = builder.ssl_cert_file(Some(ssl_cert_file));
}
builder.build().unwrap()
}
/// Test that skip_region_lookup allows basic put/get operations.
/// This verifies operations work correctly when region lookup is skipped.
#[minio_macros::test]
async fn skip_region_lookup_put_get_object(ctx: TestContext, bucket: BucketName) {
let client = create_client_with_skip_region_lookup(&ctx);
let object = rand_object_name();
let data: Bytes = Bytes::from("test data with skip_region_lookup");
// Put object using client with skip_region_lookup
let put_resp: PutObjectContentResponse = client
.put_object_content(&bucket, &object, data.clone())
.unwrap()
.build()
.send()
.await
.unwrap();
assert_eq!(put_resp.bucket(), Some(&bucket));
assert_eq!(put_resp.object(), Some(&object));
// Get object using the same client
let get_resp: GetObjectResponse = client
.get_object(&bucket, &object)
.unwrap()
.build()
.send()
.await
.unwrap();
assert_eq!(get_resp.bucket(), Some(&bucket));
assert_eq!(get_resp.object(), Some(&object));
let got = get_resp.into_bytes().await.unwrap();
assert_eq!(got, data);
}
/// Test that skip_region_lookup works for bucket operations.
#[minio_macros::test]
async fn skip_region_lookup_bucket_exists(ctx: TestContext, bucket: BucketName) {
let client = create_client_with_skip_region_lookup(&ctx);
// Check bucket exists using client with skip_region_lookup
let exists = client
.bucket_exists(&bucket)
.unwrap()
.build()
.send()
.await
.unwrap()
.exists();
assert!(exists, "Bucket should exist");
}
/// Test that skip_region_lookup works for list operations.
#[minio_macros::test]
async fn skip_region_lookup_list_objects(ctx: TestContext, bucket: BucketName) {
let client = create_client_with_skip_region_lookup(&ctx);
// List objects using client with skip_region_lookup
// Just verify the operation completes without error
let mut stream = client
.list_objects(&bucket)
.unwrap()
.build()
.to_stream()
.await;
use futures_util::StreamExt;
// Consume the stream - may be empty, but should not error
let mut count = 0;
while let Some(result) = stream.next().await {
// Just verify we can read items without error
let _item = result.unwrap();
count += 1;
// Don't iterate forever
if count > 100 {
break;
}
}
// Test passes if we get here without error
}
/// Test that multiple operations work in sequence with skip_region_lookup.
/// This verifies that the default region is consistently used.
#[minio_macros::test]
async fn skip_region_lookup_multiple_operations(ctx: TestContext, bucket: BucketName) {
let client = create_client_with_skip_region_lookup(&ctx);
// Perform multiple operations to ensure consistent behavior
for i in 0..3 {
let object = ObjectKey::try_from(format!("test-object-{}", i).as_str()).unwrap();
let data: Bytes = Bytes::from(format!("data for object {}", i));
// Put
client
.put_object_content(&bucket, &object, data.clone())
.unwrap()
.build()
.send()
.await
.unwrap();
// Get
let resp: GetObjectResponse = client
.get_object(&bucket, &object)
.unwrap()
.build()
.send()
.await
.unwrap();
let got = resp.into_bytes().await.unwrap();
assert_eq!(got, data);
// Delete
client
.delete_object(&bucket, &object)
.unwrap()
.build()
.send()
.await
.unwrap();
}
}
/// Test that skip_region_lookup does not affect stat_object operations.
#[minio_macros::test]
async fn skip_region_lookup_stat_object(ctx: TestContext, bucket: BucketName) {
let client = create_client_with_skip_region_lookup(&ctx);
let object = rand_object_name();
let data: Bytes = Bytes::from("test data for stat");
// Put object
client
.put_object_content(&bucket, &object, data.clone())
.unwrap()
.build()
.send()
.await
.unwrap();
// Stat object using client with skip_region_lookup
let stat_resp = client
.stat_object(&bucket, &object)
.unwrap()
.build()
.send()
.await
.unwrap();
assert_eq!(stat_resp.bucket(), Some(&bucket));
assert_eq!(stat_resp.object(), Some(&object));
assert_eq!(stat_resp.size().unwrap(), data.len() as u64);
}