diff --git a/check-release.py b/check-release.py
new file mode 100755
index 00000000..df5a0bc9
--- /dev/null
+++ b/check-release.py
@@ -0,0 +1,209 @@
+#!/usr/bin/python3
+
+# Copyright Red Hat
+#
+# This file is part of os-autoinst-distri-fedora.
+#
+# os-autoinst-distri-fedora 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, see .
+#
+# Author: Lukas Ruzicka
+
+
+"""
+This script provides a simple test for Eof of Life dates on Fedora.
+You can use it for two types of testing. The first test checks that
+the SUPPORT_END value is at least a year ahead (in the time of testing),
+which it should be. The second test checks if the End of Life date is
+consisant across the three sources, the os-release file, Bodhi, and Fedora
+Schedule.
+
+When the test passes, it returns 0, otherwise there is one of the error codes.
+"""
+
+
+import argparse
+import sys
+from datetime import date, datetime, timedelta
+import requests
+
+VERBOSE = False
+RESULT = 100
+
+
+def cli():
+ """Return the CLI arguments."""
+
+ parser = argparse.ArgumentParser(
+ description="Fedora '/etc/os-release' support date validator."
+ )
+
+ parser.add_argument(
+ "--test",
+ "-t",
+ type=str,
+ required=True,
+ help="Test to perform [future, compare]",
+ )
+
+ parser.add_argument(
+ "--release",
+ "-r",
+ type=str,
+ required=False,
+ help="Fedora release number (42, 43, ...)",
+ )
+
+ parser.add_argument(
+ "--verbose",
+ "-v",
+ action="store_true",
+ help="Prints detailed info on the screen.",
+ )
+
+ args = parser.parse_args()
+ return args
+
+
+def log(*args, **kwargs):
+ """Print out messages on CLI if VERBOSE."""
+ if VERBOSE:
+ print(*args, **kwargs)
+ else:
+ pass
+
+
+def epochdate(epoch: int) -> date:
+ """Return the date object calculated from the epoch integer."""
+ converted = datetime.fromtimestamp(epoch)
+ return converted.date()
+
+
+def isodate(iso: str) -> date:
+ """Return the date object calculated from the ISO format."""
+ converted = date.fromisoformat(iso)
+ return converted
+
+
+def get_file_support() -> date:
+ """Returns the support date from the os-release file."""
+ with open("/etc/os-release", "r", encoding="utf-8") as release:
+ lines = release.readlines()
+ log("The /etc/os-release successfully read.")
+
+ support_day = epochdate(0)
+ for line in lines:
+ if "SUPPORT_END" in line:
+ _, value = line.split("=")
+ value = value.strip()
+ if value:
+ support_day = isodate(value)
+ return support_day
+
+
+def support_date_in_future(eol: date) -> bool:
+ """This function checks the support date from the os-release
+ file, compares it with the current system date and tests if
+ the os-release support date lies at least 12 months in the future."""
+
+ # Get the necessary values from the operating system.
+ today = datetime.today().date()
+ log("Current date on tested system is:", today)
+ tomorrow = today + timedelta(days=365)
+ log("Minimal SUPPORT_END calculated from system time is:", tomorrow)
+ log("Real /etc/os-release SUPPORT_END is:", eol)
+
+ # Test if the support end date is in the future.
+ result = False
+ if eol >= tomorrow:
+ log("Real SUPPORT_END is one year in the future.")
+ result = 0
+ else:
+ log("Real SUPPORT_END is NOT one year in the future.")
+ result = 1
+ return result
+
+
+def compare_eol_dates(release: int, eol: date) -> bool:
+ """This function checks the support date on Fedora Schedule, Bodhi
+ and the os-release file and compares them whether they are the same
+ and fails if they are not."""
+ log("The EOL date shown by the os-release file is:", eol.isoformat())
+ # Get the Bodhi EOL date
+ bodhi_response = requests.get(
+ f"https://bodhi.fedoraproject.org/releases/F{release}", timeout=60
+ )
+ bodhi = bodhi_response.json()
+ # Only convert the date if it is present, otherwise record 0.
+ if bodhi["eol"]:
+ bodhi_eol = isodate(bodhi["eol"])
+ else:
+ bodhi_eol = epochdate(0)
+ log("The EOL date shown by Bodhi is:", bodhi_eol.isoformat())
+
+ # Get the Schedule EOL date
+ schedule_response = requests.get(
+ f"https://fedorapeople.org/groups/schedule/f-{release}/"
+ f"f-{release}-key.json",
+ timeout=60,
+ )
+ schedule = schedule_response.json()
+ tasks = schedule["tasks"][0]["tasks"][0]["tasks"]
+ schedule_eol = epochdate(0)
+ for task in tasks:
+ if "End of Life" in task["name"]:
+ schedule_eol = epochdate(int(task["end"]))
+ break
+ log("The EOL date shown by Fedora Schedule is:", schedule_eol.isoformat())
+
+ # Compare the dates
+ result = None
+ if eol == bodhi_eol and eol == schedule_eol:
+ log("All EOL dates have the same value.")
+ result = 0
+ elif eol == bodhi_eol:
+ log("The os-release matches Bodhi but Fedora Schedule is different.")
+ result = 1
+ elif eol == schedule_eol:
+ log("The os-release matches Fedora Schedule but Bodhi is different.")
+ result = 2
+ elif bodhi_eol == schedule_eol:
+ log("Bodhi matches Fedora Schedule, but os-release is different.")
+ result = 3
+ else:
+ log("All EOL dates have different values.")
+ result = 4
+ return result
+
+
+arguments = cli()
+VERBOSE = arguments.verbose
+os_release_eol = get_file_support()
+
+RESULT = 100
+if arguments.test == "compare":
+ if not arguments.release:
+ print("Please, run again with --release option. Finishing.")
+ sys.exit(5)
+
+ RESULT = compare_eol_dates(arguments.release, os_release_eol)
+else:
+ RESULT = support_date_in_future(os_release_eol)
+
+if RESULT != 0:
+ log("Test failed.")
+else:
+ log("Test passed.")
+
+# Sysexit based on the results.
+sys.exit(RESULT)
diff --git a/tests/os_release.pm b/tests/os_release.pm
index acaa7eba..89965214 100644
--- a/tests/os_release.pm
+++ b/tests/os_release.pm
@@ -14,136 +14,11 @@ sub strip_marks {
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 download_python_tests {
+ # Download the Python test script and change mode to rwx,rx,rx.
+ assert_script_run("curl https://pagure.io/fedora-qa/os-autoinst-distri-fedora/raw/os-release-addon/f/check-release.py -o ~/check-release.py --retry 10 --retry-delay 2", timeout => 60);
+ assert_script_run("chmod 755 ~/check-release.py", timeout => 20);
+ sleep(5);
}
sub run {
@@ -316,15 +191,16 @@ sub run {
}
+ # Download Python test script to run the tests.
+ download_python_tests();
# 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);
+ my $result = script_run("~/check-release.py --test future --verbose");
+ rec_log("The SUPPORT_END date is $os_release_eol which is at least a year ahead in time.", $result == 0, $failref);
# Test for EOL dates match each other.
- $result = check_eols_match($os_release_eol);
- rec_log($result->[1], $result->[0] == 1, $failref);
+ $result = script_run("~/check-release.py --test compare --release $version_id --verbose");
+ rec_log("The End of Life dates match each other (local, Bodhi, Schedule)", $result == 0, $failref);
# Check for fails, count them, collect their messages and die if something was found.
my $failcount = scalar @fails;