Amazon-S3-Lite
view release on metacpan or search on metacpan
t/01-s3-lite.t view on Meta::CPAN
subtest 'delete_object' => sub {
my $s3 = new_s3();
my $captured = {};
no warnings 'redefine';
local *Amazon::S3::Lite::_request = mock_request(
status => 204,
capture => \$captured,
);
my $r = $s3->delete_object( 'test-bucket', 'hello.txt' );
is $r, 1, 'returns 1 on success';
is $captured->{method}, 'DELETE', 'method is DELETE';
like $captured->{url}, qr{test-bucket/hello\.txt}, 'URL correct';
ok( $captured->{url} !~ /versionId/, 'no versionId without option' );
# version_id
$s3->delete_object( 'test-bucket', 'hello.txt', version_id => 'v123' );
like $captured->{url}, qr/versionId=v123/, 'versionId in URL';
# version_id with special chars
$s3->delete_object( 'test-bucket', 'hello.txt', version_id => 'v 1+2' );
like $captured->{url}, qr/versionId=v%201/, 'version_id encoded';
# 5xx croaks
local *Amazon::S3::Lite::_request = mock_request( status => 500 );
eval { $s3->delete_object( 'test-bucket', 'hello.txt' ) };
like $@, qr/delete_object failed/, '5xx croaks';
# missing args
eval { $s3->delete_object() };
like $@, qr/bucket is required/, 'croaks without bucket';
eval { $s3->delete_object('b') };
like $@, qr/key is required/, 'croaks without key';
};
subtest 'copy_object' => sub {
my $s3 = new_s3();
my $captured = {};
my $success_xml = <<'XML';
<?xml version="1.0" encoding="UTF-8"?>
<CopyObjectResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<LastModified>2024-01-01T00:00:00.000Z</LastModified>
<ETag>"copietag"</ETag>
</CopyObjectResult>
XML
no warnings 'redefine';
local *Amazon::S3::Lite::_request = mock_request(
content => $success_xml,
capture => \$captured,
);
my $r = $s3->copy_object(
src_bucket => 'src-bucket',
src_key => 'orig/file.json',
dst_bucket => 'dst-bucket',
dst_key => 'copy/file.json',
);
is $captured->{method}, 'PUT', 'method is PUT';
like $captured->{url}, qr{dst-bucket/copy/file\.json}, 'dst URL correct';
like $captured->{headers}{'x-amz-copy-source'}, qr{src-bucket/orig/file\.json}, 'copy-source header set';
is $captured->{headers}{'Content-Length'}, 0, 'Content-Length is 0';
is $r->{etag}, 'copietag', 'etag clean';
is $r->{last_modified}, '2024-01-01T00:00:00.000Z', 'last_modified';
# special chars in src_key
$s3->copy_object(
src_bucket => 'src',
src_key => 'path/my file.txt',
dst_bucket => 'dst',
dst_key => 'copy.txt',
);
like $captured->{headers}{'x-amz-copy-source'}, qr/%20/, 'spaces encoded in copy-source';
like $captured->{headers}{'x-amz-copy-source'}, qr{path/}, 'slashes preserved';
# 200-with-error body
my $error_xml = <<'XML';
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InternalError</Code>
<Message>Something went wrong</Message>
</Error>
XML
local *Amazon::S3::Lite::_request = mock_request( content => $error_xml );
eval { $s3->copy_object( src_bucket => 'src', src_key => 'k', dst_bucket => 'dst', dst_key => 'k2', ); };
like $@, qr/copy_object failed.*InternalError/, '200-with-error body croaks';
# missing required args
for my $missing (qw(src_bucket src_key dst_bucket dst_key)) {
my %args = (
src_bucket => 'src',
src_key => 'k',
dst_bucket => 'dst',
dst_key => 'k2',
);
delete $args{$missing};
eval { $s3->copy_object(%args) };
like $@, qr/$missing is required/, "croaks without $missing";
}
};
subtest 'error XML body extracted' => sub {
my $s3 = new_s3();
my $error_xml = <<'XML';
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
</Error>
XML
no warnings 'redefine';
local *Amazon::S3::Lite::_request = mock_request(
status => 403,
content => $error_xml,
);
eval { $s3->list_buckets };
like $@, qr/AccessDenied/, 'error Code extracted from XML body';
like $@, qr/Access Denied/, 'error Message extracted from XML body';
( run in 0.468 second using v1.01-cache-2.11-cpan-13bb782fe5a )