1
0
mirror of https://pagure.io/fedora-qa/os-autoinst-distri-fedora.git synced 2024-12-18 16:43:07 +00:00
os-autoinst-distri-fedora/tests/os_release.pm
Lukáš Růžička df9766b051 Add checks for SUPPORT_END (EOL) in /etc/os-release.
Fixes #347.

This PR adds two tests to check the EOL written in the
/etc/os-release file. The first test checks that the
SUPPORT_END value lies at least 12 months in the future.
The second test checks the EOL values in Fedora Schedule,
Bodhi, and /etc/os-release if they are the same.
2024-12-03 21:04:38 +00:00

348 lines
13 KiB
Perl

use base "installedtest";
use strict;
use JSON;
use Time::Piece;
use testapi;
use utils;
# This test checks that the descriptions in /etc/os-release file are correct and that they
# match the current version.
sub strip_marks {
# Remove the quotation marks from the string:
my $string = shift;
$string =~ tr/"//d;
return $string;
}
sub json_to_hash {
# Take a string formed as json and return a valid Perl hash
# for further processing.
my $json = shift;
my $hash = decode_json($json);
# If the json is not decoded correctly, fail.
die("Failed to parse JSON: $@") if ($@);
return $hash;
}
sub date_to_epoch {
# Take the date as YYYY-MM-DD and convert it into epoch.
my $dstring = shift;
my $date = Time::Piece->strptime($dstring, '%Y-%m-%d');
my $epoch = $date->epoch;
return $epoch;
}
sub epoch_to_date {
# Take the epoch and return YYYY-MM-DD.
my $epoch = shift;
my $time = localtime($epoch);
my $date = $time->strftime('%Y-%m-%d');
return $date;
}
sub get_bodhi_eol {
# Load the Bodhi json file and return the EOL epoch.
my $ver = shift;
# Use the openQA script output to read the json file. We use jq to make
# sure that the content is a valid json file.
my $json = script_output("cat ~/version_data/bodhi-$ver.json | jq -c");
my $bodhi = json_to_hash($json);
my $eol = $bodhi->{"eol"};
$eol = date_to_epoch($eol);
return $eol;
}
sub get_schedule_eol {
# Load the Fedora Schedule json file and return the EOL epoch.
my $ver = shift;
my $json = script_output("cat ~/version_data/schedule-$ver.json | jq -c");
my $schedule = json_to_hash($json);
my $eol;
# Identify the events and find the EOL field.
my $tasks = $schedule->{'tasks'}[0]{'tasks'}[0]{'tasks'};
my $eol;
foreach my $task (@$tasks) {
if ($task->{'name'} and $task->{'name'} =~ /End of Life/) {
$eol = $task->{'end'};
last;
}
}
# The EOL is already formed as epoch, just return it.
return $eol;
}
sub get_current_date {
# This returns the current date in as the epoch and YYYY-MM-DD.
# which we need to see if the EOL is correctly set in the future.
my $time = localtime;
my $dates = {};
$dates->{'date'} = $time->strftime('%Y-%m-%d');
$dates->{'epoch'} = date_to_epoch($dates->{'date'});
return $dates;
}
sub check_eol_in_year {
# This reads the EOL date from the /etc/os-release
# file and checks that it is at least a year in
# the future (when tested on non-published ISOs).
# Returns true if successful.
my $tested = shift;
$tested = date_to_epoch($tested);
my $dates = get_current_date();
my $current = $dates->{epoch};
# The EOL in the os-release.pm must be at least a year
# in the future, so we calculate the epoch difference
# between $tested and $current.
# An epoch year should be
# 1 * 60 (min) *60 (hour) *24 (day) *365 (year)
my $year = 1 * 60 * 60 * 24 * 365;
my $delta = $tested - $current;
my $bool = 1;
if ($delta < $year) {
$bool = 0;
}
return $bool;
}
sub check_eols_match {
# This takes the EOL dates from the /etc/os-release
# file and compares the value with those from
# Bodhi and Fedora Schedule and will succeed when they
# match each other.
my $tested = shift;
my $version = get_release_number();
my $bodhi = get_bodhi_eol($version);
$bodhi = epoch_to_date($bodhi);
my $schedule = get_schedule_eol($version);
$schedule = epoch_to_date($schedule);
# Let's set the return code to 0 to indicate that none of the EOL date
# can be matched with another one.
my $rcode = 0;
my $overall = 1;
# Start comparisons among the EOL dates.
if ($bodhi eq $schedule and $bodhi eq $tested) {
$rcode = 1;
}
elsif ($bodhi eq $schedule) {
$rcode = 2;
}
elsif ($tested eq $bodhi) {
$rcode = 3;
}
elsif ($tested eq $schedule) {
$rcode = 4;
}
# If the EOL dates do not match each other, consider this a test failure.
$overall = 0 if ($rcode != 1);
my $return_codes = {
0 => "No EOL dates do match:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule",
2 => "The os-release doesn't match Bodhi or Schedule, but they match each other:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule",
3 => "The os-release file matches Bodhi but Schedule differs:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule",
4 => "The os-release file matches Schedule but Bodhi differs:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule",
1 => "All EOL dates match:\n\tos-release: $tested\n\tBodhi: $bodhi\n\tSchedule: $schedule"
};
my $result = [$overall, $return_codes->{$rcode}];
return $result;
}
sub run {
# First, let us define some variables needed to run the program.
my $self = shift;
# The file to be checked
my $filename = '/etc/os-release';
# Read the content of the file to compare. Let us parse the file
# and create a hash with those values, so that we can easily access
# them and assert them.
my $infile = script_output "cat /etc/os-release";
my @infile = split /\n/, $infile;
my %content = ();
foreach (@infile) {
chomp $_;
my ($key, $value) = split /=/, $_;
$content{$key} = $value;
}
# Now, we have all the data ready and we can start testing, first let us get
# correct variables to compare the system data with.
# First, we know the basic stuff
# Should be "fedora"
my $id = get_var("DISTRI");
# extract expected version components from ISO name for canned variants,
# which have their os-release rewritten by rpm-ostree, see:
# https://github.com/projectatomic/rpm-ostree/blob/master/docs/manual/treefile.md
# we use the ISO name because rpm-ostree uses elements from the compose
# ID for nightlies, but from the label for candidate composes; BUILD
# always gives us the compose ID, but the ISO name contains the compose
# ID for nightlies but the label for candidate composes, so it works for
# our purposes here.
my $isovar = get_var("ISO");
# Split the ISO variable at "-" and read second-to-last (release
# number) and last (compose ID: date and respin, label: major and
# minor) fields.
my ($cannedver, $cannednum) = (split /-/, $isovar)[-2, -1];
# Get rid of the ".iso" part of the tag.
$cannednum =~ s/\.iso//g;
# also get rid of the arch, which osbuild puts in here
my $arch = get_var("ARCH");
$cannednum =~ s/\.$arch//g;
# Now, we merge the fields into one expression to create the correct canned tag
# that will contain both the version number and the build number.
my $cannedtag = "$cannedver.$cannednum";
# If this is a CoreOS build, though, throw all that away and
# just use the build version
my $build = get_var("BUILD");
if ($build =~ /^Fedora-CoreOS/) {
$cannedtag = (split /-/, $build)[-1];
}
my $name = ucfirst($id);
my $fullname = $name . " Linux";
my $rawrel = get_var("RAWREL", '');
# Should be the version number or Rawhide.
my $version_id = get_var("VERSION");
# IoT has a branch that acts more or less like Rawhide, but has
# its version as the Rawhide release number, not 'Rawhide'. This
# handles that
$version_id = 'Rawhide' if ($version_id eq $rawrel);
my $varstr = spell_version_number($version_id);
my $target = lc($version_id);
$version_id = $rawrel if ($version_id eq "Rawhide");
# the 'generic' os-release in fedora-release has no VARIANT or
# VARIANT_ID and the string used in values like VERSION, that in other
# cases is the VARIANT, is 'Rawhide' for Rawhide and the spelt version
# number for other releases. These are the values we'll see for an
# Everything image.
my $variant_id = "";
my $variant = "generic";
# now replace the values with the correct ones if we are testing a
# subvariant that maps to a known variant
my $subvariant = get_var('SUBVARIANT');
my %variants = (
Server => ["server", "Server Edition"],
Workstation => ["workstation", "Workstation Edition"],
AtomicHost => ["atomic.host", "Atomic Host"],
CoreOS => ["coreos", "CoreOS"],
KDE => ["kde", "KDE Plasma"],
Silverblue => ["silverblue", "Silverblue"],
IoT => ["iot", "IoT Edition"],
);
if (exists($variants{$subvariant})) {
($variant_id, $variant) = @{$variants{$subvariant}};
$varstr = $variant;
}
# If fedora-release-common release starts with a 0, we'll have
# "Prerelease" in varstr
my $reltag = script_output 'rpm -q fedora-release-common --qf "%{RELEASE}\n"';
if (index($reltag, "0.") == 0) {
$varstr .= " Prerelease";
# ...however, we shouldn't just wave this through if we're
# an RC candidate or update compose, those should never be
# done with a 0.x fedora-release-common. so let's blow up
# here if so. unless it's IoT, because IoT is weird
my $label = get_var("LABEL");
if ($label =~ /^(RC|Update)-/ && $subvariant ne "IoT") {
die "RC candidate or update compose should not have 0.x versioned fedora-release!";
}
}
my $version = "$version_id ($varstr)";
# for canned variants, we need to form a different string here by using
# the above created cannedtag. See earlier comment
if (get_var("CANNED")) {
$version = "$cannedtag ($varstr)";
}
my $platform_id = "platform:f$version_id";
my $pretty = "$fullname $version_id ($varstr)";
# Same problem is when testing the PRETTY_NAME.
if (get_var("CANNED")) {
$pretty = "$fullname $cannedtag ($varstr)";
# ...and FCOS uses a different format, sigh
if ($build =~ /^Fedora-CoreOS/) {
$pretty = "Fedora CoreOS $cannedtag";
}
}
#Now. we can start testing the real values from the installed system.
my @fails = ();
my $failref = \@fails;
# Test for name
my $strip = strip_marks($content{'NAME'});
rec_log "NAME should be $fullname and is $strip", $strip eq $fullname, $failref;
# Test for version.
$strip = strip_marks($content{'VERSION'});
rec_log "VERSION should be $version and is $strip", $strip eq $version, $failref;
# Test for version_id
rec_log "VERSION_ID should be $version_id and is $content{'VERSION_ID'}", $content{'VERSION_ID'} eq $version_id, $failref;
# Test for platform_id
$strip = strip_marks($content{'PLATFORM_ID'});
rec_log "PLATFORM_ID should be $platform_id and is $strip", $strip eq $platform_id, $failref;
# Test for pretty name
$strip = strip_marks($content{'PRETTY_NAME'});
rec_log "PRETTY_NAME should be $pretty and is $strip", $strip eq $pretty, $failref;
# Test for RH Bugzilla Product
$strip = strip_marks($content{'REDHAT_BUGZILLA_PRODUCT'});
rec_log "REDHAT_BUGZILLA_PRODUCT should be $name and is $strip", $strip eq $name, $failref;
# Test for RH Bugzilla Product Version
rec_log "REDHAT_BUGZILLA_PRODUCT_VERSION should be $target and is $content{'REDHAT_BUGZILLA_PRODUCT_VERSION'}", $content{'REDHAT_BUGZILLA_PRODUCT_VERSION'} eq $target, $failref;
# Test for RH Support Product
$strip = strip_marks($content{'REDHAT_SUPPORT_PRODUCT'});
rec_log "REDHAT_SUPPORT_PRODUCT should be $name and is $strip", $strip eq $name, $failref;
# Test for RH Support Product Version
rec_log "REDHAT_SUPPORT_PRODUCT_VERSION should be $target and is $content{'REDHAT_SUPPORT_PRODUCT_VERSION'}", $content{'REDHAT_SUPPORT_PRODUCT_VERSION'} eq $target, $failref;
# Test for Variant but only in case of Server or Workstation
if ($variant ne "generic") {
$strip = strip_marks($content{'VARIANT'});
rec_log "VARIANT should be $variant and is $strip", $strip eq $variant, $failref;
# Test for VARIANT_ID
rec_log "VARIANT_ID should be $variant_id and is $content{'VARIANT_ID'}", $content{'VARIANT_ID'} eq $variant_id, $failref;
}
else {
print "VARIANT was not tested because the compose is not Workstation or Server Edition.\n";
print "VARIANT_ID was not tested because the compose is not Workstation or Server Edition.\n";
}
# Test for EOL date in the distant future.
my $os_release_eol = $content{'SUPPORT_END'};
my $result = check_eol_in_year($os_release_eol);
my $current = get_current_date();
rec_log("The SUPPORT_END date is $os_release_eol which is at least a year ahead in time (now is $current->{date})", $result == 1, $failref);
# Test for EOL dates match each other.
$result = check_eols_match($os_release_eol);
rec_log($result->[1], $result->[0] == 1, $failref);
# Check for fails, count them, collect their messages and die if something was found.
my $failcount = scalar @fails;
script_run "echo \"There were $failcount failures in total.\" >> /tmp/os-release.log";
upload_logs "/tmp/os-release.log", failok => 1;
my $failmessages = "";
foreach my $fail (@fails) {
$failmessages .= "\n" . $fail;
}
die $failmessages if ($failcount > 0);
}
sub test_flags {
return {always_rollback => 1};
}
1;
# vim: set sw=4 et: