File Coverage

blib/lib/Shared/Examples/Net/Amazon/S3.pm
Criterion Covered Total %
statement 215 227 94.7
branch 35 50 70.0
condition 15 29 51.7
subroutine 65 67 97.0
pod 0 42 0.0
total 330 415 79.5


line stmt bran cond sub pod time code
1             # ABSTRACT: used for testing and as example
2             $Shared::Examples::Net::Amazon::S3::VERSION = '0.991';
3             use strict;
4 90     90   5151339 use warnings;
  90         450  
  90         2399  
5 90     90   435  
  90         162  
  90         2195  
6             use parent qw[ Exporter::Tiny ];
7 90     90   445  
  90         163  
  90         548  
8             use Hash::Util;
9 90     90   184325 use Ref::Util (
  90         121254  
  90         674  
10             qw[ is_regexpref ],
11 90         5370 );
12 90     90   4658  
  90         240  
13             use Test::Deep;
14 90     90   514 use Test::More;
  90         202  
  90         707  
15 90     90   22211 use Test::LWP::UserAgent;
  90         181  
  90         733  
16 90     90   62449  
  90         3351302  
  90         3496  
17             use Net::Amazon::S3;
18 90     90   25952  
  90         298  
  90         2770  
19             use Shared::Examples::Net::Amazon::S3::API;
20 90     90   40280 use Shared::Examples::Net::Amazon::S3::Client;
  90         262  
  90         865  
21 90     90   47089 use Shared::Examples::Net::Amazon::S3::Request;
  90         242  
  90         883  
22 90     90   51117  
  90         264  
  90         931  
23             our @EXPORT_OK = (
24             qw[ s3_api_with_signature_4 ],
25             qw[ s3_api_with_signature_2 ],
26             qw[ expect_net_amazon_s3_feature ],
27             qw[ expect_net_amazon_s3_operation ],
28             qw[ expect_operation_list_all_my_buckets ],
29             qw[ expect_operation_bucket_create ],
30             qw[ expect_operation_bucket_delete ],
31             qw[ with_fixture ],
32             qw[ fixture ],
33             qw[ with_response_fixture ],
34             );
35              
36             my %fixtures;
37             my ($name) = @_;
38              
39 177     177 0 2942 $fixtures{$name} = eval "require Shared::Examples::Net::Amazon::S3::Fixture::$name"
40             unless defined $fixtures{$name};
41              
42 177 100       11439 die "Fixture $name not found: $@"
43             unless defined $fixtures{$name};
44              
45 177 50       892 return +{ %{ $fixtures{$name} } };
46             }
47 177         355  
  177         1070  
