diff --git a/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm b/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm index c5bf05fdfed..2785fdf2d86 100644 --- a/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm +++ b/lib/OpenQA/WebAPI/Controller/API/V1/Worker.pm @@ -2,7 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later package OpenQA::WebAPI::Controller::API::V1::Worker; -use Mojo::Base 'Mojolicious::Controller'; +use Mojo::Base 'Mojolicious::Controller', -signatures; use OpenQA::App; use OpenQA::Log 'log_warning'; @@ -42,21 +42,30 @@ websocket status. =cut -sub list { - my ($self) = @_; - my $limits = OpenQA::App->singleton->config->{misc_limits}; - my $limit = min($limits->{generic_max_limit}, $self->param('limit') // $limits->{generic_default_limit}); +sub list ($self) { my $validation = $self->validation; + $validation->optional('limit')->num; $validation->optional('live')->num(1); + $validation->optional('offset')->num; return $self->reply->validation_error({format => 'json'}) if $validation->has_error; + + my $limits = OpenQA::App->singleton->config->{misc_limits}; + my $limit = min($limits->{generic_max_limit}, $validation->param('limit') // $limits->{generic_default_limit}); + my $offset = $validation->param('offset') // 0; my $live = $validation->param('live'); - my $workers = $self->schema->resultset("Workers")->search({}, {rows => $limit}); - my $ret = []; - while (my $w = $workers->next) { - next unless ($w->id); - push(@$ret, $w->info($live)); + my @all = $self->schema->resultset('Workers')->search({}, {rows => $limit + 1, offset => $offset})->all; + + # Pagination + pop @all if my $has_more = @all > $limit; + $self->pagination_links_header($limit, $offset, $has_more); + + my $ret = []; + for my $worker (@all) { + next unless $worker->id; + push @$ret, $worker->info($live); } + $self->render(json => {workers => $ret}); } diff --git a/t/api/01-workers.t b/t/api/01-workers.t index efca94514a9..6d362f43a17 100644 --- a/t/api/01-workers.t +++ b/t/api/01-workers.t @@ -188,6 +188,51 @@ subtest 'server-side limit has precedence over user-specified limit' => sub { is ref $workers, 'ARRAY', 'data returned (3)' and is scalar @$workers, 2, 'default limit for workers is effective'; }; +subtest 'server-side limit with pagination' => sub { + subtest 'input validation' => sub { + $t->get_ok('/api/v1/workers?limit=a')->status_is(400) + ->json_is({error_status => 400, error => 'Erroneous parameters (limit invalid)'}); + $t->get_ok('/api/v1/workers?offset=a')->status_is(400) + ->json_is({error_status => 400, error => 'Erroneous parameters (offset invalid)'}); + }; + + subtest 'navigation with limit' => sub { + $t->get_ok('/api/v1/workers?limit=3')->status_is(200)->json_has('/workers/0')->json_has('/workers/2') + ->json_hasnt('/workers/3'); + my $links = $t->tx->res->headers->links; + ok $links->{first}, 'has first page'; + ok $links->{next}, 'has next page'; + ok !$links->{prev}, 'no previous page'; + + $t->get_ok($links->{next}{link})->status_is(200)->json_has('/workers/0')->json_has('/workers/2') + ->json_hasnt('/workers/3'); + $links = $t->tx->res->headers->links; + ok $links->{first}, 'has first page'; + ok $links->{next}, 'has next page'; + ok $links->{prev}, 'has previous page'; + + $t->get_ok($links->{next}{link})->status_is(200)->json_has('/workers/0')->json_hasnt('/workers/1'); + $links = $t->tx->res->headers->links; + ok $links->{first}, 'has first page'; + ok !$links->{next}, 'no next page'; + ok $links->{prev}, 'has previous page'; + + $t->get_ok($links->{prev}{link})->status_is(200)->status_is(200)->json_has('/workers/0') + ->json_has('/workers/2')->json_hasnt('/workers/3'); + $links = $t->tx->res->headers->links; + ok $links->{first}, 'has first page'; + ok $links->{next}, 'has next page'; + ok $links->{prev}, 'has previous page'; + + $t->get_ok($links->{first}{link})->status_is(200)->status_is(200)->json_has('/workers/0') + ->json_has('/workers/2')->json_hasnt('/workers/3'); + $links = $t->tx->res->headers->links; + ok $links->{first}, 'has first page'; + ok $links->{next}, 'has next page'; + ok !$links->{prev}, 'no previous page'; + }; +}; + subtest 'delete offline worker' => sub { my $offline_worker_id = 9; $workers->create(