# HG changeset patch # User Andrey Zelenkov # Date 1458048029 -10800 # Node ID d2cb9ed7412e5b4cf708f81ea510175525b5efc0 # Parent 89898b20f25856092c1cf15e76f3db4052ab8233 Tests: stream udp tests. diff --git a/lib/Test/Nginx/Stream.pm b/lib/Test/Nginx/Stream.pm --- a/lib/Test/Nginx/Stream.pm +++ b/lib/Test/Nginx/Stream.pm @@ -11,7 +11,7 @@ use warnings; use strict; use base qw/ Exporter /; -our @EXPORT_OK = qw/ stream /; +our @EXPORT_OK = qw/ stream dgram /; use Test::More qw//; use IO::Select; @@ -23,6 +23,16 @@ sub stream { return Test::Nginx::Stream->new(@_); } +sub dgram { + unshift(@_, "PeerAddr") if @_ == 1; + + return Test::Nginx::Stream->new( + Proto => "udp", + PeerAddr => '127.0.0.1:8080', + @_ + ); +} + sub new { my $self = {}; bless $self, shift @_; @@ -88,11 +98,17 @@ sub io { my ($data, %extra) = @_; my $length = $extra{length}; + my $read = $extra{read}; + + $read = 1 if !defined $read + && $self->{_socket}->socktype() == &SOCK_DGRAM; $self->write($data); $data = ''; while (1) { + last if defined $read && --$read < 0; + my $buf = $self->read(); last unless length($buf); diff --git a/stream_udp_limit_conn.t b/stream_udp_limit_conn.t new file mode 100644 --- /dev/null +++ b/stream_udp_limit_conn.t @@ -0,0 +1,128 @@ +#!/usr/bin/perl + +# (C) Andrey Zelenkov +# (C) Nginx, Inc. + +# Tests for stream limit_conn module with datagrams. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::Stream qw/ dgram /; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/stream stream_limit_conn shmem/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +stream { + limit_conn_zone $binary_remote_addr zone=zone:1m; + limit_conn_zone $binary_remote_addr zone=zone2:1m; + + proxy_responses 1; + proxy_timeout 1s; + + server { + listen 127.0.0.1:8081 udp; + proxy_pass 127.0.0.1:8080; + + limit_conn zone 1; + proxy_responses 2; + } + + server { + listen 127.0.0.1:8082 udp; + proxy_pass 127.0.0.1:8080; + limit_conn zone2 1; + } + + server { + listen 127.0.0.1:8083 udp; + proxy_pass 127.0.0.1:8080; + limit_conn zone 5; + } + + server { + listen 127.0.0.1:8084 udp; + proxy_pass 127.0.0.1:8081; + limit_conn zone2 1; + } + + server { + listen 127.0.0.1:8085 udp; + proxy_pass 127.0.0.1:8081; + limit_conn zone 1; + } +} + +EOF + +$t->try_run('no stream udp')->plan(8); +$t->run_daemon(\&udp_daemon, $t); +$t->waitforfile($t->testdir . '/8080'); + +############################################################################### + +my $str = '.'; + +# same and other zones + +my $s = dgram('127.0.0.1:8081'); + +is($s->io('1'), '1', 'passed'); + +is(dgram('127.0.0.1:8081')->io('1'), '', 'rejected same zone'); +is(dgram('127.0.0.1:8082')->io('1'), '1', 'passed different zone'); +is(dgram('127.0.0.1:8083')->io('1'), '1', 'passed same zone unlimited'); + +is($s->io('2', read => 2), '12', 'long connection'); + +is(dgram('127.0.0.1:8081')->io('2', read => 2), '12', 'passed 2'); + +# zones proxy chain + +is(dgram('127.0.0.1:8084')->io('1'), '1', 'passed proxy'); +is(dgram('127.0.0.1:8085')->io('1'), '', 'rejected proxy'); + +############################################################################### + +sub udp_daemon { + my $t = shift; + + my $server = IO::Socket::INET->new( + Proto => 'udp', + LocalAddr => '127.0.0.1:8080', + Reuse => 1, + ) + or die "Can't create listening socket: $!\n"; + + # signal we are ready + + open my $fh, '>', $t->testdir() . '/8080'; + close $fh; + + while (1) { + $server->recv(my $buffer, 65536); + $server->send($_) for (1 .. $buffer); + } +} + +############################################################################### diff --git a/stream_udp_proxy.t b/stream_udp_proxy.t new file mode 100644 --- /dev/null +++ b/stream_udp_proxy.t @@ -0,0 +1,101 @@ +#!/usr/bin/perl + +# (C) Nginx, Inc. + +# Tests for stream proxy module with datagrams. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::Stream qw/ dgram /; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/stream/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +stream { + proxy_timeout 1s; + + server { + listen 127.0.0.1:8080 udp; + proxy_pass 127.0.0.1:8081; + + proxy_responses 0; + } + + server { + listen 127.0.0.1:8082 udp; + proxy_pass 127.0.0.1:8081; + + proxy_responses 2; + } + + server { + listen 127.0.0.1:8083 udp; + proxy_pass 127.0.0.1:8081; + } +} + +EOF + + +$t->run_daemon(\&udp_daemon, 8081, $t); +$t->try_run('no stream udp')->plan(5); +$t->waitforfile($t->testdir . '/8081'); + +############################################################################### + +my $s = dgram('127.0.0.1:8080'); +is($s->io('1', read => 1), '', 'proxy responses 0'); + +$s = dgram('127.0.0.1:8082'); +is($s->io('1'), '1', 'proxy responses 1'); +is($s->io('2', read => 2), '12', 'proxy responses 2'); +is($s->io('3', read => 3), '12', 'proxy responses 3'); + +$s = dgram('127.0.0.1:8083'); +is($s->io('3', read => 3), '123', 'proxy responses default'); + +############################################################################### + +sub udp_daemon { + my ($port, $t) = @_; + + my $server = IO::Socket::INET->new( + Proto => 'udp', + LocalAddr => "127.0.0.1:$port", + Reuse => 1, + ) + or die "Can't create listening socket: $!\n"; + + # signal we are ready + + open my $fh, '>', $t->testdir() . '/' . $port; + close $fh; + + while (1) { + $server->recv(my $buffer, 65536); + $server->send($_) for (1 .. $buffer); + } +} + +############################################################################### diff --git a/stream_udp_upstream.t b/stream_udp_upstream.t new file mode 100644 --- /dev/null +++ b/stream_udp_upstream.t @@ -0,0 +1,141 @@ +#!/usr/bin/perl + +# (C) Sergey Kandaurov +# (C) Nginx, Inc. + +# Stream tests for upstream module and balancers with datagrams. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::Stream qw/ dgram /; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/stream/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +stream { + proxy_responses 1; + proxy_timeout 1s; + + upstream u { + server 127.0.0.1:8087; + server 127.0.0.1:8088; + } + + upstream u2 { + server 127.0.0.1:8089 down; + server 127.0.0.1:8089; + server 127.0.0.1:8087; + server 127.0.0.1:8088; + } + + upstream u3 { + server 127.0.0.1:8087; + server 127.0.0.1:8088 weight=2; + } + + upstream u4 { + server 127.0.0.1:8089; + server 127.0.0.1:8087 backup; + } + + server { + listen 127.0.0.1:8081 udp; + proxy_pass u; + } + + server { + listen 127.0.0.1:8082 udp; + proxy_pass u2; + } + + server { + listen 127.0.0.1:8083 udp; + proxy_pass u3; + } + + server { + listen 127.0.0.1:8084 udp; + proxy_pass u4; + } +} + +EOF + +$t->run_daemon(\&udp_daemon, 8087, $t); +$t->run_daemon(\&udp_daemon, 8088, $t); +$t->try_run('no stream udp')->plan(4); + +$t->waitforfile($t->testdir . '/8087'); +$t->waitforfile($t->testdir . '/8088'); + +############################################################################### + +is(many('.', 30, peer => '127.0.0.1:8081'), '8087: 15, 8088: 15', 'balanced'); +is(many('.', 30, peer => '127.0.0.1:8082'), '8087: 15, 8088: 15', 'failures'); +is(many('.', 30, peer => '127.0.0.1:8083'), '8087: 10, 8088: 20', 'weight'); +is(many('.', 30, peer => '127.0.0.1:8084'), '8087: 30', 'backup'); + +############################################################################### + +sub many { + my ($data, $count, %opts) = @_; + my (%ports, $peer); + + $peer = $opts{peer}; + + for (1 .. $count) { + if (dgram($peer)->io($data) =~ /(\d+)/) { + $ports{$1} = 0 unless defined $ports{$1}; + $ports{$1}++; + } + } + + return join ', ', map { $_ . ": " . $ports{$_} } sort keys %ports; +} + +############################################################################### + +sub udp_daemon { + my ($port, $t) = @_; + + my $server = IO::Socket::INET->new( + Proto => 'udp', + LocalAddr => '127.0.0.1:' . $port, + Reuse => 1, + ) + or die "Can't create listening socket: $!\n"; + + # signal we are ready + + open my $fh, '>', $t->testdir() . '/' . $port; + close $fh; + + while (1) { + $server->recv(my $buffer, 65536); + $buffer = $server->sockport(); + $server->send($buffer); + } +} + +############################################################################### diff --git a/stream_udp_upstream_hash.t b/stream_udp_upstream_hash.t new file mode 100644 --- /dev/null +++ b/stream_udp_upstream_hash.t @@ -0,0 +1,120 @@ +#!/usr/bin/perl + +# (C) Sergey Kandaurov +# (C) Nginx, Inc. + +# Stream tests for upstream hash balancer module with datagrams. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::Stream qw/ dgram /; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/stream stream_upstream_hash/); + +$t->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +stream { + proxy_responses 1; + proxy_timeout 1s; + + upstream hash { + hash $remote_addr; + server 127.0.0.1:8087; + server 127.0.0.1:8088; + } + + upstream cons { + hash $remote_addr consistent; + server 127.0.0.1:8087; + server 127.0.0.1:8088; + } + + server { + listen 127.0.0.1:8081 udp; + proxy_pass hash; + } + + server { + listen 127.0.0.1:8082 udp; + proxy_pass cons; + } +} + +EOF + +$t->run_daemon(\&udp_daemon, 8087, $t); +$t->run_daemon(\&udp_daemon, 8088, $t); +$t->try_run('no stream udp')->plan(2); + +$t->waitforfile($t->testdir . '/8087'); +$t->waitforfile($t->testdir . '/8088'); + +############################################################################### + +is(many('.', 10, peer => '127.0.0.1:8081'), '8088: 10', 'hash'); +is(many('.', 10, peer => '127.0.0.1:8082'), '8088: 10', 'hash consistent'); + +############################################################################### + +sub many { + my ($data, $count, %opts) = @_; + my (%ports, $peer); + + $peer = $opts{peer}; + + for (1 .. $count) { + if (dgram($peer)->io($data) =~ /(\d+)/) { + $ports{$1} = 0 unless defined $ports{$1}; + $ports{$1}++; + } + } + + return join ', ', map { $_ . ": " . $ports{$_} } sort keys %ports; +} + +############################################################################### + +sub udp_daemon { + my ($port, $t) = @_; + + my $server = IO::Socket::INET->new( + Proto => 'udp', + LocalAddr => '127.0.0.1:' . $port, + Reuse => 1, + ) + or die "Can't create listening socket: $!\n"; + + # signal we are ready + + open my $fh, '>', $t->testdir() . '/' . $port; + close $fh; + + while (1) { + $server->recv(my $buffer, 65536); + $buffer = $server->sockport(); + $server->send($buffer); + } +} + +############################################################################### diff --git a/stream_udp_upstream_least_conn.t b/stream_udp_upstream_least_conn.t new file mode 100644 --- /dev/null +++ b/stream_udp_upstream_least_conn.t @@ -0,0 +1,124 @@ +#!/usr/bin/perl + +# (C) Sergey Kandaurov +# (C) Nginx, Inc. + +# Stream tests for upstream least_conn balancer module with datagrams. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; +use Test::Nginx::Stream qw/ dgram /; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/stream stream_upstream_least_conn/) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +stream { + proxy_responses 1; + proxy_timeout 1s; + + upstream u { + least_conn; + server 127.0.0.1:8081; + server 127.0.0.1:8082; + } + + server { + listen 127.0.0.1:8080 udp; + proxy_pass u; + } +} + +EOF + +$t->run_daemon(\&udp_daemon, 8081, $t); +$t->run_daemon(\&udp_daemon, 8082, $t); +$t->try_run('no stream udp')->plan(2); + +$t->waitforfile($t->testdir . '/8081'); +$t->waitforfile($t->testdir . '/8082'); + +############################################################################### + +is(many('.', 10), '8081: 5, 8082: 5', 'balanced'); + +my @sockets; +for (1 .. 2) { + my $s = dgram(); + $s->write('w'); + push @sockets, $s; +} + +select undef, undef, undef, 0.2; + +is(many('.', 10), '8082: 10', 'least_conn'); + +############################################################################### + +sub many { + my ($data, $count, %opts) = @_; + my (%ports); + + for (1 .. $count) { + if (dgram()->io($data) =~ /(\d+)/) { + $ports{$1} = 0 unless defined $ports{$1}; + $ports{$1}++; + } + } + + return join ', ', map { $_ . ": " . $ports{$_} } sort keys %ports; +} + +############################################################################### + +sub udp_daemon { + my ($port, $t) = @_; + + my $server = IO::Socket::INET->new( + Proto => 'udp', + LocalAddr => '127.0.0.1:' . $port, + Reuse => 1, + ) + or die "Can't create listening socket: $!\n"; + + # signal we are ready + + open my $fh, '>', $t->testdir() . '/' . $port; + close $fh; + + while (1) { + $server->recv(my $buffer, 65536); + + my $port = $server->sockport(); + + if ($buffer =~ /w/ && $port == 8081) { + select undef, undef, undef, 2.5; + } + + $buffer = $port; + + $server->send($buffer); + } +} + +###############################################################################