Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

load_templates: better error handling #2690

Merged
merged 1 commit into from
Feb 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/OpenQA/WebAPI/Controller/API/V1/JobTemplate.pm
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,11 @@ sub update {
$yaml .= "\n";
}
try {
my $template = $self->param('template') or die "No template specified\n";

# No objects (aka SafeYAML)
$YAML::XS::LoadBlessed = 0;
$data = YAML::XS::Load($yaml);
$data = YAML::XS::Load($template);
$errors = $self->app->validate_yaml($data, $self->param('schema'), $self->app->log->level eq 'debug');
}
catch {
Expand Down
15 changes: 11 additions & 4 deletions script/load_templates
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ use OpenQA::Client;
use Mojo::JSON; # booleans
use Cpanel::JSON::XS ();
use YAML::XS;
use Scalar::Util qw(reftype);

use Getopt::Long;

Expand Down Expand Up @@ -130,11 +131,17 @@ my @tables = (qw(Machines TestSuites Products JobTemplates JobGroups));

sub print_error {
my ($res) = @_;
die 'unknown error code - host ' . $url->host . ' unreachable?' unless $res->code;
printf STDERR "ERROR: %s - %s\n", $res->code, $res->message // 'no error message';
if ($res->body) {
dd($res->json || $res->body);
if (my $err = $res->error) {
if (my $json = $res->json) {
if (my $json_err = $json->{error}) {
die "$err->{message}: " . join("\n", @{$json_err})
if reftype $json_err eq 'ARRAY';
die "$err->{message}: $json_err";
}
}
die "ERROR: $err->{code} - $err->{message}" if $err->{code};
}
die "unknown error code - host $url->{host} unreachable?";
}

sub post_entry {
Expand Down
2 changes: 1 addition & 1 deletion t/05-scheduler-full.t
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ my $schema = OpenQA::Test::Database->new->create(skip_schema => 1);
# Create webapi and websocket server services
my $mojoport = Mojo::IOLoop::Server->generate_port();
my $wspid = create_websocket_server($mojoport + 1, 0, 1, 1);
my $webapi = create_webapi($mojoport);
my $webapi = create_webapi($mojoport, sub { });

# Setup needed files for workers.

Expand Down
8 changes: 6 additions & 2 deletions t/14-grutasks.t
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use OpenQA::Utils;
use OpenQA::Jobs::Constants;
use OpenQA::Schema::Result::Jobs;
use File::Copy;
use OpenQA::SeleniumTest;
use OpenQA::Test::Database;
use OpenQA::Test::Utils;
use Test::Output 'combined_like';
use Test::MockModule;
use Test::More;
Expand All @@ -40,6 +40,7 @@ use Fcntl ':mode';
use Mojo::File 'tempdir';
use Mojo::Log;
use Storable qw(store retrieve);
use Mojo::IOLoop;

# these are used to track assets being 'removed from disk' and 'deleted'
# by mock methods (so we don't *actually* lose them)
Expand Down Expand Up @@ -95,7 +96,8 @@ $assets_mock->mock(refresh_assets => sub { });
my $t = Test::Mojo->new('OpenQA::WebAPI');

# launch an additional app to serve some file for testing blocking downloads
my $mojo_port = OpenQA::SeleniumTest::start_app(sub { });
my $mojo_port = Mojo::IOLoop::Server->generate_port;
my $pid = OpenQA::Test::Utils::create_webapi($mojo_port, sub { });

# define a fix asset_size_limit configuration for this test to be independent of the default value
# we possibly want to adjust without going into the details of this test
Expand Down Expand Up @@ -576,6 +578,8 @@ subtest 'download assets with correct permissions' => sub {
}
};

kill TERM => $pid;

done_testing();

# clear gru task queue at end of execution so no 'dangling' tasks
Expand Down
39 changes: 39 additions & 0 deletions t/40-script_load_templates.t
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use Mojo::Base -strict;

use File::Temp qw(tempfile);
use Mojo::File qw(path curfile);
use OpenQA::Test::Database;
use OpenQA::Test::Utils;
use Test::More;
use Test::Output;
use Test::Warnings;
Expand All @@ -42,4 +44,41 @@ $args = "--host $host $filename";
combined_like sub { $ret = run_once($args); }, qr/unknown error code - host $host unreachable?/, 'invalid host error';
is $ret, 22, 'error because host is invalid';

$ENV{MOJO_LOG_LEVEL} = 'fatal';
my $mojoport = Mojo::IOLoop::Server->generate_port;
$host = "localhost:$mojoport";
my $pid = OpenQA::Test::Utils::create_webapi($mojoport, sub { OpenQA::Test::Database->new->create; });
# Note: See t/fixtures/03-users.pl for test user credentials
my $apikey = 'PERCIVALKEY02';
my $apisecret = 'PERCIVALSECRET02';
$args = "--host $host --apikey $apikey --apisecret $apisecret $filename";
combined_like sub { $ret = run_once($args); }, qr/Administrator level required/, 'Operator is not allowed';
is $ret, 255, 'error because of insufficient permissions';

$apikey = 'ARTHURKEY01';
$apisecret = 'EXCALIBUR';
$args = "--host $host --apikey $apikey --apisecret $apisecret $filename";
combined_like sub { $ret = run_once($args); }, qr/Job group.+not found/, 'Invalid job group';
is $ret, 255, 'failed to load templates with invalid job group';
kill TERM => $pid;

sub schema_hook {
my $schema = OpenQA::Test::Database->new->create;
my $job_groups = $schema->resultset('JobGroups');
$job_groups->create({name => 'openSUSE Leap 42.3 Updates'});
}
$mojoport = Mojo::IOLoop::Server->generate_port;
$host = "localhost:$mojoport";
$pid = OpenQA::Test::Utils::create_webapi($mojoport, \&schema_hook);
$args = "--host $host --apikey $apikey --apisecret $apisecret $filename";
stdout_like sub { $ret = run_once($args); }, qr/JobGroups.+=> \{ added => 1, of => 1 \}/, 'Admin may load templates';
is $ret, 0, 'successfully loaded templates';

$filename = 't/data/40-templates.json';
$args = "--host $host --apikey $apikey --apisecret $apisecret $filename";
combined_like sub { $ret = run_once($args); }, qr/Bad Request: No template specified/,
'YAML template is mandatory (JSON)';
is $ret, 255, 'failed to load templates without YAML (JSON)';
kill TERM => $pid;

done_testing;
35 changes: 35 additions & 0 deletions t/data/40-templates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"Machines" : [
{
"name" : "32bit",
"backend" : "qemu"
}
],
"JobGroups" : [
{
"group_name" : "openSUSE Leap 42.3 Updates"
}
],
"Products" : [
{
"arch" : "x86_64",
"version" : "42.2",
"flavor" : "DVD",
"distri" : "opensuse"
}
],
"JobTemplates" : [
],
"TestSuites" : [
{
"description" : "Maintainer: averagea\n\nThat's some test right there",
"name" : "uefi",
"settings" : [
{
"key" : "DESKTOP",
"value" : "gnome"
}
]
}
]
}
63 changes: 8 additions & 55 deletions t/lib/OpenQA/SeleniumTest.pm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use Try::Tiny;
use Time::HiRes 'time';
use OpenQA::WebAPI;
use OpenQA::Utils;
use OpenQA::Test::Utils;
use POSIX '_exit';

our $_driver;
Expand All @@ -32,68 +33,20 @@ our $mojoport;
our $startingpid = 0;
our $drivermissing = 'Install Selenium::Remote::Driver and Selenium::Chrome to run these tests';

=head2 start_app
start_app([$schema_hook]);
Fork a server instance with database creation and return the server port.
By default the database is created based on the fixture set.
The optional parameter C<$schema_hook> allows to provide a custom way of creating a database, e.g.
sub schema_hook {
my $schema = OpenQA::Test::Database->new->create;
# delete unused job id 1234
$schema->resultset('Jobs')->find(1234)->delete;
}
start_app(\&schema_hook);
=cut

sub start_app {
sub _start_app {
my ($schema_hook, $args) = @_;
$schema_hook = sub { OpenQA::Test::Database->new->create }
unless $schema_hook;
$mojoport = $args->{mojoport} // $ENV{MOJO_PORT} // Mojo::IOLoop::Server->generate_port;

$startingpid = $$;
$mojopid = fork();
if ($mojopid == 0) {
log_info("inserting fixtures into database\n");
if ($schema_hook) {
$schema_hook->();
}
else {
OpenQA::Test::Database->new->create;
}

log_info("starting web UI\n");
$ENV{MOJO_MODE} = 'test';
my $daemon = Mojo::Server::Daemon->new(
listen => ["http://127.0.0.1:$mojoport"],
silent => 1,
);
$daemon->build_app('OpenQA::WebAPI');
$daemon->run;
Devel::Cover::report() if Devel::Cover->can('report');
_exit(0);
}
$mojopid = OpenQA::Test::Utils::create_webapi($mojoport, $schema_hook);

# as this might download assets on first test, we need to wait a while
my $wait = time + 50;
while (time < $wait) {
my $t = time;
my $socket = IO::Socket::INET->new(
PeerHost => '127.0.0.1',
PeerPort => $mojoport,
Proto => 'tcp',
);
last if $socket;
sleep 1 if time - $t < 1;
}
start_gru() if ($args->{with_gru});
_start_gru() if ($args->{with_gru});
return $mojoport;
}

sub start_gru {
sub _start_gru {
$gru_pid = fork();
if ($gru_pid == 0) {
log_info("starting gru\n");
Expand Down Expand Up @@ -220,7 +173,7 @@ sub call_driver {
# are available, otherwise return undef
return undef unless check_driver_modules;
my ($schema_hook, $args) = @_;
my $mojoport = start_app($schema_hook, $args);
my $mojoport = _start_app($schema_hook, $args);
return start_driver($mojoport);
}

Expand Down
10 changes: 7 additions & 3 deletions t/lib/OpenQA/Test/Utils.pm
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,16 @@ sub wait_for_worker {
}

sub create_webapi {
my $mojoport = shift;
my ($mojoport, $schema_hook) = @_;
die 'No port specified ' unless $mojoport;
die 'No schema hook specified' unless $schema_hook;
note("Starting WebUI service. Port: $mojoport");

my $startingpid = $$;
my $mojopid = fork();
my $mojopid = fork();
if ($mojopid == 0) {
log_info("inserting fixtures into database\n");
$schema_hook->();

local $ENV{MOJO_MODE} = 'test';
my $daemon = Mojo::Server::Daemon->new(listen => ["http://127.0.0.1:$mojoport"], silent => 1);
$daemon->build_app('OpenQA::WebAPI');
Expand Down
2 changes: 1 addition & 1 deletion t/ui/27-plugin_obs_rsync_status_details.t
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ foreach my $proj (sort { $b cmp $a } keys %params) {

# refresh page and make sure that last sync is gone
$driver->get("/admin/obs_rsync/$parent");
is($driver->find_element("tr#folder_$proj .lastsync")->get_text(), 'no data', "$proj last sync forgotten");
is($driver->find_element("tr#folder_$proj .lastsync")->get_text(), 'no data', "$proj last sync absent from web UI");

# Update project status
$driver->find_element("tr#folder_$proj .dirtystatusupdate")->click();
Expand Down