48             my ($name) = @_;
49              
50             my $fixture = fixture ($name);
51 0     0 0 0 return wantarray
52             ? %$fixture
53 0         0 : $fixture
54             ;
55 0 0       0 }
56              
57             my ($name) = @_;
58              
59             my $fixture = fixture ($name);
60             my $response_fixture = {};
61 167     167 0 3866  
62             for my $key (keys %$fixture) {
63 167         541 my $new_key;
64 167         369 $new_key ||= "with_response_data" if $key eq 'content';
65             $new_key ||= "with_$key" if $key =~ m/^response/;
66 167         638 $new_key ||= "with_response_header_$key";
67 556         721  
68 556 100 50     1543 $response_fixture->{$new_key} = $fixture->{$key};
69 556 100 33     2081 }
70 556   66     1676  
71             return wantarray
72 556         1227 ? %$response_fixture
73             : $response_fixture
74             ;
75             }
76 167 50       2410  
77              
78             my $api = Net::Amazon::S3->new (@_);
79              
80             $api->ua (Test::LWP::UserAgent->new (network_fallback => 0));
81              
82             $api;
83 405     405 0 12047 }
84              
85 405         2837 my ($self, $api, %params) = @_;
86              
87 405         5930 $params{with_response_code} ||= HTTP::Status::HTTP_OK;
88              
89             my %headers = (
90             content_type => 'application/xml',
91 210     210 0 960 (
92             map {
93 210   100     718 m/^with_response_header_(.*)/;
94             defined $1 && length $1
95             ? ($1 => $params{$_})
96             : ()
97             } keys %params
98             ),
99 2117         2781 %{ $params{with_response_headers} || {} },
100             );
101 2117 100 66     4630  
102             $api->ua->map_response (
103             sub {
104             ${ $params{into} } = $_[0];
105 210 100       789 1;
  210         1306  
106             },
107             HTTP::Response->new (
108             $params{with_response_code},
109             HTTP::Status::status_message ($params{with_response_code}),
110 210     210   49788 [ %headers ],
  210         505  
111 210         418 $params{with_response_data},
112             ),
113             );
114             }
115              
116             s3_api (
117             @_,
118 210         4913 aws_access_key_id => 'AKIDEXAMPLE',
119             aws_secret_access_key => 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
120             authorization_method => 'Net::Amazon::S3::Signature::V4',
121             secure => 1,
122             use_virtual_host => 1,
123 4     4 0 3275 );
124             }
125              
126             s3_api (
127             @_,
128             aws_access_key_id => 'AKIDEXAMPLE',
129             aws_secret_access_key => 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY',
130             authorization_method => 'Net::Amazon::S3::Signature::V2',
131             secure => 1,
132             use_virtual_host => 1,
133             );
134 401     401 0 9499 }
135              
136             my ($title, %params) = @_;
137              
138             my $s3 = delete $params{with_s3};
139             my $feature = delete $params{feature};
140             my $expectation = "expect_$feature";
141              
142             local $Test::Builder::Level = $Test::Builder::Level + 1;
143              
144             subtest $title => sub {
145 4     4 0 55 plan tests => 2;
146              
147 4         13 if (my $code = Shared::Examples::Net::Amazon::S3::API->can ($expectation)) {
148 4         9 $code->( "using S3 API" => (
149 4         11 with_s3 => $s3,
150             %params
151 4         11 ));
152             } else {
153             fail "Net::Amazon::S3 feature expectation $expectation not found";
154 4     4   4096 }
155              
156 4 50       2859 if (my $code = Shared::Examples::Net::Amazon::S3::Client->can ($expectation)) {
157 4         25 $code->( "using S3 Client" => (
158             with_client => Net::Amazon::S3::Client->new (s3 => $s3),
159             %params
160             ));
161             } else {
162 0         0 fail "Net::Amazon::S3::Client feature expectation $expectation not found";
163             }
164             };
165 4 50       2083 }
166 4         136  
167             my ($params, @names) = @_;
168             my $map = {};
169             $map = shift @names if Ref::Util::is_plain_hashref ($names[0]);
170              
171 0         0 return
172             map +( ($map->{$_} || $_) => $params->{"with_$_"} ),
173 4         30 grep exists $params->{"with_$_"},
174             @names
175             ;
176             }
177 0     0   0  
178 0         0 map "with_$_", @_;
179 0 0       0 }
180              
181             return (
182             qw[ -shared_examples ],
183 0   0     0 qw[ -method ],
184             qw[ with_s3 ],
185             qw[ with_client ],
186             qw[ shared_examples ],
187             qw[ with_response_code ],
188             qw[ with_response_data ],
189 210     210   1296 qw[ with_response_headers ],
190             qw[ with_response_header_content_type ],
191             qw[ with_response_header_content_length ],
192             qw[ expect_s3_err ],
193             qw[ expect_s3_errstr ],
194 210     210   1462 qw[ expect_data ],
195             qw[ expect_request ],
196             qw[ expect_request_content ],
197             qw[ expect_request_headers ],
198             qw[ throws ],
199             );
200             }
201              
202             my ($request, $expect, $title) = @_;
203              
204             local $Test::Builder::Level = $Test::Builder::Level + 1;
205              
206             my ($method, $uri) = %$expect;
207             cmp_deeply
208             $request,
209             all (
210             methods (method => $method),
211             methods (uri => methods (as_string => $uri)),
212             ),
213             $title || 'expect request'
214             ;
215 201     201   500 }
216              
217 201         438 my ($request, $expected, $title) = @_;
218              
219 201         629 local $Test::Builder::Level = $Test::Builder::Level + 1;
220 201   50     806  
221             my $got = Shared::Examples::Net::Amazon::S3::Request::_canonical_xml ($request->content);
222             $expected = Shared::Examples::Net::Amazon::S3::Request::_canonical_xml ($expected);
223              
224             cmp_deeply $got, $expected, $title || "expect request content";
225             }
226              
227             my ($request, $expected, $title) = @_;
228              
229             local $Test::Builder::Level = $Test::Builder::Level + 1;
230              
231 64     64   182 my %got = map +($_ => scalar $request->header ($_)), keys %$expected;
232              
233 64         135 cmp_deeply
234             \ %got,
235 64         245 $expected,
236 64         181 $title || "expect request headers"
237             ;
238 64   50     401 }
239              
240             my ($got, $expected, $title) = @_;
241              
242 51     51   147 SKIP: {
243             skip "Net::Amazon::S3->err test irrelevant for Client", 1
244 51         104 if eq_deeply $got, obj_isa ('Net::Amazon::S3::Client');
245              
246 51         291 cmp_deeply $got, methods (err => $expected), $title || 'expect S3->err';
247             }
248 51   50     4244 }
249              
250             my ($got, $expected, $title) = @_;
251              
252             SKIP: {
253             skip "Net::Amazon::S3->errstr test irrelevant for Client", 1
254             if eq_deeply $got, obj_isa ('Net::Amazon::S3::Client');
255              
256 62     62   167 cmp_deeply $got, methods (errstr => $expected), $title || 'expect S3->errstr';
257             }
258             }
259 62 50       115  
  62         216  
