API-Docker
view release on metacpan or search on metacpan
t/distribution.t view on Meta::CPAN
use strict;
use warnings;
use Test::More;
use FindBin;
use lib "$FindBin::Bin/lib";
use JSON::MaybeXS qw( decode_json );
use API::Docker;
use Test::API::Docker::FakeTransport;
use Test::API::Docker::Mock;
# GET /distribution/{name}/json -- asking a registry for an image manifest
# without pulling it (karr k15).
#
# Nothing here opens a socket or reaches a daemon, and nothing is gated on
# is_live() except the one subtest that says so. Test::API::Docker::Mock is
# deliberately not used for the bulk of this file: under API_DOCKER_TEST_HOST
# it ignores its route table and returns a real client, and the only engine
# reachable here is Podman, which serves no route for this endpoint at all --
# measured, rootless Podman 5.4.2 (API 1.41):
#
# GET /v1.41/distribution/nginx:latest/json
# -> 404 {"cause":"","message":"Path /v1.41/distribution/nginx:latest/json
# is not supported","response":0}
#
# and the same for a bare name and for a percent-escaped reference. That
# version number just echoes the requested path prefix, not a fixed daemon
# constant -- re-measured live on 5.8.4 / API 1.44 the same request gets
# "/v1.44/distribution/..." back instead (karr k62). $PODMAN_404 below reads
# "/v1.41/..." because fake_client() always negotiates api_version 1.41; no
# assertion matches the number either way, only qr/is not supported/. So the
# daemon is faked below the socket instead, and the real _request runs. The
# success payload is the Engine API reference's own example descriptor.
#
# The one exception is the karr k38 subtest near the end, which drives the
# same ->exists 404-handling through Mock's route table instead of the real
# transport, now that Mock honours a >= 400 mock_response the way _request
# does. It is skipped live for the same reason as the rest of this file would
# be if it used Mock: no engine reachable here serves the route to check it
# against.
my $DESCRIPTOR = <<'JSON';
{"Descriptor":{"MediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96","size":3987},"Platforms":[{"architecture":"amd64","os":"linux"}]}
JSON
sub fake_client {
my ($body, $status) = @_;
return Test::API::Docker::FakeTransport->new(
host => 'unix:///nonexistent.sock',
api_version => '1.41',
canned => [$status // 200, 'Not Found', {}, $body // $DESCRIPTOR],
);
}
sub request_line {
my ($raw) = @_;
my ($line) = $raw =~ /\A([^\r\n]*)/;
return $line;
}
# The two 404s this endpoint can give. Only the message tells them apart.
my $REGISTRY_404 = '{"message":"manifest unknown"}';
my $PODMAN_404 = '{"cause":"","message":"Path /v1.41/distribution/'
. 'nginx:latest/json is not supported","response":0}';
my $DOCKER_404 = '{"message":"page not found"}';
# ---------------------------------------------------------------------------
subtest 'the reference keeps its slashes and its tag in the path' => sub {
# Percent-encoding them breaks the reference: the daemon parses the path
# segment as a docker reference, and %2F is not a repository separator.
my $c = fake_client();
$c->distribution->inspect('myrepo/app:1.0');
is request_line($c->written),
'GET /v1.41/distribution/myrepo/app:1.0/json HTTP/1.1',
'slashes and the colon survive into the request line';
my $plain = fake_client();
$plain->distribution->inspect('nginx:latest');
is request_line($plain->written),
'GET /v1.41/distribution/nginx:latest/json HTTP/1.1',
'and so does a plain library reference';
ok !eval { fake_client()->distribution->inspect; 1 },
'no reference croaks';
like $@, qr/image reference/, 'and says what was missing';
};
# ---------------------------------------------------------------------------
subtest 'inspect returns the descriptor as the engine gave it' => sub {
my $c = fake_client();
my $d = $c->distribution->inspect('nginx:latest');
is_deeply $d, decode_json($DESCRIPTOR),
'the decoded response, not an entity object -- there is no '
. 'API::Docker::Distribution class to wrap it in';
is $d->{Descriptor}{size}, 3987, 'the descriptor is reachable';
};
# ---------------------------------------------------------------------------
subtest 'inspect croaks on 404, like every other endpoint method' => sub {
my $c = fake_client($REGISTRY_404, 404);
my %res;
ok !eval { $c->distribution->inspect('nginx:latest', response => \%res); 1 },
'a reference the registry does not have croaks';
like $@, qr/manifest unknown/, 'with the registry message';
is $res{status}, 404,
'and response is filled before the croak, so an eval-ing caller reaches '
. 'the status';
( run in 0.526 second using v1.01-cache-2.11-cpan-364913b4093 )