about summary refs log tree commit homepage
path: root/t/repobrowse_git_httpd.t
diff options
context:
space:
mode:
Diffstat (limited to 't/repobrowse_git_httpd.t')
-rw-r--r--t/repobrowse_git_httpd.t138
1 files changed, 138 insertions, 0 deletions
diff --git a/t/repobrowse_git_httpd.t b/t/repobrowse_git_httpd.t
new file mode 100644
index 00000000..3e6c074c
--- /dev/null
+++ b/t/repobrowse_git_httpd.t
@@ -0,0 +1,138 @@
+# Copyright (C) 2016 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+#
+# Integration test for public-inbox-httpd and (git) repobrowse
+# since we may use some special APIs not available in other servers
+use strict;
+use warnings;
+use Test::More;
+foreach my $mod (qw(Danga::Socket HTTP::Date HTTP::Status
+                Plack::Test::ExternalServer)) {
+        eval "require $mod";
+        plan skip_all => "$mod missing for repobrowse_git_httpd.t" if $@;
+}
+my $test = require './t/repobrowse_common_git.perl';
+{
+        no warnings 'once';
+        $Plack::Test::Impl = 'ExternalServer';
+}
+use File::Temp qw/tempdir/;
+use Cwd qw/getcwd/;
+use IO::Socket;
+use Fcntl qw(F_SETFD);
+use POSIX qw(dup2);
+my $tmpdir = tempdir('repobrowse_git_httpd-XXXXXX', TMPDIR => 1, CLEANUP => 1);
+my $err = "$tmpdir/stderr.log";
+my $out = "$tmpdir/stdout.log";
+my $httpd = 'blib/script/public-inbox-httpd';
+my $psgi = getcwd() . '/' . $test->{psgi};
+my %opts = (
+        LocalAddr => '127.0.0.1',
+        ReuseAddr => 1,
+        Proto => 'tcp',
+        Type => SOCK_STREAM,
+        Listen => 1024,
+);
+my $sock = IO::Socket::INET->new(%opts);
+my $host = $sock->sockhost;
+my $port = $sock->sockport;
+my $uri = "http://$host:$port/";
+my $pid;
+END { kill 'TERM', $pid if defined $pid };
+my $spawn_httpd = sub {
+        $pid = fork;
+        if ($pid == 0) {
+                # pretend to be systemd:
+                dup2(fileno($sock), 3) or die "dup2 failed: $!\n";
+                my $t = IO::Handle->new_from_fd(3, 'r');
+                $t->fcntl(F_SETFD, 0);
+                $ENV{REPOBROWSE_CONFIG} = $test->{repobrowse_config};
+                $ENV{LISTEN_PID} = $$;
+                $ENV{LISTEN_FDS} = 1;
+                exec $httpd, '-W0', $psgi;
+                # exec $httpd, '-W0', "--stdout=$out", "--stderr=$err", $psgi;
+                die "FAIL: $!\n";
+        }
+        ok(defined $pid, 'forked httpd process successfully');
+};
+
+$spawn_httpd->();
+
+{ # git clone tests
+        my $url = $uri . 'test.git';
+        is(system(qw(git clone -q --mirror), $url, "$tmpdir/smart.git"),
+                0, 'smart clone successful');
+        is(system('git', "--git-dir=$tmpdir/smart.git", 'fsck'), 0, 'fsck OK');
+        is(system('git', "--git-dir=$test->{git_dir}",
+                qw(config http.uploadpack 0)), 0, 'disabled smart HTTP');
+        is(system('git', "--git-dir=$test->{git_dir}",
+                qw(update-server-info)), 0, 'enable dumb HTTP');
+        is(system(qw(git clone -q --mirror), $url, "$tmpdir/dumb.git"),
+                0, 'dumb clone successful');
+        is(system('git', "--git-dir=$tmpdir/dumb.git", 'fsck'),
+                0, 'fsck dumb OK');
+}
+
+test_psgi(uri => $uri, client => sub {
+        my ($cb) = @_;
+        my $res = $cb->(GET($uri . 'test.git/info/refs'));
+        is(200, $res->code, 'got info/refs');
+
+        $res = $cb->(GET($uri . 'best.git/info/refs'));
+        is(404, $res->code, 'bad request fails');
+
+        $res = $cb->(GET($uri . 'test.git/patch'));
+        is(200, $res->code, 'got patch');
+        is('text/plain; charset=UTF-8', $res->header('Content-Type'),
+                'got proper content-type with patch');
+
+        # ignore signature from git-format-patch:
+        my ($patch, undef) = split(/\n-- \n/s, $res->content);
+
+        my $cmd = 'format-patch --signature=git -1 -M --stdout HEAD';
+        my ($exp, undef) = split(/\n-- \n/s,
+                `git --git-dir=$test->{git_dir} $cmd`);
+        is($patch, $exp, 'patch content matches expected');
+});
+
+{
+        # allow reading description file
+        my %conn = ( PeerAddr => $host, PeerPort => $port, Proto => 'tcp',
+                Type => SOCK_STREAM);
+        my $conn = IO::Socket::INET->new(%conn);
+        ok($conn, "connected for description check");
+        $conn->write("GET /test.git/description HTTP/1.0\r\n\r\n");
+        ok($conn->read(my $buf, 8192), 'read response');
+        my ($head, $body) = split(/\r\n\r\n/, $buf, 2);
+        like($head, qr!\AHTTP/1\.0 200 !s, 'got 200 response for description');
+
+        $conn = IO::Socket::INET->new(%conn);
+        ok($conn, "connected for range check");
+        $conn->write("GET /test.git/description HTTP/1.0\r\n" .
+                        "Range: bytes=5-\r\n\r\n");
+        ok($conn->read($buf, 8192), 'read partial response');
+        my ($h2, $b2) = split(/\r\n\r\n/, $buf, 2);
+        like($h2, qr!\AHTTP/1\.0 206 !s, 'got 206 response for range');
+        is($b2, substr($body, 5), 'substring matches on 206');
+}
+
+test_psgi(uri => $uri, client => sub {
+        my ($cb) = @_;
+        my $res = $cb->(GET($uri . 'test.git/snapshot/test-master.tar.gz'));
+        is(200, $res->code, 'got gzipped tarball');
+        my $got = "$tmpdir/got.tar.gz";
+        my $exp = "$tmpdir/exp.tar.gz";
+        open my $fh, '>', $got or die "open got.tar.gz: $!";
+        print $fh $res->content;
+        close $fh or die "close failed: $!";
+        $res = undef;
+        my $rc = system('git', "--git-dir=$test->{git_dir}",
+                        qw(archive --prefix=test-master/ --format=tar.gz),
+                        '-o', $exp, 'master');
+        is(0, $rc, 'git-archive generated check correctly');
+        is(0, system('cmp', $got, $exp), 'got expected gzipped tarball');
+
+});
+
+done_testing();
+1;