metan-ucw / runltp-ng

Minimalistic LTP testrunner
11 stars 16 forks source link

Stucked while trying to match login prompt #16

Open shunghsiyu opened 4 years ago

shunghsiyu commented 4 years ago

When there is a newline before the login prompt (i.e. "\nlocalhost login: "), runltp-ng will fail to recognize the prompt, thus not proceed with entering the username; this is because it get stucked polling forever at $poll->poll($timeout) (since timeout is not passed to backend::start).

Below is a script that mimics this issue. wait_regexp and try_readline is copied directly from the backend module, with minor modification to avoid actually reading file descriptor (by mocking sysread).

#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);

use lib './';
use backend;
use log;

my $mock_sysread_cnt = 0;
my $out_fd_buf = "\nlocalhost login: ";

sub try_readline
{
    my ($self, $timeout) = @_;

    return backend::split_line($self) if backend::has_newline($self);

    #my $poll = IO::Poll->new();
    #$poll->mask($self->{'out_fd'} => POLLIN);

    while (1) {
        #if ($poll->poll($timeout) == 0) {
        #   msg("$self->{'name'}: Timeouted!\n");
        #   return undef;
        #}
        if (!defined($timeout) && $out_fd_buf eq '') {
            die("Will get stucked here polling forever\n");
        }

        my $buf = '';
        #my $ret = sysread($self->{'out_fd'}, $buf, 128);
        # --- Mocking sysread ---
        my $ret = 0;
        if ($mock_sysread_cnt == 0) {
            $ret = length($out_fd_buf);
            $buf = $out_fd_buf;
            $out_fd_buf = '';
            $mock_sysread_cnt += 1;
        } else {
            die("Will not reach here");
        }
        # -----------------------

        #print("R: '$buf'\n");
        $self->{'buf'} .= $buf;
        last if !defined($ret) && $!{EAGAIN};
        last if $ret > 0;
        return undef if !defined($ret);
        return undef if $ret == 0;
    }

    return backend::split_line($self) if backend::has_newline($self);

    return $self->{'buf'};
}

sub wait_regexp
{
    my ($self, $regexp, $newline, $timeout) = @_;
    my $out_fd = $self->{'out_fd'};
    my @log;
    my $line;

    msg("Waiting for regexp '$regexp'\n");

    my $start_time = backend::clock_gettime(CLOCK_MONOTONIC);

    while (1) {
        $line = try_readline($self, $timeout);

        if (!defined($line)) {
            msg("$self->{'name'}: died!\n");
            return @log;
        }

        if ($line =~ /\n/) {
            msg("$self->{'name'}: $line");
            my $l = $line;
            # Strip CR LF
            $l =~ s/(\x0d|\x0a)//g;
            # Strip escape sequencies
            $l =~ s/\x1b\[[0-9;]*[a-zA-Z]//g;
            push(@log, $l);
            my $fh = $self->{'raw_logfile'};
            print($fh "$l\n") if defined($fh);
        }
        #print("N: $self->{'name'}: $line\n") if $verbose;

        if (defined($timeout) and clock_gettime(CLOCK_MONOTONIC) - $start_time > $timeout) {
            msg("$self->{'name'}: timeouted!\n");
            return @log;
        }

        next if (defined($newline) && $newline && $line !~ /\n/);

        last if ($line =~ m/$regexp/);
    }

    return @log;
}

log::set_verbosity(1);

my %instance;
$instance{'name'} = 'qemu';
$instance{'buf'} = '';
wait_regexp(\%instance, qr/login:/);
shunghsiyu commented 4 years ago

A possible workaround is to have the console set to automatic login

richiejp commented 4 years ago

Yes and also, in the future we can start the test executor in .profile (similar to https://gitlab.com/Palethorpe/ltp-executor/-/blob/master/test/qemu-dracut.sh#L19, https://gitlab.com/Palethorpe/ltp-executor/-/blob/master/test/run-executor-on-vsport.sh).