From 68f83ca5236078128a0ccf47a1e54bd955777120 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 31 Dec 2016 11:16:47 +0000 Subject: initial git async work This will allow us to handle network operations while waiting on "git cat-file" to seek and unpack things. --- t/git_async.t | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 t/git_async.t (limited to 't') diff --git a/t/git_async.t b/t/git_async.t new file mode 100644 index 00000000..c20d48e3 --- /dev/null +++ b/t/git_async.t @@ -0,0 +1,138 @@ +# 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($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($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($f, sub { $git = undef }); + Danga::Socket->EventLoop; + + $git = PublicInbox::Git->new($dir); + my $info; + my $str = ''; + my @missing; + $git->cat_async('HEAD:miss', sub { + my ($miss) = @_; + push @missing, $miss; + }); + $git->cat_async($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 = ''; + $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; + } else { + fail "fail type: $t"; + } + }); + is_deeply(\@info, [ [ 'bf4f17855632367a160bef055fc8ba4675d10e6b', + 'blob', 18 ]], 'info matches compat'); + is($str, "-----\nhello\nworld\n", 'data matches compat'); +} + +done_testing(); + +1; -- cgit v1.2.3-24-ge0c7