# HG changeset patch # User Maxim Dounin # Date 1370650253 -14400 # Node ID 71e275487aeb430194c5e94a530059eb0010454c # Parent 719285b89d7e617be2334d77812a9da025b10fd6 Tests: upstream least_conn and ip_hash tests. diff --git a/upstream_ip_hash.t b/upstream_ip_hash.t new file mode 100644 --- /dev/null +++ b/upstream_ip_hash.t @@ -0,0 +1,111 @@ +#!/usr/bin/perl + +# (C) Maxim Dounin + +# Tests for upstream ip_hash balancer. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +use Socket qw/ CRLF /; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http proxy upstream_ip_hash realip/) + ->write_file_expand('nginx.conf', <<'EOF')->run(); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + upstream u { + ip_hash; + server 127.0.0.1:8081; + server 127.0.0.1:8082; + } + + upstream u2 { + ip_hash; + server 127.0.0.1:8081; + server 127.0.0.1:8082; + server 127.0.0.1:8083; + } + + server { + listen 127.0.0.1:8080; + server_name localhost; + + set_real_ip_from 127.0.0.0/8; + add_header X-IP $remote_addr; + + location / { + proxy_pass http://u; + } + location /u2 { + proxy_pass http://u2; + } + } + + server { + listen 127.0.0.1:8081; + listen 127.0.0.1:8082; + listen 127.0.0.1:8083; + server_name localhost; + + location / { + add_header X-Port $server_port; + return 204; + } + } +} + +EOF + +plan(skip_all => 'no 127.0.0.1 on host') + if http_get('/') !~ /X-IP: 127.0.0.1/m; + +$t->plan(2); + +############################################################################### + +is(many('/', 30), '8081: 15, 8082: 15', 'ip_hash'); +is(many('/u2', 30), '8081: 10, 8082: 10, 8083: 10', 'ip_hash 3 peers'); + +############################################################################### + +sub many { + my ($uri, $count) = @_; + my %ports; + + for my $i (1 .. $count) { + my $req = "GET $uri HTTP/1.0" . CRLF + . "X-Real-IP: 127.0.$i.2" . CRLF . CRLF; + + if (http($req) =~ /X-Port: (\d+)/) { + $ports{$1} = 0 unless defined $ports{$1}; + $ports{$1}++; + } + } + + return join ', ', map { $_ . ": " . $ports{$_} } sort keys %ports; +} + +############################################################################### diff --git a/upstream_least_conn.t b/upstream_least_conn.t new file mode 100644 --- /dev/null +++ b/upstream_least_conn.t @@ -0,0 +1,199 @@ +#!/usr/bin/perl + +# (C) Maxim Dounin + +# Tests for upstream least_conn balancer module. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +use Socket qw/ CRLF /; + +BEGIN { use FindBin; chdir($FindBin::Bin); } + +use lib 'lib'; +use Test::Nginx; + +############################################################################### + +select STDERR; $| = 1; +select STDOUT; $| = 1; + +my $t = Test::Nginx->new()->has(qw/http proxy upstream_least_conn/)->plan(2); + +$t->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + upstream u { + least_conn; + server 127.0.0.1:8081; + server 127.0.0.1:8082; + } + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location / { + proxy_pass http://u; + } + } +} + +EOF + +$t->run_daemon(\&http_daemon, 8081); +$t->run_daemon(\&http_daemon, 8082); +$t->run(); + +$t->waitforsocket('127.0.0.1:8081'); +$t->waitforsocket('127.0.0.1:8082'); + +############################################################################### + +is(many('/', 10), '8081: 5, 8082: 5', 'balanced'); +is(parallel('/w', 10), '8081: 1, 8082: 9', 'least conn'); + +############################################################################### + +sub many { + my ($uri, $count) = @_; + my %ports; + + for (1 .. $count) { + if (http_get($uri) =~ /X-Port: (\d+)/) { + $ports{$1} = 0 unless defined $ports{$1}; + $ports{$1}++; + } + } + + return join ', ', map { $_ . ": " . $ports{$_} } sort keys %ports; +} + +sub parallel { + my ($uri, $count, %opts) = @_; + my (@sockets, %ports); + + for (1 .. $count) { + push(@sockets, http_start($uri)); + select undef, undef, undef, 0.1; + } + + for (1 .. $count) { + if (http_end(pop(@sockets)) =~ /X-Port: (\d+)/) { + $ports{$1} = 0 unless defined $ports{$1}; + $ports{$1}++; + } + } + + return join ', ', map { $_ . ": " . $ports{$_} } sort keys %ports; +} + +sub http_start { + my ($uri) = @_; + + my $s; + my $request = "GET $uri HTTP/1.0" . CRLF . CRLF; + + eval { + local $SIG{ALRM} = sub { die "timeout\n" }; + local $SIG{PIPE} = sub { die "sigpipe\n" }; + alarm(3); + $s = IO::Socket::INET->new( + Proto => 'tcp', + PeerAddr => '127.0.0.1:8080' + ); + log_out($request); + $s->print($request); + alarm(0); + }; + alarm(0); + if ($@) { + log_in("died: $@"); + return undef; + } + return $s; +} + +sub http_end { + my ($s) = @_; + my $reply; + + eval { + local $SIG{ALRM} = sub { die "timeout\n" }; + local $SIG{PIPE} = sub { die "sigpipe\n" }; + alarm(3); + local $/; + $reply = $s->getline(); + log_in($reply); + alarm(0); + }; + alarm(0); + if ($@) { + log_in("died: $@"); + return undef; + } + return $reply; +} + +############################################################################### + +sub http_daemon { + my ($port) = @_; + + my $server = IO::Socket::INET->new( + Proto => 'tcp', + LocalHost => '127.0.0.1', + LocalPort => $port, + Listen => 5, + Reuse => 1 + ) + or die "Can't create listening socket: $!\n"; + + local $SIG{PIPE} = 'IGNORE'; + + while (my $client = $server->accept()) { + $client->autoflush(1); + + my $headers = ''; + my $uri = ''; + + while (<$client>) { + $headers .= $_; + last if (/^\x0d?\x0a?$/); + } + + $uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i; + + if ($uri eq '/w' && $port == 8081) { + Test::Nginx::log_core('||', "$port: sleep(1.5)"); + select undef, undef, undef, 1.5; + } + + Test::Nginx::log_core('||', "$port: response, 200"); + print $client <