Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Solved: Testing an interactive script with EOF on input

by mamawe (Sexton)
on Oct 12, 2011 at 08:09 UTC ( [id://930929]=perlquestion: print w/replies, xml ) Need Help??

mamawe has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

The solution I've taken is in my comment further down.

I have a module that contains an interactive script. For this script I would like to write a regression test for the behaviour on EOF of the input (it should exit cleanly with a defined output).

My first idea was, to use IPC::Open2 as written in perlipc. But then I would have to implement some timer to make sure the script exits at all.

My next idea was, to try something with Expect. But I can't see a way to close stdin for the process within Expect.

So that's where I am, any hints/suggestions appreciated.

Mathias

Update. To make it more clear here is some code.

Given this script
while(1) { if (eof(STDIN)) { print "END"; exit; } $_ = <STDIN>; if (/^q/i) { print "END"; exit; } print; print '$ '; }
and this test
#!/usr/bin/perl -w # use Test::More tests => 4; use Expect; $script = './test1-script.pl'; @match_pattern = ( [ qr/END/ => sub { print "\n"; ok(1,"got end"); } ] + ); #----------------------- 1 --------------------------- $exp = Expect->spawn($script); $exp->send("q\n"); $exp->expect(10, @match_pattern); #----------------------- 2 --------------------------- $exp = Expect->spawn($script); $exp->send("\4\n"); $exp->expect(10, @match_pattern); #===================================================== use IPC::Open3; #----------------------- 3 --------------------------- $pid = open3($in, $out, $err, $script); print $in "q\n"; like(<$out>,qr/END/,"Quit"); waitpid($pid, 0); #----------------------- 4 --------------------------- $pid = open3($in, $out, $err, $script); close $in; like(<$out>,qr/END/,"EOF in Input"); waitpid($pid, 0);
I get mostly what I want.

I see the following problems:

  • The $exp->send("\4\n"); in 2 is not portable. It depends on the operating system and the settings of the tty AFAIK
  • 3 and 4 lack the timeout, so the test hangs if the tested script fails to exit.

Replies are listed 'Best First'.
Re: Testing an interactive script with EOF on input
by roboticus (Chancellor) on Oct 12, 2011 at 10:46 UTC

    mamawe:

    Looking at the Expect documentation, I'd try a few different things:

    • First, I'd try the soft_close function to close the file handle on the sending side. I would expect that would have the desired result of making the recipient process get an EOF.
    • Failing that, I'd give the hard_close function a try (since it's just a four-character change).
    • The slave function returns a filehandle that you might try closing.
    • If neither of those work, then I'd try explicitly setting up the communications file handle and starting Expect using that filehandle. Then when you could explicitly close it when you want.

    Note: I've never used Expect, so so take these with a grain of salt. However, while reading the FAQ section, the question "How come when I automate the passwd program to change passwords for me passwd dies before changing the password sometimes/every time?", it leads me to think that soft_close should do the trick.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Thanks for your reply.

      I did try soft_close and hard_close, but these function close the whole pty so that I can't get the output of my program afterwards.

      The slave function returns the pty as seen by the tested script. But from there I don't see a way to close STDIN for this script.

Re: Testing an interactive script with EOF on input
by mamawe (Sexton) on Oct 30, 2011 at 18:46 UTC
    Just for the records, I settled for IPC::Open3 with a $SIG{ALRM} handler like this:
    #!/usr/bin/perl -w # use Test::More tests => 3; use IPC::Open3; $script = './test1-script.pl'; eval { local $SIG{ALRM} = sub { die "not completed\n" }; alarm(5); #----------------------- 1 --------------------------- $pid = open3($in, $out, $err, $script); print $in "q\n"; like(<$out>, qr/^QUIT$/,"Quit"); waitpid($pid, 0); #----------------------- 2 --------------------------- $pid = open3($in, $out, $err, $script); close $in; like(<$out>, qr/^EOI$/,"End of input"); waitpid($pid, 0); }; unlike($@, qr/^not completed$/, "All tests completed in time");
    which tests this script:
    #!/usr/bin/perl while(1) { if (eof(STDIN)) { print "EOI\n"; exit; } $_ = <STDIN>; if (/^q/i) { print "QUIT\n"; exit; } print; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://930929]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (3)
As of 2024-04-19 17:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found