From: Remi Tricot-Le Breton Date: Thu, 1 Oct 2026 12:33:28 +0000 (+0200) Subject: REGTESTS: vars: Add a test for the set-vars-from-map action X-Git-Tag: v3.5-dev8~1 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=82ad0449d30d5ff45f10e0b9aacd2fbee285bd64;p=haproxy.git REGTESTS: vars: Add a test for the set-vars-from-map action Test the new "set-vars-from-map" action with different input types and with valid and invalid values. --- diff --git a/reg-tests/http-rules/set_vars_from_map.vtc b/reg-tests/http-rules/set_vars_from_map.vtc new file mode 100644 index 000000000..4323157bb --- /dev/null +++ b/reg-tests/http-rules/set_vars_from_map.vtc @@ -0,0 +1,123 @@ +varnishtest "Test the set-vars-from-map() action" + +# This config tests the set-vars-from-map() action. It loads three map files +# (string, integer and boolean values) and populates session, transaction and +# request variables from them. The resulting scopes are observed through the +# dump_all_vars() sample fetch so that the variables don't have to be listed +# one by one. It checks that: +# - string values keep their spaces (they are quoted by dump_all_vars), +# - integer values are stored unquoted as integers, so that arithmetic +# converters can work on them, +# - an unparsable integer entry is silently skipped and never appears, +# - an entry whose name is not a valid variable name is silently ignored, +# - boolean values are rendered as unquoted true/false, accepting both the +# 0/1 and the false/true spellings, +# - entries added through the CLI ("add map") are picked up by subsequent +# sessions, since the action always evaluates the current map generation. + +feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.5-dev6)'" +feature ignore_unknown_macro + +shell { + cat << EOF > ${tmpdir}/set_vars_from_map.map +# Variable names are unqualified, the scope comes from the action itself. +str1 this is a string +str2 another one +# This name contains an invalid character and must be silently ignored +bad-name ignored +EOF + + cat << EOF > ${tmpdir}/set_vars_from_map_int.map +int1 12 +int2 30 +# This one cannot be parsed as an integer, it must be silently ignored +notanint hello +extra_var1 1 +extra_var2 1 +EOF + + cat << EOF > ${tmpdir}/set_vars_from_map_bool.map +bool1 true +bool2 0 +EOF +} + +haproxy h1 -conf { + global + .if feature(THREAD) + thread-groups 1 + .endif + tune.vars.from-map.max 4 + + defaults + mode http + timeout connect "${HAPROXY_TEST_TIMEOUT-5s}" + timeout client "${HAPROXY_TEST_TIMEOUT-5s}" + timeout server "${HAPROXY_TEST_TIMEOUT-5s}" + + frontend fe1 + bind "fd@${fe1}" + + # default type is "str" + tcp-request session set-vars-from-map(sess,${tmpdir}/set_vars_from_map.map) + + # "int" values are real integers, arithmetic converters must work on + # them. The "notanint" entry cannot be parsed and must be skipped + # without affecting the other entries. + http-request set-vars-from-map(txn,${tmpdir}/set_vars_from_map_int.map,int) + + # "bool" accepts 0/1 and false/true + http-request set-vars-from-map(req,${tmpdir}/set_vars_from_map_bool.map,bool) + + # Dump the whole scopes rather than fetching each variable. Note that + # dump_all_vars() outputs the variables in hash order, so the test + # below only checks the presence of each expected entry. + http-request return status 200 hdr x-sess "%[dump_all_vars(sess)]" hdr x-txn "%[dump_all_vars(txn)]" hdr x-req "%[dump_all_vars(req)]" +} -start + +client c1 -connect ${h1_fe1_sock} { + txreq -url / + rxresp + expect resp.status == 200 + # string values keep their spaces and are quoted by dump_all_vars, which + # proves they are stored as strings + expect resp.http.x-sess ~ "sess.str1=\"this is a string\"" + expect resp.http.x-sess ~ "sess.str2=\"another one\"" + # integer values are unquoted, proving they are stored as integers. The + # unparsable "notanint" entry was skipped and must not appear. + expect resp.http.x-txn ~ "txn.int1=12" + expect resp.http.x-txn ~ "txn.int2=30" + expect resp.http.x-txn !~ "notanint" + # the maximum number of entries is set to 4 so the fifth one should not be present + expect resp.http.x-txn !~ "extra_var2" + # boolean values are rendered as unquoted true/false + expect resp.http.x-req ~ "req.bool1=true" + expect resp.http.x-req ~ "req.bool2=false" + # no "str3" entry exists in the map yet + expect resp.http.x-sess !~ "str3" + # the "bad-name" entry has an invalid name and is silently ignored + expect resp.http.x-sess !~ "bad-name" +} -run + +# The action always evaluates the current generation of the map, so an entry +# added through the CLI must be reflected by the variables of new sessions. +haproxy h1 -cli { + send "add map ${tmpdir}/set_vars_from_map.map str3 updated-from-cli" + expect ~ "^\\n" + + send "show map ${tmpdir}/set_vars_from_map.map" + expect ~ ".*str3 updated-from-cli.*" +} + +client c2 -connect ${h1_fe1_sock} { + txreq -url / + rxresp + expect resp.status == 200 + # the entry added through the CLI is now visible in the session scope + expect resp.http.x-sess ~ "sess.str3=\"updated-from-cli\"" + # pre-existing entries are still present + expect resp.http.x-sess ~ "sess.str1=\"this is a string\"" + expect resp.http.x-sess ~ "sess.str2=\"another one\"" +} -run + +haproxy h1 -wait