The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# -*- mode: cperl -*-
use strict;
use warnings;
use Test::More;

eval "use IO::Scalar;";
plan skip_all => 'this test requires IO::Scalar' if $@;

plan tests => 8;

use Archer;
use Archer::Shell;
use Archer::Parallel::ForkManager;
use FindBin;
use List::MoreUtils qw/uniq/;

no warnings 'redefine';
local *Archer::Shell::callback = sub {
    my ( $self, $server, $cmd ) = @_;
    print "$server:$cmd\n";
};
use warnings 'redefine';

my $OUT;

sub capture(&) {
    my $code = shift;

    $OUT = undef;
    tie *STDOUT, 'IO::Scalar', \$OUT;

    eval { $code->(); };
    if ($@) {
        warn "capture: $@";
    }

    untie *STDOUT;
}

$FindBin::Bin .= "/..";

my $archer =
    Archer->new(
        {
            project      => 'YourProj',
            dry_run_fg   => 0,
            parallel_num => 0,
            skips        => {},
            config_yaml  => 't/02_shell.yaml',
            argv_str     => '',
            shell        => 1,
            write_config => 0,
            log_level    => 'error',
        }
       );
my $context = $archer->context;

my @servers
    = uniq map { @{ $_ } }
    values
    %{ $context->{ config }->{ projects }->{ $archer->{ project } } };
my $shell = Archer::Shell->new(
    {   context => $archer,
        config  => $archer->{ config },
        servers => \@servers,
        parallel => "Archer::Parallel::ForkManager",
    }
   );


my @app = qw(127.0.0.1 127.0.0.2);
my @db  = qw(127.0.0.3 127.0.0.4);
my @all = (@app, @db);

capture { $shell->catch_run("date"); };
is($OUT, join("\n",map{"$_:date"}@all)."\n","command");

capture { $shell->catch_run("on 127.0.0.0 127.0.0.2 127.0.0.2 do date"); };
is($OUT, join("\n",map{"$_:date"}qw(127.0.0.2))."\n", "on host do command");

capture { $shell->catch_run("with app do uname"); };
is($OUT, join("\n",map{"$_:uname"}@app)."\n", "with role do command");

capture { $shell->catch_run("with app db do w"); };
is($OUT, join("\n",map{"$_:w"}@app,@db)."\n", "with role role do command");


capture { $shell->catch_run("!test"); };
is($OUT, join("\n",map{"$_:hostname"}@all)."\n", "task");

capture { $shell->catch_run("!test on 127.0.0.0 127.0.0.2 127.0.0.2"); };
is($OUT, join("\n",map{"$_:hostname"}qw(127.0.0.2))."\n", "task on host");

capture { $shell->catch_run("!test with app"); };
is($OUT, join("\n",map{"$_:hostname"}@app)."\n", "task with role");

capture { $shell->catch_run("!test with app db"); };
is($OUT, join("\n",map{"$_:hostname"}@app,@db)."\n", "task with role role");