diff --git a/script/test-smoke.sh b/script/test-smoke.sh index 22fb648e..3d8d26ce 100755 --- a/script/test-smoke.sh +++ b/script/test-smoke.sh @@ -118,52 +118,6 @@ fi # Advanced testing via S3API if [ -z "$SKIP_AWS" ]; then - echo "Test Multipart Upload" - aws s3api create-multipart-upload --bucket eprouvette --key a - aws s3api create-multipart-upload --bucket eprouvette --key a - aws s3api create-multipart-upload --bucket eprouvette --key c - aws s3api create-multipart-upload --bucket eprouvette --key c/a - aws s3api create-multipart-upload --bucket eprouvette --key c/b - - aws s3api list-multipart-uploads --bucket eprouvette >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 5 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ] - aws s3api list-multipart-uploads --bucket eprouvette --page-size 1 >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 5 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ] - aws s3api list-multipart-uploads --bucket eprouvette --delimiter '/' >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 3 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ] - aws s3api list-multipart-uploads --bucket eprouvette --delimiter '/' --page-size 1 >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 3 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ] - aws s3api list-multipart-uploads --bucket eprouvette --prefix 'c' >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 3 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ] - aws s3api list-multipart-uploads --bucket eprouvette --prefix 'c' --page-size 1 >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 3 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ] - aws s3api list-multipart-uploads --bucket eprouvette --prefix 'c' --delimiter '/' >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 1 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ] - aws s3api list-multipart-uploads --bucket eprouvette --prefix 'c' --delimiter '/' --page-size 1 >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 1 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ] - aws s3api list-multipart-uploads --bucket eprouvette --starting-token 'ZZZZZ' >$CMDOUT - [ $(jq '.Uploads | length' $CMDOUT) == 5 ] - [ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ] - aws s3api list-multipart-uploads --bucket eprouvette --starting-token 'd' >$CMDOUT - ! [ -s $CMDOUT ] - - aws s3api list-multipart-uploads --bucket eprouvette | \ - jq -r '.Uploads[] | "\(.Key) \(.UploadId)"' | \ - while read r; do - key=$(echo $r|cut -d' ' -f 1); - uid=$(echo $r|cut -d' ' -f 2); - aws s3api abort-multipart-upload --bucket eprouvette --key $key --upload-id $uid; - echo "Deleted ${key}:${uid}" - done - echo "Test for ListParts" UPLOAD_ID=$(aws s3api create-multipart-upload --bucket eprouvette --key list-parts | jq -r .UploadId) aws s3api list-parts --bucket eprouvette --key list-parts --upload-id $UPLOAD_ID >$CMDOUT diff --git a/src/garage/tests/bucket.rs b/src/garage/tests/bucket.rs index 386f19b4..35aea3c7 100644 --- a/src/garage/tests/bucket.rs +++ b/src/garage/tests/bucket.rs @@ -24,12 +24,14 @@ async fn test_bucket_all() { { // List buckets let r = ctx.client.list_buckets().send().await.unwrap(); - - assert_eq!(r.buckets.as_ref().unwrap().len(), 1); - assert_eq!( - r.buckets.unwrap().first().unwrap().name.as_ref().unwrap(), - bucket_name - ); + assert!(r + .buckets + .as_ref() + .unwrap() + .into_iter() + .filter(|x| x.name.as_ref().is_some()) + .find(|x| x.name.as_ref().unwrap() == "hello") + .is_some()); } { // Get its location @@ -74,6 +76,13 @@ async fn test_bucket_all() { { // Check bucket is deleted with List buckets let r = ctx.client.list_buckets().send().await.unwrap(); - assert_eq!(r.buckets.as_ref().unwrap().len(), 0); + assert!(r + .buckets + .as_ref() + .unwrap() + .into_iter() + .filter(|x| x.name.as_ref().is_some()) + .find(|x| x.name.as_ref().unwrap() == "hello") + .is_none()); } } diff --git a/src/garage/tests/list.rs b/src/garage/tests/list.rs index 72492a89..6e092a3f 100644 --- a/src/garage/tests/list.rs +++ b/src/garage/tests/list.rs @@ -1,6 +1,7 @@ use crate::common; const KEYS: [&str; 8] = ["a", "a/a", "a/b", "a/c", "a/d/a", "a/é", "b", "c"]; +const KEYS_MULTIPART: [&str; 5] = ["a", "a", "c", "c/a", "c/b"]; #[tokio::test] async fn test_listobjectsv2() { @@ -430,3 +431,185 @@ async fn test_listobjectsv1() { assert!(r.common_prefixes.is_none()); } } + +#[tokio::test] +async fn test_listmultipart() { + let ctx = common::context(); + let bucket = ctx.create_bucket("listmultipartuploads"); + + for k in KEYS_MULTIPART { + ctx.client + .create_multipart_upload() + .bucket(&bucket) + .key(k) + .send() + .await + .unwrap(); + } + + { + // Default + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .send() + .await + .unwrap(); + + assert_eq!(r.uploads.unwrap().len(), 5); + assert!(r.common_prefixes.is_none()); + } + { + // With pagination + let mut next = None; + let mut upnext = None; + let last_idx = KEYS_MULTIPART.len() - 1; + + for i in 0..KEYS_MULTIPART.len() { + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .set_key_marker(next) + .set_upload_id_marker(upnext) + .max_uploads(1) + .send() + .await + .unwrap(); + + next = r.next_key_marker; + upnext = r.next_upload_id_marker; + + assert_eq!(r.uploads.unwrap().len(), 1); + assert!(r.common_prefixes.is_none()); + if i != last_idx { + assert!(next.is_some()); + } + } + } + { + // With delimiter + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .delimiter("/") + .send() + .await + .unwrap(); + + assert_eq!(r.uploads.unwrap().len(), 3); + assert_eq!(r.common_prefixes.unwrap().len(), 1); + } + { + // With delimiter and pagination + let mut next = None; + let mut upnext = None; + let mut upcnt = 0; + let mut pfxcnt = 0; + let mut loopcnt = 0; + + while loopcnt < KEYS_MULTIPART.len() { + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .delimiter("/") + .max_uploads(1) + .set_key_marker(next) + .set_upload_id_marker(upnext) + .send() + .await + .unwrap(); + + next = r.next_key_marker; + upnext = r.next_upload_id_marker; + + loopcnt += 1; + upcnt += r.uploads.unwrap_or(vec![]).len(); + pfxcnt += r.common_prefixes.unwrap_or(vec![]).len(); + + if next.is_none() { + break; + } + } + + assert_eq!(upcnt + pfxcnt, loopcnt); + assert_eq!(upcnt, 3); + assert_eq!(pfxcnt, 1); + } + { + // With prefix + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .prefix("c") + .send() + .await + .unwrap(); + + assert_eq!(r.uploads.unwrap().len(), 3); + assert!(r.common_prefixes.is_none()); + } + { + // With prefix and delimiter + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .prefix("c") + .delimiter("/") + .send() + .await + .unwrap(); + + assert_eq!(r.uploads.unwrap().len(), 1); + assert_eq!(r.common_prefixes.unwrap().len(), 1); + } + { + // With prefix, delimiter and max keys + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .prefix("c") + .delimiter("/") + .max_uploads(1) + .send() + .await + .unwrap(); + + assert_eq!(r.uploads.unwrap().len(), 1); + assert!(r.common_prefixes.is_none()); + } + { + // With starting token before the first element + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .key_marker("ZZZZZ") + .send() + .await + .unwrap(); + + assert_eq!(r.uploads.unwrap().len(), 5); + assert!(r.common_prefixes.is_none()); + } + { + // With starting token after the last element + let r = ctx + .client + .list_multipart_uploads() + .bucket(&bucket) + .key_marker("d") + .send() + .await + .unwrap(); + + assert!(r.uploads.is_none()); + assert!(r.common_prefixes.is_none()); + } +}