use strict; use warnings; use utf8; use FindBin (); use lib "$FindBin::Bin/lib"; use Test::More; use TestServer qw(se_address json new_client); use Cepis; use Time::HiRes (); { my $server = TestServer->new( routes => { '/01001000' => [ [ 500, json( { erro => 'interno' } ), {} ], [ 200, json( se_address() ), {} ], ] } ); my $client = new_client($server); is( $client->lookup('01001000')->localidade, 'São Paulo', 'a retry recovers' ); is( $server->count('/01001000'), 2, 'it took two attempts' ); $server->stop; } { my $server = TestServer->new( routes => { '/01001000' => [ 503, json( { erro => 'interno' } ), {} ] } ); my $client = new_client($server); my $ok = eval { $client->lookup('01001000'); 1 }; ok( !$ok, 'exhausting the attempts throws' ); isa_ok( $@, 'Cepis::Error::ServerError' ); is( $@->status, 503, 'the status of the last attempt is exposed' ); is( $server->count('/01001000'), 3, 'three attempts by default' ); $server->stop; } { my $server = TestServer->new( routes => { '/01001000' => [ 500, '{}', {} ] } ); my $client = new_client( $server, max_attempts => 1 ); my $ok = eval { $client->lookup('01001000'); 1 }; ok( !$ok, 'max_attempts of 1 still throws' ); is( $server->count('/01001000'), 1, 'and disables retrying' ); $server->stop; } { my $server = TestServer->new( routes => { '/01001000' => [ 429, '{}', { 'Retry-After' => '7' } ] } ); my $client = new_client($server); my $ok = eval { $client->lookup('01001000'); 1 }; ok( !$ok, 'a 429 throws' ); isa_ok( $@, 'Cepis::Error::RateLimited' ); cmp_ok( abs( $@->retry_after - 7 ), '<', 1e-9, 'Retry-After in seconds is read' ); $server->stop; } { my @day = qw(Sun Mon Tue Wed Thu Fri Sat); my @month = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); my @t = gmtime( time + 4 ); my $date = sprintf '%s, %02d %s %04d %02d:%02d:%02d GMT', $day[ $t[6] ], $t[3], $month[ $t[4] ], $t[5] + 1900, $t[2], $t[1], $t[0]; my $server = TestServer->new( routes => { '/01001000' => [ 429, '{}', { 'Retry-After' => $date } ] } ); my $client = new_client($server); my $ok = eval { $client->lookup('01001000'); 1 }; ok( !$ok, 'a 429 with an HTTP date throws' ); isa_ok( $@, 'Cepis::Error::RateLimited' ); cmp_ok( $@->retry_after, '>', 0, 'the date form is parsed too' ); cmp_ok( $@->retry_after, '<=', 5, 'and lands where it should' ); $server->stop; } { my $server = TestServer->new( routes => { '/01001000' => [ 429, '{}', { 'Retry-After' => '3600' } ] } ); my $client = new_client($server); my $started = Time::HiRes::time(); my $ok = eval { $client->lookup('01001000'); 1 }; ok( !$ok, 'an absurd Retry-After still throws' ); cmp_ok( Time::HiRes::time() - $started, '<', 5, 'and is capped by backoff_max' ); $server->stop; } { my $client = Cepis::Client->new( base_url => 'http://127.0.0.1:1', max_attempts => 2, backoff_base => 0.001, backoff_max => 0.01, timeout => 1.0, ); my $ok = eval { $client->lookup('01001000'); 1 }; ok( !$ok, 'nothing listening throws' ); isa_ok( $@, 'Cepis::Error::Network' ); like( "$@", qr/127\.0\.0\.1:1/, 'the message names the URL' ); } { my $server = TestServer->new( routes => { '/01001000' => [ 500, '{}', {} ] } ); my $client = new_client( $server, max_attempts => 50, backoff_base => 0.05, backoff_max => 0.05, total_timeout => 0.3, ); my $started = Time::HiRes::time(); my $ok = eval { $client->lookup('01001000'); 1 }; ok( !$ok, 'the call still throws' ); isa_ok( $@, 'Cepis::Error::ServerError' ); cmp_ok( Time::HiRes::time() - $started, '<', 3, 'total_timeout bounds the whole call' ); cmp_ok( $server->count('/01001000'), '<', 50, 'and cuts the attempts short' ); $server->stop; } { my $server = TestServer->new( routes => { '/01001000' => [ [ 502, '{}', {} ], [ 504, '{}', {} ], [ 200, json( se_address() ), {} ], ] } ); my $client = new_client($server); is( $client->lookup('01001000')->uf, 'SP', '502 and 504 are retried too' ); is( $server->count('/01001000'), 3, 'across three attempts' ); $server->stop; } done_testing();