]> Sergey Matveev's repositories - public-inbox.git/blob - t/gcf2.t
gcf2: libgit2-based git cat-file alternative
[public-inbox.git] / t / gcf2.t
1 #!perl -w
2 # Copyright (C) 2020 all contributors <meta@public-inbox.org>
3 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
4 use strict;
5 use PublicInbox::TestCommon;
6 use Test::More;
7 use Fcntl qw(:seek);
8 use IO::Handle ();
9 use POSIX qw(_exit);
10 require_mods('PublicInbox::Gcf2');
11 use_ok 'PublicInbox::Gcf2';
12 my $gcf2 = PublicInbox::Gcf2::new();
13 is(ref($gcf2), 'PublicInbox::Gcf2', '::new works');
14 chomp(my $objdir = xqx([qw(git rev-parse --git-path objects)]));
15 if ($objdir =~ /\A--git-path\n/) { # git <2.5
16         chomp($objdir = xqx([qw(git rev-parse --git-dir)]));
17         $objdir .= '/objects';
18         $objdir = undef unless -d $objdir;
19 }
20
21 my $COPYING = 'dba13ed2ddf783ee8118c6a581dbf75305f816a3';
22 open my $agpl, '<', 'COPYING' or BAIL_OUT "AGPL-3 missing: $!";
23 $agpl = do { local $/; <$agpl> };
24
25 SKIP: {
26         skip 'not in git worktree', 15 unless defined($objdir);
27         $gcf2->add_alternate($objdir);
28         open my $fh, '+>', undef or BAIL_OUT "open: $!";
29         my $fd = fileno($fh);
30         $fh->autoflush(1);
31
32         $gcf2->cat_oid($fd, 'invalid');
33         seek($fh, 0, SEEK_SET) or BAIL_OUT "seek: $!";
34         is(do { local $/; <$fh> }, "invalid missing\n", 'got missing message');
35
36         seek($fh, 0, SEEK_SET) or BAIL_OUT "seek: $!";
37         $gcf2->cat_oid($fd, '0'x40);
38         seek($fh, 0, SEEK_SET) or BAIL_OUT "seek: $!";
39         is(do { local $/; <$fh> }, ('0'x40)." missing\n",
40                 'got missing message for 0x40');
41
42         seek($fh, 0, SEEK_SET) or BAIL_OUT "seek: $!";
43         $gcf2->cat_oid($fd, $COPYING);
44         my $buf;
45         my $ck_copying = sub {
46                 my ($desc) = @_;
47                 seek($fh, 0, SEEK_SET) or BAIL_OUT "seek: $!";
48                 is(<$fh>, "$COPYING blob 34520\n", 'got expected header');
49                 $buf = do { local $/; <$fh> };
50                 is(chop($buf), "\n", 'got trailing \\n');
51                 is($buf, $agpl, "AGPL matches ($desc)");
52         };
53         $ck_copying->('regular file');
54
55         $^O eq 'linux' or skip('pipe tests are Linux-only', 12);
56         my $size = -s $fh;
57         for my $blk (1, 0) {
58                 my ($r, $w);
59                 pipe($r, $w) or BAIL_OUT $!;
60                 fcntl($w, 1031, 4096) or
61                         skip('Linux too old for F_SETPIPE_SZ', 12);
62                 $w->blocking($blk);
63                 seek($fh, 0, SEEK_SET) or BAIL_OUT "seek: $!";
64                 truncate($fh, 0) or BAIL_OUT "truncate: $!";
65                 defined(my $pid = fork) or BAIL_OUT "fork: $!";
66                 if ($pid == 0) {
67                         close $w;
68                         tick; # wait for parent to block on writev
69                         $buf = do { local $/; <$r> };
70                         print $fh $buf or _exit(1);
71                         _exit(0);
72                 }
73                 $gcf2->cat_oid(fileno($w), $COPYING);
74                 close $w or BAIL_OUT "close: $!";
75                 is(waitpid($pid, 0), $pid, 'child exited');
76                 is($?, 0, 'no error in child');
77                 $ck_copying->("pipe blocking($blk)");
78
79                 pipe($r, $w) or BAIL_OUT $!;
80                 fcntl($w, 1031, 4096) or BAIL_OUT $!;
81                 $w->blocking($blk);
82                 close $r;
83                 local $SIG{PIPE} = 'IGNORE';
84                 eval { $gcf2->cat_oid(fileno($w), $COPYING) };
85                 like($@, qr/writev error:/, 'got writev error');
86         }
87 }
88
89 if (my $nr = $ENV{TEST_LEAK_NR}) {
90         open my $null, '>', '/dev/null' or BAIL_OUT "open /dev/null: $!";
91         my $fd = fileno($null);
92         my $cat = $ENV{TEST_LEAK_CAT} // 10;
93         diag "checking for leaks... (TEST_LEAK_NR=$nr TEST_LEAK_CAT=$cat)";
94         local $SIG{PIPE} = 'IGNORE';
95         my ($r, $w);
96         pipe($r, $w);
97         close $r;
98         my $broken = fileno($w);
99         for (1..$nr) {
100                 my $obj = PublicInbox::Gcf2::new();
101                 if (defined($objdir)) {
102                         $obj->add_alternate($objdir);
103                         for (1..$cat) {
104                                 $obj->cat_oid($fd, $COPYING);
105                                 eval { $obj->cat_oid($broken, $COPYING) };
106                                 $obj->cat_oid($fd, '0'x40);
107                                 $obj->cat_oid($fd, 'invalid');
108                         }
109                 }
110         }
111 }
112 done_testing;