Net-LibSSH
view release on metacpan or search on metacpan
t/03-channel-after-close.t view on Meta::CPAN
use strict;
use warnings;
use lib 't/lib';
use Test::More;
use TestSSHD;
use Net::LibSSH;
# A closed channel has self->channel == NULL. Before the guard every channel
# method handed that NULL straight to libssh, which absorbed it and returned
# a plausible-looking value: exit_status() gave -1 (indistinguishable from
# "the remote process has not exited yet") and read() gave "". A caller that
# got the documented order wrong therefore got silent wrong answers instead
# of an error. Each method must now croak.
my $srv = TestSSHD->start;
unless ($srv) {
plan skip_all => 'sshd or ssh-keygen not available';
}
my $ssh = Net::LibSSH->new;
$ssh->option(host => $srv->host);
$ssh->option(port => $srv->port);
$ssh->option(user => scalar getpwuid($<));
$ssh->option(knownhosts => '/dev/null');
$ssh->connect
or plan skip_all => 'connect failed: ' . ($ssh->error // '');
$ssh->auth_publickey($srv->client_key)
or plan skip_all => 'auth failed: ' . ($ssh->error // '');
my $ch = $ssh->channel;
ok defined $ch, 'channel() returns object';
# The documented order still works: read the output and the exit status
# while the channel is open.
ok $ch->exec('echo hello'), 'exec() succeeds on an open channel';
my $out = $ch->read;
chomp $out;
is $out, 'hello', 'read() returns output on an open channel';
is $ch->exit_status, 0, 'exit_status() readable before close()';
$ch->close;
# close() owns teardown and must stay idempotent â svt_free calls the same
# path again when the SV is collected.
eval { $ch->close; 1 };
is $@, '', 'close() is idempotent';
for my $case (
[ exec => sub { $_[0]->exec('echo x') } ],
[ read => sub { $_[0]->read } ],
[ read => sub { $_[0]->read(16) } ],
[ write => sub { $_[0]->write('x') } ],
[ send_eof => sub { $_[0]->send_eof } ],
[ eof => sub { $_[0]->eof } ],
[ exit_status => sub { $_[0]->exit_status } ],
) {
my ($method, $code) = @$case;
my $rv = eval { $code->($ch); 1 };
ok !$rv, "$method() after close() does not return a value";
like $@, qr/\QNet::LibSSH::Channel::$method\E: channel is closed/,
"$method() after close() croaks naming the method";
}
# A fresh channel on the same session is unaffected by the close above.
my $ch2 = $ssh->channel;
ok defined $ch2, 'channel() still works after a channel was closed';
ok $ch2->exec('exit 42'), 'exec() succeeds on the new channel';
$ch2->read;
is $ch2->exit_status, 42, 'exit_status() on the new channel is correct';
$ch2->close;
done_testing;
( run in 0.551 second using v1.01-cache-2.11-cpan-7f9471e7e0a )