diff options
Diffstat (limited to 't')
-rw-r--r-- | t/git.t | 23 | ||||
-rw-r--r-- | t/git_async.t | 138 | ||||
-rw-r--r-- | t/hval.t | 20 | ||||
-rw-r--r-- | t/repobrowse.t | 21 | ||||
-rw-r--r-- | t/repobrowse_common_git.perl | 67 | ||||
-rw-r--r-- | t/repobrowse_git.t | 11 | ||||
-rw-r--r-- | t/repobrowse_git_atom.t | 39 | ||||
-rw-r--r-- | t/repobrowse_git_commit.t | 31 | ||||
-rw-r--r-- | t/repobrowse_git_httpd.t | 138 | ||||
-rw-r--r-- | t/repobrowse_git_plain.t | 29 | ||||
-rw-r--r-- | t/repobrowse_git_snapshot.t | 46 | ||||
-rw-r--r-- | t/repobrowse_git_tree.t | 33 | ||||
-rw-r--r-- | t/spawn.t | 11 |
13 files changed, 596 insertions, 11 deletions
@@ -139,4 +139,27 @@ if (1) { ok($nl > 1, "qx returned array length of $nl"); } +{ + my $git = PublicInbox::Git->new($dir); + + my $err = $git->popen([qw(cat-file blob non-existent)], undef, + { 2 => $git->err_begin }); + my @out = <$err>; + my $close_ret = close $err; + my $close_err = $?; + is(join('', @out), '', 'no output on stdout on error'); + isnt($close_err, 0, 'close set $? on bad command'); + ok(!$close_ret, 'close returned error on bad command'); + isnt($git->err, '', 'got stderr output'); + + $err = $git->popen([qw(tag -l)], undef, { 2 => $git->err_begin }); + @out = <$err>; + $close_ret = close $err; + $close_err = $?; + is(join('', @out), '', 'no output on stdout on error'); + ok(!$close_err, 'close clobbered $? on empty output'); + ok($close_ret, 'close returned error on empty output'); + is($git->err, '', 'no stderr output'); +} + done_testing(); 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 <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +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; diff --git a/t/hval.t b/t/hval.t new file mode 100644 index 00000000..f824752c --- /dev/null +++ b/t/hval.t @@ -0,0 +1,20 @@ +# Copyright (C) 2015 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ (https://www.gnu.org/licenses/agpl-3.0.txt) +use strict; +use warnings; +use Test::More; +use PublicInbox::Hval qw(to_attr from_attr); + +foreach my $s ('Hello/World.pm', 'Zcat', 'hello world.c', 'Eléanor', '$at') { + my $attr = to_attr($s); + is(from_attr($attr), $s, "$s => $attr => $s round trips"); +} + +{ + my $bad = eval { to_attr('foo//bar') }; + my $err = $@; + ok(!$bad, 'double-slash rejected'); + like($err, qr/invalid filename:/, 'got exception message'); +} + +done_testing(); diff --git a/t/repobrowse.t b/t/repobrowse.t new file mode 100644 index 00000000..de8a7952 --- /dev/null +++ b/t/repobrowse.t @@ -0,0 +1,21 @@ +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use warnings; + +my $test = require './t/repobrowse_common_git.perl'; +test_psgi($test->{app}, sub { + my ($cb) = @_; + my $req = 'http://example.com/test.git/tree/dir'; + my $res = $cb->(GET($req . '/')); + is($res->code, 301, 'got 301 with trailing slash'); + is($res->header('Location'), $req, 'redirected without tslash'); + + my $q = '?id=deadbeef'; + + $res = $cb->(GET($req . "/$q")); + is($res->code, 301, 'got 301 with trailing slash + query string'); + is($res->header('Location'), $req.$q, 'redirected without tslash'); +}); + +done_testing(); diff --git a/t/repobrowse_common_git.perl b/t/repobrowse_common_git.perl new file mode 100644 index 00000000..de61efe6 --- /dev/null +++ b/t/repobrowse_common_git.perl @@ -0,0 +1,67 @@ +#!/usr/bin/perl -w +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use warnings; +use Test::More; +use File::Temp qw/tempdir/; +use Cwd qw/getcwd/; +my @mods = qw(HTTP::Request::Common Plack::Test URI::Escape); +foreach my $mod (@mods) { + eval "require $mod"; + plan skip_all => "$mod missing for $0" if $@; +} + +sub dechunk ($) { + my ($res) = @_; + my $s = $res->content; + if (lc($res->header('Transfer-Encoding') || '') eq 'chunked') { + my $rv = ''; + while ($s =~ s/\A([a-f0-9]+)\r\n//i) { # no comment support :x + my $n = hex($1) or last; + $rv .= substr($s, 0, $n); + $s = substr($s, $n); + $s =~ s/\A\r\n// or die "broken parsing in $s\n"; + } + $s =~ s/\A\r\n// or die "broken end parsing in $s\n"; + $s = $rv; + } + $s; +} + +use_ok $_ foreach @mods; +my $git_dir = tempdir('repobrowse-XXXXXX', CLEANUP => 1, TMPDIR => 1); +my $psgi = "examples/repobrowse.psgi"; +my $repobrowse_config = "$git_dir/repobrowse_config"; +my $app; +ok(-f $psgi, 'psgi example for repobrowse.psgi found'); +{ + is(system(qw(git init -q --bare), $git_dir), 0, 'created git directory'); + my @cmd = ('git', "--git-dir=$git_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 $fh; + ok((open $fh, '>', $repobrowse_config and + print $fh '[repo "test.git"]', "\n", + "\t", "path = $git_dir", "\n" and + close $fh), 'created repobrowse config'); + local $ENV{REPOBROWSE_CONFIG} = $repobrowse_config; + ok($app = require $psgi, 'loaded PSGI app'); +} + +# return value +bless { + psgi => $psgi, + git_dir => $git_dir, + app => $app, + repobrowse_config => $repobrowse_config, +}, 'Repobrowse::TestGit'; diff --git a/t/repobrowse_git.t b/t/repobrowse_git.t new file mode 100644 index 00000000..6ae7475b --- /dev/null +++ b/t/repobrowse_git.t @@ -0,0 +1,11 @@ +# Copyright (C) 2015 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ (https://www.gnu.org/licenses/agpl-3.0.txt) +use strict; +use warnings; +use Test::More; +use PublicInbox::RepobrowseGit qw(git_unquote); + +is("foo\nbar", git_unquote('"foo\\nbar"'), 'unquoted newline'); +is("Eléanor", git_unquote('"El\\303\\251anor"'), 'unquoted octal'); + +done_testing(); diff --git a/t/repobrowse_git_atom.t b/t/repobrowse_git_atom.t new file mode 100644 index 00000000..2525effd --- /dev/null +++ b/t/repobrowse_git_atom.t @@ -0,0 +1,39 @@ +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use warnings; +my $have_xml_feed = eval { require XML::Feed; 1 }; +my $test = require './t/repobrowse_common_git.perl'; +use Test::More; + +test_psgi($test->{app}, sub { + my ($cb) = @_; + my $req = 'http://example.com/test.git/atom'; + my $res = $cb->(GET($req)); + is($res->code, 200, 'got 200'); + is($res->header('Content-Type'), 'application/atom+xml', + 'got correct Content-Type'); + my $body = dechunk($res); + SKIP: { + skip 'XML::Feed missing', 2 unless $have_xml_feed; + my $p = XML::Feed->parse(\$body); + is($p->format, "Atom", "parsed atom feed"); + is(scalar $p->entries, 6, "parsed six entries"); + } + + $res = $cb->(GET($req . '/')); + my $sl = dechunk($res); + is($body, $sl, 'slash returned identical to non-trailing slash'); + + $res = $cb->(GET($req . '/foo.txt')); + is($res->code, 200, 'got 200'); + $body = dechunk($res); + SKIP: { + skip 'XML::Feed missing', 2 unless $have_xml_feed; + my $p = XML::Feed->parse(\$body); + is($p->format, "Atom", "parsed atom feed"); + is(scalar $p->entries, 4, "parsed 4 entries"); + } +}); + +done_testing(); diff --git a/t/repobrowse_git_commit.t b/t/repobrowse_git_commit.t new file mode 100644 index 00000000..969a0b5e --- /dev/null +++ b/t/repobrowse_git_commit.t @@ -0,0 +1,31 @@ +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use warnings; + +my $test = require './t/repobrowse_common_git.perl'; +test_psgi($test->{app}, sub { + my ($cb) = @_; + my $path = '/path/to/something'; + my $req = 'http://example.com/test.git/commit'; + my $res = $cb->(GET($req . $path)); + is($res->code, 301, 'got 301 to anchor'); + is($res->header('Location'), "$req#path:to:something", + 'redirected to anchor from path'); + + my $q = '?id=deadbeef'; + $res = $cb->(GET($req . $path . $q)); + is($res->code, 301, 'got 301 with query string'); + is($res->header('Location'), "$req$q#path:to:something", + 'redirected to anchor from path with query'); + + $res = $cb->(GET($req)); + is($res->code, 200, 'got proper 200 response for default'); + my $body = dechunk($res); + like($body, qr!</html>\z!, 'response body finished'); + + $res = $cb->(GET($req.$q)); + is($res->code, 404, 'got 404 response for default'); +}); + +done_testing(); 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; diff --git a/t/repobrowse_git_plain.t b/t/repobrowse_git_plain.t new file mode 100644 index 00000000..27347f70 --- /dev/null +++ b/t/repobrowse_git_plain.t @@ -0,0 +1,29 @@ +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use warnings; +my $test = require './t/repobrowse_common_git.perl'; + +test_psgi($test->{app}, sub { + my ($cb) = @_; + + my $req = 'http://example.com/test.git/plain/dir'; + my $res = $cb->(GET($req)); + is(200, $res->code, 'got 200 response from dir'); + my $noslash_body = dechunk($res); + like($noslash_body, qr{href="dir/dur">dur</a></li>}, 'path ok w/o slash'); + + my $slash = $req . '/'; + my $r2 = $cb->(GET($slash)); + is(200, $r2->code, 'got 200 response from dir'); + my $slash_body = dechunk($r2); + like($slash_body, qr{href="\./dur\">dur</a></li>}, 'path ok w/ slash'); + + $req = 'http://example.com/test.git/plain/foo.txt'; + my $blob = $cb->(GET($req)); + like($blob->header('Content-Type'), qr!\Atext/plain\b!, + 'got text/plain blob'); + is($blob->content, "-----\nhello\nworld\n", 'raw blob passed'); +}); + +done_testing(); diff --git a/t/repobrowse_git_snapshot.t b/t/repobrowse_git_snapshot.t new file mode 100644 index 00000000..b608459e --- /dev/null +++ b/t/repobrowse_git_snapshot.t @@ -0,0 +1,46 @@ +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use warnings; +my $test = require './t/repobrowse_common_git.perl'; + +test_psgi($test->{app}, sub { + my ($cb) = @_; + my ($req, $rc, $res); + + $req = 'http://example.com/test.git/snapshot/test-master.tar.gz'; + $res = $cb->(GET($req)); + is($res->code, 200, 'got 200 response from $NAME-master-tar.gz'); + is($res->header('Content-Type'), 'application/x-gzip', + 'Content-Type is as expected'); + + $req = 'http://example.com/test.git/snapshot/test-nonexistent.tar.gz'; + $res = $cb->(GET($req)); + is($res->code, 404, 'got 404 for non-existent'); + + $rc = system('git', "--git-dir=$test->{git_dir}", 'tag', '-a', + '-m', 'annotated tag!', 'v1.0.0'); + is($rc, 0, 'created annotated 1.0.0 tag'); + $req = 'http://example.com/test.git/snapshot/test-1.0.0.tar.gz'; + $res = $cb->(GET($req)); + is($res->code, 200, 'got 200 response for tag'); + is($res->header('Content-Type'), 'application/x-gzip', + 'Content-Type is as expected'); + is($res->header('Content-Disposition'), + 'inline; filename="test-1.0.0.tar.gz"', + 'Content-Disposition is as expected'); + + $rc = system('git', "--git-dir=$test->{git_dir}", 'tag', + '-m', 'lightweight tag!', 'v2.0.0'); + is($rc, 0, 'created lightweight 2.0.0 tag'); + $req = 'http://example.com/test.git/snapshot/test-2.0.0.tar.gz'; + $res = $cb->(GET($req)); + is($res->code, 200, 'got 200 response for tag'); + is($res->header('Content-Type'), 'application/x-gzip', + 'Content-Type is as expected'); + is($res->header('Content-Disposition'), + 'inline; filename="test-2.0.0.tar.gz"', + 'Content-Disposition is as expected'); +}); + +done_testing(); diff --git a/t/repobrowse_git_tree.t b/t/repobrowse_git_tree.t new file mode 100644 index 00000000..531f914c --- /dev/null +++ b/t/repobrowse_git_tree.t @@ -0,0 +1,33 @@ +# Copyright (C) 2016 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> +use strict; +use warnings; +my $test = require './t/repobrowse_common_git.perl'; + +test_psgi($test->{app}, sub { + my ($cb) = @_; + + my $req = 'http://example.com/test.git/tree/dir'; + my $res = $cb->(GET($req)); + is(200, $res->code, 'got 200 response from dir'); + my $noslash_body = dechunk($res); + like($noslash_body, qr{href="dir/dur\?id=\w+">dur/</a>}, + 'path ok w/o slash'); + + my $slash = $req . '/'; + my $r2 = $cb->(GET($slash)); + is(301, $r2->code, 'got 301 response from dir with slash'); + is($req, $r2->header('Location'), 'redirected w/o slash'); + + $req = 'http://example.com/test.git/tree/foo.txt'; + my $blob = $cb->(GET($req)); + is($blob->header('Content-Type'), 'text/html; charset=UTF-8', + 'got text/html blob'); + + my $body = dechunk($blob); + foreach (qw(----- hello world)) { + ok(index($body, $_) >= 0, "substring $_ in body"); + } +}); + +done_testing(); @@ -81,17 +81,6 @@ use PublicInbox::Spawn qw(which spawn popen_rd); isnt($?, 0, '$? set properly: '.$?); } -{ - my ($fh, $pid) = popen_rd([qw(sleep 60)], undef, { Blocking => 0 }); - ok(defined $pid && $pid > 0, 'returned pid when array requested'); - is(kill(0, $pid), 1, 'child process is running'); - ok(!defined(sysread($fh, my $buf, 1)) && $!{EAGAIN}, - 'sysread returned quickly with EAGAIN'); - is(kill(9, $pid), 1, 'child process killed early'); - is(waitpid($pid, 0), $pid, 'child process reapable'); - isnt($?, 0, '$? set properly: '.$?); -} - done_testing(); 1; |