API-Docker
view release on metacpan or search on metacpan
t/transport_shape.t view on Meta::CPAN
is fake_client('"hello"')->get('/x'), 'hello',
'a quoted string, without its quotes';
is fake_client(qq{ null\n})->get('/x'), undef,
'leading whitespace and a trailing newline do not stop it';
};
subtest 'the two endpoints that send a bare null' => sub {
# computePrivileges starts from a `var privileges types.PluginPrivileges`
# and appends only what the plugin config asks for, so a plugin needing
# nothing marshals a nil Go slice. GET /containers/{id}/changes does the
# same for a container that changed nothing. Both are documented as
# returning an ArrayRef, and both used to hand over 'null' instead -- which
# /plugins/pull would then have been POSTed as a JSON string where the
# engine expects an array.
is fake_client('null')->get('/plugins/privileges', params => { remote => 'x' }),
undef, 'GET /plugins/privileges: null is undef, which is not iterable-looking';
is fake_client('null')->get('/containers/deadbeef/changes'), undef,
'GET /containers/{id}/changes: the same';
};
subtest 'a body that is not JSON is still returned as itself' => sub {
# GET /_ping answers with the two bytes OK and no JSON anywhere.
is fake_client('OK')->get('/_ping'), 'OK', 'the ping body survives';
# The eval decides, not the pattern: these start with a character the
# pattern lets through and are not JSON.
is fake_client('null pointer dereference')->get('/x'),
'null pointer dereference', 'a sentence starting with null';
is fake_client('42 things happened')->get('/x'), '42 things happened',
'a sentence starting with a digit';
is fake_client('{not json')->get('/x'), '{not json',
'and a body that only looks like an object';
};
subtest 'raw is still bytes, whatever they spell' => sub {
is fake_client('null')->get('/x', raw => 1), 'null',
'raw => 1 hands back the four characters, decoding nothing';
};
# ===========================================================================
# karr k33 -- an ArrayRef param is the same parameter given more than once
# ===========================================================================
subtest 'an ArrayRef param expands to repeated pairs' => sub {
my $c = fake_client('');
$c->get('/images/get', params => { names => ['alpine:3', 'registry:2'] });
is $c->request_line,
'GET /v1.41/images/get?names=alpine:3&names=registry:2 HTTP/1.1',
'one names= pair per element, and the reference colon is left raw';
};
subtest 'element order is the caller\'s, key order is sorted' => sub {
my $c = fake_client('');
$c->get('/x', params => { z => 1, names => ['b', 'a'], a => 2 });
is $c->request_line, 'GET /v1.41/x?a=2&names=b&names=a&z=1 HTTP/1.1',
'keys sorted, but b still precedes a inside the list';
};
subtest 'the elements are escaped the way a single value is' => sub {
my $c = fake_client('');
$c->get('/images/get', params => { names => ['my repo/img:1', 'a&b=c'] });
is $c->request_line,
'GET /v1.41/images/get?names=my%20repo/img:1&names=a%26b%3Dc HTTP/1.1',
'a space, an ampersand and an equals sign are encoded; / and : are not';
};
subtest 'the empty and undef corners of a list' => sub {
my $c = fake_client('');
$c->get('/images/get', params => { names => [] });
is $c->request_line, 'GET /v1.41/images/get HTTP/1.1',
'an empty ArrayRef appends no query string at all, not a bare ?';
$c = fake_client('');
$c->get('/x', params => { names => ['a', undef, 'b'] });
is $c->request_line, 'GET /v1.41/x?names=a&names=b HTTP/1.1',
'an undef element is skipped, like an undef value is';
};
subtest 'a scalar and a HashRef param are unchanged' => sub {
my $c = fake_client('');
$c->get('/containers/json', params => { all => 1, filters => { status => ['running'] } });
is $c->request_line,
'GET /v1.41/containers/json?all=1&filters=%7B%22status%22:%5B%22running%22%5D%7D HTTP/1.1',
'a scalar stays one pair and a HashRef is still JSON-encoded; the colon in the JSON is left raw, like every other colon';
$c = fake_client('');
$c->get('/x', params => { f => [ { a => 1 }, { b => 2 } ] });
my ($qs) = $c->request_line =~ /\?(\S+) HTTP/;
my @encoded = map { my ($v) = /^f=(.*)$/; $v =~ s/%([0-9A-Fa-f]{2})/chr hex $1/ge; $v }
split /&/, $qs;
is_deeply [ map { decode_json($_) } @encoded ], [ { a => 1 }, { b => 2 } ],
'a HashRef inside a list is JSON-encoded per element, same rule';
};
# ===========================================================================
# karr k34 -- zero bytes is a different answer in each shape
# ===========================================================================
subtest 'an empty body keeps the shape the caller asked for' => sub {
my $raw = fake_client('')->get('/images/get', raw => 1);
is $raw, '', 'raw => 1 returns the empty string, not undef';
is length($raw), 0, 'so length() reads 0 instead of warning on undef';
my $events = fake_client('')->post('/images/load', undef, ndjson => 1);
is ref $events, 'ARRAY', 'ndjson => 1 returns an ArrayRef';
is scalar @$events, 0, 'an empty one, for a stream that carried nothing';
is fake_client('')->get('/x'), undef,
'with neither option there is nothing to hand back, so undef';
};
subtest 'a 204 is taken at its word' => sub {
is fake_client('', 204)->post('/containers/deadbeef/start'), undef,
'no body, no option: undef';
is fake_client('should not be here', 204)->get('/x'), undef,
'and bytes after a 204 do not change that';
( run in 1.227 second using v1.01-cache-2.11-cpan-54e63673c56 )