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