361 lines
12 KiB
Perl
361 lines
12 KiB
Perl
#! /usr/bin/perl
|
|
|
|
# Copyright (C) 2016-2019 SUSE LLC
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
BEGIN {
|
|
unshift @INC, 'lib';
|
|
}
|
|
|
|
use Mojo::Base;
|
|
use Mojo::IOLoop;
|
|
|
|
use FindBin;
|
|
use lib "$FindBin::Bin/lib";
|
|
use OpenQA::Client;
|
|
use OpenQA::Jobs::Constants;
|
|
use OpenQA::Test::Database;
|
|
use Test::MockModule;
|
|
use Test::More;
|
|
use Test::Mojo;
|
|
use Test::Warnings;
|
|
use Mojo::File qw(tempdir path);
|
|
use OpenQA::WebAPI::Plugin::AMQP;
|
|
|
|
my %published;
|
|
my $plugin_mock_callcount;
|
|
|
|
my $uuid_mock = Test::MockModule->new('UUID::URandom');
|
|
$uuid_mock->mock(
|
|
create_uuid_string => sub {
|
|
return '9fbba7a5-2402-4f6b-a20e-af478eee05f5';
|
|
}
|
|
);
|
|
|
|
# we mock the parent class here so we can test the child class
|
|
my $plugin_mock = Test::MockModule->new('OpenQA::WebAPI::Plugin::AMQP');
|
|
$plugin_mock->mock(
|
|
publish_amqp => sub {
|
|
my ($self, $topic, $body, $headerframe) = @_;
|
|
# ignore the non-fedoraci messages, makes it easier to
|
|
# understand the expected call counts
|
|
if ($topic =~ /\.ci\./) {
|
|
$plugin_mock_callcount++;
|
|
# strip the time-based bits, at least till
|
|
# https://github.com/cho45/Test-Time/issues/14 is done
|
|
delete $body->{'generated_at'};
|
|
delete $headerframe->{'headers'}->{'sent-at'};
|
|
$published{$topic} = [$body, $headerframe];
|
|
}
|
|
}
|
|
);
|
|
|
|
OpenQA::Test::Database->new->create(fixtures_glob => '01-jobs.pl 03-users.pl 05-job_modules.pl');
|
|
|
|
# this test also serves to test plugin loading via config file
|
|
my $conf = << 'EOF';
|
|
[global]
|
|
plugins=FedoraMessaging
|
|
base_url=https://openqa.stg.fedoraproject.org
|
|
[amqp]
|
|
topic_prefix=org.fedoraproject.stg
|
|
EOF
|
|
|
|
my $tempdir = tempdir;
|
|
$ENV{OPENQA_CONFIG} = $tempdir;
|
|
path($ENV{OPENQA_CONFIG})->make_path->child("openqa.ini")->spurt($conf);
|
|
|
|
my $t = Test::Mojo->new('OpenQA::WebAPI');
|
|
|
|
# XXX: Test::Mojo loses its app when setting a new ua
|
|
# https://github.com/kraih/mojo/issues/598
|
|
my $app = $t->app;
|
|
$t->ua(
|
|
OpenQA::Client->new(apikey => 'PERCIVALKEY02', apisecret => 'PERCIVALSECRET02')->ioloop(Mojo::IOLoop->singleton));
|
|
$t->app($app);
|
|
|
|
my $settings = {
|
|
DISTRI => 'Unicorn',
|
|
FLAVOR => 'pink',
|
|
VERSION => '42',
|
|
BUILD => 'Fedora-Rawhide-20180129.n.0',
|
|
TEST => 'rainbow',
|
|
ISO => 'whatever.iso',
|
|
DESKTOP => 'DESKTOP',
|
|
KVM => 'KVM',
|
|
ISO_MAXSIZE => 1,
|
|
MACHINE => "RainbowPC",
|
|
ARCH => 'x86_64',
|
|
SUBVARIANT => 'workstation',
|
|
TEST_TARGET => 'ISO',
|
|
};
|
|
|
|
my $expected_artifact = {
|
|
id => 'Fedora-Rawhide-20180129.n.0',
|
|
type => 'productmd-compose',
|
|
compose_type => 'nightly',
|
|
};
|
|
|
|
my $expected_contact = {
|
|
name => 'Fedora openQA',
|
|
team => 'Fedora QA',
|
|
url => 'https://openqa.stg.fedoraproject.org',
|
|
docs => 'https://fedoraproject.org/wiki/OpenQA',
|
|
irc => '#fedora-qa',
|
|
email => 'qa-devel@lists.fedoraproject.org',
|
|
};
|
|
|
|
my $expected_image = {
|
|
id => 'whatever.iso',
|
|
name => 'whatever.iso',
|
|
type => 'ISO',
|
|
};
|
|
|
|
my $expected_pipeline = {
|
|
id => 'openqa.Fedora-Rawhide-20180129.n.0.rainbow.RainbowPC.pink.x86_64',
|
|
name => 'openqa.Fedora-Rawhide-20180129.n.0.rainbow.RainbowPC.pink.x86_64',
|
|
};
|
|
|
|
my $expected_run = {
|
|
url => '',
|
|
log => '',
|
|
id => '',
|
|
};
|
|
|
|
my $expected_system = {
|
|
os => 'fedora-42',
|
|
provider => 'openqa',
|
|
architecture => 'x86_64',
|
|
variant => 'workstation',
|
|
};
|
|
|
|
my $expected_test = {
|
|
category => 'validation',
|
|
type => 'rainbow RainbowPC pink x86_64',
|
|
namespace => 'compose',
|
|
lifetime => 240,
|
|
};
|
|
|
|
my $expected_error;
|
|
|
|
my $expected_version = '0.2.1';
|
|
|
|
sub get_expected {
|
|
my $expected = {
|
|
artifact => $expected_artifact,
|
|
contact => $expected_contact,
|
|
image => $expected_image,
|
|
pipeline => $expected_pipeline,
|
|
run => $expected_run,
|
|
system => [$expected_system],
|
|
test => $expected_test,
|
|
version => $expected_version,
|
|
};
|
|
$expected->{'error'} = $expected_error if ($expected_error);
|
|
return $expected;
|
|
}
|
|
|
|
# create a job via API
|
|
my $job;
|
|
my $newjob;
|
|
subtest 'create job' => sub {
|
|
# reset the call count
|
|
$plugin_mock_callcount = 0;
|
|
$t->post_ok("/api/v1/jobs" => form => $settings)->status_is(200);
|
|
ok($job = $t->tx->res->json->{id}, 'got ID of new job');
|
|
ok($plugin_mock_callcount == 1, 'plugin mock was called');
|
|
my ($body, $headerframe) = @{$published{'org.fedoraproject.stg.ci.productmd-compose.test.queued'}};
|
|
$expected_run = {
|
|
url => "https://openqa.stg.fedoraproject.org/tests/$job",
|
|
log => "https://openqa.stg.fedoraproject.org/tests/$job/file/autoinst-log.txt",
|
|
id => $job,
|
|
};
|
|
my $expected = get_expected;
|
|
my $expected_headerframe = {
|
|
headers => {
|
|
fedora_messaging_severity => 20,
|
|
fedora_messaging_schema => 'base.message',
|
|
},
|
|
content_encoding => 'utf-8',
|
|
delivery_mode => 2,
|
|
# if this fails, probably means mock broke
|
|
message_id => '9fbba7a5-2402-4f6b-a20e-af478eee05f5',
|
|
};
|
|
is_deeply($body, $expected, 'job create triggers standardized amqp');
|
|
is_deeply($headerframe, $expected_headerframe, 'amqp header frame is as expected');
|
|
};
|
|
|
|
subtest 'mark job as done' => sub {
|
|
$plugin_mock_callcount = 0;
|
|
$t->post_ok("/api/v1/jobs/$job/set_done")->status_is(200);
|
|
ok($plugin_mock_callcount == 1, 'mock was called');
|
|
my ($body, $headerframe) = @{$published{'org.fedoraproject.stg.ci.productmd-compose.test.error'}};
|
|
$expected_error = {reason => INCOMPLETE,};
|
|
delete $expected_test->{'lifetime'};
|
|
my $expected = get_expected;
|
|
is_deeply($body, $expected, 'job done (failed) triggers standardized amqp');
|
|
};
|
|
|
|
subtest 'duplicate and cancel job' => sub {
|
|
$plugin_mock_callcount = 0;
|
|
$t->post_ok("/api/v1/jobs/$job/duplicate")->status_is(200);
|
|
$newjob = $t->tx->res->json->{id};
|
|
ok($plugin_mock_callcount == 1, 'mock was called');
|
|
my ($body, $headerframe) = @{$published{'org.fedoraproject.stg.ci.productmd-compose.test.queued'}};
|
|
$expected_run = {
|
|
clone_of => $job,
|
|
url => "https://openqa.stg.fedoraproject.org/tests/$newjob",
|
|
log => "https://openqa.stg.fedoraproject.org/tests/$newjob/file/autoinst-log.txt",
|
|
id => $newjob,
|
|
};
|
|
$expected_test->{'lifetime'} = 240;
|
|
$expected_error = '';
|
|
delete $expected_test->{'result'};
|
|
my $expected = get_expected;
|
|
is_deeply($body, $expected, 'job duplicate triggers standardized amqp');
|
|
|
|
$plugin_mock_callcount = 0;
|
|
$t->post_ok("/api/v1/jobs/$newjob/cancel")->status_is(200);
|
|
ok($plugin_mock_callcount == 1, 'mock was called');
|
|
my ($body, $headerframe) = @{$published{'org.fedoraproject.stg.ci.productmd-compose.test.error'}};
|
|
$expected_error = {reason => 'user_cancelled',};
|
|
delete $expected_test->{'lifetime'};
|
|
delete $expected_run->{'clone_of'};
|
|
my $expected = get_expected;
|
|
is_deeply($body, $expected, 'job cancel triggers standardized amqp');
|
|
};
|
|
|
|
subtest 'duplicate and pass job' => sub {
|
|
$plugin_mock_callcount = 0;
|
|
$t->post_ok("/api/v1/jobs/$newjob/duplicate")->status_is(200);
|
|
my $newerjob = $t->tx->res->json->{id};
|
|
# explicitly set job as passed
|
|
$t->post_ok("/api/v1/jobs/$newerjob/set_done?result=passed")->status_is(200);
|
|
ok($plugin_mock_callcount == 2, 'mock was called');
|
|
my ($body, $headerframe) = @{$published{'org.fedoraproject.stg.ci.productmd-compose.test.complete'}};
|
|
$expected_run = {
|
|
url => "https://openqa.stg.fedoraproject.org/tests/$newerjob",
|
|
log => "https://openqa.stg.fedoraproject.org/tests/$newerjob/file/autoinst-log.txt",
|
|
id => $newerjob,
|
|
};
|
|
$expected_test->{'result'} = 'passed';
|
|
$expected_error = '';
|
|
my $expected = get_expected;
|
|
is_deeply($body, $expected, 'job done (passed) triggers standardized amqp');
|
|
};
|
|
|
|
subtest 'create update job' => sub {
|
|
$plugin_mock_callcount = 0;
|
|
diag("Count: $plugin_mock_callcount");
|
|
$settings->{BUILD} = 'Update-FEDORA-2019-6bda4c81f4';
|
|
# this is intentionally not in alphabetical order
|
|
$settings->{ADVISORY_NVRS} = 'kernel-5.2.7-100.fc29 kernel-tools-5.2.7-100.fc29 kernel-headers-5.2.7-100.fc29';
|
|
# let's test HDD_* impact on system->{os} here too
|
|
$settings->{HDD_1} = 'disk_f40_minimal.qcow2';
|
|
$settings->{BOOTFROM} = 'c';
|
|
# some update tests don't have SUBVARIANT, in which case system
|
|
# variant should not be set
|
|
delete $settings->{SUBVARIANT};
|
|
$t->post_ok("/api/v1/jobs" => form => $settings)->status_is(200);
|
|
ok(my $updatejob = $t->tx->res->json->{id}, 'got ID of update job');
|
|
diag("Count: $plugin_mock_callcount");
|
|
ok($plugin_mock_callcount == 1, 'mock was called');
|
|
my ($body, $headerframe) = @{$published{'org.fedoraproject.stg.ci.fedora-update.test.queued'}};
|
|
$expected_artifact = {
|
|
alias => 'FEDORA-2019-6bda4c81f4',
|
|
builds => [
|
|
{
|
|
nvr => 'kernel-5.2.7-100.fc29'
|
|
},
|
|
{
|
|
nvr => 'kernel-headers-5.2.7-100.fc29'
|
|
},
|
|
{
|
|
nvr => 'kernel-tools-5.2.7-100.fc29'
|
|
}
|
|
],
|
|
id => 'sha256:cf6f57a196a213606246070a99b94053160fee43c7987d071f422de30b2f2953',
|
|
type => 'fedora-update',
|
|
release => {
|
|
version => '42',
|
|
name => 'F42'
|
|
},
|
|
};
|
|
$expected_pipeline = {
|
|
id => 'openqa.Update-FEDORA-2019-6bda4c81f4.rainbow.RainbowPC.pink.x86_64',
|
|
name => 'openqa.Update-FEDORA-2019-6bda4c81f4.rainbow.RainbowPC.pink.x86_64',
|
|
};
|
|
$expected_run = {
|
|
url => "https://openqa.stg.fedoraproject.org/tests/$updatejob",
|
|
log => "https://openqa.stg.fedoraproject.org/tests/$updatejob/file/autoinst-log.txt",
|
|
id => $updatejob,
|
|
};
|
|
$expected_system->{'os'} = 'fedora-40';
|
|
$expected_test->{'namespace'} = 'update';
|
|
$expected_test->{'lifetime'} = 240;
|
|
delete $expected_system->{'variant'};
|
|
delete $expected_test->{'result'};
|
|
my $expected = get_expected;
|
|
# no image for update message
|
|
delete $expected->{'image'};
|
|
is_deeply($body, $expected, 'update job create triggers standardized amqp');
|
|
};
|
|
|
|
subtest 'create update job (new-style ADVISORY_NVR_N)' => sub {
|
|
$plugin_mock_callcount = 0;
|
|
diag("Count: $plugin_mock_callcount");
|
|
delete $settings->{ADVISORY_NVRS};
|
|
# these are intentionally not in alphabetical order
|
|
$settings->{ADVISORY_NVRS_1} = 'kernel-5.2.8-100.fc29 kernel-tools-5.2.8-100.fc29';
|
|
$settings->{ADVISORY_NVRS_2} = 'kernel-headers-5.2.8-100.fc29';
|
|
$t->post_ok("/api/v1/jobs" => form => $settings)->status_is(200);
|
|
ok(my $newupdatejob = $t->tx->res->json->{id}, 'got ID of new-style update job');
|
|
diag("Count: $plugin_mock_callcount");
|
|
ok($plugin_mock_callcount == 1, 'mock was called');
|
|
my ($body, $headerframe) = @{$published{'org.fedoraproject.stg.ci.fedora-update.test.queued'}};
|
|
$expected_artifact = {
|
|
alias => 'FEDORA-2019-6bda4c81f4',
|
|
builds => [
|
|
{
|
|
nvr => 'kernel-5.2.8-100.fc29'
|
|
},
|
|
{
|
|
nvr => 'kernel-headers-5.2.8-100.fc29'
|
|
},
|
|
{
|
|
nvr => 'kernel-tools-5.2.8-100.fc29'
|
|
}
|
|
],
|
|
id => 'sha256:b85bba148cec9d9c4dafea3a49785abef1f549fbad368f3818e20d9802340b16',
|
|
type => 'fedora-update',
|
|
release => {
|
|
version => '42',
|
|
name => 'F42'
|
|
},
|
|
};
|
|
$expected_run = {
|
|
url => "https://openqa.stg.fedoraproject.org/tests/$newupdatejob",
|
|
log => "https://openqa.stg.fedoraproject.org/tests/$newupdatejob/file/autoinst-log.txt",
|
|
id => $newupdatejob,
|
|
};
|
|
my $expected = get_expected;
|
|
# no image for update message
|
|
delete $expected->{'image'};
|
|
is_deeply($body, $expected, 'update job create triggers standardized amqp');
|
|
};
|
|
|
|
done_testing();
|