API-Docker
view release on metacpan or search on metacpan
t/containers_endpoints.t view on Meta::CPAN
ok $seen{raw}, 'the request asked the transport for raw bytes';
ok !$seen{ndjson}, 'and not for a decoded event stream';
is_deeply $seen{params}, { path => '/etc/hostname' },
'path is the only query parameter';
is $out, $TAR, 'the daemon bytes come back verbatim';
is length($out), length($TAR), 'no truncation';
};
subtest 'get_archive: raw bytes survive the real _request' => sub {
my $t = fake_client();
$t->canned([200, 'OK', { 'content-type' => 'application/x-tar' }, $TAR]);
my $out = $t->containers->get_archive('deadbeef', path => '/var/log/app.log');
is $out, $TAR, 'byte-exact through _request';
is $t->request_line,
'GET /v1.41/containers/deadbeef/archive?path=/var/log/app.log HTTP/1.1',
'GET on the versioned path, the path parameter keeping its slashes';
};
subtest 'get_archive: a body that looks like JSON is still not decoded' => sub {
t/containers_endpoints.t view on Meta::CPAN
is_deeply $t->containers->attach('deadbeef', require_running => 0), [],
'a container that wrote nothing gives no frames, not undef';
};
# ===========================================================================
# karr k23 -- changes, export, resize
# ===========================================================================
subtest 'changes: the diff, and what the Kind numbers are' => sub {
my $t = fake_client();
$t->canned([200, 'OK', { 'content-type' => 'application/json' },
'[{"Path":"/etc/hostname","Kind":0},{"Path":"/tmp/new","Kind":1},'
. '{"Path":"/etc/gone","Kind":2}]']);
my $changes = $t->containers->changes('deadbeef');
is $t->request_line, 'GET /v1.41/containers/deadbeef/changes HTTP/1.1',
'GET on the changes path, no query parameters';
is ref $changes, 'ARRAY', 'an ArrayRef';
is scalar @$changes, 3, 'one entry per changed path';
is_deeply $changes->[0], { Path => '/etc/hostname', Kind => 0 }, '0 is modified';
t/containers_endpoints.t view on Meta::CPAN
my $err = do { local $@; eval { $t->containers->changes }; $@ };
like $err, qr/Container ID required/, 'a missing id croaks';
};
subtest 'changes: a container with nothing changed is an empty ArrayRef' => sub {
# The engine answers that case with a JSON null. The transport decodes any
# JSON body, scalars included (karr k30), so a null body reaches this
# method as undef -- which a caller iterating the result would dereference
# and die on just the same.
my $t = fake_client();
$t->canned([200, 'OK', { 'content-type' => 'application/json' }, 'null']);
is_deeply $t->containers->changes('deadbeef'), [],
'a null body is normalised to an empty ArrayRef, not left as undef';
$t->canned([204, 'No Content', {}, '']);
is_deeply $t->containers->changes('deadbeef'), [],
'and so is an empty body';
};
subtest 'export: raw tar bytes, never decoded' => sub {
my $t = fake_client();
$t->canned([200, 'OK', { 'content-type' => 'application/x-tar' }, $TAR]);
my $out = $t->containers->export('deadbeef');
is $t->request_line, 'GET /v1.41/containers/deadbeef/export HTTP/1.1',
'GET on the export path';
is $out, $TAR, 'byte-exact';
is length($out), length($TAR), 'no truncation';
$t->canned([200, 'OK', {}, '{"Id":"not really a tar"}']);
is ref $t->containers->export('deadbeef'), '',
t/images_build_prune.t view on Meta::CPAN
'all three parameters present, sorted by key';
};
# ---------------------------------------------------------------------------
subtest 'the Podman 404 croaks with the plain-text body' => sub {
# Podman 5.4.2 does not implement /build/prune and answers text/plain,
# so there is no {"message":...} for the transport to unwrap. A caller that
# must work on both engines reads this as "no build cache here".
my $t = fake_client();
$t->canned([404, 'Not Found',
{ 'content-type' => 'text/plain; charset=utf-8' }, "Not Found\n"]);
my $err = do { local $@; eval { $t->images->build_prune(all => 1) }; $@ };
like $err, qr/Docker API error \(404\)/, 'it croaks rather than returning undef';
like $err, qr/Not Found/, 'with the plain body, since it is not JSON to unwrap';
};
done_testing;
t/images_tar.t view on Meta::CPAN
is $out, $TAR, 'the daemon bytes come back verbatim';
is length($out), length($TAR), 'no truncation';
my $err = do { local $@; eval { $docker->images->get }; $@ };
like $err, qr/Image name required/, 'a missing name croaks';
};
# ---------------------------------------------------------------------------
subtest 'get: raw bytes survive the real _request' => sub {
my $t = fake_client();
$t->canned([200, 'OK', { 'content-type' => 'application/octet' }, $TAR]);
my $out = $t->images->get('alpine:3');
is $out, $TAR, 'byte-exact through _request';
like $t->written, qr{\AGET /v1\.41/images/alpine:3/get HTTP/1\.1\r\n},
'the request line keeps the colon in the image reference';
};
subtest 'get: a body that looks like JSON is still not decoded' => sub {
# The transport tries decode_json on any body starting with { or [ unless
t/images_tar.t view on Meta::CPAN
'the digest @ is percent-encoded, the colon after sha256 is not';
like $line, qr{names=has%20space}, 'a space is encoded';
my $err = do { local $@; eval { $t->images->get_all }; $@ };
like $err, qr/At least one image name required/, 'no names croaks';
};
# ---------------------------------------------------------------------------
subtest 'load: sends the tar as the body and decodes the progress stream' => sub {
my $t = fake_client();
$t->canned([200, 'OK', { 'content-type' => 'application/json' }, $STREAM]);
my $events = $t->images->load($TAR);
is ref $events, 'ARRAY', 'an ArrayRef of events, as for build and pull';
is scalar @$events, 1, 'the captured stream carried one object';
like $events->[0]{stream}, qr/^Loaded image: /, 'and it names what was loaded';
my $req = $t->written;
like $req, qr{\APOST /v1\.41/images/load HTTP/1\.1\r\n},
'no query string when quiet was not asked for';
t/role_http.t view on Meta::CPAN
my $raw = "HTTP/1.1 200 OK\r\n"
. "Content-Type: application/json\r\n"
. "X-Mixed-CASE: value with spaces \r\n"
. "Content-Length: 2\r\n"
. "\r\n"
. "{}";
my $fh = string_handle($raw);
my $resp = $client->_read_response($fh);
my $headers = $resp->[2];
is $headers->{'content-type'}, 'application/json',
'an already-lowercase key is kept';
is $headers->{'x-mixed-case'}, 'value with spaces ',
'a mixed-case key is lowercased; leading space after the colon is '
. 'trimmed, the rest of the value is kept verbatim (trailing spaces too)';
is $headers->{'content-length'}, '2', 'colon splits key from value';
is $resp->[3], '{}', 'body still decoded via content-length';
};
subtest '_read_response: chunked body' => sub {
my $raw = "HTTP/1.1 200 OK\r\n"
( run in 2.713 seconds using v1.01-cache-2.11-cpan-800906f7e73 )