App-karr

 view release on metacpan or  search on metacpan

t/93-syncguard-push-rejection.t  view on Meta::CPAN

    chdir $cwd or die "chdir $cwd: $!";
    my $eh  = gensym;
    my $pid = open3( my $in, my $out, $eh, $^X, "-I$ROOT/lib", $BIN, @argv );
    close $in;
    my $stdout = do { local $/; <$out> };
    my $stderr = do { local $/; <$eh> };
    waitpid $pid, 0;
    my $exit = $? >> 8;
    chdir $old or die "chdir $old: $!";
    return { exit => $exit, stdout => $stdout // '', stderr => $stderr // '' };
}

my $DAEMON_PID;
END { kill 'TERM', $DAEMON_PID if $DAEMON_PID }

sub start_daemon {
    my ($work) = @_;
    for ( 1 .. 5 ) {
        my $port = 20000 + int rand 20000;
        my $pid  = fork();
        return () unless defined $pid;
        if ( !$pid ) {
            open STDOUT, '>',  "$work/daemon.log";
            open STDERR, '>>', "$work/daemon.log";
            exec( 'git', 'daemon', '--export-all', '--enable=receive-pack',
                "--base-path=$work", "--port=$port", $work );
            exit 1;
        }
        for ( 1 .. 25 ) {
            Time::HiRes::sleep(0.1);
            system("git ls-remote 'git://127.0.0.1:$port/origin.git' >/dev/null 2>&1");
            return ( $pid, $port ) if $? == 0;
        }
        kill 'TERM', $pid;
        waitpid $pid, 0;
    }
    return ();
}

subtest 'end to end: a command that dies into a refused push says so' => sub {
    my $work = tempdir( CLEANUP => 1 );
    system( 'git', 'init', '-q', '--bare', "$work/origin.git" );
    path("$work/origin.git/git-daemon-export-ok")->spew('');

    my ( $pid, $port ) = start_daemon($work);
    plan skip_all => 'no git daemon on a loopback port here' unless $pid;
    $DAEMON_PID = $pid;

    system("git clone -q 'git://127.0.0.1:$port/origin.git' '$work/a' 2>/dev/null");
    system( 'git', '-C', "$work/a", 'config', 'user.email', 'a@karr.test' );
    system( 'git', '-C', "$work/a", 'config', 'user.name',  'agent-a' );

    is run_karr( "$work/a", 'init', '--name', 'Demo' )->{exit}, 0,
        'setup: the board is created and pushed';
    is run_karr( "$work/a", 'create', 'task one' )->{exit}, 0,
        'setup: and carries a task';

    # Only now does the server start refusing.
    my $hook = path("$work/origin.git/hooks/pre-receive");
    $hook->spew("#!/bin/sh\necho 'board is protected' >&2\nexit 1\n");
    chmod 0755, "$hook";

    # Writes task 1, then dies on the missing 999 -- so the push happens from
    # the END-block flush, with no sync_after ever reached.
    my $r = run_karr( "$work/a", 'move', '1,999', 'in-progress',
        '--claim', 'flush-agent' );

    is $r->{exit}, 1, 'the command still fails on its own error';
    like $r->{stderr}, qr/Task 999 not found/,
        'and that error still reaches the user';

    like $r->{stderr}, qr{refs/karr/tasks/1/data: pre-receive hook declined},
        'the insurance push names the ref the server refused';
    like $r->{stderr}, qr/Push rejected by the remote/,
        'and reports it as a refusal';
    unlike $r->{stderr}, qr/Push retry \d of 3/,
        'without retrying an answer that was already given';
    unlike $r->{stderr}, qr/Run 'karr sync' to retry/,
        'and without advising a sync that would be refused identically';

    kill 'TERM', $pid;
    waitpid $pid, 0;
    undef $DAEMON_PID;
};

done_testing;



( run in 1.274 second using v1.01-cache-2.11-cpan-6736b670a1e )