netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Phil Sutter <phil@nwl.cc>
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
Subject: [nft PATCH 07/28] tests: py: Implement payload_record()
Date: Thu, 23 Oct 2025 18:13:56 +0200	[thread overview]
Message-ID: <20251023161417.13228-8-phil@nwl.cc> (raw)
In-Reply-To: <20251023161417.13228-1-phil@nwl.cc>

This is a helper function to store payload records (and JSON
equivalents) in .got files. The code it replaces missed to insert a
newline before the new entry and also did not check for existing records
in all spots.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 tests/py/nft-test.py | 117 ++++++++++++++++++++++++++-----------------
 1 file changed, 71 insertions(+), 46 deletions(-)

diff --git a/tests/py/nft-test.py b/tests/py/nft-test.py
index 019c828f957a5..dc074d4c3872a 100755
--- a/tests/py/nft-test.py
+++ b/tests/py/nft-test.py
@@ -16,6 +16,7 @@
 from __future__ import print_function
 import sys
 import os
+import io
 import argparse
 import signal
 import json
@@ -741,6 +742,66 @@ def set_delete_elements(set_element, set_name, table, filename=None,
     return i > 0
 
 
+def payload_record(path, rule, payload, desc="payload"):
+    '''
+    Record payload for @rule in file at @path
+
+    - @payload may be a file handle, a string or an array of strings
+    - Avoid duplicate entries by searching for a match first
+    - Separate entries by a single empty line, so check for trailing newlines
+      before writing
+    - @return False if already existing, True otherwise
+    '''
+    try:
+        with open(path, 'r') as f:
+            lines = f.readlines()
+    except:
+        lines = []
+
+    plines = []
+    if isinstance(payload, io.TextIOWrapper):
+        payload.seek(0, 0)
+        while True:
+            line = payload.readline()
+            if line.startswith("family "):
+                continue
+            if line == "":
+                break
+            plines.append(line)
+    elif isinstance(payload, str):
+        plines = [l + "\n" for l in payload.split("\n")]
+    elif isinstance(payload, list):
+        plines = payload
+    else:
+        raise Exception
+
+    found = False
+    for i in range(len(lines)):
+        if lines[i] == rule + "\n":
+            found = True
+            for pline in plines:
+                i += 1
+                if lines[i] != pline:
+                    found = False
+                    break
+            if found:
+                return False
+
+    try:
+        with open(path, 'a') as f:
+            if len(lines) > 0 and lines[-1] != "\n":
+                f.write("\n")
+            f.write("# %s\n" % rule)
+            f.writelines(plines)
+    except:
+        warnfmt = "Failed to write %s for rule %s"
+    else:
+        warnfmt = "Wrote %s for rule %s"
+
+    print_warning(warnfmt % (desc, rule[0]), os.path.basename(path), 1)
+    return True
+
+
 def json_dump_normalize(json_string, human_readable = False):
     json_obj = json.loads(json_string)
 
@@ -867,28 +928,8 @@ def set_delete_elements(set_element, set_name, table, filename=None,
             if state == "ok" and not payload_check(table_payload_expected,
                                                    payload_log, cmd):
                 error += 1
-
-                try:
-                    gotf = open("%s.got" % table_payload_path)
-                    gotf_payload_expected = payload_find_expected(gotf, rule[0])
-                    gotf.close()
-                except:
-                    gotf_payload_expected = None
-                payload_log.seek(0, 0)
-                if not payload_check(gotf_payload_expected, payload_log, cmd):
-                    gotf = open("%s.got" % table_payload_path, 'a')
-                    payload_log.seek(0, 0)
-                    gotf.write("# %s\n" % rule[0])
-                    while True:
-                        line = payload_log.readline()
-                        if line.startswith("family "):
-                            continue
-                        if line == "":
-                            break
-                        gotf.write(line)
-                    gotf.close()
-                    print_warning("Wrote payload for rule %s" % rule[0],
-                                  gotf.name, 1)
+                payload_record("%s.got" % table_payload_path,
+                               rule[0], payload_log)
 
             # Check for matching ruleset listing
             numeric_proto_old = nftables.set_numeric_proto_output(True)
@@ -979,13 +1020,9 @@ def set_delete_elements(set_element, set_name, table, filename=None,
                         json_output = item["rule"]
                         break
                 json_input = json.dumps(json_output["expr"], sort_keys = True)
-
-                gotf = open("%s.json.got" % filename_path, 'a')
-                jdump = json_dump_normalize(json_input, True)
-                gotf.write("# %s\n%s\n\n" % (rule[0], jdump))
-                gotf.close()
-                print_warning("Wrote JSON equivalent for rule %s" % rule[0],
-                              gotf.name, 1)
+                payload_record("%s.json.got" % filename_path, rule[0],
+                               json_dump_normalize(json_input, True),
+                               "JSON equivalent")
 
             table_flush(table, filename, lineno)
             payload_log = tempfile.TemporaryFile(mode="w+")
@@ -1013,17 +1050,8 @@ def set_delete_elements(set_element, set_name, table, filename=None,
             # Check for matching payload
             if not payload_check(table_payload_expected, payload_log, cmd):
                 error += 1
-                gotf = open("%s.json.payload.got" % filename_path, 'a')
-                payload_log.seek(0, 0)
-                gotf.write("# %s\n" % rule[0])
-                while True:
-                    line = payload_log.readline()
-                    if line == "":
-                        break
-                    gotf.write(line)
-                gotf.close()
-                print_warning("Wrote JSON payload for rule %s" % rule[0],
-                              gotf.name, 1)
+                payload_record("%s.json.payload.got" % filename_path,
+                               rule[0], payload_log, "JSON payload")
 
             # Check for matching ruleset listing
             numeric_proto_old = nftables.set_numeric_proto_output(True)
@@ -1049,12 +1077,9 @@ def set_delete_elements(set_element, set_name, table, filename=None,
                 print_differences_warning(filename, lineno,
                                           json_input, json_output, cmd)
                 error += 1
-                gotf = open("%s.json.output.got" % filename_path, 'a')
-                jdump = json_dump_normalize(json_output, True)
-                gotf.write("# %s\n%s\n\n" % (rule[0], jdump))
-                gotf.close()
-                print_warning("Wrote JSON output for rule %s" % rule[0],
-                              gotf.name, 1)
+                payload_record("%s.json.output.got" % filename_path, rule[0],
+                               json_dump_normalize(json_output, True),
+                               "JSON output")
                 # prevent further warnings and .got file updates
                 json_expected = json_output
             elif json_expected and json_output != json_expected:
-- 
2.51.0


  parent reply	other threads:[~2025-10-23 16:14 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-23 16:13 [nft PATCH 00/28] Fix netlink debug output on Big Endian Phil Sutter
2025-10-23 16:13 ` [nft PATCH 01/28] datatype: Fix boolean type " Phil Sutter
2025-10-23 16:13 ` [nft PATCH 02/28] optimize: Fix verdict expression comparison Phil Sutter
2025-10-23 16:13 ` [nft PATCH 03/28] tests: py: any/tcpopt.t.json: Fix JSON equivalent Phil Sutter
2025-10-23 16:13 ` [nft PATCH 04/28] tests: py: any/ct.t.json.output: Drop leftover entry Phil Sutter
2025-10-23 16:13 ` [nft PATCH 05/28] tests: py: inet/osf.t: Fix element ordering in JSON equivalents Phil Sutter
2025-10-23 16:13 ` [nft PATCH 06/28] tests: py: Fix for using wrong payload path Phil Sutter
2025-10-23 16:13 ` Phil Sutter [this message]
2025-10-23 16:13 ` [nft PATCH 08/28] tests: py: Do not rely upon '[end]' marker Phil Sutter
2025-10-23 16:13 ` [nft PATCH 09/28] netlink: No need to reference array when passing as pointer Phil Sutter
2025-10-23 16:13 ` [nft PATCH 10/28] datatype: Increase symbolic constant printer robustness Phil Sutter
2025-10-29 18:36   ` Pablo Neira Ayuso
2025-10-30 11:00     ` Phil Sutter
2025-10-30 21:56       ` Pablo Neira Ayuso
2025-10-30 22:35         ` Phil Sutter
2025-10-30 23:22           ` Pablo Neira Ayuso
2025-10-23 16:14 ` [nft PATCH 11/28] tests: py: ip6/vmap.t: Drop double whitespace in rule Phil Sutter
2025-10-23 16:14 ` [nft PATCH 12/28] netlink: Zero nft_data_linearize objects when populating Phil Sutter
2025-10-29 18:37   ` Pablo Neira Ayuso
2025-10-30 11:08     ` Phil Sutter
2025-10-30 22:02       ` Pablo Neira Ayuso
2025-10-30 22:54         ` Phil Sutter
2025-10-23 16:14 ` [nft PATCH 13/28] Define string-based data types as Big Endian Phil Sutter
2025-10-29 18:22   ` Pablo Neira Ayuso
2025-10-30 10:20     ` Phil Sutter
2025-10-23 16:14 ` [nft PATCH 14/28] segtree: No byteorder conversion for string prefix len calculation Phil Sutter
2025-10-23 16:14 ` [nft PATCH 15/28] Fix byteorder conversion of concatenated value expressions and ranges Phil Sutter
2025-10-23 16:14 ` [nft PATCH 16/28] expression: Set range expression 'len' field Phil Sutter
2025-10-23 16:14 ` [nft PATCH 17/28] segtree: Export complete data before editing Phil Sutter
2025-10-23 16:14 ` [nft PATCH 18/28] segtree: Drop problematic constant expr len adjustment Phil Sutter
2025-10-23 16:14 ` [nft PATCH 19/28] netlink: Introduce struct nft_data_linearize::byteorder Phil Sutter
2025-10-23 16:14 ` [nft PATCH 20/28] netlink: Introduce struct nft_data_linearize::sizes Phil Sutter
2025-10-29 18:34   ` Pablo Neira Ayuso
2025-10-30 10:53     ` Phil Sutter
2025-10-23 16:14 ` [nft PATCH 21/28] netlink: Make use of nftnl_{expr,set_elem}_set_imm() Phil Sutter
2025-10-23 16:14 ` [nft PATCH 22/28] mergesort: Linearize concatentations in network byte order Phil Sutter
2025-10-29 18:27   ` Pablo Neira Ayuso
2025-10-30 10:47     ` Phil Sutter
2025-10-23 16:14 ` [nft PATCH 23/28] tests: Adjust JSON records to improved element sorting Phil Sutter
2025-10-23 16:14 ` [nft PATCH 24/28] tests: py: tools: Add regen_payloads.sh Phil Sutter
2025-10-23 16:14 ` [nft PATCH 25/28] tests: py: Update payload records Phil Sutter
2025-10-23 16:14 ` [nft PATCH 26/28] utils: Introduce expr_print_debug() Phil Sutter
2025-10-29 12:46   ` Florian Westphal
2025-10-29 18:31   ` Pablo Neira Ayuso
2025-10-30 10:16     ` Phil Sutter
2025-10-23 16:14 ` [nft PATCH 27/28] utils: Cover for missing newline after BUG() messages Phil Sutter
2025-10-29 12:47   ` Florian Westphal
2025-10-30 10:17     ` Phil Sutter
2025-10-23 16:14 ` [nft PATCH 28/28] Drop no longer needed newline in " Phil Sutter
2025-10-29 18:33   ` Pablo Neira Ayuso
2025-10-30 10:51     ` Phil Sutter
2025-10-23 20:45 ` [nft PATCH 00/28] Fix netlink debug output on Big Endian Florian Westphal
2025-10-23 20:47   ` Phil Sutter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251023161417.13228-8-phil@nwl.cc \
    --to=phil@nwl.cc \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pablo@netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).