App-FuguVM

 view release on metacpan or  search on metacpan

t/fuguvm/remote.t  view on Meta::CPAN

#!/usr/bin/env perl
# ex:ts=8 sw=4:
# The remote side of one running guest: the argument quoting, the
# local walk, the batching, and the failure shape of put and get.
# No test here opens a real connection: the closed-port tests prove
# the failure path, and a mock SSH object proves the batching.

use v5.36;
use Test::More;
use FindBin qw($RealBin);
use lib "$RealBin/../../lib";
use Fugu::TestLog;
use File::Path qw(make_path);
use File::Temp qw(tempdir);
use IO::Socket::INET;
use POSIX      ();

# The module depends on SSH, which requires Net::SSH2
BEGIN {
    eval { require Net::SSH2 };
    if ($@) {
	plan skip_all => 'Net::SSH2 not available';
    }
}

use_ok('App::FuguVM::Remote');

# A mock transport. The batching tests read the commands that put
# would run, without a guest.
package Mock::SSH {
    sub new ($class) {
	return bless { commands => [], writes => [] }, $class;
    }

    sub run_command ($self, $command) {
	push @{ $self->{commands} }, $command;
	return { stdout => '', stderr => '', exit_code => 0 };
    }

    sub write_file ($self, $path, $content, $mode) {
	push @{ $self->{writes} }, [ $path, $mode ];
	return 0;
    }
}

# ============================================================
# quote_argv
# ============================================================

{
    is(App::FuguVM::Remote->quote_argv('word'), "'word'",
	'a plain word gets single quotes');
    is(App::FuguVM::Remote->quote_argv('a b'), "'a b'",
	'a word with a space stays one word');
    is(App::FuguVM::Remote->quote_argv("it's"), "'it'\\''s'",
	"a single quote becomes the '\\'' form");
    is(App::FuguVM::Remote->quote_argv(''), "''",
	"an empty word becomes ''");
    is(App::FuguVM::Remote->quote_argv('a', 'b', 'c'), "'a' 'b' 'c'",
	'several words join with one space');

    # The strongest proof of the rule is a real shell. sh -c parses
    # the quoted string as the remote login shell would, and printf
    # reports each word that arrives.
    my @words = ('*', '$HOME', 'a;b', 'x&y', '`id`', "it's", 'a b', '');
    my $command =
	App::FuguVM::Remote->quote_argv('printf', '%s\n', @words);
    open my $sh, '-|', 'sh', '-c', $command
	or die "Cannot run sh: $!";
    my @lines = <$sh>;
    close $sh;
    chomp @lines;
    is_deeply(\@lines, \@words,
	'a shell splits the string at the word boundaries only,'
	    . ' with no expansion and no globbing');
}

# ============================================================
# new and run
# ============================================================

{
    my $remote = App::FuguVM::Remote->new(host => '127.0.0.1', port => 2299);
    is($remote->{port}, 2299, 'new stores the port');
    is($remote->{host}, '127.0.0.1', 'new stores the host');

    eval { App::FuguVM::Remote->new(host => '127.0.0.1') };
    like($@, qr/needs a port/, 'new dies with no port');

    eval { App::FuguVM::Remote->new(port => 2299) };
    like($@, qr/needs a host/, 'new dies with no host');

    eval { $remote->run() };
    like($@, qr/argument vector/, 'run dies on an empty vector');
}

# ============================================================



( run in 1.850 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )