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 )