From bacb6f1f7be115febb5eead1e5da672137460b06 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Fri, 30 Sep 2016 08:42:45 -0700 Subject: [PATCH] redo console_login with multiple matches, move to main_common Summary: Since we can match on multiple needles, we can drop the loop from console_login and instead do it this way, which is simpler and should work better on ARM (the timeouts will scale and allow ARM to be slow here). Also move it to main_common as there's no logical reason for it to be a class method. Also remove the `check` arg. `check` was only set to 0 by two tests, _console_shutdown and anacondatest's _post_fail_hook. For _console_shutdown, I think I just wanted to give it the best possible chance of succeeding. But we're really not going to lose anything significant by checking, the only case where check=>0 would've helped is if the 'good' needle had stopped matching, and all sorts of other tests will fail in that case. anacondatest was only using it to save a screenshot of whatever was on the tty if it didn't reach a root console, which doesn't seem that useful, and we'll get screenshots from check_screen and assert_screen anyway. Test Plan: Run all tests, check they behave as expected and none inappropriately fails on console login. Reviewers: jskladan, garretraziel Reviewed By: garretraziel Subscribers: tflink Differential Revision: https://phab.qadevel.cloud.fedoraproject.org/D1016 --- README.md | 8 +-- lib/anacondatest.pm | 61 +++++++++---------- lib/fedorabase.pm | 86 --------------------------- lib/installedtest.pm | 3 +- lib/main_common.pm | 69 ++++++++++++++++++++- tests/_console_shutdown.pm | 2 +- tests/_console_wait_login.pm | 4 +- tests/freeipa_client.pm | 3 +- tests/freeipa_password_change.pm | 2 +- tests/freeipa_webui.pm | 2 +- tests/install_arm_image_deployment.pm | 3 +- 11 files changed, 110 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index 3e458d4a..febde744 100644 --- a/README.md +++ b/README.md @@ -88,8 +88,8 @@ these functions: - `anacondatest` should be used in tests where Anaconda is running. It uploads Anaconda logs (for example `anaconda.log` or `packaging.log`) in `post_fail_hook()`. It also provides these convenient methods for Anaconda: - `root_console()` tries to login is as a root. It decides to what TTY to switch into and then calls `console_login()` - for root. If you set `check` argument, it dies if it fails to log in. Example usage: - after calling `$self->root_console(check=>1);`, console should be shown with root logged in. + for root. Example usage: + after calling `$self->root_console();`, console should be shown with root logged in. - `select_disks()` handles disk selecting. It have one optional argument - number of disks to select. It should be run when main Anaconda hub is displayed. It enters disk selection spoke and then ensures that required number of disks are selected. Additionally, if `$PARTITIONING` variable (set in Web UI) starts with `custom_`, it selects @@ -116,8 +116,8 @@ these functions: - `installedtest` should be used in tests that are running on installed system (either in postinstall phase or in upgrade tests). It uploads `/var/log` in `post_fail_hook()`. It provides these functions: - `root_console()` tries to login is as a root. It switches to TTY that is set as an argument (default is TTY1) - and then calls `console_login()` for root. If you set `check` argument, it dies if it fails to log in. - Example usage: running `$self->root_console(tty=>2, check=>0);` results in TTY2 displayed with root logged + and then calls `console_login()` for root. + Example usage: running `$self->root_console(tty=>2);` results in TTY2 displayed with root logged in. - `check_release()` checks whether the installed release matches a given value. E.g. `check_release(23)` checks whether the installed system is Fedora 23. The value can be 'Rawhide' or a Fedora release number; diff --git a/lib/anacondatest.pm b/lib/anacondatest.pm index 4153fa8e..3edc4817 100644 --- a/lib/anacondatest.pm +++ b/lib/anacondatest.pm @@ -22,45 +22,40 @@ sub post_fail_hook { $has_traceback = 1; } - $self->root_console(check=>0); - if (check_screen "root_console", 10) { - upload_logs "/tmp/X.log", failok=>1; - upload_logs "/tmp/anaconda.log", failok=>1; - upload_logs "/tmp/packaging.log", failok=>1; - upload_logs "/tmp/storage.log", failok=>1; - upload_logs "/tmp/syslog", failok=>1; - upload_logs "/tmp/program.log", failok=>1; - upload_logs "/tmp/dnf.log", failok=>1; - upload_logs "/tmp/dnf.librepo.log", failok=>1; - upload_logs "/tmp/dnf.rpm.log", failok=>1; + save_screenshot; + $self->root_console(); + upload_logs "/tmp/X.log", failok=>1; + upload_logs "/tmp/anaconda.log", failok=>1; + upload_logs "/tmp/packaging.log", failok=>1; + upload_logs "/tmp/storage.log", failok=>1; + upload_logs "/tmp/syslog", failok=>1; + upload_logs "/tmp/program.log", failok=>1; + upload_logs "/tmp/dnf.log", failok=>1; + upload_logs "/tmp/dnf.librepo.log", failok=>1; + upload_logs "/tmp/dnf.rpm.log", failok=>1; - if ($has_traceback) { - # Upload Anaconda traceback logs - script_run "tar czf /tmp/anaconda_tb.tar.gz /tmp/anaconda-tb-*"; - upload_logs "/tmp/anaconda_tb.tar.gz"; - } - - # Upload all ABRT logs - script_run "tar czf /var/tmp/var_tmp.tar.gz /var/tmp"; - upload_logs "/var/tmp/var_tmp.tar.gz"; - - # Upload /var/log - script_run "tar czf /tmp/var_log.tar.gz /var/log"; - upload_logs "/tmp/var_log.tar.gz"; - - # Upload anaconda core dump, if there is one - script_run "ls /tmp/anaconda.core.* && tar czf /tmp/anaconda.core.tar.gz /tmp/anaconda.core.*"; - upload_logs "/tmp/anaconda.core.tar.gz", failok=>1; - } - else { - save_screenshot; + if ($has_traceback) { + # Upload Anaconda traceback logs + script_run "tar czf /tmp/anaconda_tb.tar.gz /tmp/anaconda-tb-*"; + upload_logs "/tmp/anaconda_tb.tar.gz"; } + + # Upload all ABRT logs + script_run "tar czf /var/tmp/var_tmp.tar.gz /var/tmp"; + upload_logs "/var/tmp/var_tmp.tar.gz"; + + # Upload /var/log + script_run "tar czf /tmp/var_log.tar.gz /var/log"; + upload_logs "/tmp/var_log.tar.gz"; + + # Upload anaconda core dump, if there is one + script_run "ls /tmp/anaconda.core.* && tar czf /tmp/anaconda.core.tar.gz /tmp/anaconda.core.*"; + upload_logs "/tmp/anaconda.core.tar.gz", failok=>1; } sub root_console { my $self = shift; my %args = ( - check => 1, # whether to fail when console wasn't reached @_); if (get_var("LIVE")) { @@ -72,7 +67,7 @@ sub root_console { send_key "ctrl-b"; send_key "2"; } - $self->console_login(user=>"root",check=>$args{check}); + console_login(user=>"root"); } sub select_disks { diff --git a/lib/fedorabase.pm b/lib/fedorabase.pm index 49d97692..acbee6d0 100644 --- a/lib/fedorabase.pm +++ b/lib/fedorabase.pm @@ -8,84 +8,6 @@ use lockapi; use testapi; -# this subroutine handles logging in as a root/specified user into console -# it requires TTY to be already displayed (handled by the root_console() method of subclasses) -sub console_login { - my $self = shift; - my %args = ( - user => "root", - password => get_var("ROOT_PASSWORD", "weakpassword"), - check => 1, - @_); - - # There's a timing problem when we switch from a logged-in console - # to a non-logged in console and immediately call this function; - # if the switch lags a bit, this function will match one of the - # logged-in needles for the console we switched from, and get out - # of sync (e.g. https://openqa.stg.fedoraproject.org/tests/1664 ) - # To avoid this, we'll sleep a couple of seconds before starting - sleep 2; - - my $good = ""; - my $bad = ""; - my $needuser = 1; - my $needpass = 1; - if ($args{user} eq "root") { - $good = "root_console"; - $bad = "user_console"; - } - else { - $good = "user_console"; - $bad = "root_console"; - } - - for my $n (1 .. 10) { - # This little loop should handle all possibilities quite - # efficiently: already at a prompt (previously logged in, or - # anaconda case), only need to enter username (live case), - # need to enter both username and password (installed system - # case). There are some annoying cases here involving delays - # to various commands and the limitations of needles; - # text_console_login also matches when the password prompt - # is displayed (as the login prompt is still visible), and - # both still match after login is complete, unless something - # runs 'clear'. The sleeps and $needuser / $needpass attempt - # to mitigate these problems. - if (check_screen $good, 0) { - return; - } - elsif (check_screen $bad, 0) { - # we don't want to 'wait' for this as it won't return - script_run "exit", 0; - sleep 2; - } - if ($needuser and check_screen "text_console_login", 0) { - type_string "$args{user}\n"; - $needuser = 0; - sleep 2; - } - elsif ($needpass and check_screen "console_password_required", 0) { - type_string "$args{password}"; - if (get_var("SWITCHED_LAYOUT") and $args{user} ne "root") { - # see _do_install_and_reboot; when layout is switched - # user password is doubled to contain both US and native - # chars - $self->console_switch_layout(); - type_string "$args{password}"; - $self->console_switch_layout(); - } - send_key "ret"; - $needpass = 0; - # Sometimes login takes a bit of time, so add an extra sleep - sleep 2; - } - - sleep 1; - } - # If we got here we failed; if 'check' is set, die. - $args{check} && die "Failed to reach console!" -} - sub do_bootloader { # Handle bootloader screen. 'bootloader' is syslinux or grub. # 'uefi' is whether this is a UEFI install, will get_var UEFI if @@ -192,14 +114,6 @@ sub setup_tap_static { script_run "systemctl restart NetworkManager.service"; } -sub console_switch_layout { - # switcher key combo differs between layouts, for console - my $self = shift; - if (get_var("LANGUAGE", "") eq "russian") { - send_key "ctrl-shift"; - } -} - sub get_host_dns { # get DNS server addresses from the host my @forwards; diff --git a/lib/installedtest.pm b/lib/installedtest.pm index b48971d3..064b5fa7 100644 --- a/lib/installedtest.pm +++ b/lib/installedtest.pm @@ -13,11 +13,10 @@ sub root_console { my $self = shift; my %args = ( tty => 1, # what TTY to login to - check => 1, # whether to fail when console wasn't reached @_); send_key "ctrl-alt-f$args{tty}"; - $self->console_login(check=>$args{check}); + console_login; } sub post_fail_hook { diff --git a/lib/main_common.pm b/lib/main_common.pm index 9b3cd4fb..ef7db37e 100644 --- a/lib/main_common.pm +++ b/lib/main_common.pm @@ -6,7 +6,7 @@ use base 'Exporter'; use Exporter; use testapi; -our @EXPORT = qw/run_with_error_check check_type_string type_safely type_very_safely desktop_vt boot_to_login_screen/; +our @EXPORT = qw/run_with_error_check check_type_string type_safely type_very_safely desktop_vt boot_to_login_screen console_login console_switch_layout/; sub run_with_error_check { my ($func, $error_screen) = @_; @@ -84,3 +84,70 @@ sub boot_to_login_screen { assert_screen "login_screen"; } } + +# Switch keyboard layouts at a console +sub console_switch_layout { + # switcher key combo differs between layouts, for console + if (get_var("LANGUAGE", "") eq "russian") { + send_key "ctrl-shift"; + } +} + +# this subroutine handles logging in as a root/specified user into console +# it requires TTY to be already displayed (handled by the root_console() +# method of distribution classes) +sub console_login { + my %args = ( + user => "root", + password => get_var("ROOT_PASSWORD", "weakpassword"), + @_); + + # There's a timing problem when we switch from a logged-in console + # to a non-logged in console and immediately call this function; + # if the switch lags a bit, this function will match one of the + # logged-in needles for the console we switched from, and get out + # of sync (e.g. https://openqa.stg.fedoraproject.org/tests/1664 ) + # To avoid this, we'll sleep a couple of seconds before starting + sleep 2; + + my $good = ""; + my $bad = ""; + if ($args{user} eq "root") { + $good = "root_console"; + $bad = "user_console"; + } + else { + $good = "user_console"; + $bad = "root_console"; + } + + if (check_screen $bad, 0) { + # we don't want to 'wait' for this as it won't return + script_run "exit", 0; + sleep 2; + } + + check_screen [$good, 'text_console_login'], 10; + # if we're already logged in, all is good + return if (match_has_tag $good); + # if we see the login prompt, type the username + type_string("$args{user}\n") if (match_has_tag 'text_console_login'); + check_screen [$good, 'console_password_required'], 30; + # on a live image, just the user name will be enough + return if (match_has_tag $good); + # otherwise, type the password if we see the prompt + if (match_has_tag 'console_password_required') { + type_string "$args{password}"; + if (get_var("SWITCHED_LAYOUT") and $args{user} ne "root") { + # see _do_install_and_reboot; when layout is switched + # user password is doubled to contain both US and native + # chars + console_switch_layout; + type_string "$args{password}"; + console_switch_layout; + } + send_key "ret"; + } + # make sure we reached the console + assert_screen($good, 30); +} diff --git a/tests/_console_shutdown.pm b/tests/_console_shutdown.pm index 31dd0d82..cfd5e4a6 100644 --- a/tests/_console_shutdown.pm +++ b/tests/_console_shutdown.pm @@ -10,7 +10,7 @@ sub run { # use the desktops' graphical shutdown methods, we just go to a # console and run 'poweroff'. We can write separate tests for # properly testing shutdown/reboot/log out from desktops. - $self->root_console(tty=>3, check=>0); + $self->root_console(tty=>3); script_run("poweroff", 0); assert_shutdown; } diff --git a/tests/_console_wait_login.pm b/tests/_console_wait_login.pm index ea068a0b..79c712a6 100644 --- a/tests/_console_wait_login.pm +++ b/tests/_console_wait_login.pm @@ -20,10 +20,10 @@ sub run { # do user login unless USER_LOGIN is set to string 'false' unless (get_var("USER_LOGIN") eq "false") { - $self->console_login(user=>get_var("USER_LOGIN", "test"), password=>get_var("USER_PASSWORD", "weakpassword")); + console_login(user=>get_var("USER_LOGIN", "test"), password=>get_var("USER_PASSWORD", "weakpassword")); } if (get_var("ROOT_PASSWORD")) { - $self->console_login(user=>"root", password=>get_var("ROOT_PASSWORD")); + console_login(user=>"root", password=>get_var("ROOT_PASSWORD")); } } diff --git a/tests/freeipa_client.pm b/tests/freeipa_client.pm index b5073062..420395c9 100644 --- a/tests/freeipa_client.pm +++ b/tests/freeipa_client.pm @@ -1,6 +1,7 @@ use base "installedtest"; use strict; use testapi; +use main_common; sub run { my $self=shift; @@ -22,7 +23,7 @@ sub run { # switch to tty3 send_key "ctrl-alt-f3"; # try and login as test1, should work - $self->console_login(user=>'test1@DOMAIN.LOCAL', password=>'batterystaple'); + console_login(user=>'test1@DOMAIN.LOCAL', password=>'batterystaple'); type_string "exit\n"; # try and login as test2, should fail. we cannot use console_login # as it takes 10 seconds to complete when login fails, and diff --git a/tests/freeipa_password_change.pm b/tests/freeipa_password_change.pm index 4b72635b..756504e9 100644 --- a/tests/freeipa_password_change.pm +++ b/tests/freeipa_password_change.pm @@ -6,7 +6,7 @@ use freeipa; sub run { my $self = shift; - $self->console_login(user=>'root'); + console_login(user=>'root'); # clear browser data so we don't go back to the 'admin' login assert_script_run 'rm -rf /root/.mozilla'; # clear kerberos ticket so we don't auto-auth as 'test4' diff --git a/tests/freeipa_webui.pm b/tests/freeipa_webui.pm index d4a51359..142048f0 100644 --- a/tests/freeipa_webui.pm +++ b/tests/freeipa_webui.pm @@ -52,7 +52,7 @@ sub run { # switch to tty4 (boy, the tty jugglin') send_key "ctrl-alt-f4"; # try and login as test3, should work - $self->console_login(user=>'test3@DOMAIN.LOCAL', password=>'batterystaple'); + console_login(user=>'test3@DOMAIN.LOCAL', password=>'batterystaple'); type_string "exit\n"; # try and login as test4, should fail. we cannot use console_login # as it takes 10 seconds to complete when login fails, and diff --git a/tests/install_arm_image_deployment.pm b/tests/install_arm_image_deployment.pm index f25a13cd..111c1439 100644 --- a/tests/install_arm_image_deployment.pm +++ b/tests/install_arm_image_deployment.pm @@ -1,6 +1,7 @@ use base "installedtest"; use strict; use testapi; +use main_common; sub run { my $self = shift; @@ -58,7 +59,7 @@ sub run { assert_screen "text_console_login", 60; # Try to log in as an user - $self->console_login(user=>get_var("USER_LOGIN", "test"), password=>get_var("USER_PASSWORD", "weakpassword")); + console_login(user=>get_var("USER_LOGIN", "test"), password=>get_var("USER_PASSWORD", "weakpassword")); }