[PATCH] Tests: respecting Cache-Control stale-while-revalidate directive
Chris Branch
cbranch at cloudflare.com
Mon Feb 13 16:50:39 UTC 2017
# HG changeset patch
# User Chris Branch <cbranch at 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
+ }
+}
+
+###############################################################################
More information about the nginx-devel
mailing list