Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 111 additions & 2 deletions proxy_next_upstream.t
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/perl

# (C) Maxim Dounin
# (C) Nginx, Inc.

# Tests for http proxy module, proxy_next_upstream directive.

Expand All @@ -21,7 +22,7 @@ use Test::Nginx;
select STDERR; $| = 1;
select STDOUT; $| = 1;

my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(8);
my $t = Test::Nginx->new()->has(qw/http proxy rewrite/);

$t->write_file_expand('nginx.conf', <<'EOF');

Expand Down Expand Up @@ -50,6 +51,15 @@ http {
server 127.0.0.1:8082 down;
}

upstream u4 {
server 127.0.0.1:8081;
}

upstream u5 {
server 127.0.0.1:8083;
server 127.0.0.1:8084;
}

server {
listen 127.0.0.1:8080;
server_name localhost;
Expand All @@ -74,6 +84,83 @@ http {
proxy_pass http://u3;
proxy_next_upstream http_404;
}

# no_live reinitializes peer selection once every peer has been
# tried, so that retries continue up to proxy_next_upstream_tries

location = /no_live {
proxy_pass http://u2/all/;
proxy_next_upstream http_404 no_live;
proxy_next_upstream_tries 3;
proxy_intercept_errors on;
error_page 404 = /no_live/status;
}

# a single server, retried more times than there are servers

location = /no_live/single {
proxy_pass http://u4/all/;
proxy_next_upstream http_404 no_live;
proxy_next_upstream_tries 3;
proxy_intercept_errors on;
error_page 404 = /no_live/addr;
}

# an upstream created from an address rather than an upstream block

location = /no_live/resolved {
set $back 127.0.0.1:%%PORT_8081%%;
proxy_pass http://$back/all/;
proxy_next_upstream http_404 no_live;
proxy_next_upstream_tries 3;
proxy_intercept_errors on;
error_page 404 = /no_live/status;
}

# without proxy_next_upstream_tries there is nothing to retry up to,
# and peers are tried once

location = /no_live/unlimited {
proxy_pass http://u2/all/;
proxy_next_upstream http_404 no_live;
proxy_intercept_errors on;
error_page 404 = /no_live/status;
}

# peers disabled by max_fails are retried as well

location = /no_live/dead {
proxy_pass http://u5;
proxy_next_upstream error no_live;
proxy_next_upstream_tries 4;
proxy_intercept_errors on;
error_page 502 = /no_live/status;
}

location = /no_live/status {
return 200 "x${upstream_status}x";
}

location = /no_live/addr {
return 200 "x${upstream_addr}x";
}

# each upstream request has its own proxy_next_upstream_tries budget

location = /chain {
proxy_pass http://u2/all/;
proxy_next_upstream http_404;
proxy_next_upstream_tries 2;
proxy_intercept_errors on;
error_page 404 = /chain/second;
}

location = /chain/second {
proxy_pass http://u2/all/;
proxy_next_upstream http_404;
proxy_next_upstream_tries 2;
add_header X-Upstream-Status "x${upstream_status}x" always;
}
}

server {
Expand Down Expand Up @@ -111,7 +198,7 @@ http {

EOF

$t->run();
$t->try_run('no no_live')->plan(14);

###############################################################################

Expand Down Expand Up @@ -148,4 +235,26 @@ like(http_get('/all/rr'),

like(http_get('/down/'), qr/Not Found/, 'all tried with down');

# make sure peers are tried again once all of them have been tried

like(http_get('/no_live'), qr/x404, 404, 404x/, 'no_live');
like(http_get('/no_live/single'),
qr/x127.0.0.1:$p1, 127.0.0.1:$p1, 127.0.0.1:${p1}x/,
'no_live single server');
like(http_get('/no_live/resolved'), qr/x404, 404, 404x/, 'no_live resolved');

# make sure no_live alone does not change anything

like(http_get('/no_live/unlimited'), qr/x404, 404x/, 'no_live no tries');

# make sure peers disabled by max_fails are retried as well

like(http_get('/no_live/dead'), qr/x502, 502, 502, 502x/, 'no_live no live');

# make sure a second upstream request in the same request is not limited
# by the attempts for the first one

like(http_get('/chain'), qr/x404, 404 : 404, 404x/,
'tries per upstream request');

###############################################################################
137 changes: 137 additions & 0 deletions proxy_next_upstream_delay.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#!/usr/bin/perl

# (C) Nginx, Inc.

# Tests for http proxy module, proxy_next_upstream_delay directive.

###############################################################################

use warnings;
use strict;

use Test::More;
use Time::HiRes qw(time);
use IO::Select;

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 rewrite ssi/);

$t->write_file_expand('nginx.conf', <<'EOF');

%%TEST_GLOBALS%%

daemon off;

events {
}

http {
%%TEST_GLOBALS_HTTP%%

upstream u {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}

upstream dead {
server 127.0.0.1:8083;
server 127.0.0.1:8084;
}

server {
listen 127.0.0.1:8080;
server_name localhost;

root %%TESTDIR%%;

location = /delay {
proxy_pass http://u/all/;
proxy_next_upstream http_404 no_live;
proxy_next_upstream_tries 3;
proxy_next_upstream_delay 1s;
proxy_intercept_errors on;
error_page 404 = /status;
}

location = /status {
return 200 "x${upstream_status}x";
}

location = /sub {
proxy_pass http://dead;
proxy_next_upstream error no_live;
proxy_next_upstream_tries 3;
proxy_next_upstream_delay 100ms;
}

location / {
ssi on;
}
}

server {
listen 127.0.0.1:8081;
listen 127.0.0.1:8082;
server_name localhost;

location /all/ {
return 404;
}
}
}

EOF

$t->write_file('sub.html', '<!--#include virtual="/sub" -->');

$t->try_run('no proxy_next_upstream_delay')->plan(5);

###############################################################################

# 3 tries over 2 peers and the delay is fired once

my $t1 = time();
like(http_get('/delay'), qr/x404, 404, 404x/, 'delayed retry');

my $elapsed = time() - $t1;
cmp_ok($elapsed, '>=', 1, 'delay applied');
cmp_ok($elapsed, '<', 2, 'delay applied once');

# the pending retry timer has to be removed when the request finalized

my $s = http_get('/delay', start => 1);
select undef, undef, undef, 0.2;
close $s;
select undef, undef, undef, 1.2;

like(http_get('/delay'), qr/x404, 404, 404x/, 'client abort during delay');

# a subrequest finalized from the retry timer has to wake up its parent

like(get_slow('/sub.html'), qr/502 Bad Gateway/, 'subrequest parent woken');

###############################################################################

sub get_slow {
my ($uri) = @_;

my $s = http_get($uri, start => 1);

unless (IO::Select->new($s)->can_read(2)) {
close $s;
return '';
}

return http_end($s);
}

###############################################################################