[PATCH 2 of 2] Tests: Update and add tests for Age header
Hiroaki Nakamura
hnakamur at gmail.com
Mon Jul 1 13:47:39 UTC 2024
# HG changeset patch
# User Hiroaki Nakamura <hnakamur at gmail.com>
# Date 1719839239 -32400
# Mon Jul 01 22:07:19 2024 +0900
# Node ID dcb24ed2502869338b8a1f591cbe586edfce53c1
# Parent 685f47b210263988886db6fe15a95e177616de1f
Tests: Update and add tests for Age header.
diff -r 685f47b21026 -r dcb24ed25028 h2_proxy_cache_age.t
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/h2_proxy_cache_age.t Mon Jul 01 22:07:19 2024 +0900
@@ -0,0 +1,228 @@
+#!/usr/bin/perl
+
+# (C) Sergey Kandaurov
+# (C) Nginx, Inc.
+# (C) Hiroaki Nakamura
+
+# Tests for age in HTTP/2 proxy cache.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+use Test::Nginx::HTTP2;
+
+use POSIX qw/ ceil /;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/http http_v2 proxy cache/)->plan(10)
+ ->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+http {
+ %%TEST_GLOBALS_HTTP%%
+
+ proxy_cache_path %%TESTDIR%%/cache keys_zone=NAME:1m;
+ proxy_cache_path %%TESTDIR%%/cache2 keys_zone=NAME2:1m;
+
+ map $arg_slow $rate {
+ default 8k;
+ 1 90;
+ }
+
+ server {
+ listen 127.0.0.1:8080 http2;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8080.log debug;
+
+ location / {
+ proxy_pass http://127.0.0.1:8081;
+ proxy_cache NAME;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8081;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8081.log debug;
+
+ location / {
+ proxy_pass http://127.0.0.1:8082;
+ proxy_cache NAME2;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8082;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8082.log debug;
+
+ location / {
+ add_header Cache-Control s-maxage=$arg_ttl;
+ limit_rate $rate;
+ }
+ }
+}
+
+EOF
+
+$t->write_file('t.html', 'SEE-THIS');
+$t->write_file('t2.html', 'SEE-THIS');
+$t->write_file('t3.html', 'SEE-THIS');
+
+# suppress deprecation warning
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+###############################################################################
+
+my $s = Test::Nginx::HTTP2->new();
+
+my ($path, $sid, $frames, $frame, $t1, $age);
+
+# normal origin
+
+wait_until_next_second();
+
+$path = '/t.html?ttl=2';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age first');
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 0, 'age hit');
+
+select undef, undef, undef, 2.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 2, 'age hit');
+
+select undef, undef, undef, 1.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age updated');
+
+SKIP: {
+skip 'no exec on win32', 3 if $^O eq 'MSWin32';
+
+# slow origin
+
+wait_until_next_second();
+
+$path = '/t2.html?ttl=10&slow=1';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'slow origin first');
+
+select undef, undef, undef, 2.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 2, 'slow origin hit');
+
+select undef, undef, undef, 9.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'slow origin updated');
+$t1 = time();
+
+$t->stop();
+
+select undef, undef, undef, 1.0;
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+$age = time() - $t1;
+
+$s = Test::Nginx::HTTP2->new();
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, $age, 'age after restart');
+
+}
+
+# update age after restart
+
+wait_until_next_second();
+
+$path = '/t3.html?ttl=20';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age before restart');
+$t1 = time();
+
+$t->stop();
+
+select undef, undef, undef, 1.0;
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+$age = time() - $t1;
+
+$s = Test::Nginx::HTTP2->new();
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, $age, 'age after restart');
+
+$t->stop();
+
+###############################################################################
+
+# Wait until the next second boundary.
+# Calling this before sending a request increases the likelihood that the
+# timestamp value does not cross into the next second while sending a request
+# and receiving a response.
+sub wait_until_next_second {
+ my $now = time();
+ my $next_second = ceil($now);
+ my $sleep = $next_second - $now;
+ select undef, undef, undef, $sleep;
+}
+
+###############################################################################
diff -r 685f47b21026 -r dcb24ed25028 h2_ssl_proxy_cache_age.t
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/h2_ssl_proxy_cache_age.t Mon Jul 01 22:07:19 2024 +0900
@@ -0,0 +1,274 @@
+#!/usr/bin/perl
+
+# (C) Sergey Kandaurov
+# (C) Nginx, Inc.
+# (C) Hiroaki Nakamura
+
+# Tests for age in HTTP/2 ssl proxy cache.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+use Test::Nginx::HTTP2;
+
+use POSIX qw/ ceil /;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()
+ ->has(qw/http http_ssl http_v2 proxy cache socket_ssl/)->plan(13)
+ ->has_daemon('openssl');
+
+$t->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+http {
+ %%TEST_GLOBALS_HTTP%%
+
+ proxy_cache_path %%TESTDIR%%/cache keys_zone=NAME:1m;
+ proxy_cache_path %%TESTDIR%%/cache2 keys_zone=NAME2:1m;
+
+ map $arg_slow $rate {
+ default 8k;
+ 1 90;
+ }
+
+ server {
+ listen 127.0.0.1:8080 http2 ssl;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8080.log debug;
+
+ ssl_certificate_key localhost.key;
+ ssl_certificate localhost.crt;
+
+ location / {
+ proxy_pass http://127.0.0.1:8081;
+ proxy_cache NAME;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8081;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8081.log debug;
+
+ location / {
+ proxy_pass http://127.0.0.1:8082;
+ proxy_cache NAME2;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8082;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8082.log debug;
+
+ location / {
+ add_header Cache-Control s-maxage=$arg_ttl;
+ limit_rate $rate;
+ }
+ }
+}
+
+EOF
+
+$t->write_file('openssl.conf', <<EOF);
+[ req ]
+default_bits = 2048
+encrypt_key = no
+distinguished_name = req_distinguished_name
+[ req_distinguished_name ]
+EOF
+
+my $d = $t->testdir();
+
+foreach my $name ('localhost') {
+ system('openssl req -x509 -new '
+ . "-config $d/openssl.conf -subj /CN=$name/ "
+ . "-out $d/$name.crt -keyout $d/$name.key "
+ . ">>$d/openssl.out 2>&1") == 0
+ or die "Can't create certificate for $name: $!\n";
+}
+
+$t->write_file('t.html', 'SEE-THIS');
+$t->write_file('t2.html', 'SEE-THIS');
+$t->write_file('t3.html', 'SEE-THIS');
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+###############################################################################
+
+my $s = getconn(port(8080));
+ok($s, 'ssl connection');
+
+my ($path, $sid, $frames, $frame, $t1, $age);
+
+# normal origin
+
+wait_until_next_second();
+
+$path = '/t.html?ttl=2';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age first');
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 0, 'age hit');
+
+select undef, undef, undef, 2.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 2, 'age hit');
+
+select undef, undef, undef, 1.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age updated');
+
+# slow origin
+
+SKIP: {
+skip 'no exec on win32', 3 if $^O eq 'MSWin32';
+
+wait_until_next_second();
+
+$path = '/t2.html?ttl=10&slow=1';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'slow origin first');
+
+select undef, undef, undef, 2.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 2, 'slow origin hit');
+
+select undef, undef, undef, 9.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'slow origin updated');
+$t1 = time();
+
+$t->stop();
+
+select undef, undef, undef, 1.0;
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+$age = time() - $t1;
+
+$s = getconn(port(8080));
+ok($s, 'ssl connection');
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, $age, 'age after restart');
+
+}
+
+# update age after restart
+
+$path = '/t3.html?ttl=20';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age before restart');
+$t1 = time();
+
+$t->stop();
+
+select undef, undef, undef, 1.0;
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+$age = time() - $t1;
+
+$s = getconn(port(8080));
+ok($s, 'ssl connection');
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, $age, 'age after restart');
+
+$t->stop();
+
+###############################################################################
+
+sub getconn {
+ my ($port) = @_;
+ my $s;
+
+ eval {
+ my $sock = Test::Nginx::HTTP2::new_socket($port, SSL => 1,
+ alpn => 'h2');
+ $s = Test::Nginx::HTTP2->new($port, socket => $sock)
+ if $sock->alpn_selected();
+ };
+
+ return $s if defined $s;
+
+ eval {
+ my $sock = Test::Nginx::HTTP2::new_socket($port, SSL => 1,
+ npn => 'h2');
+ $s = Test::Nginx::HTTP2->new($port, socket => $sock)
+ if $sock->next_proto_negotiated();
+ };
+
+ return $s;
+}
+
+# Wait until the next second boundary.
+# Calling this before sending a request increases the likelihood that the
+# timestamp value does not cross into the next second while sending a request
+# and receiving a response.
+sub wait_until_next_second {
+ my $now = time();
+ my $next_second = ceil($now);
+ my $sleep = $next_second - $now;
+ select undef, undef, undef, $sleep;
+}
+
+###############################################################################
diff -r 685f47b21026 -r dcb24ed25028 h3_proxy_cache_age.t
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/h3_proxy_cache_age.t Mon Jul 01 22:07:19 2024 +0900
@@ -0,0 +1,222 @@
+#!/usr/bin/perl
+
+# (C) Sergey Kandaurov
+# (C) Nginx, Inc.
+# (C) Hiroaki Nakamura
+
+# Tests for age in HTTP/3 proxy cache.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+use Test::Nginx::HTTP3;
+
+use POSIX qw/ ceil /;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/http http_v3 proxy cryptx/)
+ ->has_daemon('openssl')->plan(9)
+ ->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+http {
+ %%TEST_GLOBALS_HTTP%%
+
+ ssl_certificate_key localhost.key;
+ ssl_certificate localhost.crt;
+
+ log_format test $uri:$status:$request_completion;
+
+ proxy_cache_path %%TESTDIR%%/cache keys_zone=NAME:1m;
+
+ map $arg_slow $rate {
+ default 8k;
+ 1 90;
+ }
+
+ server {
+ listen 127.0.0.1:%%PORT_8980_UDP%% quic;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8080.log debug;
+
+ location / {
+ proxy_pass http://127.0.0.1:8081/;
+ proxy_cache NAME;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8081;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8081.log debug;
+
+ location / {
+ proxy_pass http://127.0.0.1:8082;
+ proxy_cache NAME;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8082;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8082.log debug;
+
+ location / {
+ add_header Cache-Control s-maxage=$arg_ttl;
+ limit_rate $rate;
+ }
+ }
+}
+
+EOF
+
+$t->write_file('openssl.conf', <<EOF);
+[ req ]
+default_bits = 2048
+encrypt_key = no
+distinguished_name = req_distinguished_name
+[ req_distinguished_name ]
+EOF
+
+my $d = $t->testdir();
+
+foreach my $name ('localhost') {
+ system('openssl req -x509 -new '
+ . "-config $d/openssl.conf -subj /CN=$name/ "
+ . "-out $d/$name.crt -keyout $d/$name.key "
+ . ">>$d/openssl.out 2>&1") == 0
+ or die "Can't create certificate for $name: $!\n";
+}
+
+my $content = 'SEE-THIS';
+$t->write_file('t.html', $content);
+$t->write_file('t2.html', $content);
+$t->write_file('t3.html', $content);
+$t->run();
+
+###############################################################################
+
+my $s = Test::Nginx::HTTP3->new();
+
+my ($path, $sid, $frames, $frame, $t1, $age);
+
+# normal origin
+
+wait_until_next_second();
+
+$path = '/t.html?ttl=2';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age first');
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 0, 'age hit');
+
+select undef, undef, undef, 2.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 2, 'age hit');
+
+select undef, undef, undef, 1.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age updated');
+
+# slow origin
+
+wait_until_next_second();
+
+$path = '/t2.html?ttl=4&slow=1';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'slow origin first');
+
+select undef, undef, undef, 2.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, 2, 'slow origin hit');
+
+select undef, undef, undef, 3.0;
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'slow origin updated');
+
+# update age after restart
+
+$path = '/t3.html?ttl=20';
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, undef, 'age before restart');
+$t1 = time();
+
+$t->stop();
+
+select undef, undef, undef, 1.0;
+
+open OLDERR, ">&", \*STDERR; close STDERR;
+$t->run();
+open STDERR, ">&", \*OLDERR;
+
+$age = time() - $t1;
+
+$s = Test::Nginx::HTTP3->new();
+
+$sid = $s->new_stream({ path => $path });
+$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
+($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
+is($frame->{headers}->{'age'}, $age, 'age after restart');
+
+$t->stop();
+
+###############################################################################
+
+# Wait until the next second boundary.
+# Calling this before sending a request increases the likelihood that the
+# timestamp value does not cross into the next second while sending a request
+# and receiving a response.
+sub wait_until_next_second {
+ my $now = time();
+ my $next_second = ceil($now);
+ my $sleep = $next_second - $now;
+ select undef, undef, undef, $sleep;
+}
+
+###############################################################################
diff -r 685f47b21026 -r dcb24ed25028 proxy_cache_age.t
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proxy_cache_age.t Mon Jul 01 22:07:19 2024 +0900
@@ -0,0 +1,195 @@
+#!/usr/bin/perl
+
+# (C) Maxim Dounin
+# (C) Hiroaki Nakamura
+
+# Tests for age in http proxy cache.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+use Socket qw/ CRLF /;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+
+use POSIX qw/ ceil /;
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/http proxy cache/)->plan(10)
+ ->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;
+ proxy_cache_path %%TESTDIR%%/cache2 levels=1:2
+ keys_zone=NAME2:1m;
+
+ map $arg_slow $rate {
+ default 8k;
+ 1 100;
+ }
+
+ server {
+ listen 127.0.0.1:8080;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8080.log debug;
+
+ location / {
+ proxy_pass http://127.0.0.1:8081;
+ proxy_cache NAME;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ add_header parent_date $upstream_http_date;
+ add_header child_msec $msec;
+ add_header child_cache $upstream_cache_status;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8081;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8081.log debug;
+
+ location / {
+ proxy_pass http://127.0.0.1:8082;
+ proxy_cache NAME2;
+ proxy_http_version 1.1;
+ proxy_cache_revalidate on;
+ add_header origin_date $upstream_http_date;
+ add_header parent_msec $msec;
+ add_header parent_cache $upstream_cache_status;
+ }
+ }
+
+ server {
+ listen 127.0.0.1:8082;
+ server_name localhost;
+ error_log %%TESTDIR%%/error8082.log debug;
+
+ location / {
+ add_header Cache-Control $http_x_cache_control;
+ limit_rate $rate;
+ add_header origin_msec $msec;
+ }
+ }
+}
+
+EOF
+
+$t->write_file('t.html', 'SEE-THIS');
+$t->write_file('t2.html', 'SEE-THIS');
+$t->write_file('t3.html', 'SEE-THIS');
+
+$t->run();
+
+###############################################################################
+
+# normal origin
+
+wait_until_next_second();
+
+unlike(get('/t.html', 's-maxage=2'), qr/\r\nAge: /, 'age first');
+like(get('/t.html', 's-maxage=2'), qr/\r\nAge: 0\r\n/, 'age hit');
+
+sleep 2;
+
+like(get('/t.html', 's-maxage=2'), qr/\r\nAge: 2\r\n/, 'age hit');
+
+sleep 1;
+
+unlike(http_get('/t.html'), qr/\r\nAge: /, 'age updated');
+
+# slow origin
+
+SKIP: {
+skip 'no exec on win32', 3 if $^O eq 'MSWin32';
+
+wait_until_next_second();
+
+unlike(get('/t2.html?slow=1', 's-maxage=4'), qr/\r\nAge: /,
+ 'slow origin first');
+
+sleep 2;
+
+like(http_get('/t2.html?slow=1'), qr/\r\nAge: 2\r\n/, 'slow origin hit');
+
+sleep 3;
+
+unlike(http_get('/t2.html?slow=1'), qr/\r\nAge: /, 'slow origin updated');
+my $t1 = time();
+
+$t->stop();
+
+sleep 1;
+
+$t->run();
+
+my $age = time() - $t1;
+like(http_get('/t2.html?slow=1'), qr/\r\nAge: $age\r\n/,
+ 'age after restart');
+
+}
+
+# update age after restart
+
+wait_until_next_second();
+
+unlike(get('/t3.html', 's-maxage=20'), qr/\r\nAge: /, 'age before restart');
+my $t1 = time();
+
+$t->stop();
+
+sleep 1;
+
+$t->run();
+
+my $age = time() - $t1;
+like(http_get('/t3.html'), qr/\r\nAge: $age\r\n/,
+ 'age after restart');
+
+$t->stop();
+
+###############################################################################
+
+sub get {
+ my ($url, $extra, %extra) = @_;
+ return http(<<EOF, %extra);
+GET $url HTTP/1.1
+Host: localhost
+Connection: close
+X-Cache-Control: $extra
+
+EOF
+}
+
+# Wait until the next second boundary.
+# Calling this before sending a request increases the likelihood that the
+# timestamp value does not cross into the next second while sending a request
+# and receiving a response.
+sub wait_until_next_second {
+ my $now = time();
+ my $next_second = ceil($now);
+ my $sleep = $next_second - $now;
+ select undef, undef, undef, $sleep;
+}
+
+###############################################################################
diff -r 685f47b21026 -r dcb24ed25028 proxy_cache_use_stale.t
--- a/proxy_cache_use_stale.t Mon Jul 01 22:07:12 2024 +0900
+++ b/proxy_cache_use_stale.t Mon Jul 01 22:07:19 2024 +0900
@@ -206,7 +206,8 @@ like(http_get('/regexp.html'), qr/HIT/,
$t->write_file('t6.html', 'SEE-THAT');
-my $s = get('/t6.html', 'max-age=1, stale-while-revalidate=2', start => 1);
+# max-age must be 5 here since response delay is 4 seconds.
+my $s = get('/t6.html', 'max-age=5, stale-while-revalidate=2', start => 1);
select undef, undef, undef, 0.2;
like(http_get('/t6.html'), qr/UPDATING.*SEE-THIS/s, 's-w-r - updating');
like(http_end($s), qr/STALE.*SEE-THIS/s, 's-w-r - updating stale');
More information about the nginx-devel
mailing list