diff mbox series

[nft,6/6] tests: shell: Add test case for JSON 'flags' arrays

Message ID 20250508214722.20808-7-phil@nwl.cc
State Accepted
Headers show
Series Add test for parse_flags_array() | expand

Commit Message

Phil Sutter May 8, 2025, 9:47 p.m. UTC
Ensure these arrays are reduced if containing just a single item and
parser interprets them correctly in any case.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 tests/shell/testcases/json/single_flag | 189 +++++++++++++++++++++++++
 1 file changed, 189 insertions(+)
 create mode 100755 tests/shell/testcases/json/single_flag
diff mbox series

Patch

diff --git a/tests/shell/testcases/json/single_flag b/tests/shell/testcases/json/single_flag
new file mode 100755
index 0000000000000..41fab63b0a23b
--- /dev/null
+++ b/tests/shell/testcases/json/single_flag
@@ -0,0 +1,189 @@ 
+#!/bin/bash
+#
+# Test various "flags" properties in JSON syntax:
+# - single item arrays are abbreviated as non-array in output
+# - both non-array and single item array accepted in input
+# - single and multiple item values are correctly printed in output and
+#   recognized in input (checked against standard syntax input/output)
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+
+set -e
+
+json_sanitize() {
+	sed -e 's/{"metainfo": {[^}]*}}, //' \
+	    -e 's/\("handle":\) [0-9]*/\1 0/g'
+}
+back_n_forth() { # (std, json)
+	$NFT flush ruleset
+	$NFT -f - <<< "$1"
+	diff --label "line ${BASH_LINENO[0]}: JSON output" \
+	     --label "line ${BASH_LINENO[0]}: JSON expect" \
+	     -u <($NFT -j list ruleset | json_sanitize) <(echo "$2")
+
+	$NFT flush ruleset
+	$NFT -j -f - <<< "$2"
+	diff --label "line ${BASH_LINENO[0]}: std output" \
+	     --label "line ${BASH_LINENO[0]}: std expect" \
+	     -u <($NFT list ruleset) <(echo "$1")
+}
+json_equiv() { # (json_in, json_out)
+	$NFT flush ruleset
+	$NFT -j -f - <<< "$1"
+	diff --label "line ${BASH_LINENO[0]}: JSON equiv output" \
+	     --label "line ${BASH_LINENO[0]}: JSON equiv expect" \
+	     -u <($NFT -j list ruleset | json_sanitize) <(echo "$2")
+}
+
+#
+# test table flags
+#
+
+STD_TABLE_1="table ip t {
+	flags dormant
+}"
+JSON_TABLE_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0, "flags": "dormant"}}]}'
+JSON_TABLE_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_TABLE_1")
+
+STD_TABLE_2=$(sed 's/\(flags dormant\)/\1,persist/' <<< "$STD_TABLE_1")
+JSON_TABLE_2=$(sed 's/\("flags":\) \("dormant"\)/\1 [\2, "persist"]/' <<< "$JSON_TABLE_1")
+
+back_n_forth "$STD_TABLE_1" "$JSON_TABLE_1"
+json_equiv "$JSON_TABLE_1_EQUIV" "$JSON_TABLE_1"
+back_n_forth "$STD_TABLE_2" "$JSON_TABLE_2"
+
+#
+# test set flags
+#
+
+STD_SET_1="table ip t {
+	set s {
+		type inet_proto
+		flags interval
+	}
+}"
+JSON_SET_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"set": {"family": "ip", "name": "s", "table": "t", "type": "inet_proto", "handle": 0, "flags": "interval"}}]}'
+JSON_SET_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_SET_1")
+
+STD_SET_2=$(sed 's/\(flags interval\)/\1,timeout/' <<< "$STD_SET_1")
+JSON_SET_2=$(sed 's/\("flags":\) \("interval"\)/\1 [\2, "timeout"]/' <<< "$JSON_SET_1")
+
+back_n_forth "$STD_SET_1" "$JSON_SET_1"
+json_equiv "$JSON_SET_1_EQUIV" "$JSON_SET_1"
+back_n_forth "$STD_SET_2" "$JSON_SET_2"
+
+#
+# test fib expression flags
+#
+
+STD_FIB_1="table ip t {
+	chain c {
+		fib saddr oif exists
+	}
+}"
+JSON_FIB_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"fib": {"result": "oif", "flags": "saddr"}}, "right": true}}]}}]}'
+JSON_FIB_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_FIB_1")
+
+STD_FIB_2=$(sed 's/\(fib saddr\)/\1 . iif/' <<< "$STD_FIB_1")
+JSON_FIB_2=$(sed 's/\("flags":\) \("saddr"\)/\1 [\2, "iif"]/' <<< "$JSON_FIB_1")
+
+back_n_forth "$STD_FIB_1" "$JSON_FIB_1"
+json_equiv "$JSON_FIB_1_EQUIV" "$JSON_FIB_1"
+back_n_forth "$STD_FIB_2" "$JSON_FIB_2"
+
+#
+# test nat statement flags
+#
+
+STD_NAT_1="table ip t {
+	chain c {
+		dnat to 192.168.0.0/24 persistent
+	}
+}"
+JSON_NAT_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"dnat": {"addr": {"prefix": {"addr": "192.168.0.0", "len": 24}}, "flags": "persistent"}}]}}]}'
+JSON_NAT_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_NAT_1")
+
+STD_NAT_2=$(sed 's/\(persistent\)/random,\1/' <<< "$STD_NAT_1")
+JSON_NAT_2=$(sed 's/\("flags":\) \("persistent"\)/\1 ["random", \2]/' <<< "$JSON_NAT_1")
+
+back_n_forth "$STD_NAT_1" "$JSON_NAT_1"
+json_equiv "$JSON_NAT_1_EQUIV" "$JSON_NAT_1"
+back_n_forth "$STD_NAT_2" "$JSON_NAT_2"
+
+#
+# test log statement flags
+#
+
+STD_LOG_1="table ip t {
+	chain c {
+		log flags tcp sequence
+	}
+}"
+JSON_LOG_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"log": {"flags": "tcp sequence"}}]}}]}'
+JSON_LOG_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_LOG_1")
+
+STD_LOG_2=$(sed 's/\(tcp sequence\)/\1,options/' <<< "$STD_LOG_1")
+JSON_LOG_2=$(sed 's/\("flags":\) \("tcp sequence"\)/\1 [\2, "tcp options"]/' <<< "$JSON_LOG_1")
+
+back_n_forth "$STD_LOG_1" "$JSON_LOG_1"
+json_equiv "$JSON_LOG_1_EQUIV" "$JSON_LOG_1"
+back_n_forth "$STD_LOG_2" "$JSON_LOG_2"
+
+#
+# test synproxy statement flags
+#
+
+STD_SYNPROXY_1="table ip t {
+	chain c {
+		synproxy sack-perm
+	}
+}"
+JSON_SYNPROXY_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"synproxy": {"flags": "sack-perm"}}]}}]}'
+JSON_SYNPROXY_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_SYNPROXY_1")
+
+STD_SYNPROXY_2=$(sed 's/\(sack-perm\)/timestamp \1/' <<< "$STD_SYNPROXY_1")
+JSON_SYNPROXY_2=$(sed 's/\("flags":\) \("sack-perm"\)/\1 ["timestamp", \2]/' <<< "$JSON_SYNPROXY_1")
+
+back_n_forth "$STD_SYNPROXY_1" "$JSON_SYNPROXY_1"
+json_equiv "$JSON_SYNPROXY_1_EQUIV" "$JSON_SYNPROXY_1"
+back_n_forth "$STD_SYNPROXY_2" "$JSON_SYNPROXY_2"
+
+#
+# test synproxy object flags
+#
+
+STD_SYNPROXY_OBJ_1="table ip t {
+	synproxy s {
+		mss 1280
+		wscale 64
+		 sack-perm
+	}
+}"
+JSON_SYNPROXY_OBJ_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"synproxy": {"family": "ip", "name": "s", "table": "t", "handle": 0, "mss": 1280, "wscale": 64, "flags": "sack-perm"}}]}'
+JSON_SYNPROXY_OBJ_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_SYNPROXY_OBJ_1")
+
+STD_SYNPROXY_OBJ_2=$(sed 's/ \(sack-perm\)/timestamp \1/' <<< "$STD_SYNPROXY_OBJ_1")
+JSON_SYNPROXY_OBJ_2=$(sed 's/\("flags":\) \("sack-perm"\)/\1 ["timestamp", \2]/' <<< "$JSON_SYNPROXY_OBJ_1")
+
+back_n_forth "$STD_SYNPROXY_OBJ_1" "$JSON_SYNPROXY_OBJ_1"
+json_equiv "$JSON_SYNPROXY_OBJ_1_EQUIV" "$JSON_SYNPROXY_OBJ_1"
+back_n_forth "$STD_SYNPROXY_OBJ_2" "$JSON_SYNPROXY_OBJ_2"
+
+#
+# test queue statement flags
+#
+
+STD_QUEUE_1="table ip t {
+	chain c {
+		queue flags bypass to 1-10
+	}
+}"
+JSON_QUEUE_1='{"nftables": [{"table": {"family": "ip", "name": "t", "handle": 0}}, {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}, {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"queue": {"num": {"range": [1, 10]}, "flags": "bypass"}}]}}]}'
+JSON_QUEUE_1_EQUIV=$(sed 's/\("flags":\) \([^}]*\)/\1 [\2]/' <<< "$JSON_QUEUE_1")
+
+STD_QUEUE_2=$(sed 's/\(bypass\)/\1,fanout/' <<< "$STD_QUEUE_1")
+JSON_QUEUE_2=$(sed 's/\("flags":\) \("bypass"\)/\1 [\2, "fanout"]/' <<< "$JSON_QUEUE_1")
+
+back_n_forth "$STD_QUEUE_1" "$JSON_QUEUE_1"
+json_equiv "$JSON_QUEUE_1_EQUIV" "$JSON_QUEUE_1"
+back_n_forth "$STD_QUEUE_2" "$JSON_QUEUE_2"