Move ListObjects tests to Rust
This commit is contained in:
parent
2a3afcaf65
commit
0f4e0e8bb9
3 changed files with 433 additions and 88 deletions
|
@ -143,94 +143,6 @@ fi
|
||||||
|
|
||||||
# Advanced testing via S3API
|
# Advanced testing via S3API
|
||||||
if [ -z "$SKIP_AWS" ]; then
|
if [ -z "$SKIP_AWS" ]; then
|
||||||
echo "🔌 Test S3API"
|
|
||||||
|
|
||||||
echo "Test Objects"
|
|
||||||
aws s3api put-object --bucket eprouvette --key a
|
|
||||||
aws s3api put-object --bucket eprouvette --key a/a
|
|
||||||
aws s3api put-object --bucket eprouvette --key a/b
|
|
||||||
aws s3api put-object --bucket eprouvette --key a/c
|
|
||||||
aws s3api put-object --bucket eprouvette --key a/d/a
|
|
||||||
aws s3api put-object --bucket eprouvette --key a/é
|
|
||||||
aws s3api put-object --bucket eprouvette --key b
|
|
||||||
aws s3api put-object --bucket eprouvette --key c
|
|
||||||
|
|
||||||
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --page-size 0 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --page-size 999999999 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --page-size 1 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --delimiter '/' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 3 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --delimiter '/' --page-size 1 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 3 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --prefix 'a/' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 5 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --prefix 'a/' --delimiter '/' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 4 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --prefix 'a/' --page-size 1 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 5 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --prefix 'a/' --delimiter '/' --page-size 1 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 4 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --start-after 'Z' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette --start-after 'c' >$CMDOUT
|
|
||||||
! [ -s $CMDOUT ]
|
|
||||||
|
|
||||||
|
|
||||||
aws s3api list-objects --bucket eprouvette >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects --bucket eprouvette --page-size 1 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects --bucket eprouvette --delimiter '/' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 3 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
# @FIXME it does not work as expected but might be a limitation of aws s3api
|
|
||||||
# The problem is the conjunction of a delimiter + pagination + v1 of listobjects
|
|
||||||
#aws s3api list-objects --bucket eprouvette --delimiter '/' --page-size 1 >$CMDOUT
|
|
||||||
#[ $(jq '.Contents | length' $CMDOUT) == 3 ]
|
|
||||||
#[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
aws s3api list-objects --bucket eprouvette --prefix 'a/' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 5 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects --bucket eprouvette --prefix 'a/' --delimiter '/' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 4 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
aws s3api list-objects --bucket eprouvette --prefix 'a/' --page-size 1 >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 5 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
# @FIXME idem
|
|
||||||
#aws s3api list-objects --bucket eprouvette --prefix 'a/' --delimiter '/' --page-size 1 >$CMDOUT
|
|
||||||
#[ $(jq '.Contents | length' $CMDOUT) == 4 ]
|
|
||||||
#[ $(jq '.CommonPrefixes | length' $CMDOUT) == 1 ]
|
|
||||||
aws s3api list-objects --bucket eprouvette --starting-token 'Z' >$CMDOUT
|
|
||||||
[ $(jq '.Contents | length' $CMDOUT) == 8 ]
|
|
||||||
[ $(jq '.CommonPrefixes | length' $CMDOUT) == 0 ]
|
|
||||||
aws s3api list-objects --bucket eprouvette --starting-token 'c' >$CMDOUT
|
|
||||||
! [ -s $CMDOUT ]
|
|
||||||
|
|
||||||
aws s3api list-objects-v2 --bucket eprouvette | \
|
|
||||||
jq -c '. | {Objects: [.Contents[] | {Key: .Key}], Quiet: true}' | \
|
|
||||||
aws s3api delete-objects --bucket eprouvette --delete file:///dev/stdin
|
|
||||||
|
|
||||||
|
|
||||||
echo "Test Multipart Upload"
|
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 a
|
aws s3api create-multipart-upload --bucket eprouvette --key a
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
mod listobjects;
|
||||||
mod simple;
|
mod simple;
|
||||||
|
|
432
src/garage/tests/listobjects.rs
Normal file
432
src/garage/tests/listobjects.rs
Normal file
|
@ -0,0 +1,432 @@
|
||||||
|
use crate::common;
|
||||||
|
|
||||||
|
const KEYS: [&str; 8] = ["a", "a/a", "a/b", "a/c", "a/d/a", "a/é", "b", "c"];
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_listobjectsv2() {
|
||||||
|
let ctx = common::context();
|
||||||
|
let bucket = ctx.create_bucket("listobjectsv2");
|
||||||
|
|
||||||
|
for k in KEYS {
|
||||||
|
ctx.client
|
||||||
|
.put_object()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.key(k)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Scoping the variable to avoid reusing it
|
||||||
|
// in a following assert due to copy paste
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 8);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
//@FIXME aws-sdk-s3 automatically checks max-key values.
|
||||||
|
// If we set it to zero, it drops it, and it is probably
|
||||||
|
// the same behavior on values bigger than 1000.
|
||||||
|
// Boto and awscli do not perform these tests, we should write
|
||||||
|
// our own minimal library to bypass AWS SDK's tests and be
|
||||||
|
// sure that we behave correctly.
|
||||||
|
|
||||||
|
{
|
||||||
|
// With 2 elements
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.max_keys(2)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 2);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
assert!(r.next_continuation_token.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With pagination
|
||||||
|
let mut cnt = 0;
|
||||||
|
let mut next = None;
|
||||||
|
let last_idx = KEYS.len() - 1;
|
||||||
|
|
||||||
|
for i in 0..KEYS.len() {
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.set_continuation_token(next)
|
||||||
|
.max_keys(1)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
cnt += 1;
|
||||||
|
next = r.next_continuation_token;
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 1);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
if i != last_idx {
|
||||||
|
assert!(next.is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(cnt, KEYS.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a delimiter
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.delimiter("/")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 3);
|
||||||
|
assert_eq!(r.common_prefixes.unwrap().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a delimiter and pagination
|
||||||
|
let mut cnt_pfx = 0;
|
||||||
|
let mut cnt_key = 0;
|
||||||
|
let mut next = None;
|
||||||
|
|
||||||
|
for _i in 0..KEYS.len() {
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.set_continuation_token(next)
|
||||||
|
.delimiter("/")
|
||||||
|
.max_keys(1)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
next = r.next_continuation_token;
|
||||||
|
match (r.contents, r.common_prefixes) {
|
||||||
|
(Some(k), None) if k.len() == 1 => cnt_key += 1,
|
||||||
|
(None, Some(pfx)) if pfx.len() == 1 => cnt_pfx += 1,
|
||||||
|
_ => unreachable!("logic error"),
|
||||||
|
};
|
||||||
|
if next.is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(cnt_key, 3);
|
||||||
|
assert_eq!(cnt_pfx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a prefix
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.prefix("a/")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 5);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a prefix and a delimiter
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.prefix("a/")
|
||||||
|
.delimiter("/")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 4);
|
||||||
|
assert_eq!(r.common_prefixes.unwrap().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a prefix, a delimiter and max_key
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.prefix("a/")
|
||||||
|
.delimiter("/")
|
||||||
|
.max_keys(1)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.as_ref().unwrap().len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
r.contents
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.key
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.as_str(),
|
||||||
|
"a/a"
|
||||||
|
);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// With start_after before all keys
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.start_after("Z")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 8);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// With start_after after all keys
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects_v2()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.start_after("c")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(r.contents.is_none());
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_listobjectsv1() {
|
||||||
|
let ctx = common::context();
|
||||||
|
let bucket = ctx.create_bucket("listobjects");
|
||||||
|
|
||||||
|
for k in KEYS {
|
||||||
|
ctx.client
|
||||||
|
.put_object()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.key(k)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 8);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With 2 elements
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.max_keys(2)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 2);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
assert!(r.next_marker.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With pagination
|
||||||
|
let mut cnt = 0;
|
||||||
|
let mut next = None;
|
||||||
|
let last_idx = KEYS.len() - 1;
|
||||||
|
|
||||||
|
for i in 0..KEYS.len() {
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.set_marker(next)
|
||||||
|
.max_keys(1)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
cnt += 1;
|
||||||
|
next = r.next_marker;
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 1);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
if i != last_idx {
|
||||||
|
assert!(next.is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(cnt, KEYS.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a delimiter
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.delimiter("/")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 3);
|
||||||
|
assert_eq!(r.common_prefixes.unwrap().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a delimiter and pagination
|
||||||
|
let mut cnt_pfx = 0;
|
||||||
|
let mut cnt_key = 0;
|
||||||
|
let mut next = None;
|
||||||
|
|
||||||
|
for _i in 0..KEYS.len() {
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.delimiter("/")
|
||||||
|
.set_marker(next)
|
||||||
|
.max_keys(1)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
next = r.next_marker;
|
||||||
|
match (r.contents, r.common_prefixes) {
|
||||||
|
(Some(k), None) if k.len() == 1 => cnt_key += 1,
|
||||||
|
(None, Some(pfx)) if pfx.len() == 1 => cnt_pfx += 1,
|
||||||
|
_ => unreachable!("logic error"),
|
||||||
|
};
|
||||||
|
if next.is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(cnt_key, 3);
|
||||||
|
// We have no optimization to skip the whole prefix
|
||||||
|
// on listobjectsv1 so we return the same one 5 times,
|
||||||
|
// for each element. It is up to the client to merge its result.
|
||||||
|
// This is compliant with AWS spec.
|
||||||
|
assert_eq!(cnt_pfx, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a prefix
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.prefix("a/")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 5);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a prefix and a delimiter
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.prefix("a/")
|
||||||
|
.delimiter("/")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 4);
|
||||||
|
assert_eq!(r.common_prefixes.unwrap().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// With a prefix, a delimiter and max_key
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.prefix("a/")
|
||||||
|
.delimiter("/")
|
||||||
|
.max_keys(1)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.as_ref().unwrap().len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
r.contents
|
||||||
|
.unwrap()
|
||||||
|
.first()
|
||||||
|
.unwrap()
|
||||||
|
.key
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.as_str(),
|
||||||
|
"a/a"
|
||||||
|
);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// With marker before all keys
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.marker("Z")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(r.contents.unwrap().len(), 8);
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// With start_after after all keys
|
||||||
|
let r = ctx
|
||||||
|
.client
|
||||||
|
.list_objects()
|
||||||
|
.bucket(&bucket)
|
||||||
|
.marker("c")
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(r.contents.is_none());
|
||||||
|
assert!(r.common_prefixes.is_none());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue