|
| 1 | +''' |
| 2 | +Implement general-purpose ATS test extensions using proxy verifier replay files. |
| 3 | +''' |
| 4 | +# Licensed to the Apache Software Foundation (ASF) under one |
| 5 | +# or more contributor license agreements. See the NOTICE file |
| 6 | +# distributed with this work for additional information |
| 7 | +# regarding copyright ownership. The ASF licenses this file |
| 8 | +# to you under the Apache License, Version 2.0 (the |
| 9 | +# "License"); you may not use this file except in compliance |
| 10 | +# with the License. You may obtain a copy of the License at |
| 11 | +# |
| 12 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 13 | +# |
| 14 | +# Unless required by applicable law or agreed to in writing, software |
| 15 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 16 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 17 | +# See the License for the specific language governing permissions and |
| 18 | +# limitations under the License. |
| 19 | + |
| 20 | +from typing import Optional |
| 21 | +import os |
| 22 | +import yaml |
| 23 | + |
| 24 | + |
| 25 | +def configure_ats(obj: 'TestRun', server: 'Process', ats_config: dict, dns: Optional['Process'] = None): |
| 26 | + '''Configure ATS per the configuration in the replay file. |
| 27 | + |
| 28 | + :param obj: The Test object to configure ATS for. |
| 29 | + :param server: The Proxy Verifier Server process to use. |
| 30 | + :param ats_config: The ATS configuration from the replay file. |
| 31 | + :param dns: The DNS process to use. Optional. |
| 32 | + :returns: The ATS process object. |
| 33 | + ''' |
| 34 | + name = ats_config.get('name', 'ts') |
| 35 | + process_config = ats_config.get('process_config', {}) |
| 36 | + ts = obj.MakeATSProcess(name, **process_config) |
| 37 | + records_config = ats_config.get('records_config', {}) |
| 38 | + ts.Disk.records_config.update(records_config) |
| 39 | + remap_config = ats_config.get('remap_config', []) |
| 40 | + for remap_entry in remap_config: |
| 41 | + if isinstance(remap_entry, str): |
| 42 | + ts.Disk.remap_config.AddLine(remap_entry) |
| 43 | + elif isinstance(remap_entry, dict): |
| 44 | + from_url = remap_entry['from'] |
| 45 | + to_url = remap_entry['to'] |
| 46 | + to_url = to_url.replace('{SERVER_HTTP_PORT}', str(server.Variables.http_port)) |
| 47 | + to_url = to_url.replace('{SERVER_HTTPS_PORT}', str(server.Variables.https_port)) |
| 48 | + plugins = remap_entry.get('plugins', []) |
| 49 | + line = f'map {from_url} {to_url}' |
| 50 | + for plugin in plugins: |
| 51 | + line += f' @plugin={plugin["name"]}' |
| 52 | + for arg in plugin["args"]: |
| 53 | + line += f' @pparam={arg}' |
| 54 | + ts.Disk.remap_config.AddLine(line) |
| 55 | + if dns: |
| 56 | + ts.Disk.records_config.update( |
| 57 | + { |
| 58 | + 'proxy.config.dns.nameservers': f'127.0.0.1:{dns.Variables.Port}', |
| 59 | + 'proxy.config.dns.resolv_conf': 'NULL', |
| 60 | + }) |
| 61 | + |
| 62 | + for item in ats_config.get('copy_to_config_dir', []): |
| 63 | + item_path = os.path.join(obj.TestDirectory, item) |
| 64 | + if os.path.isdir(item_path): |
| 65 | + src_dir = item_path |
| 66 | + dst_dir = os.path.join(ts.Variables.CONFIGDIR, item) |
| 67 | + ts.Setup.MakeDir(dst_dir) |
| 68 | + ts.Setup.Copy(src_dir, dst_dir) |
| 69 | + else: |
| 70 | + ts.Setup.CopyAs(item, ts.Variables.CONFIGDIR) |
| 71 | + return ts |
| 72 | + |
| 73 | + |
| 74 | +def ATSReplayTest(obj, replay_file: str): |
| 75 | + '''Create a TestRun that configures ATS and runs HTTP traffic using the replay file. |
| 76 | + |
| 77 | + :param obj: The Test object to add the test run to. |
| 78 | + :param replay_file: Replay file specifying the test configuration and test traffic. |
| 79 | + :returns: The TestRun object. |
| 80 | + ''' |
| 81 | + |
| 82 | + replay_path = replay_file if os.path.isabs(replay_file) else os.path.join(obj.TestDirectory, replay_file) |
| 83 | + with open(replay_path, 'r') as f: |
| 84 | + replay_config = yaml.safe_load(f) |
| 85 | + |
| 86 | + # The user must specify the 'autest' node. |
| 87 | + if not 'autest' in replay_config: |
| 88 | + raise ValueError(f"Replay file {replay_file} does not contain 'autest' section") |
| 89 | + autest_config = replay_config['autest'] |
| 90 | + |
| 91 | + tr = obj.AddTestRun(autest_config['description']) |
| 92 | + |
| 93 | + # Copy the specified files and directories down. |
| 94 | + tr.Setup.Copy(replay_file, tr.RunDirectory) |
| 95 | + |
| 96 | + for files_to_copy in autest_config.get('files_to_copy', []): |
| 97 | + tr.Setup.Copy(files_to_copy) |
| 98 | + for dirs_to_copy in autest_config.get('dirs_to_copy', []): |
| 99 | + tr.Setup.Copy(dirs_to_copy) |
| 100 | + |
| 101 | + # DNS configuration. |
| 102 | + dns = None |
| 103 | + if 'dns' in autest_config: |
| 104 | + dns_config = autest_config['dns'] |
| 105 | + name = dns_config['name'] |
| 106 | + if 'process_config' in dns_config: |
| 107 | + process_config = dns_config['process_config'] |
| 108 | + dns = tr.MakeDNServer(name, **process_config) |
| 109 | + else: |
| 110 | + dns = tr.MakeDNServer(name, default='127.0.0.1') |
| 111 | + |
| 112 | + # Proxy Verifier Server configuration. |
| 113 | + if not 'server' in autest_config: |
| 114 | + raise ValueError(f"Replay file {replay_file} does not contain 'autest.server' section") |
| 115 | + server_config = autest_config['server'] |
| 116 | + name = server_config['name'] |
| 117 | + process_config = server_config.get('process_config', {}) |
| 118 | + server = tr.AddVerifierServerProcess(name, replay_file, **process_config) |
| 119 | + |
| 120 | + # ATS configuration. |
| 121 | + if not 'ats' in autest_config: |
| 122 | + raise ValueError(f"Replay file {replay_file} does not contain 'autest.ats' section") |
| 123 | + ats_config = autest_config['ats'] |
| 124 | + enable_tls = ats_config.get('enable_tls', False) |
| 125 | + ts = configure_ats(tr, server=server, ats_config=ats_config, dns=dns) |
| 126 | + |
| 127 | + # Proxy Verifier Client configuration. |
| 128 | + if not 'client' in autest_config: |
| 129 | + raise ValueError(f"Replay file {replay_file} does not contain 'autest.client' section") |
| 130 | + client_config = autest_config['client'] |
| 131 | + name = client_config.get('name', 'client') |
| 132 | + process_config = client_config.get('process_config', {}) |
| 133 | + https_ports = [ts.Variables.ssl_port] if enable_tls else None |
| 134 | + client = tr.AddVerifierClientProcess( |
| 135 | + name, replay_file, http_ports=[ts.Variables.port], https_ports=https_ports, **process_config) |
| 136 | + |
| 137 | + if dns: |
| 138 | + ts.StartBefore(dns) |
| 139 | + ts.StartBefore(server) |
| 140 | + client.StartBefore(ts) |
| 141 | + |
| 142 | + return tr |
| 143 | + |
| 144 | + |
| 145 | +ExtendTest(ATSReplayTest, name="ATSReplayTest") |
0 commit comments