260             my ($title, %params) = @_;
261              
262 62   50     21859 local $Test::Builder::Level = $Test::Builder::Level + 1;
263              
264             my $class = delete $params{-shared_examples};
265             my $operation = delete $params{-operation};
266              
267 62     62   178 my $api = $class->_default_with_api (\%params);
268             $class->_mock_http_response ($api, %params, into => \ (my $request));
269              
270 62 50       103 if (my $code = $class->can ($operation)) {
  62         183  
271             subtest $title => sub {
272             plan tests => 1
273 62   50     10609 + int (!! exists $params{expect_request})
274             + int (!! exists $params{expect_request_content})
275             + int (!! exists $params{expect_request_headers})
276             + int (!! exists $params{expect_s3_err})
277             + int (!! exists $params{expect_s3_errstr})
278 210     210   1190 ;
279              
280 210         503 my $got;
281             my $lives = eval { $got = $api->$code (%params); 1 };
282 210         490 my $error = $@;
283 210         429  
284             if ($lives) {
285 210         1520 exists $params{throws}
286 210         1632 ? fail "operation expected to throw but lives"
287             : cmp_deeply $got, $params{expect_data}, "expect operation return data"
288 210 50       43371 ;
289             }
290             else {
291             $params{throws} = re $params{throws}
292             if is_regexpref $params{throws};
293             $params{throws} = obj_isa $params{throws}
294             if defined $params{throws} && ! ref $params{throws};
295              
296 210     210   213955 defined $params{throws}
297             ? cmp_deeply $error, $params{throws}, "it should throw"
298 210         148823 : do { fail "operation expected to live but died" ; diag $error }
299 210         406 ;
  210         1051  
  141         16095  
300 210         2507 }
301              
302 210 100       566 _expect_request $request, $params{expect_request}
303             if exists $params{expect_request};
304             _expect_request_content $request, $params{expect_request_content}
305 141 50       776 if exists $params{expect_request_content};
306             _expect_request_headers ($request, $params{expect_request_headers})
307             if exists $params{expect_request_headers};
308              
309             _expect_s3_err $api, $params{expect_s3_err}
310 69 100       469 if exists $params{expect_s3_err};
311             _expect_s3_errstr $api, $params{expect_s3_errstr}
312 69 100 66     50587 if exists $params{expect_s3_errstr};
313             };
314             } else {
315             fail $title or diag "Operation ${class}::$operation not found";
316 69 50       492 }
  0         0  
  0         0  
317             }
318              
319             my ($name, @parameters) = @_;
320              
321 210 100       172075 my @on = (
322             ('bucket') x!! ($name =~ m/^ ( bucket | object )/x),
323 210 100       262789 ('key') x!! ($name =~ m/^ ( object )/x),
324             );
325 210 100       28235  
326             my $on = "qw[ ${ \ join ' ', @on } ]";
327              
328 210 100       174320 eval <<"OPERATION_DECLARATION";
329             sub parameters_$name {
330 210 100       25253 qw[ ${ \ join ' ', @parameters } ]
331 210         1540 }
332              
333 0 0       0 sub expect_operation_$name {
334             my (\$title, \%params) = \@_;
335             local \$Test::Builder::Level = \$Test::Builder::Level + 1;
336             Hash::Util::lock_keys \%params, _with_keys ($on, parameters_$name), _keys_operation;
337             _expect_operation \$title, \%params, -operation => 'operation_$name';
338 1530     1530   3884 }
339             OPERATION_DECLARATION
340 1530         7523 }
341              
342             _generate_operation_expectation list_all_my_buckets =>
343             ;
344              
345 1530         2315 _generate_operation_expectation bucket_acl_get =>
  1530         4677  
