# HG changeset patch # User Chris Branch <cbra...@cloudflare.com> # Date 1487004211 0 # Mon Feb 13 16:43:31 2017 +0000 # Node ID cc76d621a5f95e9297cf38fd3e721f4a392c9bd2 # Parent bef8be8a622429f4ce07753f9133b15e5f08cac1 Tests: respecting Cache-Control stale-while-revalidate directive.
diff -r bef8be8a6224 -r cc76d621a5f9 proxy_cache_stale.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/proxy_cache_stale.t Mon Feb 13 16:43:31 2017 +0000 @@ -0,0 +1,197 @@ +#!/usr/bin/perl + +# Tests for http proxy cache use stale. + +############################################################################### + +use warnings; +use strict; + +use Test::More; + +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/http proxy cache/)->plan(22) + ->write_file_expand('nginx.conf', <<'EOF'); + +%%TEST_GLOBALS%% + +daemon off; + +events { +} + +http { + %%TEST_GLOBALS_HTTP%% + + proxy_cache_path %%TESTDIR%%/cache levels=1:2 + keys_zone=NAME:1m; + + server { + listen 127.0.0.1:8080; + server_name localhost; + + location / { + proxy_pass http://127.0.0.1:8081; + proxy_cache NAME; + + proxy_cache_lock on; + proxy_cache_use_stale updating; + proxy_cache_background_update on; + } + + location /nolock { + proxy_pass http://127.0.0.1:8081; + proxy_cache NAME; + + proxy_cache_use_stale updating; + proxy_cache_background_update on; + } + } +} + +EOF + +$t->run_daemon(\&http_fake_daemon); + +$t->run(); + +$t->waitforsocket('127.0.0.1:' . port(8081)); + +############################################################################### + +# sequential requests +for my $i (1 .. 3) { + like(http_get('/seq'), qr/response 1/, 'sequential request ' . $i); + # response 1 to request 1 is cached + # requests 2 & 3 can be served from cache instantly +} + +# wait for first cached request to become stale (max age = 2) +sleep 3; + +# request 4 should get stale response while revalidating in background +like(http_get('/seq'), qr/response 1/, 'stale response'); + +# wait for revalidated response to enter cache +sleep 1; + +# response to request 4 enters cache and is younger than max age +for my $i (1 .. 3) { + # request 5-7 should get response to request 4 from cache + like(http_get('/seq'), qr/response 2/, 'fresh response after stale'); +} + +# wait for response to exceed max-age and stale time (2 + 2 seconds) +sleep 5; + +# response must come from origin +like(http_get('/seq'), qr/response 3/, 'fresh response after invalidation'); + +# tests without cache lock + +my @sockets; + +# start 3 concurrent requests without locking; all go to origin simultaneously +for my $i (1 .. 3) { + $sockets[$i] = http_get('/nolock', start => 1); +} + +# combine results into one string, because we cannot assume ordering +my $rest = join '', map { http_end($sockets[$_]) } (1 .. 3); + +# each request should get a unique response as they missed cache +like($rest, qr/response 1/, 'nolock - first'); +like($rest, qr/response 2/, 'nolock - second'); +like($rest, qr/response 3/, 'nolock - third'); + +# making a new request immediately should get a cached response +like(http_get('/nolock'), qr/response 3/, 'nolock - last cached'); + +# wait for last cached request to become stale (max age = 2) +sleep 4; + +# start 3 concurrent requests without locking; all should get stale responses +# while revalidating, but go to origin in the background. +for my $i (1 .. 3) { + $sockets[$i] = http_get('/nolock', start => 1); +} +for my $i (1 .. 3) { + like(http_end($sockets[$i]), qr/response 3/, 'nolock - stale ' . $i); +} + +# wait for revalidated response to first request to enter cache +sleep 1; +like(http_get('/nolock'), qr/response 4/, 'nolock - one revalidated'); + +# wait for response to exceed max-age and stale time (2 + 2 seconds, and we +# slept for 1 second earlier) +sleep 4; + +# start 3 concurrent requests without locking; all go to origin simultaneously +for my $i (1 .. 3) { + $sockets[$i] = http_get('/nolock', start => 1); +} + +# combine results into one string, because we cannot assume ordering +$rest = join '', map { http_end($sockets[$_]) } (1 .. 3); + +# each request should get a unique response as they missed cache +like($rest, qr/response 5/, 'nolock - first after invalidation'); +like($rest, qr/response 6/, 'nolock - second after invalidation'); +like($rest, qr/response 7/, 'nolock - third after invalidation'); + +# making a new request immediately should get a cached response +like(http_get('/nolock'), qr/response 7/, 'nolock - last cached after invalidation'); + +############################################################################### + +sub http_fake_daemon { + my $server = IO::Socket::INET->new( + Proto => 'tcp', + LocalAddr => '127.0.0.1:' . port(8081), + Listen => 5, + Reuse => 1 + ) + or die "Can't create listening socket: $!\n"; + + my $num = 0; + my $uri = ''; + + while (my $client = $server->accept()) { + $client->autoflush(1); + + while (<$client>) { + if (/GET (.*) HTTP/ && $1 ne $uri) { + $uri = $1; + $num = 0; + } + + $uri = $1 if /GET (.*) HTTP/; + last if /^\x0d?\x0a?$/; + } + + next unless $uri; + + select(undef, undef, undef, 0.3); + + $num++; + print $client <<"EOF"; +HTTP/1.1 200 OK +Cache-Control: max-age=2; stale-while-revalidate=2; +Connection: close + +response $num +EOF + } +} + +############################################################################### _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel