From e746e23607978f1fbecfbbb88c8e7eaedf437b95 Mon Sep 17 00:00:00 2001 From: Brian Neradt Date: Mon, 27 Jun 2022 21:34:06 +0000 Subject: [PATCH] proxy_serve_stale: Test updates This updates the proxy_serve_stale test to run more quickly (about 15 seconds instead of about 2 minutes). While doing so, the test is also converted to use Proxy Verifier. --- .../gold/proxy_serve_stale.gold | 58 ------- .../proxy_protocol/proxy_serve_stale.test.py | 101 ++++++------- .../replay/proxy_serve_stale.replay.yaml | 142 ++++++++++++++++++ 3 files changed, 189 insertions(+), 112 deletions(-) delete mode 100644 tests/gold_tests/proxy_protocol/gold/proxy_serve_stale.gold create mode 100644 tests/gold_tests/proxy_protocol/replay/proxy_serve_stale.replay.yaml diff --git a/tests/gold_tests/proxy_protocol/gold/proxy_serve_stale.gold b/tests/gold_tests/proxy_protocol/gold/proxy_serve_stale.gold deleted file mode 100644 index d3654629fb9..00000000000 --- a/tests/gold_tests/proxy_protocol/gold/proxy_serve_stale.gold +++ /dev/null @@ -1,58 +0,0 @@ -`` -> GET / HTTP/1.1 -> Host: `` -> User-Agent: curl/`` -> Accept: */* -`` -< HTTP/1.1 200 OK -< Server: ATS/{} -< Accept-Ranges: bytes -< Content-Length: 6 -< Cache-Control: public, max-age=5 -< Age: `` -< Date: `` -< Connection: keep-alive -< Warning: `` -`` -> GET / HTTP/1.1 -> Host: `` -> User-Agent: curl/`` -> Accept: */* -`` -< HTTP/1.1 200 OK -< Server: ATS/{} -< Accept-Ranges: bytes -< Content-Length: 6 -< Cache-Control: public, max-age=5 -< Age: `` -< Date: `` -< Connection: keep-alive -< Warning: `` -`` -> GET / HTTP/1.1 -> Host: `` -> User-Agent: curl/`` -> Accept: */* -`` -< HTTP/1.1 200 OK -< Server: ATS/{} -< Accept-Ranges: bytes -< Content-Length: 6 -< Cache-Control: public, max-age=5 -< Age: `` -< Date: `` -< Connection: keep-alive -< Warning: `` -`` -> GET / HTTP/1.1 -> Host: `` -> User-Agent: curl/`` -> Accept: */* -`` -< HTTP/1.1 502 Next Hop Connection Failed -< Date: `` -< Connection: keep-alive -< Server: ATS/{} -< Cache-Control: `` -< Content-Length: `` -`` diff --git a/tests/gold_tests/proxy_protocol/proxy_serve_stale.test.py b/tests/gold_tests/proxy_protocol/proxy_serve_stale.test.py index ec25592f7eb..e012d394f74 100644 --- a/tests/gold_tests/proxy_protocol/proxy_serve_stale.test.py +++ b/tests/gold_tests/proxy_protocol/proxy_serve_stale.test.py @@ -1,6 +1,6 @@ -''' +""" Test child proxy serving stale content when parents are exhausted -''' +""" # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -17,64 +17,57 @@ # See the License for the specific language governing permissions and # limitations under the License. + +Test.testName = "proxy_serve_stale" Test.ContinueOnFail = True -# Set up hierarchical caching processes -ts_child = Test.MakeATSProcess("ts_child") -# Parent ATS process is not created to mock parent being "down" -# but parent hostname is recognized in hostdb to match with child successfully -ts_parent_hostname = "localhost:82" -server = Test.MakeOriginServer("server") -Test.testName = "STALE" -# Request from client -request_header = {"headers": - "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n", - "timestamp": "1469733493.993", - "body": ""} -# Expected response from the origin server -response_header = {"headers": - "HTTP/1.1 200 OK\r\nConnection: close\r\nCache-Control: max-age=5,public\r\n\r\n", - "timestamp": "1469733493.993", - "body": "CACHED"} +class ProxyServeStaleTest: + """Verify that stale content is served when the parent is down.""" + + single_transaction_replay = "replay/proxy_serve_stale.replay.yaml" + ts_parent_hostname = "localhost:82" + + def __init__(self): + """Initialize the test.""" + self._configure_server() + self._configure_ts() -# Add request/response -server.addResponse("sessionlog.log", request_header, response_header) + def _configure_server(self): + self.server = Test.MakeVerifierServerProcess( + "server", + self.single_transaction_replay) -# Config child proxy to route to parent proxy -ts_child.Disk.records_config.update({ - 'proxy.config.http.parent_proxy.fail_threshold': 2, - 'proxy.config.http.parent_proxy.total_connect_attempts': 1, - 'proxy.config.http.cache.max_stale_age': 90, - 'proxy.config.http.parent_proxy.self_detect': 0, -}) -ts_child.Disk.parent_config.AddLine( - f'dest_domain=. parent="{ts_parent_hostname}" round_robin=consistent_hash go_direct=false' -) -ts_child.Disk.remap_config.AddLine( - f'map http://localhost:{ts_child.Variables.port} http://localhost:{server.Variables.Port}' -) + def _configure_ts(self): + self.ts_child = Test.MakeATSProcess("ts_child") + # Config child proxy to route to parent proxy + self.ts_child.Disk.records_config.update({ + 'proxy.config.http.parent_proxy.fail_threshold': 2, + 'proxy.config.http.parent_proxy.total_connect_attempts': 1, + 'proxy.config.http.cache.max_stale_age': 10, + 'proxy.config.http.parent_proxy.self_detect': 0, + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http|dns|parent_proxy', + }) + self.ts_child.Disk.parent_config.AddLine( + f'dest_domain=. parent="{self.ts_parent_hostname}" round_robin=consistent_hash go_direct=false' + ) + self.ts_child.Disk.remap_config.AddLine( + f'map / http://localhost:{self.server.Variables.http_port}' + ) -stale_output = "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public, max-age=5\n\nCACHED" + def run(self): + """Run the test cases.""" + tr = Test.AddTestRun() + tr.AddVerifierClientProcess( + 'client', + self.single_transaction_replay, + http_ports=[self.ts_child.Variables.port]) + tr.Processes.Default.ReturnCode = 0 + tr.StillRunningAfter = self.ts_child + tr.Processes.Default.StartBefore(self.server) + tr.Processes.Default.StartBefore(self.ts_child) -# Testing scenarios -# 1. Child proxy serves stale with warning header when parent returns invalid response -# 2. Child proxy serves stale with warning header when parent failcount meets fail_threshold and parent is unavailable -# 3. Child proxy does not serve stale when object is past the max_stale_age expiration date -curl_request = ( - f'curl -X PUSH -d "{stale_output}" "http://localhost:{ts_child.Variables.port}";' - f'sleep 10; curl -s -v http://localhost:{ts_child.Variables.port};' # 1. serve stale with warning, failcount=1 - f'curl -s -v http://localhost:{ts_child.Variables.port};' # 1. serve stale with warning, failcount=2 - f'curl -s -v http://localhost:{ts_child.Variables.port};' # 2. serve stale with warning, parent unavailable - f'sleep 90; curl -v http://localhost:{ts_child.Variables.port}' # 3. max_stale_age expires, stale content cannot be served -) -# Test case for when parent server is down but child proxy can serve cache object -tr = Test.AddTestRun() -tr.Processes.Default.Command = curl_request -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.StartBefore(server) -tr.Processes.Default.StartBefore(ts_child) -tr.Processes.Default.Streams.stderr = "gold/proxy_serve_stale.gold" -tr.StillRunningAfter = ts_child +ProxyServeStaleTest().run() diff --git a/tests/gold_tests/proxy_protocol/replay/proxy_serve_stale.replay.yaml b/tests/gold_tests/proxy_protocol/replay/proxy_serve_stale.replay.yaml new file mode 100644 index 00000000000..9a04d86e247 --- /dev/null +++ b/tests/gold_tests/proxy_protocol/replay/proxy_serve_stale.replay.yaml @@ -0,0 +1,142 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# This replay file assumes that caching is enabled and +# proxy.config.http.cache.ignore_client_cc_max_age is set to 0 so that we can +# test max-age in the client requests. +# + +meta: + version: "1.0" + + blocks: + + # All responses should be served out of the cache for this test, so this + # response from the origin should never been seen. + - origin_response: &origin_response + server-response: + status: 500 + reason: "Internal Server Error" + headers: + fields: + - [ Content-Length, 16 ] + - [ X-Response, should_not_see ] + + +sessions: +- transactions: + + # Use a PUSH to populate the cache with a max-age response of 2 seconds. + - client-request: + method: "PUSH" + version: "1.1" + url: /a/path + headers: + fields: + - [ Host, example.com ] + - [ uuid, push ] + - [ X-Request, push ] + - [ Content-Length, 113 ] + content: + encoding: plain + data: "HTTP/1.1 200 OK\nServer: ATS/10.0.0\nAccept-Ranges: bytes\nContent-Length: 6\nCache-Control: public,max-age=2\n\nCACHED" + + <<: *origin_response + + # Verify that ATS confirmed that the PUSH was successful, which it does + # with a 201 response. + proxy-response: + status: 201 + + # Issue a GET request after the 2 second max-age. The test configures the + # parent ATS cache to be non-existent, so it appears as down to this ATS + # host. After this transaction, failcount == 1. + - client-request: + delay: 4s + + method: "GET" + version: "1.1" + url: /a/path + headers: + fields: + - [ Host, example.com ] + - [ uuid, first_stale ] + - [ X-Request, first_stale ] + + <<: *origin_response + + proxy-response: + status: 200 + headers: + fields: + - [ Cache-Control, {value: max-age=2, as: contains } ] + + # Request the stale resource a second time. After this transaction, failcount == 2. + - client-request: + method: "GET" + version: "1.1" + url: /a/path + headers: + fields: + - [ Host, example.com ] + - [ uuid, second_stale ] + - [ X-Request, second_stale ] + + <<: *origin_response + + proxy-response: + status: 200 + + # Request the stale resource a third time. Here the failcount will exceed the + # fail_threshold of 2. ATS will still serve the stale entry, but it now + # considers the parent unavailable. + - client-request: + method: "GET" + version: "1.1" + url: /a/path + headers: + fields: + - [ Host, example.com ] + - [ uuid, third_stale ] + - [ X-Request, third_stale ] + + <<: *origin_response + + proxy-response: + status: 200 + + # Request the stale resource after enough delay to guarantee that the cached + # object's age exceeds max_stale_age (10 seconds). Note that we already + # delayed 4 seconds in a previous transaction. ATS should not serve the stale + # entry anymore because it is too old. + - client-request: + delay: 8s + + method: "GET" + version: "1.1" + url: /a/path + headers: + fields: + - [ Host, example.com ] + - [ uuid, past_max_age ] + - [ X-Request, past_max_age ] + + <<: *origin_response + + # At this point, ATS should respond with a 502 since max_stale_age is exceeded. + proxy-response: + status: 502