# Copyright (C) 2016 all contributors # License: AGPL-3.0+ use strict; use warnings; use Test::More; $SIG{PIPE} = 'IGNORE'; foreach my $mod (qw(Danga::Socket)) { eval "require $mod"; plan skip_all => "$mod missing for git_async.t" if $@; } use File::Temp qw/tempdir/; use Cwd qw/getcwd/; my $tmpdir = tempdir('git_async-XXXXXX', TMPDIR => 1, CLEANUP => 1); use_ok 'PublicInbox::Git'; my $dir = "$tmpdir/git.git"; { is(system(qw(git init -q --bare), $dir), 0, 'created git directory'); my @cmd = ('git', "--git-dir=$dir", 'fast-import', '--quiet'); my $fi_data = getcwd().'/t/git.fast-import-data'; ok(-r $fi_data, "fast-import data readable (or run test at top level)"); my $pid = fork; defined $pid or die "fork failed: $!\n"; if ($pid == 0) { open STDIN, '<', $fi_data or die "open $fi_data: $!\n"; exec @cmd; die "failed exec: ",join(' ', @cmd),": $!\n"; } waitpid $pid, 0; is($?, 0, 'fast-import succeeded'); } { my $f = 'HEAD:foo.txt'; my @args; my $n = 0; my $git = PublicInbox::Git->new($dir); Danga::Socket->SetPostLoopCallback(sub { my ($fdmap) = @_; foreach (values %$fdmap) { return 1 if ref($_) =~ /::GitAsync/; } 0 }); $git->check_async_ds($f, sub { $n++; @args = @_; $git = undef; }); Danga::Socket->EventLoop; my @exp = PublicInbox::Git->new($dir)->check($f); my $exp = [ \@exp ]; is_deeply(\@args, $exp, 'matches regular check'); is($n, 1, 'callback only called once'); $git = PublicInbox::Git->new($dir); $n = 0; my $max = 100; my $missing = 'm'; my $m = 0; for my $i (0..$max) { my $k = "HEAD:m$i"; $git->check_async_ds($k, sub { my ($info) = @_; ++$n; ++$m if $info->[1] eq 'missing' && $info->[0] eq $k; }); if ($git->{async_c}->{wr}->{write_buf_size}) { diag("async_check capped at $i"); $max = $i; last; } } is($m, $n, 'everything expected missing is missing'); $git->check_async_ds($f, sub { $git = undef }); Danga::Socket->EventLoop; $git = PublicInbox::Git->new($dir); my $info; my $str = ''; my @missing; $git->cat_async_ds('HEAD:miss', sub { my ($miss) = @_; push @missing, $miss; }); $git->cat_async_ds($f, sub { my $res = $_[0]; if (ref($res) eq 'ARRAY') { is($info, undef, 'info unset, setting..'); $info = $res; } elsif (ref($res) eq 'SCALAR') { $str .= $$res; if (length($str) >= $info->[2]) { is($info->[2], length($str), 'length match'); $git = undef } } }); Danga::Socket->EventLoop; is_deeply(\@missing, [['HEAD:miss', 'missing']], 'missing cat OK'); is($git, undef, 'git undefined'); $git = PublicInbox::Git->new($dir); my $sref = $git->cat_file($f); is($str, $$sref, 'matches synchronous version'); $git = undef; Danga::Socket->RunTimers; } { my $git = PublicInbox::Git->new($dir); foreach my $s (qw(check_async_compat cat_async_compat)) { my @missing; $git->check_async_compat('HED:miss1ng', sub { my ($miss) = @_; push @missing, $miss; }); is_deeply(\@missing, [['HED:miss1ng', 'missing']], "missing $s OK"); } my @info; my $str = ''; my $eof_seen = 0; $git->cat_async_compat('HEAD:foo.txt', sub { my $ref = $_[0]; my $t = ref $ref; if ($t eq 'ARRAY') { push @info, $ref; } elsif ($t eq 'SCALAR') { $str .= $$ref; } elsif ($ref == 0) { $eof_seen++; } else { fail "fail type: $t"; } }); is($eof_seen, 1, 'EOF seen once'); is_deeply(\@info, [ [ 'bf4f17855632367a160bef055fc8ba4675d10e6b', 'blob', 18 ]], 'info matches compat'); is($str, "-----\nhello\nworld\n", 'data matches compat'); } done_testing(); 1;