| ''' |
| ''' |
| # 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. |
| |
| import os |
| import urllib.parse |
| |
| Test.Summary = ''' |
| Test prefetch.so plugin (simple mode). |
| ''' |
| |
| origin = Test.MakeOriginServer("origin") |
| |
| asset_name = 'request.txt' |
| pf_name = 'prefetch.txt' |
| pf_header = f'Cmcd-Request: foo=12,nor="{pf_name}",bar=42' |
| |
| request_header = { |
| "headers": |
| f"GET /tests/{asset_name} HTTP/1.1\r\n" |
| "Host: does.not.matter\r\n" # But cant be omitted |
| f"{pf_header}\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": "" |
| } |
| response_header = { |
| "headers": "HTTP/1.1 200 OK\r\n" |
| "Connection: close\r\n" |
| "Cache-control: max-age=60\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": f"This is the body for {asset_name}\n" |
| } |
| origin.addResponse("sessionlog.json", request_header, response_header) |
| |
| # query string |
| query_name = 'query?this=foo&that' |
| query_pf_name = 'query?bar=baz' |
| query_pf_header = f'Cmcd-Request: nor="{query_pf_name}"' |
| |
| # nor field may be percent encoded |
| query_pf_perc_name = urllib.parse.quote(query_pf_name) |
| query_pf_perc_header = f'Cmcd-Request: nor="{query_pf_perc_name}"' |
| |
| request_header = { |
| "headers": |
| f"GET /tests/{query_name} HTTP/1.1\r\n" |
| "Host: does.not.matter\r\n" # But cant be omitted |
| f"{query_pf_perc_header}\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": "" |
| } |
| response_header = { |
| "headers": "HTTP/1.1 200 OK\r\n" |
| "Connection: close\r\n" |
| "Cache-control: max-age=60\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": f"This is the body for {query_name}\n" |
| } |
| origin.addResponse("sessionlog.json", request_header, response_header) |
| |
| # setup the prefetched assets |
| names = [pf_name, query_pf_name] |
| |
| for name in names: |
| request_header = { |
| "headers": |
| f"GET /tests/{name} HTTP/1.1\r\n" |
| "Host: does.not.matter\r\n" # But cant be omitted |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": "" |
| } |
| response_header = { |
| "headers": "HTTP/1.1 200 OK\r\n" |
| "Connection: close\r\n" |
| "Cache-control: max-age=60\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": f"This is the body for {name}\n" |
| } |
| origin.addResponse("sessionlog.json", request_header, response_header) |
| |
| # prefetch from root |
| root_name = 'root.txt' |
| root_header = f'Cmcd-Request: nor="rooted"' |
| |
| request_header = { |
| "headers": |
| f"GET /{root_name} HTTP/1.1\r\n" |
| "Host: does.not.matter\r\n" # But cant be omitted |
| f"{root_header}\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": "" |
| } |
| response_header = { |
| "headers": "HTTP/1.1 200 OK\r\n" |
| "Connection: close\r\n" |
| "Cache-control: max-age=60\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": f"This is the body for {root_name}\n" |
| } |
| origin.addResponse("sessionlog.json", request_header, response_header) |
| |
| request_header = { |
| "headers": |
| f"GET /rooted HTTP/1.1\r\n" |
| "Host: does.not.matter\r\n" # But cant be omitted |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": "" |
| } |
| response_header = { |
| "headers": "HTTP/1.1 200 OK\r\n" |
| "Connection: close\r\n" |
| "Cache-control: max-age=60\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": f"This is the body for rooted\n" |
| } |
| origin.addResponse("sessionlog.json", request_header, response_header) |
| |
| # ignore if cmcd-request nrr= found |
| crr_name = 'crr.txt' |
| crr_header = f'Cmcd-Request: foo=12,nor="{crr_name}",bar=42,nrr="0-"' |
| request_header = { |
| "headers": |
| f"GET /tests/{crr_name} HTTP/1.1\r\n" |
| "Host: does.not.matter\r\n" # But cant be omitted |
| f"{crr_header}\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": "" |
| } |
| response_header = { |
| "headers": "HTTP/1.1 200 OK\r\n" |
| "Connection: close\r\n" |
| "Cache-control: max-age=60\r\n" |
| "\r\n", |
| "timestamp": "1469733493.993", |
| "body": f"This is the body for {crr_name}\n" |
| } |
| origin.addResponse("sessionlog.json", request_header, response_header) |
| |
| # allows for multiple ats on localhost |
| dns = Test.MakeDNServer("dns") |
| |
| # next hop trafficserver instance |
| ts1 = Test.MakeATSProcess("ts1", enable_uds=False) |
| ts1.Disk.records_config.update( |
| { |
| 'proxy.config.diags.debug.enabled': 1, |
| 'proxy.config.diags.debug.tags': 'prefetch|http', |
| 'proxy.config.dns.nameservers': f"127.0.0.1:{dns.Variables.Port}", |
| 'proxy.config.dns.resolv_conf': "NULL", |
| 'proxy.config.http.parent_proxy.self_detect': 0, |
| }) |
| dns.addRecords(records={f"ts1": ["127.0.0.1"]}) |
| ts1.Disk.remap_config.AddLine( |
| f"map / http://127.0.0.1:{origin.Variables.Port}" + " @plugin=cachekey.so @pparam==--sort-params=true" |
| " @plugin=prefetch.so @pparam==--front=false") |
| |
| ts1.Disk.logging_yaml.AddLines( |
| ''' |
| logging: |
| formats: |
| - name: custom |
| format: '%<cquup> %<pssc> %<crc> %<cwr> %<pscl> %<{X-CDN-Prefetch}cqh>' |
| logs: |
| - filename: transaction |
| format: custom |
| '''.split("\n")) |
| |
| ts0 = Test.MakeATSProcess("ts0") |
| ts0.Disk.records_config.update( |
| { |
| 'proxy.config.diags.debug.enabled': 1, |
| 'proxy.config.diags.debug.tags': 'prefetch|http', |
| 'proxy.config.dns.nameservers': f"127.0.0.1:{dns.Variables.Port}", |
| 'proxy.config.dns.resolv_conf': "NULL", |
| 'proxy.config.http.parent_proxy.self_detect': 0, |
| }) |
| |
| dns.addRecords(records={f"ts0": ["127.0.0.1"]}) |
| ts0.Disk.remap_config.AddLine( |
| f"map http://ts0 http://ts1:{ts1.Variables.port}" + " @plugin=cachekey.so @pparam=--sort-params=true" |
| " @plugin=prefetch.so" + " @pparam=--front=true" + " @pparam=--fetch-policy=simple" + " @pparam=--cmcd-nor=true") |
| |
| ts0.Disk.logging_yaml.AddLines( |
| ''' |
| logging: |
| formats: |
| - name: custom |
| format: '%<cquup> %<pssc> %<crc> %<cwr> %<pscl> %<{X-CDN-Prefetch}cqh>' |
| logs: |
| - filename: transaction |
| format: custom |
| '''.split("\n")) |
| |
| # start everything up |
| tr = Test.AddTestRun() |
| tr.Processes.Default.StartBefore(origin) |
| tr.Processes.Default.StartBefore(dns) |
| tr.Processes.Default.StartBefore(ts0) |
| tr.Processes.Default.StartBefore(ts1) |
| tr.Processes.Default.Command = 'echo start TS, TSH_N, HTTP origin and DNS.' |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # attempt to get normal asset |
| tr = Test.AddTestRun() |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} http://ts0/tests/{asset_name}", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # issue curl form same asset, with prefetch |
| tr = Test.AddTestRun() |
| tr.DelayStart = 1 |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} http://ts0/tests/{asset_name} -H \'{pf_header}\'", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # fetch the prefetched asset (only cached on ts1) |
| tr = Test.AddTestRun() |
| tr.DelayStart = 1 |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} http://ts0/tests/{pf_name}", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # attempt to prefetch again |
| tr = Test.AddTestRun() |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} http://ts0/tests/{asset_name} -H \'{pf_header}\'", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # request the prefetched asset |
| tr = Test.AddTestRun() |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} http://ts0/tests/{pf_name}", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # prefetch using query params with query prefetch perc encoded |
| tr = Test.AddTestRun() |
| tr.MakeCurlCommand( |
| f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} \'http://ts0/tests/{query_name}\' -H \'{query_pf_perc_header}\'", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # request the prefetched asset without perc encoding |
| tr = Test.AddTestRun() |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} \'http://ts0/tests/{query_pf_name}\'", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # ensure root path prefetch works |
| tr = Test.AddTestRun() |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} \'http://ts0/{root_name}\' -H \'{root_header}\'", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| # ensure request with nrr= field is skipped |
| tr = Test.AddTestRun() |
| tr.MakeCurlCommand(f"--verbose --proxy 127.0.0.1:{ts0.Variables.port} \'http://ts0/{crr_name}\' -H \'{crr_header}\'", ts=ts0) |
| tr.Processes.Default.ReturnCode = 0 |
| |
| ts0log = os.path.join(ts0.Variables.LOGDIR, 'transaction.log') |
| Test.AddAwaitFileContainsTestRun('Await ts transactions to finish logging.', ts0log, 'crr.txt') |
| |
| ts1log = os.path.join(ts1.Variables.LOGDIR, 'transaction.log') |
| Test.AddAwaitFileContainsTestRun('Await ts1 transactions to finish logging.', ts1log, 'crr.txt') |
| |
| tr = Test.AddTestRun() |
| tr.Processes.Default.Command = (f"cat {ts0log}") |
| tr.Streams.stdout = "prefetch_cmcd0.gold" |
| tr.Processes.Default.ReturnCode = 0 |
| |
| tr = Test.AddTestRun() |
| tr.Processes.Default.Command = (f"cat {ts1log}") |
| tr.Streams.stdout = "prefetch_cmcd1.gold" |
| tr.Processes.Default.ReturnCode = 0 |