346             ;
347 1530     8 0 2885  
  8     17 0 56  
  8     29 0 23  
  8     10 0 37  
  8     8 0 1134  
  17     15 0 136  
  17     8 0 45  
  17     8 0 53  
  17     8 0 2565  
  29     5 0 188  
  29     18 0 66  
  29     20 0 85  
  29     10 0 4305  
  10     13 0 62  
  10     15 0 23  
  10     8 0 32  
  10     10 0 1374  
  8     8 0 58  
  8     17 0 22  
  8     29 0 28  
  8     10 0 1160  
  15     8 0 106  
  15     15 0 36  
  15     8 0 68  
  15     8 0 2385  
  8     8 0 65  
  8     5 0 23  
  8     18 0 30  
  8     20 0 1209  
  8     10 0 60  
  8     13 0 24  
  8     15 0 33  
  8     8 0 1223  
  8     10 0 60  
  8         26  
  8         30  
  8         1117  
  5         31  
  5         11  
  5         13  
  5         689  
  18         167  
  18         50  
  18         78  
  18         3069  
  20         156  
  20         46  
  20         73  
  20         4022  
  10         61  
  10         21  
  10         29  
  10         1330  
  13         81  
  13         30  
  13         38  
  13         2277  
  15         115  
  15         40  
  15         51  
  15         2208  
  8         66  
  8         20  
  8         26  
  8         1314  
  10         73  
  10         25  
  10         33  
  10         1556  
  8         31  
  17         70  
  29         105  
  10         33  
  8         30  
  15         68  
  8         36  
  8         63  
  8         32  
  5         14  
  18         96  
  20         116  
  10         33  
  13         41  
  15         51  
  8         33  
  10         37  
348             _generate_operation_expectation bucket_acl_set =>
349 1530         159160 qw[ acl ],
350             qw[ acl_xml ],
351             qw[ acl_short ],
352             ;
353              
354             _generate_operation_expectation bucket_create =>
355             qw[ acl ],
356             qw[ acl_short ],
357             qw[ region ],
358             ;
359              
360             _generate_operation_expectation bucket_delete =>
361             ;
362              
363             _generate_operation_expectation bucket_objects_list =>
364             qw[ delimiter ],
365             qw[ max_keys ],
366             qw[ marker ],
367             qw[ prefix ],
368             ;
369              
370             _generate_operation_expectation bucket_objects_delete =>
371             qw[ keys ],
372             ;
373              
374             _generate_operation_expectation object_acl_get =>
375             ;
376              
377             _generate_operation_expectation object_acl_set =>
378             qw[ acl ],
379             qw[ acl_xml ],
380             qw[ acl_short ],
381             ;
382              
383             _generate_operation_expectation object_create =>
384             qw[ headers ],
385             qw[ value ],
386             qw[ cache_control ],
387             qw[ content_disposition ],
388             qw[ content_encoding ],
389             qw[ content_type ],
390             qw[ encryption ],
391             qw[ expires ],
392             qw[ storage_class ],
393             qw[ user_metadata ],
394             qw[ acl ],
395             qw[ acl_short ],
396             ;
397              
398             _generate_operation_expectation object_delete =>
399             ;
400              
401             _generate_operation_expectation object_fetch =>
402             qw[ range ],
403             ;
404              
405             _generate_operation_expectation object_head =>
406             ;
407              
408             _generate_operation_expectation bucket_tags_add =>
409             qw[ tags ],
410             ;
411              
412             _generate_operation_expectation object_tags_add =>
413             qw[ tags ],
414             qw[ version_id ],
415             ;
416              
417             _generate_operation_expectation bucket_tags_delete =>
418             ;
419              
420             _generate_operation_expectation object_tags_delete =>
421             qw[ version_id ],
422             ;
423              
424              
425             1;
426              
427              
428             =pod
429              
430             =encoding UTF-8
431              
432             =head1 NAME
433              
434             Shared::Examples::Net::Amazon::S3 - used for testing and as example
435              
436             =head1 VERSION
437              
438             version 0.991
439              
440             =head1 AUTHOR
441              
442             Branislav Zahradník <barney@cpan.org>
443              
444             =head1 COPYRIGHT AND LICENSE
445              
446             This software is copyright (c) 2022 by Amazon Digital Services, Leon Brocard, Brad Fitzpatrick, Pedro Figueiredo, Rusty Conover, Branislav Zahradník.
447              
448             This is free software; you can redistribute it and/or modify it under
449             the same terms as the Perl 5 programming language system itself.
450              
451             =cut