Implement distribution methods to replace the testapi defaults.

This PR adds implementations of distribution methods to make them
usable on Fedora. It adds the following methods

* ensure_installed (to install packages)
* become_root (to switch to root account)
* script_sudo (run script with sudo)
* assert_script_sudo (run and assert a sudo script)

It also adds a helper script to the utils.pm

* make_serial_writable

that makes the serial console writable for normal users
and so enables to run commands that check their progress
by sending messages to the serial console. Normally, they
fail, because the messages will not be written their, so
the checking mechanism will never see them.
This commit is contained in:
Lukáš Růžička 2021-12-23 13:08:13 +01:00 committed by adamwill
parent 9c225c5b40
commit fe8306d2cd
4 changed files with 169 additions and 7 deletions

View File

@ -11,15 +11,17 @@ use Cwd;
# (and it's completely up to us to implement them) should be here
# functions that can be reimplemented:
# ensure_installed
# x11_start_program
# become_root
# script_sudo
# type_password
# ensure_installed (reimplemented here)
# x11_start_program (reimplemented here)
# become_root (reimplemented here)
# script_sudo (reimplemented here)
# assert_script_sudo (reimplemented here
# type_password (works as is)
# importing whole testapi creates circular dependency, so import only
# necessary functions from testapi
use testapi qw(check_var get_var send_key type_string assert_screen);
use testapi qw(check_var get_var send_key type_string assert_screen check_screen assert_script_run validate_script_output enter_cmd type_password);
use utils qw(console_login desktop_vt menu_launch_type);
sub init() {
my ($self) = @_;
@ -36,6 +38,10 @@ sub init() {
}
}
# This routine should be able to start a graphical application in various DEs
# across Fedora, as it uses the Alt-F2 combination that is known to work
# similarly everywhere, maybe not in i3 or sway, but we do not test them so often anyway.
# If this should change in the future, we would need to enhance this routine.
sub x11_start_program {
my ($self, $program, $timeout, $options) = @_;
send_key "alt-f2";
@ -45,5 +51,117 @@ sub x11_start_program {
send_key "ret", 1;
}
# ensure_installed checks if a package is already installed and if not install it.
# To make it happen, it will switch to a virtual terminal (if not already there)
# and try to install the package. DNF will skip the installation,
# if it is already installed.
sub ensure_installed {
my ($self, @packages) = @_;
# First, let's assume that we are in the virtual console and that we want to stay there
# when the routine finishes.
my $stay_on_console = 1;
# We will check if GUI elements are present, that would suggest that we are not in the
# console but in GUI.
if (check_screen("apps_menu_button")) {
# In that case, we want to return to GUI after the routine finishes.
$stay_on_console = 0;
# From GUI we need to switch to the console.
send_key("ctrl-alt-f3");
# Let's wait to allow for screen changes.
sleep 5;
# And do the login.
console_login();
}
# Try to install the packages via dnf. If it is already installed, DNF will not do anything
# so there is no need to do any complicated magic.
assert_script_run("dnf install -y @packages", timeout => 240);
# If we need to leave the console.
if ($stay_on_console == 0) {
desktop_vt();
}
}
# This subroutine switches to the root account.
# On Fedora, the system can be installed with a valid root account (root password assigned)
# or without it (with root password empty). If no root password is provided through environment
# variables, we assume that the system is a "rootless" system. In that case we will use
# `sudo -i` to acquire the administrator access.
sub become_root {
# If ROOT_PASSWORD exists, it means that the root account exists, too.
# To become root, we will use the real root account and we'll switch to it.
if (check_var("ROOT_PASSWORD")) {
my $password = get_var("ROOT_PASSWORD");
enter_cmd("su -", max_interval => 15, wait_screen_changes => 3);
type_password($password, max_interval => 15);
send_key("ret");
}
# If no root password is set, it means, that we are only using an administrator
# who is in the wheel group and therefore we will use the sudo command to obtain
# the admin rights.
else {
my $password = get_var("USER_PASSWORD") || "weakpassword";
enter_cmd("sudo -i", max_interval => 15, wait_screen_changes => 3);
# The SUDO warning might be displayed so let's wait it out a bit.
sleep 2;
type_password($password, max_interval => 15);
send_key("ret");
}
sleep 2;
# Now we should be root. Let's check for root prompt.
assert_screen("root_logged_in");
}
# This routine is adapted from the SuSE distribution file.
# There are two differences however. To save a needle,
# we actually call the `sudo -k` command instead plain sudo to always
# require a password. Then, we do not need to check for
# password prompt and and we can provide the password any time.
# Also, the routine uses the serial console to check for messages
# passed to it after the command has finished to save some time.
# The serial console is only accessible for the root user, so that
# mechanism does not work when not root (why would anyone use sudo
# if they were root already anyway).
# To override this, call `make_serial_writable` from `utils.pm` in the
# beginning of the test script to enable serial console for normal users.
sub script_sudo {
my ($self, $prog, $wait) = @_;
# If $wait is not assigned, let's make it 10 seconds to give some
# time to the commands to finish.
$wait //= 10;
my $str;
if ($wait > 0) {
# Create a uniqe hash from the command and the wait time.
$str = testapi::hashed_string("SS$prog$wait");
# Chain the commands to pass the message to the serial console.
$prog = "$prog; echo $str > /dev/$testapi::serialdev";
}
# Run the command with `sudo -k`
type_string "sudo -k $prog\n";
# Put a user password (we might not know the root password anyway)
my $password = get_var("USER_PASSWORD") || "weakpassword";
type_password($password);
send_key "ret";
# Wait for the message hash to appear on the serial console which indicates
# that the command has finished. No matter what time has passed, finish
# or die if no message appears on time.
if ($str) {
return testapi::wait_serial($str, $wait);
}
send_key("ret");
return;
}
# Run the script with sudo and check the exit code after it has run.
# See the script_sudo subroutine for details.
sub assert_script_sudo {
my ($self, $prog, $wait) = @_;
script_sudo($prog, $wait);
# Validate that the command exited with a correct exit code.
validate_script_output('echo $?', sub { $_ == 0 } );
return;
}
1;
# vim: set sw=4 et:

View File

@ -7,7 +7,7 @@ use Exporter;
use lockapi;
use testapi;
our @EXPORT = qw/run_with_error_check type_safely type_very_safely desktop_vt boot_to_login_screen console_login console_switch_layout desktop_switch_layout console_loadkeys_us do_bootloader boot_decrypt check_release menu_launch_type repo_setup setup_workaround_repo cleanup_workaround_repo console_initial_setup handle_welcome_screen gnome_initial_setup anaconda_create_user check_desktop download_modularity_tests quit_firefox advisory_get_installed_packages advisory_check_nonmatching_packages start_with_launcher quit_with_shortcut disable_firefox_studies select_rescue_mode copy_devcdrom_as_isofile get_release_number check_left_bar check_top_bar check_prerelease check_version spell_version_number _assert_and_click is_branched rec_log click_unwanted_notifications repos_mirrorlist register_application get_registered_applications solidify_wallpaper check_and_install_git download_testdata/;
our @EXPORT = qw/run_with_error_check type_safely type_very_safely desktop_vt boot_to_login_screen console_login console_switch_layout desktop_switch_layout console_loadkeys_us do_bootloader boot_decrypt check_release menu_launch_type repo_setup setup_workaround_repo cleanup_workaround_repo console_initial_setup handle_welcome_screen gnome_initial_setup anaconda_create_user check_desktop download_modularity_tests quit_firefox advisory_get_installed_packages advisory_check_nonmatching_packages start_with_launcher quit_with_shortcut disable_firefox_studies select_rescue_mode copy_devcdrom_as_isofile get_release_number check_left_bar check_top_bar check_prerelease check_version spell_version_number _assert_and_click is_branched rec_log click_unwanted_notifications repos_mirrorlist register_application get_registered_applications solidify_wallpaper check_and_install_git download_testdata make_serial_writable/;
# We introduce this global variable to hold the list of applications that have
# registered during the apps_startstop_test when they have sucessfully run.
@ -1464,4 +1464,24 @@ sub download_testdata {
assert_script_run("chown -R test:test $location");
}
# On Fedora, the serial console is not writable for regular users which lames
# some of the openQA commands that send messages to the serial console to check
# that a command has finished, for example assert_script_run, etc.
# This routine changes the rights on the serial console file and makes it
# writable for everyone, so that those commands work. This is actually very useful
# for testing commands from users' perspective. The routine also handles becoming the root.
# We agree that this is not the "correct" way, to enable users to type onto serial console
# and that it correctly should be done via groups (dialout) but that would require rebooting
# the virtual machine. Therefore we do it this way, which has immediate effect.
sub make_serial_writable{
become_root();
sleep 2;
# Make serial console writable for everyone.
enter_cmd("chmod 666 /dev/${serialdev}");
sleep 2;
# Exit the root account
enter_cmd("exit");
sleep 2;
}
1;

View File

@ -0,0 +1,24 @@
{
"area": [
{
"width": 40,
"type": "match",
"xpos": 191,
"ypos": 346,
"height": 16
},
{
"xpos": 297,
"ypos": 346,
"type": "match",
"height": 14,
"width": 17
}
],
"properties": [],
"tags": [
"ENV-DISTRI-fedora",
"root_console",
"root_logged_in"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 KiB