diff options
Diffstat (limited to 't')
-rw-r--r-- | t/nntp_compress.t | 55 | ||||
-rw-r--r-- | t/nntp_deflate.t | 109 |
2 files changed, 164 insertions, 0 deletions
diff --git a/t/nntp_compress.t b/t/nntp_compress.t new file mode 100644 index 0000000..7a0cc63 --- /dev/null +++ b/t/nntp_compress.t @@ -0,0 +1,55 @@ +#!perl +# integration test for NNTP COMPRESS usage +use 5.008001; +use strict; +use warnings; +use Test::More; +use Net::Config; +use Net::NNTP; +if (!eval { require Net::NNTP::Deflate }) { + plan skip_all => 'no DEFLATE support'; +} + +# tested on news.gmane.org, we can move it to nntp.lore.kernel.org if +# gmane goes away since nntp.lore.kernel.org will likely start support +# STARTTLS + COMPRESS soon +my $host = $ENV{NNTP_COMPRESS_SERVER}; +unless($host && $NetConfig{test_hosts}) { + plan skip_all => 'NNTP_COMPRESS_SERVER not set'; +} + +plan tests => 16; + +# git 2.22.0 release announcement +my $mid = '<xmqq36klozfu.fsf@gitster-ct.c.googlers.com>'; +my $orig; +{ + my $nntp = Net::NNTP->new($host); + ok($nntp, "opened connection to $host"); + is($nntp->compression, undef, '->compression not active by default'); + $orig = $nntp->article($mid); + ok($nntp->compress, '->compress successful'); + is($nntp->compression, 'DEFLATE', '->compression active'); + is_deeply($nntp->article($mid), $orig, 'got the same article after compress'); + + # check for misuse + is(eval { $nntp->starttls }, undef, '->starttls fails'); + like($@, qr/DEFLATE/, '$@ mentions compression on ->starttls'); + is(eval { $nntp->compress }, undef, '->compress fails again'); + like($@, qr/DEFLATE/, '$@ mentions compression on ->compress'); + ok($nntp->quit, 'QUIT OK'); +} + +SKIP: { + skip('no SSL support found in Net::NNTP', 6) if ! Net::NNTP->can_ssl; + my $nntp = Net::NNTP->new($host); + ok($nntp, "connected to $host again"); + $orig ||= $nntp->article($mid); + ok($nntp->starttls, '->starttls works before ->compress'); + ok($nntp->compress, '->compress works after ->starttls'); + my $date = $nntp->date; + like($date, qr/[0-9]+/, 'DATE works'); + is_deeply($nntp->article($mid), $orig, + 'got the same article with both compress and starttls'); + ok($nntp->quit, 'QUIT OK'); +} diff --git a/t/nntp_deflate.t b/t/nntp_deflate.t new file mode 100644 index 0000000..6a031f8 --- /dev/null +++ b/t/nntp_deflate.t @@ -0,0 +1,109 @@ +#!perl +# unit test for internal Net::NNTP::Deflate class +# This exercises some rare code paths which may not be exercised +# in normal use and reaches into internal data structures to test them. +use 5.008001; +use strict; +use warnings; +use Test::More; +use IO::Handle; +if (!eval { require Net::NNTP::Deflate }) { + plan skip_all => 'no DEFLATE support'; +} +Compress::Raw::Zlib->import(qw(Z_OK Z_PARTIAL_FLUSH Z_FINISH)); +plan tests => 21; + +my ($r, $w); + +# we don't want Net::NNTP::DESTROY triggering and blocking on select() +# because it waits on the ->quit response; +END { + $w->close if $w; + $r->close if $r; +} + +# easy stuff, first +pipe($r, $w) or die; +Net::NNTP::Deflate->wrap($r); +Net::NNTP::Deflate->wrap($w); +is(12, $w->syswrite("HELLO HELLO\n"), 'syswrite OK'); +my $buf = ''; +my $n = $r->sysread($buf, 4096, 0); +is($n, 12, 'read expected number of bytes'); +is($buf, "HELLO HELLO\n", 'got expected output'); + +is(4, $w->syswrite("s'more!!1", 4, 2), 'wrote "more" using offset/length'); +$buf = ''; +is($r->sysread($buf, 4096, 0), 4, 'reader read data'); +is($buf, 'more', 'syswrite respected length and offset'); + +# reach into internal state to simulate the real-world blocks +# being split in non-optimal ways for inflate: +{ + my $deflate = ${*$w}{net_nntp_deflate}; + my $zout = $deflate->[0]; + open my $fh, '<', __FILE__ or die; + my $orig = do { local $/; <$fh> }; + my $status = $zout->deflate($orig, $deflate->[1]); + $status == Z_OK() or die "->deflate failed: $status"; + + $status = $zout->flush($deflate->[1], Z_PARTIAL_FLUSH()); + $status == Z_OK() or die "->flush failed: $status"; + + # start with a single-byte incomplete write, zlib has no chance of + # making sense of one byte of input: + my $len = length($deflate->[1]); + my $olen = 1; + my $remain = $len - $olen; + my $wrote = syswrite($w, $deflate->[1], $olen, $deflate->[2]); + is($wrote, $olen, 'wrote one byte'); + $deflate->[2] += $olen; + $r->blocking(0); + $buf = ''; + $n = $r->sysread($buf, 4096, 0); + is($n, undef, 'sysread can return undef'); + ok($!{EAGAIN} || $!{EWOULDBLOCK}, 'EAGAIN/EWOULDBLOCK set'); + + # write the first half of the input, minus one byte we just wrote + $olen = int($len / 2) - 1; + my $wr1 = syswrite($w, $deflate->[1], $olen, $deflate->[2]); + ok($wr1, 'wrote some more'); + $remain -= $wr1; + $deflate->[2] += $wr1; + $wrote += $wr1; + + # and we should be able to read something, now + $n = $r->sysread($buf, 4096, 0); + ok($n, 'read something inflatable'); + is($buf, substr($orig, 0, $n), 'able to read partial buffer'); + + # finish the write and make sure the reader sees it + my $wr2 = syswrite($w, $deflate->[1], $remain, $deflate->[2]); + is($wr2 + $wrote, $len, 'totally written'); + $n = $r->sysread(my $rest = '', 4096, 0); + is($buf . $rest, $orig, 'completely read after incomplete read'); + + # trigger Z_STREAM_END in reader: + $deflate->[1] = ''; + $deflate->[2] = 0; + $zout->flush($deflate->[1], Z_FINISH()); + my $last = syswrite($w, $deflate->[1]); + is($r->sysread(my $end = '', 4096, 0), 0, 'got EOF on Z_STREAM_END'); + ok($w->close, 'closed writer'); + ok($r->close, 'closed reader'); +} + +# make sure ->sysread detects undecodable input +{ + $r = $w = undef; + pipe($r, $w) or die; + Net::NNTP::Deflate->wrap($r); + my @warn; + + is(syswrite($w, "random junk\0"), 12, 'wrote random junk (not deflated)'); + local $SIG{__WARN__} = sub { push @warn, @_ }; + is($r->sysread(my $junk = '', 4096, 0), undef, + 'refused to decode random junk'); + ok($!{ECONNRESET}, 'got ECONNRESET on sysread failure'); + like(join('', @warn), qr/Error:/, 'warned on inflate error'); +} |