From: Willy Tarreau Date: Mon, 21 Sep 2026 20:28:13 +0000 (+0000) Subject: REGTESTS: stick-table: test the traffic counters of the stick counters X-Git-Tag: v3.5-dev8~63 X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=9a7db2d760ac2c25cf77f17dfe45238f649c8322;p=haproxy.git REGTESTS: stick-table: test the traffic counters of the stick counters The connection, session, request, error, failure and byte counters of the stick tables had no coverage, nor had the sc_*, sc0_*, src_* and table_* families giving access to them, nor sc_key, sc_tracked, sc_trackers, table_trackers, table_server_id, table_expire, table_idle, in_table, table_avl and table_cnt. A single client connection issues a normal request, a request denied with a 403 and a request answered with a 500 by the server so that the request, error and failure counters all move, and the three access families are compared against each other at each step. The values are grouped into a few headers because vtest only parses a limited number of them. --- diff --git a/reg-tests/stick-table/sc_counters.vtc b/reg-tests/stick-table/sc_counters.vtc new file mode 100644 index 000000000..70643bfdc --- /dev/null +++ b/reg-tests/stick-table/sc_counters.vtc @@ -0,0 +1,131 @@ +varnishtest "Test the traffic counters of the stick counters" + +# The connection, session, request, error and byte counters of the stick +# tables were not covered, nor were the sc_*, sc0_*, src_* and table_* +# families which give access to them, nor table_avl, table_cnt, +# table_expire, table_idle and in_table. +# +# A single client connection issues a normal request, a request denied by +# haproxy and a request answered with a 5xx by the server, so that the +# request, error and failure counters all get a chance to move. The +# values are grouped into a few headers because vtest only parses a +# limited number of them. + +feature ignore_unknown_macro + +server s1 { + rxreq + expect req.url == "/srv" + txresp + + rxreq + expect req.url == "/fail" + txresp -status 500 +} -start + +haproxy h1 -conf { + global + .if feature(THREAD) + thread-groups 1 + .endif + chroot / + + defaults + mode http + timeout connect "${HAPROXY_TEST_TIMEOUT-5s}" + timeout client "${HAPROXY_TEST_TIMEOUT-5s}" + timeout server "${HAPROXY_TEST_TIMEOUT-5s}" + + backend st + stick-table type ip size 1m expire 1h store conn_cnt,conn_cur,conn_rate(10s),sess_cnt,sess_rate(10s),http_req_cnt,http_req_rate(10s),http_err_cnt,http_err_rate(10s),http_fail_cnt,http_fail_rate(10s),bytes_in_cnt,bytes_in_rate(10s),bytes_out_cnt,bytes_out_rate(10s),glitch_cnt,glitch_rate(10s),server_id + + frontend fe + bind "fd@${fe}" + + tcp-request connection track-sc0 src table st + + http-request deny deny_status 403 if { path /denied } + # use_backend is only evaluated once all the http-request rules have + # run, so the local response must be skipped for the forwarded paths + http-request return status 200 unless { path /srv } || { path /fail } + use_backend be + + # the stick counter family, with an explicit counter id + http-after-response set-header x-sc-cnt "%[sc_conn_cnt(0)] %[sc_conn_cur(0)] %[sc_conn_rate(0)] %[sc_sess_cnt(0)] %[sc_sess_rate(0)]" + http-after-response set-header x-sc-req "%[sc_http_req_cnt(0)] %[sc_http_req_rate(0)] %[sc_http_err_cnt(0)] %[sc_http_err_rate(0)] %[sc_http_fail_cnt(0)] %[sc_http_fail_rate(0)]" + http-after-response set-header x-sc-byte "%[sc_kbytes_in(0)] %[sc_kbytes_out(0)] %[sc_bytes_in_rate(0)] %[sc_bytes_out_rate(0)]" + http-after-response set-header x-sc-misc "%[sc_glitch_cnt(0)] %[sc_glitch_rate(0)] %[sc_key(0)] %[sc_tracked(0)] %[sc_trackers(0)]" + + # the sc0_ shorthands must report the very same values + http-after-response set-header x-sc0 "%[sc0_conn_cnt] %[sc0_conn_cur] %[sc0_conn_rate] %[sc0_sess_cnt] %[sc0_sess_rate]" + http-after-response set-header x-sc0-req "%[sc0_http_req_cnt] %[sc0_http_req_rate] %[sc0_http_err_cnt] %[sc0_http_err_rate] %[sc0_http_fail_cnt] %[sc0_http_fail_rate]" + http-after-response set-header x-sc0-misc "%[sc0_kbytes_in] %[sc0_kbytes_out] %[sc0_glitch_cnt] %[sc0_glitch_rate] %[sc0_key] %[sc0_tracked] %[sc0_trackers]" + + # the src_ family looks the entry up by the source address + http-after-response set-header x-src-cnt "%[src_conn_cnt(st)] %[src_conn_cur(st)] %[src_conn_rate(st)] %[src_sess_cnt(st)] %[src_sess_rate(st)]" + http-after-response set-header x-src-req "%[src_http_req_cnt(st)] %[src_http_req_rate(st)] %[src_http_err_cnt(st)] %[src_http_err_rate(st)] %[src_http_fail_cnt(st)] %[src_http_fail_rate(st)]" + http-after-response set-header x-src-byte "%[src_kbytes_in(st)] %[src_kbytes_out(st)] %[src_bytes_in_rate(st)] %[src_bytes_out_rate(st)] %[src_glitch_cnt(st)] %[src_glitch_rate(st)]" + + # the table_ converters take the key on input + http-after-response set-header x-tbl-cnt "%[src,table_conn_cnt(st)] %[src,table_conn_cur(st)] %[src,table_conn_rate(st)] %[src,table_sess_cnt(st)] %[src,table_sess_rate(st)]" + http-after-response set-header x-tbl-req "%[src,table_http_req_cnt(st)] %[src,table_http_req_rate(st)] %[src,table_http_err_cnt(st)] %[src,table_http_err_rate(st)] %[src,table_http_fail_cnt(st)] %[src,table_http_fail_rate(st)]" + http-after-response set-header x-tbl-byte "%[src,table_kbytes_in(st)] %[src,table_kbytes_out(st)] %[src,table_bytes_in_rate(st)] %[src,table_bytes_out_rate(st)] %[src,table_glitch_cnt(st)] %[src,table_glitch_rate(st)]" + http-after-response set-header x-tbl-misc "%[src,table_trackers(st)] %[src,table_server_id(st)] %[src,in_table(st)] %[ipv4(10.9.9.9),in_table(st)] %[table_cnt(st)]" + + # expiration, idle time, their default value for an unknown key, and + # the number of free entries + http-after-response set-header x-tbl-exp "%[src,table_expire(st)] %[src,table_idle(st)] %[ipv4(10.9.9.9),table_expire(st,42)] %[ipv4(10.9.9.9),table_idle(st,43)] %[table_avl(st)]" + + backend be + server s1 ${s1_addr}:${s1_port} +} -start + +client c1 -connect ${h1_fe_sock} { + txreq -url "/one" + rxresp + expect resp.status == 200 + expect resp.http.x-sc-cnt == "1 1 1 1 1" + expect resp.http.x-sc-req == "1 1 0 0 0 0" + expect resp.http.x-sc-misc == "0 0 127.0.0.1 1 1" + expect resp.http.x-sc0 == resp.http.x-sc-cnt + expect resp.http.x-sc0-req == resp.http.x-sc-req + expect resp.http.x-sc0-misc == "0 0 0 0 127.0.0.1 1 1" + expect resp.http.x-src-cnt == resp.http.x-sc-cnt + expect resp.http.x-src-req == resp.http.x-sc-req + expect resp.http.x-tbl-cnt == resp.http.x-sc-cnt + expect resp.http.x-tbl-req == resp.http.x-sc-req + # one tracker, as sc_trackers() reports above, no server assigned, the + # source is in the table but 10.9.9.9 is not, and the table holds a + # single entry + expect resp.http.x-tbl-misc == "1 0 1 0 1" + expect resp.http.x-tbl-exp ~ "^[0-9]+ [0-9]+ 42 43 [0-9]+$" + + # a request denied with a 4xx feeds the error counters, the + # connection counters do not move on a kept-alive connection + txreq -url "/denied" + rxresp + expect resp.status == 403 + expect resp.http.x-sc-cnt == "1 1 1 1 1" + expect resp.http.x-sc-req == "2 2 1 1 0 0" + expect resp.http.x-src-req == "2 2 1 1 0 0" + expect resp.http.x-tbl-req == "2 2 1 1 0 0" + + # a request forwarded to the server, still no failure + txreq -url "/srv" + rxresp + expect resp.status == 200 + expect resp.http.x-sc-req == "3 3 1 1 0 0" + + # a 5xx returned by the server feeds the failure counters + txreq -url "/fail" + rxresp + expect resp.status == 500 + expect resp.http.x-sc-req == "4 4 1 1 1 1" + expect resp.http.x-src-req == "4 4 1 1 1 1" + expect resp.http.x-tbl-req == "4 4 1 1 1 1" + + # traffic was accounted in both directions, but stays below 1 kB + expect resp.http.x-sc-byte ~ "^0 0 [1-9][0-9]* [1-9][0-9]*$" + expect resp.http.x-src-byte ~ "^0 0 [1-9][0-9]* [1-9][0-9]* 0 0$" + expect resp.http.x-tbl-byte == resp.http.x-src-byte +} -run