at 25.11-pre 6.9 kB view raw
1# verifies: 2# 1. Traffic Server is able to start 3# 2. Traffic Server spawns traffic_crashlog upon startup 4# 3. Traffic Server proxies HTTP requests according to URL remapping rules 5# in 'services.trafficserver.remap' 6# 4. Traffic Server applies per-map settings specified with the conf_remap 7# plugin 8# 5. Traffic Server caches HTTP responses 9# 6. Traffic Server processes HTTP PUSH requests 10# 7. Traffic Server can load the healthchecks plugin 11# 8. Traffic Server logs HTTP traffic as configured 12# 13# uses: 14# - bin/traffic_manager 15# - bin/traffic_server 16# - bin/traffic_crashlog 17# - bin/traffic_cache_tool 18# - bin/traffic_ctl 19# - bin/traffic_logcat 20# - bin/traffic_logstats 21# - bin/tspush 22import ./make-test-python.nix ( 23 { pkgs, ... }: 24 { 25 name = "trafficserver"; 26 meta = with pkgs.lib.maintainers; { 27 maintainers = [ midchildan ]; 28 }; 29 30 nodes = { 31 ats = 32 { 33 pkgs, 34 lib, 35 config, 36 ... 37 }: 38 let 39 user = config.users.users.trafficserver.name; 40 group = config.users.groups.trafficserver.name; 41 healthchecks = pkgs.writeText "healthchecks.conf" '' 42 /status /tmp/ats.status text/plain 200 500 43 ''; 44 in 45 { 46 services.trafficserver.enable = true; 47 48 services.trafficserver.records = { 49 proxy.config.http.server_ports = "80 80:ipv6"; 50 proxy.config.hostdb.host_file.path = "/etc/hosts"; 51 proxy.config.log.max_space_mb_headroom = 0; 52 proxy.config.http.push_method_enabled = 1; 53 54 # check that cache storage is usable before accepting traffic 55 proxy.config.http.wait_for_cache = 2; 56 }; 57 58 services.trafficserver.plugins = [ 59 { 60 path = "healthchecks.so"; 61 arg = toString healthchecks; 62 } 63 { path = "xdebug.so"; } 64 ]; 65 66 services.trafficserver.remap = '' 67 map http://httpbin.test http://httpbin 68 map http://pristine-host-hdr.test http://httpbin \ 69 @plugin=conf_remap.so \ 70 @pparam=proxy.config.url_remap.pristine_host_hdr=1 71 map http://ats/tspush http://httpbin/cache \ 72 @plugin=conf_remap.so \ 73 @pparam=proxy.config.http.cache.required_headers=0 74 ''; 75 76 services.trafficserver.storage = '' 77 /dev/vdb volume=1 78 ''; 79 80 networking.firewall.allowedTCPPorts = [ 80 ]; 81 virtualisation.emptyDiskImages = [ 256 ]; 82 services.udev.extraRules = '' 83 KERNEL=="vdb", OWNER="${user}", GROUP="${group}" 84 ''; 85 }; 86 87 httpbin = 88 { pkgs, lib, ... }: 89 let 90 python = pkgs.python3.withPackages ( 91 ps: with ps; [ 92 httpbin 93 gunicorn 94 gevent 95 ] 96 ); 97 in 98 { 99 systemd.services.httpbin = { 100 enable = true; 101 after = [ "network.target" ]; 102 wantedBy = [ "multi-user.target" ]; 103 serviceConfig = { 104 ExecStart = "${python}/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent"; 105 }; 106 }; 107 108 networking.firewall.allowedTCPPorts = [ 80 ]; 109 }; 110 111 client = 112 { pkgs, lib, ... }: 113 { 114 environment.systemPackages = with pkgs; [ curl ]; 115 }; 116 }; 117 118 testScript = 119 { nodes, ... }: 120 let 121 sampleFile = pkgs.writeText "sample.txt" '' 122 It's the season of White Album. 123 ''; 124 in 125 '' 126 import json 127 import re 128 129 ats.wait_for_unit("trafficserver") 130 ats.wait_for_open_port(80) 131 httpbin.wait_for_unit("httpbin") 132 httpbin.wait_for_open_port(80) 133 client.systemctl("start network-online.target") 134 client.wait_for_unit("network-online.target") 135 136 with subtest("Traffic Server is running"): 137 out = ats.succeed("traffic_ctl server status") 138 assert out.strip() == "Proxy -- on" 139 140 with subtest("traffic_crashlog is running"): 141 ats.succeed("pgrep -f traffic_crashlog") 142 143 with subtest("basic remapping works"): 144 out = client.succeed("curl -vv -H 'Host: httpbin.test' http://ats/headers") 145 assert json.loads(out)["headers"]["Host"] == "httpbin" 146 147 with subtest("conf_remap plugin works"): 148 out = client.succeed( 149 "curl -vv -H 'Host: pristine-host-hdr.test' http://ats/headers" 150 ) 151 assert json.loads(out)["headers"]["Host"] == "pristine-host-hdr.test" 152 153 with subtest("caching works"): 154 out = client.succeed( 155 "curl -vv -D - -H 'Host: httpbin.test' -H 'X-Debug: X-Cache' http://ats/cache/60 -o /dev/null" 156 ) 157 assert "X-Cache: miss" in out 158 159 out = client.succeed( 160 "curl -vv -D - -H 'Host: httpbin.test' -H 'X-Debug: X-Cache' http://ats/cache/60 -o /dev/null" 161 ) 162 assert "X-Cache: hit-fresh" in out 163 164 with subtest("pushing to cache works"): 165 url = "http://ats/tspush" 166 167 ats.succeed(f"echo {url} > /tmp/urls.txt") 168 out = ats.succeed( 169 f"tspush -f '${sampleFile}' -u {url}" 170 ) 171 assert "HTTP/1.0 201 Created" in out, "cache push failed" 172 173 out = ats.succeed( 174 "traffic_cache_tool --spans /etc/trafficserver/storage.config find --input /tmp/urls.txt" 175 ) 176 assert "Span: /dev/vdb" in out, "cache not stored on disk" 177 178 out = client.succeed(f"curl {url}").strip() 179 expected = ( 180 open("${sampleFile}").read().strip() 181 ) 182 assert out == expected, "cache content mismatch" 183 184 with subtest("healthcheck plugin works"): 185 out = client.succeed("curl -vv http://ats/status -o /dev/null -w '%{http_code}'") 186 assert out.strip() == "500" 187 188 ats.succeed("touch /tmp/ats.status") 189 190 out = client.succeed("curl -vv http://ats/status -o /dev/null -w '%{http_code}'") 191 assert out.strip() == "200" 192 193 with subtest("logging works"): 194 access_log_path = "/var/log/trafficserver/squid.blog" 195 ats.wait_for_file(access_log_path) 196 197 out = ats.succeed(f"traffic_logcat {access_log_path}").split("\n")[0] 198 expected = "^\S+ \S+ \S+ TCP_MISS/200 \S+ GET http://httpbin/headers - DIRECT/httpbin application/json$" 199 assert re.fullmatch(expected, out) is not None, "no matching logs" 200 201 out = json.loads(ats.succeed(f"traffic_logstats -jf {access_log_path}")) 202 assert isinstance(out, dict) 203 assert out["total"]["error.total"]["req"] == "0", "unexpected log stat" 204 ''; 205 } 206)