about summary refs log tree commit
path: root/t
diff options
context:
space:
mode:
Diffstat (limited to 't')
-rw-r--r--t/nntp_compress.t55
-rw-r--r--t/nntp_deflate.t109
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');
+}