Tests: ported upstream max_conns tests to stream, reduced diffs.
diff --git a/stream_upstream_max_conns.t b/stream_upstream_max_conns.t
new file mode 100644
index 0000000..d2ebb8e
--- /dev/null
+++ b/stream_upstream_max_conns.t
@@ -0,0 +1,379 @@
+#!/usr/bin/perl
+
+# (C) Nginx, Inc.
+# (C) Sergey Kandaurov
+
+# Tests for stream upstream module with max_conns feature.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+use IO::Select;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx qw/ :DEFAULT http_end /;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/stream stream_upstream_least_conn/)
+ ->plan(12);
+
+$t->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+stream {
+ upstream u_unlim {
+ server 127.0.0.1:8081 max_conns=0;
+ server 127.0.0.1:8082;
+ }
+ upstream u_lim {
+ server 127.0.0.1:8081 max_conns=3;
+ }
+
+ upstream u_backup {
+ server 127.0.0.1:8081 max_conns=2;
+ server 127.0.0.1:8082 backup;
+ }
+ upstream u_backup_lim {
+ server 127.0.0.1:8081 max_conns=2;
+ server 127.0.0.1:8082 backup max_conns=3;
+ }
+
+ upstream u_two {
+ server 127.0.0.1:8081 max_conns=1;
+ server 127.0.0.1:8082 max_conns=1;
+ }
+ upstream u_some {
+ server 127.0.0.1:8081 max_conns=1;
+ server 127.0.0.1:8082;
+ }
+ upstream u_many {
+ server 127.0.0.1:8081 max_conns=1;
+ server 127.0.0.1:8081 max_conns=1;
+ server 127.0.0.1:8082;
+ }
+
+ upstream u_weight {
+ server 127.0.0.1:8081 weight=2 max_conns=1;
+ server 127.0.0.1:8082;
+ }
+
+ upstream u_lc {
+ least_conn;
+ server 127.0.0.1:8081 max_conns=1;
+ server 127.0.0.1:8082;
+ }
+ upstream u_lc_backup {
+ least_conn;
+ server 127.0.0.1:8081 max_conns=2;
+ server 127.0.0.1:8082 backup;
+ }
+ upstream u_lc_backup_lim {
+ least_conn;
+ server 127.0.0.1:8081 max_conns=2;
+ server 127.0.0.1:8082 backup max_conns=3;
+ }
+
+ server {
+ listen 127.0.0.1:8086;
+ proxy_pass u_unlim;
+ }
+
+ server {
+ listen 127.0.0.1:8087;
+ proxy_pass u_lim;
+ }
+
+ server {
+ listen 127.0.0.1:8088;
+ proxy_pass u_backup;
+ }
+
+ server {
+ listen 127.0.0.1:8089;
+ proxy_pass u_backup_lim;
+ }
+
+ server {
+ listen 127.0.0.1:8090;
+ proxy_pass u_two;
+ }
+
+ server {
+ listen 127.0.0.1:8091;
+ proxy_pass u_some;
+ }
+
+ server {
+ listen 127.0.0.1:8092;
+ proxy_pass u_many;
+ }
+
+ server {
+ listen 127.0.0.1:8093;
+ proxy_pass u_weight;
+ }
+
+ server {
+ listen 127.0.0.1:8094;
+ proxy_pass u_lc;
+ }
+
+ server {
+ listen 127.0.0.1:8095;
+ proxy_pass u_lc_backup;
+ }
+
+ server {
+ listen 127.0.0.1:8096;
+ proxy_pass u_lc_backup_lim;
+ }
+}
+
+EOF
+
+$t->run_daemon(\&http_daemon, port(8081), port(8082), port(8085));
+$t->run();
+
+$t->waitforsocket('127.0.0.1:' . port(8081));
+$t->waitforsocket('127.0.0.1:' . port(8082));
+$t->waitforsocket('127.0.0.1:' . port(8085));
+
+###############################################################################
+
+my @ports = my ($p1, $p2) = (port(8081), port(8082));
+
+# two peers without max_conns
+
+is(parallel(8086, '/u_unlim?delay=0', 4), "$p1: 2, $p2: 2", 'unlimited');
+
+# reopen connection to test connection subtraction
+
+my @s = http_get_multi(8087, '/u_lim', 2, 1.1);
+get(8087, '/close');
+push @s, http_get_multi(8087, '/u_lim', 1, 1.1);
+get(8085, '/closeall');
+
+is(http_end_multi(\@s), "$p1: 3", 'conn subtraction');
+
+# simple test with limited peer
+
+is(parallel(8087, '/u_lim', 4), "$p1: 3", 'single');
+
+# limited peer with backup peer
+
+is(peers(8088, '/u_backup', 6), "$p1 $p1 $p2 $p2 $p2 $p2", 'backup');
+
+# peer and backup peer, both limited
+
+is(peers(8089, '/u_backup_lim', 6), "$p1 $p1 $p2 $p2 $p2 ", 'backup limited');
+
+# all peers limited
+
+is(parallel(8090, '/u_two', 4), "$p1: 1, $p2: 1", 'all peers');
+
+# subset of peers limited
+
+is(parallel(8091, '/u_some', 4), "$p1: 1, $p2: 3", 'some peers');
+
+# ensure that peer "weight" does not affect its max_conns limit
+
+is(parallel(8093, '/u_weight', 4), "$p1: 1, $p2: 3", 'weight');
+
+# peers with equal server value aggregate max_conns limit
+
+is(parallel(8092, '/u_many', 6), "$p1: 2, $p2: 4", 'equal peer');
+
+# least_conn balancer tests
+
+is(parallel(8094, '/u_lc', 4), "$p1: 1, $p2: 3", 'least_conn');
+is(peers(8095, '/u_lc_backup', 6), "$p1 $p1 $p2 $p2 $p2 $p2",
+ 'least_conn backup');
+is(peers(8096, '/u_lc_backup_lim', 6), "$p1 $p1 $p2 $p2 $p2 ",
+ 'least_conn backup limited');
+
+###############################################################################
+
+sub peers {
+ my ($port, $uri, $count) = @_;
+
+ my @sockets = http_get_multi($port, $uri, $count, 1.1);
+ get(8085, '/closeall');
+
+ join ' ', map { defined $_ && /X-Port: (\d+)/ && $1 }
+ map { http_end $_ } (@sockets);
+}
+
+sub parallel {
+ my ($port, $uri, $count) = @_;
+
+ my @sockets = http_get_multi($port, $uri, $count);
+ for (1 .. 20) {
+ last if IO::Select->new(@sockets)->can_read(3) == $count;
+ select undef, undef, undef, 0.01;
+ }
+ get(8085, '/closeall');
+ return http_end_multi(\@sockets);
+}
+
+sub get {
+ my ($port, $uri, %opts) = @_;
+ my $s = IO::Socket::INET->new(
+ Proto => 'tcp',
+ PeerAddr => '127.0.0.1',
+ PeerPort => port($port),
+ )
+ or die "Can't connect to nginx: $!\n";
+
+ http_get($uri, socket => $s, %opts);
+}
+
+sub http_get_multi {
+ my ($port, $uri, $count, $wait) = @_;
+ my @sockets;
+
+ for (0 .. $count - 1) {
+ $sockets[$_] = get($port, $uri, start => 1);
+ IO::Select->new($sockets[$_])->can_read($wait) if $wait;
+ }
+
+ return @sockets;
+}
+
+sub http_end_multi {
+ my ($sockets) = @_;
+ my %ports;
+
+ for my $sock (@$sockets) {
+ my $r = http_end($sock);
+ if ($r && $r =~ /X-Port: (\d+)/) {
+ $ports{$1} = 0 unless defined $ports{$1};
+ $ports{$1}++;
+ }
+ close $sock;
+ }
+
+ my @keys = map { my $p = $_; grep { $p == $_ } keys %ports } @ports;
+ return join ', ', map { $_ . ": " . $ports{$_} } @keys;
+}
+
+###############################################################################
+
+sub http_daemon {
+ my (@ports) = @_;
+ my (@socks, @clients);
+
+ for my $port (@ports) {
+ my $server = IO::Socket::INET->new(
+ Proto => 'tcp',
+ LocalHost => "127.0.0.1:$port",
+ Listen => 42,
+ Reuse => 1
+ )
+ or die "Can't create listening socket: $!\n";
+ push @socks, $server;
+ }
+
+ my $sel = IO::Select->new(@socks);
+ my $skip = 4;
+ my $count = 0;
+
+ local $SIG{PIPE} = 'IGNORE';
+
+OUTER:
+ while (my @ready = $sel->can_read) {
+ foreach my $fh (@ready) {
+ if (grep $_ == $fh, @socks) {
+ my $new = $fh->accept;
+ $new->autoflush(1);
+ $sel->add($new);
+ $count++;
+
+ } else {
+ my @busy = grep { $_->sockport() } @ready;
+
+ # finish other handles
+ if ($fh->sockport() == port(8085) && @busy > 1
+ && grep $_->sockport() != port(8085),
+ @busy)
+ {
+ next;
+ }
+
+ # late events in other handles
+ if ($fh->sockport() == port(8085) && @busy == 1
+ && $count > 1 && $skip-- > 0)
+ {
+ select undef, undef, undef, 0.1;
+ next OUTER;
+ }
+
+ my $rv = process_socket($fh, \@clients);
+ if ($rv == 1) {
+ $sel->remove($fh);
+ $fh->close;
+ }
+ if ($rv == 2) {
+ for (@clients) {
+ $sel->remove($_);
+ $_->close;
+ }
+ $sel->remove($fh);
+ $fh->close;
+ $skip = 4;
+ }
+ $count--;
+ }
+ }
+ }
+}
+
+# Returns true to close connection
+
+sub process_socket {
+ my ($client, $saved) = @_;
+ my $port = $client->sockport();
+
+ my $headers = '';
+ my $uri = '';
+
+ while (<$client>) {
+ $headers .= $_;
+ last if (/^\x0d?\x0a?$/);
+ }
+ return 1 if $headers eq '';
+
+ $uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
+ return 1 if $uri eq '';
+
+ Test::Nginx::log_core('||', "$port: response, 200");
+ print $client <<EOF;
+HTTP/1.1 200 OK
+X-Port: $port
+
+OK
+EOF
+
+ return 2 if $uri =~ /closeall/;
+ return 1 if $uri =~ /close/;
+
+ push @$saved, $client;
+ return 0;
+}
+
+###############################################################################
diff --git a/upstream_max_conns.t b/upstream_max_conns.t
index 2c4f3b4..5c9bbda 100644
--- a/upstream_max_conns.t
+++ b/upstream_max_conns.t
@@ -23,8 +23,8 @@
select STDERR; $| = 1;
select STDOUT; $| = 1;
-my $t = Test::Nginx->new()
- ->has(qw/http proxy rewrite upstream_least_conn upstream_ip_hash/);
+my $t = Test::Nginx->new()->has(qw/http proxy rewrite upstream_least_conn/)
+ ->has(qw/upstream_ip_hash/)->plan(14);
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -132,9 +132,8 @@
EOF
-
$t->run_daemon(\&http_daemon, port(8081), port(8082), port(8085));
-$t->run()->plan(14);
+$t->run();
$t->waitforsocket('127.0.0.1:' . port(8081));
$t->waitforsocket('127.0.0.1:' . port(8082));
@@ -148,18 +147,18 @@
is(parallel('/u_unlim?delay=0', 4), "$p1: 2, $p2: 2", 'unlimited');
-# simple test with limited peer
-
-is(parallel('/u_lim', 4), "$p1: 3", 'single');
-
# reopen connection to test connection subtraction
-my @s = http_get_multi('/u_lim', 1, 1.1);
+my @s = http_get_multi('/u_lim', 2, 1.1);
http_get('/u_lim/close');
push @s, http_get_multi('/u_lim', 1, 1.1);
http_get('/closeall');
-is(http_end_multi(\@s), "$p1: 2", 'conn subtraction');
+is(http_end_multi(\@s), "$p1: 3", 'conn subtraction');
+
+# simple test with limited peer
+
+is(parallel('/u_lim', 4), "$p1: 3", 'single');
# limited peer with backup peer