]> git.kaiwu.me - haproxy.git/commitdiff
REGTESTS: stick-table: test the general purpose counters and tags
authorWilly Tarreau <w@1wt.eu>
Mon, 21 Sep 2026 20:25:15 +0000 (20:25 +0000)
committerWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 14:55:57 +0000 (16:55 +0200)
The sc-add-gpc, sc-inc-gpc, sc-inc-gpc0, sc-inc-gpc1, sc-set-gpt and
sc-set-gpt0 actions had no coverage, and neither had the sc_*_gpc*,
sc_*_gpt*, sc0_*, sc1_*, sc2_* and src_* fetches nor the table_*gpc*
and table_*gpt* converters.

The array form of the general purpose storage (gpc, gpc_rate and gpt)
and the legacy scalar one (gpc0, gpc1 and gpt0) may not coexist in a
same table, so the test declares one table of each kind. The legacy one
is tracked by two stick counters at once, which lets the sc0_ and sc2_
shorthands be checked against each other and against the generic
sc_get_*(<sc-id>) form.

The three ways of reaching an entry are compared on each step: the stick
counters, the src_* fetches and the table_* converters, and the
increment, addition, reset and read variants are all exercised.

Note that among the shorthands of the array form, only sc1_clr_gpc() is
registered, sc0_clr_gpc() and sc2_clr_gpc() do not exist.

reg-tests/stick-table/sc_gpc_gpt.vtc [new file with mode: 0644]

