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