# HG changeset patch # User Maxim Dounin # Date 1231729685 -10800 # Node ID bc3351f157ef3578379055339471b1231f2a3dae # Parent d053b4bf6ec625ecf43b64e09fb949801e11c400 Tests: add basic pop3 and imap tests. diff --git a/README b/README --- a/README +++ b/README @@ -10,7 +10,8 @@ nginx binary available as ../nginx/objs/ Note: some tests may fail since they are for bugs not fixed in public code. Note: tests run nginx (and backend daemons if needed) listening on localhost. -Currently this includes following ports: 8025, 8026, 8080, 8081. +Currently this includes following ports: 8025, 8026, 8080, 8081, 8110, 8111, +8143, 8144. Tests for memcached required memcached itself and Cache::Memcached to be installed. diff --git a/imap.t b/imap.t new file mode 100644 --- /dev/null +++ b/imap.t @@ -0,0 +1,129 @@ +#!/usr/bin/perl + +# (C) Maxim Dounin + +# Tests for nginx mail imap module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +use IO::Socket; +use MIME::Base64; +use Socket qw/ CRLF /; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::IMAP; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new() + ->has('mail')->plan(8) + ->run_daemon(\&Test::Nginx::IMAP::imap_test_daemon) + ->write_file_expand('nginx.conf', <<'EOF')->run(); + +master_process off; +daemon off; + +events { + worker_connections 1024; +} + +mail { + proxy_pass_error_message on; + auth_http http://127.0.0.1:8080/mail/auth; + + server { + listen 127.0.0.1:8143; + protocol imap; + smtp_auth login plain; + } +} + +http { + access_log off; + + client_body_temp_path %%TESTDIR%%/client_body_temp; + fastcgi_temp_path %%TESTDIR%%/fastcgi_temp; + proxy_temp_path %%TESTDIR%%/proxy_temp; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location = /mail/auth { + set $reply ERROR; + + if ($http_auth_smtp_to ~ example.com) { + set $reply OK; + } + + set $userpass "$http_auth_user:$http_auth_pass"; + if ($userpass ~ '^test@example.com:secret$') { + set $reply OK; + } + + add_header Auth-Status $reply; + add_header Auth-Server 127.0.0.1; + add_header Auth-Port 8144; + add_header Auth-Wait 1; + return 204; + } + } +} + +EOF + +############################################################################### + +my $s = Test::Nginx::IMAP->new(); +$s->ok('greeting'); + +# auth plain + +$s->send('1 AUTHENTICATE PLAIN ' . encode_base64("\0test\@example.com\0bad", '')); +$s->check(qr/^\S+ NO/, 'auth plain with bad password'); + +$s->send('1 AUTHENTICATE PLAIN ' . encode_base64("\0test\@example.com\0secret", '')); +$s->ok('auth plain'); + +# auth login simple + +$s = Test::Nginx::IMAP->new(); +$s->read(); + +$s->send('1 AUTHENTICATE LOGIN'); +$s->check(qr/\+ VXNlcm5hbWU6/, 'auth login username challenge'); + +$s->send(encode_base64('test@example.com', '')); +$s->check(qr/\+ UGFzc3dvcmQ6/, 'auth login password challenge'); + +$s->send(encode_base64('secret', '')); +$s->ok('auth login simple'); + +# auth login with username + +TODO: { +local $TODO = 'not supported yet'; + +$s = Test::Nginx::IMAP->new(); +$s->read(); + +$s->send('1 AUTHENTICATE LOGIN ' . encode_base64('test@example.com', '')); +$s->check(qr/\+ UGFzc3dvcmQ6/, 'auth login with username password challenge'); + +$s->send(encode_base64('secret', '')); +$s->ok('auth login with username'); + +} + +############################################################################### diff --git a/lib/Test/Nginx/IMAP.pm b/lib/Test/Nginx/IMAP.pm new file mode 100644 --- /dev/null +++ b/lib/Test/Nginx/IMAP.pm @@ -0,0 +1,109 @@ +package Test::Nginx::IMAP; + +# (C) Maxim Dounin + +# Module for nginx imap tests. + +############################################################################### + +use warnings; +use strict; + +use Test::More qw//; +use IO::Socket; +use Socket qw/ CRLF /; + +use Test::Nginx; + +use base qw/ IO::Socket::INET /; + +sub new { + my $class = shift; + + my $self = return $class->SUPER::new( + Proto => "tcp", + PeerAddr => "127.0.0.1:8143", + @_ + ) + or die "Can't connect to nginx: $!\n"; + + $self->autoflush(1); + + return $self; +} + +sub send { + my ($self, $cmd) = @_; + log_out($cmd); + $self->print($cmd . CRLF); +} + +sub read { + my ($self) = @_; + eval { + alarm(2); + local $SIG{ALRM} = sub { die "alarm\n" }; + while (<$self>) { + log_in($_); + # XXX + next if m/^\d\d\d-/; + last; + } + alarm(0); + }; + alarm(0); + if ($@) { + return undef; + } + return $_; +} + +sub check { + my ($self, $regex, $name) = @_; + Test::More->builder->like($self->read(), $regex, $name); +} + +sub ok { + my $self = shift; + Test::More->builder->like($self->read(), qr/^\S+ OK/, @_); +} + +############################################################################### + +sub imap_test_daemon { + my $server = IO::Socket::INET->new( + Proto => 'tcp', + LocalAddr => '127.0.0.1:8144', + Listen => 5, + Reuse => 1 + ) + or die "Can't create listening socket: $!\n"; + + while (my $client = $server->accept()) { + $client->autoflush(1); + print $client "* OK fake imap server ready" . CRLF; + + while (<$client>) { + my $tag = ''; + + $tag = $1 if m/^(\S+)/; + s/^(\S+)\s+//; + + if (/^logout/i) { + print $client $tag . ' OK logout ok' . CRLF; + } elsif (/^login /i) { + print $client $tag . ' OK login ok' . CRLF; + } else { + print $client $tag . ' ERR unknown command' . CRLF; + } + } + + close $client; + } +} + +############################################################################### + +1; + +############################################################################### diff --git a/lib/Test/Nginx/POP3.pm b/lib/Test/Nginx/POP3.pm new file mode 100644 --- /dev/null +++ b/lib/Test/Nginx/POP3.pm @@ -0,0 +1,106 @@ +package Test::Nginx::POP3; + +# (C) Maxim Dounin + +# Module for nginx pop3 tests. + +############################################################################### + +use warnings; +use strict; + +use Test::More qw//; +use IO::Socket; +use Socket qw/ CRLF /; + +use Test::Nginx; + +use base qw/ IO::Socket::INET /; + +sub new { + my $class = shift; + + my $self = return $class->SUPER::new( + Proto => "tcp", + PeerAddr => "127.0.0.1:8110", + @_ + ) + or die "Can't connect to nginx: $!\n"; + + $self->autoflush(1); + + return $self; +} + +sub send { + my ($self, $cmd) = @_; + log_out($cmd); + $self->print($cmd . CRLF); +} + +sub read { + my ($self) = @_; + eval { + alarm(2); + local $SIG{ALRM} = sub { die "alarm\n" }; + while (<$self>) { + log_in($_); + # XXX + next if m/^\d\d\d-/; + last; + } + alarm(0); + }; + alarm(0); + if ($@) { + return undef; + } + return $_; +} + +sub check { + my ($self, $regex, $name) = @_; + Test::More->builder->like($self->read(), $regex, $name); +} + +sub ok { + my $self = shift; + Test::More->builder->like($self->read(), qr/^\+OK/, @_); +} + +############################################################################### + +sub pop3_test_daemon { + my $server = IO::Socket::INET->new( + Proto => 'tcp', + LocalAddr => '127.0.0.1:8111', + Listen => 5, + Reuse => 1 + ) + or die "Can't create listening socket: $!\n"; + + while (my $client = $server->accept()) { + $client->autoflush(1); + print $client "+OK fake pop3 server ready" . CRLF; + + while (<$client>) { + if (/^quit/i) { + print $client '+OK quit ok' . CRLF; + } elsif (/^user test\@example.com/i) { + print $client '+OK user ok' . CRLF; + } elsif (/^pass secret/i) { + print $client '+OK pass ok' . CRLF; + } else { + print $client "-ERR unknown command" . CRLF; + } + } + + close $client; + } +} + +############################################################################### + +1; + +############################################################################### diff --git a/pop3.t b/pop3.t new file mode 100644 --- /dev/null +++ b/pop3.t @@ -0,0 +1,129 @@ +#!/usr/bin/perl + +# (C) Maxim Dounin + +# Tests for nginx mail pop3 module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +use IO::Socket; +use MIME::Base64; +use Socket qw/ CRLF /; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::POP3; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new() + ->has('mail')->plan(8) + ->run_daemon(\&Test::Nginx::POP3::pop3_test_daemon) + ->write_file_expand('nginx.conf', <<'EOF')->run(); + +master_process off; +daemon off; + +events { + worker_connections 1024; +} + +mail { + proxy_pass_error_message on; + auth_http http://127.0.0.1:8080/mail/auth; + + server { + listen 127.0.0.1:8110; + protocol pop3; + smtp_auth login plain; + } +} + +http { + access_log off; + + client_body_temp_path %%TESTDIR%%/client_body_temp; + fastcgi_temp_path %%TESTDIR%%/fastcgi_temp; + proxy_temp_path %%TESTDIR%%/proxy_temp; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location = /mail/auth { + set $reply ERROR; + + if ($http_auth_smtp_to ~ example.com) { + set $reply OK; + } + + set $userpass "$http_auth_user:$http_auth_pass"; + if ($userpass ~ '^test@example.com:secret$') { + set $reply OK; + } + + add_header Auth-Status $reply; + add_header Auth-Server 127.0.0.1; + add_header Auth-Port 8111; + add_header Auth-Wait 1; + return 204; + } + } +} + +EOF + +############################################################################### + +my $s = Test::Nginx::POP3->new(); +$s->ok('greeting'); + +# auth plain + +$s->send('AUTH PLAIN ' . encode_base64("\0test\@example.com\0bad", '')); +$s->check(qr/^-ERR/, 'auth plain with bad password'); + +$s->send('AUTH PLAIN ' . encode_base64("\0test\@example.com\0secret", '')); +$s->ok('auth plain'); + +# auth login simple + +$s = Test::Nginx::POP3->new(); +$s->read(); + +$s->send('AUTH LOGIN'); +$s->check(qr/\+ VXNlcm5hbWU6/, 'auth login username challenge'); + +$s->send(encode_base64('test@example.com', '')); +$s->check(qr/\+ UGFzc3dvcmQ6/, 'auth login password challenge'); + +$s->send(encode_base64('secret', '')); +$s->ok('auth login simple'); + +# auth login with username + +TODO: { +local $TODO = 'not supported yet'; + +$s = Test::Nginx::POP3->new(); +$s->read(); + +$s->send('AUTH LOGIN ' . encode_base64('test@example.com', '')); +$s->check(qr/\+ UGFzc3dvcmQ6/, 'auth login with username password challenge'); + +$s->send(encode_base64('secret', '')); +$s->ok('auth login with username'); + +} + +###############################################################################