diff --git a/reg-tests/stick-table/sc_gpc_gpt.vtc b/reg-tests/stick-table/sc_gpc_gpt.vtc
new file mode 100644 (file)
index 0000000..e84ea8c
--- /dev/null
@@ -0,0 +1,224 @@
+varnishtest "Test the general purpose counters and tags of the stick counters"
+
+# None of the sc-add-gpc, sc-inc-gpc, sc-inc-gpc0, sc-inc-gpc1,
+# sc-set-gpt and sc-set-gpt0 actions was covered, and neither were the
+# sc_*_gpc*/sc_*_gpt* fetches, their src_* equivalents nor the
+# table_*gpc*/table_*gpt* converters.
+#
+# The array form of the general purpose storage (gpc, gpc_rate and gpt)
+# and the legacy scalar one (gpc0, gpc1 and gpt0) may not live in the
+# same table, hence the two tables below, tracked by two distinct stick
+# counters.
+
+feature ignore_unknown_macro
+
+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 arr
+       stick-table type ip size 1m expire 1h store gpc(3),gpc_rate(3,10s),gpt(3)
+
+    backend leg
+       stick-table type ip size 1m expire 1h store gpc0,gpc0_rate(10s),gpc1,gpc1_rate(10s),gpt0
+
+    frontend fe
+       bind "fd@${fe}"
+
+       # sc0 and sc2 track the same entry of the legacy table so that both
+       # shorthand families can be checked against each other, sc1 tracks
+       # the array one
+       http-request track-sc0 src table leg
+       http-request track-sc1 src table arr
+       http-request track-sc2 src table leg
+
+       # update the counters and tags of both tables
+       http-request sc-add-gpc(1,1) 5    if { path /upd }
+       http-request sc-inc-gpc(0,1)      if { path /upd }
+       http-request sc-set-gpt(2,1) 7    if { path /upd }
+       http-request sc-inc-gpc0(0)       if { path /upd }
+       http-request sc-inc-gpc1(0)       if { path /upd }
+       http-request sc-set-gpt0(0) 9     if { path /upd }
+
+       # the fetch forms increment or reset and return the previous value
+       http-request set-var(txn.incf)  sc_inc_gpc(0,1)  if { path /fetch }
+       http-request set-var(txn.incf0) sc_inc_gpc0(0)   if { path /fetch }
+       http-request set-var(txn.incf1) sc0_inc_gpc1     if { path /fetch }
+       # note: among the shorthands, only sc1_clr_gpc() exists for the array
+       # form, sc0_clr_gpc() and sc2_clr_gpc() are not registered
+       http-request set-var(txn.clrf)  sc1_clr_gpc(0)   if { path /clear }
+       http-request set-var(txn.clrf0) sc_clr_gpc0(0)   if { path /clear }
+       http-request set-var(txn.clrf1) sc0_clr_gpc1     if { path /clear }
+
+       # the converters take the key on input and the table as an argument
+       http-request set-var(txn.tinc)  src,table_inc_gpc(0,arr)  if { path /conv }
+       http-request set-var(txn.tinc0) src,table_inc_gpc0(leg)   if { path /conv }
+       http-request set-var(txn.tinc1) src,table_inc_gpc1(leg)   if { path /conv }
+       http-request set-var(txn.tclr)  src,table_clr_gpc(0,arr)  if { path /convclr }
+       http-request set-var(txn.tclr0) src,table_clr_gpc0(leg)   if { path /convclr }
+       http-request set-var(txn.tclr1) src,table_clr_gpc1(leg)   if { path /convclr }
+
+       http-request return status 200
+
+       http-after-response set-header x-incf  "%[var(txn.incf)]"
+       http-after-response set-header x-incf0 "%[var(txn.incf0)]"
+       http-after-response set-header x-incf1 "%[var(txn.incf1)]"
+       http-after-response set-header x-clrf  "%[var(txn.clrf)]"
+       http-after-response set-header x-clrf0 "%[var(txn.clrf0)]"
+       http-after-response set-header x-clrf1 "%[var(txn.clrf1)]"
+       http-after-response set-header x-tinc  "%[var(txn.tinc)]"
+       http-after-response set-header x-tinc0 "%[var(txn.tinc0)]"
+       http-after-response set-header x-tinc1 "%[var(txn.tinc1)]"
+       http-after-response set-header x-tclr  "%[var(txn.tclr)]"
+       http-after-response set-header x-tclr0 "%[var(txn.tclr0)]"
+       http-after-response set-header x-tclr1 "%[var(txn.tclr1)]"
+
+       # read back through the three families: the generic sc_* fetches with
+       # an explicit counter id, the sc0_/sc1_ shorthands, the src_* fetches
+       # and the table_* converters
+       http-after-response set-header x-gpc0  "%[sc_get_gpc(0,1)]"
+       http-after-response set-header x-gpc1  "%[sc_get_gpc(1,1)]"
+       http-after-response set-header x-gpt2  "%[sc_get_gpt(2,1)]"
+       http-after-response set-header x-rate0 "%[sc_gpc_rate(0,1)]"
+
+       http-after-response set-header x-lgpc0 "%[sc_get_gpc0(0)]"
+       http-after-response set-header x-lgpc1 "%[sc_get_gpc1(0)]"
+       http-after-response set-header x-lgpt0 "%[sc_get_gpt0(0)]"
+       http-after-response set-header x-lr0   "%[sc_gpc0_rate(0)]"
+       http-after-response set-header x-lr1   "%[sc_gpc1_rate(0)]"
+       http-after-response set-header x-sc0   "%[sc0_get_gpc0]"
+       http-after-response set-header x-sc0b  "%[sc0_get_gpc1]"
+       http-after-response set-header x-sc0t  "%[sc0_get_gpt0]"
+       http-after-response set-header x-sc0r  "%[sc0_gpc0_rate]"
+       http-after-response set-header x-sc0r1 "%[sc0_gpc1_rate]"
+       http-after-response set-header x-sc2   "%[sc2_get_gpc0]"
+       http-after-response set-header x-sc2b  "%[sc2_get_gpc1]"
+       http-after-response set-header x-sc2t  "%[sc2_get_gpt0]"
+       http-after-response set-header x-sc2r  "%[sc2_gpc0_rate]"
+       http-after-response set-header x-sc2r1 "%[sc2_gpc1_rate]"
+
+       http-after-response set-header x-tgpc0 "%[src,table_gpc(0,arr)]"
+       http-after-response set-header x-tgpc1 "%[src,table_gpc(1,arr)]"
+       http-after-response set-header x-tgpt2 "%[src,table_gpt(2,arr)]"
+       http-after-response set-header x-trat0 "%[src,table_gpc_rate(0,arr)]"
+       http-after-response set-header x-tlgc0 "%[src,table_gpc0(leg)]"
+       http-after-response set-header x-tlgc1 "%[src,table_gpc1(leg)]"
+       http-after-response set-header x-tlgt0 "%[src,table_gpt0(leg)]"
+       http-after-response set-header x-tlr0  "%[src,table_gpc0_rate(leg)]"
+       http-after-response set-header x-tlr1  "%[src,table_gpc1_rate(leg)]"
+
+       http-after-response set-header x-sgpc0 "%[src_get_gpc(0,arr)]"
+       http-after-response set-header x-sgpt2 "%[src_get_gpt(2,arr)]"
+       http-after-response set-header x-srat0 "%[src_gpc_rate(0,arr)]"
+       http-after-response set-header x-slgc0 "%[src_get_gpc0(leg)]"
+       http-after-response set-header x-slgc1 "%[src_get_gpc1(leg)]"
+       http-after-response set-header x-slgt0 "%[src_get_gpt0(leg)]"
+       http-after-response set-header x-slr0  "%[src_gpc0_rate(leg)]"
+       http-after-response set-header x-slr1  "%[src_gpc1_rate(leg)]"
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+       # nothing was updated yet
+       txreq -url "/read"
+       rxresp
+       expect resp.status == 200
+       expect resp.http.x-gpc0  == "0"
+       expect resp.http.x-gpc1  == "0"
+       expect resp.http.x-gpt2  == "0"
+       expect resp.http.x-lgpc0 == "0"
+       expect resp.http.x-lgpc1 == "0"
+       expect resp.http.x-lgpt0 == "0"
+
+       # one increment, one addition of 5 and two tags
+       txreq -url "/upd"
+       rxresp
+       expect resp.status == 200
+       expect resp.http.x-gpc0  == "1"
+       expect resp.http.x-gpc1  == "5"
+       expect resp.http.x-gpt2  == "7"
+       expect resp.http.x-rate0 == "1"
+       expect resp.http.x-lgpc0 == "1"
+       expect resp.http.x-lgpc1 == "1"
+       expect resp.http.x-lgpt0 == "9"
+       expect resp.http.x-lr0   == "1"
+       expect resp.http.x-lr1   == "1"
+       expect resp.http.x-sc0   == "1"
+       expect resp.http.x-sc0b  == "1"
+       expect resp.http.x-sc0t  == "9"
+       expect resp.http.x-sc0r  == "1"
+       expect resp.http.x-sc0r1 == "1"
+       # sc2 tracks the same entry as sc0 and must report the same values
+       expect resp.http.x-sc2   == "1"
+       expect resp.http.x-sc2b  == "1"
+       expect resp.http.x-sc2t  == "9"
+       expect resp.http.x-sc2r  == "1"
+       expect resp.http.x-sc2r1 == "1"
+
+       # the converters and the src_* fetches see the same entries
+       expect resp.http.x-tgpc0 == "1"
+       expect resp.http.x-tgpc1 == "5"
+       expect resp.http.x-tgpt2 == "7"
+       expect resp.http.x-trat0 == "1"
+       expect resp.http.x-tlgc0 == "1"
+       expect resp.http.x-tlgc1 == "1"
+       expect resp.http.x-tlgt0 == "9"
+       expect resp.http.x-tlr0  == "1"
+       expect resp.http.x-tlr1  == "1"
+       expect resp.http.x-sgpc0 == "1"
+       expect resp.http.x-sgpt2 == "7"
+       expect resp.http.x-srat0 == "1"
+       expect resp.http.x-slgc0 == "1"
+       expect resp.http.x-slgc1 == "1"
+       expect resp.http.x-slgt0 == "9"
+       expect resp.http.x-slr0  == "1"
+       expect resp.http.x-slr1  == "1"
+
+       # the fetch forms increment and return the new value
+       txreq -url "/fetch"
+       rxresp
+       expect resp.status == 200
+       expect resp.http.x-incf  == "2"
+       expect resp.http.x-incf0 == "2"
+       expect resp.http.x-incf1 == "2"
+       expect resp.http.x-gpc0  == "2"
+       expect resp.http.x-lgpc0 == "2"
+       expect resp.http.x-lgpc1 == "2"
+
+       # so do the converters
+       txreq -url "/conv"
+       rxresp
+       expect resp.status == 200
+       expect resp.http.x-tinc  == "3"
+       expect resp.http.x-tinc0 == "3"
+       expect resp.http.x-tinc1 == "3"
+
+       # the clear forms return the previous value and reset the counter
+       txreq -url "/clear"
+       rxresp
+       expect resp.status == 200
+       expect resp.http.x-clrf  == "3"
+       expect resp.http.x-clrf0 == "3"
+       expect resp.http.x-clrf1 == "3"
+       expect resp.http.x-gpc0  == "0"
+       expect resp.http.x-lgpc0 == "0"
+       expect resp.http.x-lgpc1 == "0"
+       # the tags are not affected by the counter resets
+       expect resp.http.x-gpt2  == "7"
+       expect resp.http.x-lgpt0 == "9"
+
+       txreq -url "/convclr"
+       rxresp
+       expect resp.status == 200
+       expect resp.http.x-tclr  == "0"
+       expect resp.http.x-tclr0 == "0"
+       expect resp.http.x-tclr1 == "0"
+} -run