From 956f2b620da24566c00bcaeef9ff60e316c9f7a6 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Mon, 17 Nov 2025 14:27:27 +0100 Subject: [PATCH] test: new syslog test to verify property based filtering Signed-off-by: Joachim Wiberg --- test/case/ietf_syslog/all.yaml | 3 + .../ietf_syslog/property_filter/Readme.adoc | 1 + .../ietf_syslog/property_filter/test.adoc | 25 ++++ test/case/ietf_syslog/property_filter/test.py | 134 ++++++++++++++++++ .../ietf_syslog/property_filter/topology.dot | 1 + .../ietf_syslog/property_filter/topology.svg | 33 +++++ 6 files changed, 197 insertions(+) create mode 120000 test/case/ietf_syslog/property_filter/Readme.adoc create mode 100644 test/case/ietf_syslog/property_filter/test.adoc create mode 100755 test/case/ietf_syslog/property_filter/test.py create mode 120000 test/case/ietf_syslog/property_filter/topology.dot create mode 100644 test/case/ietf_syslog/property_filter/topology.svg diff --git a/test/case/ietf_syslog/all.yaml b/test/case/ietf_syslog/all.yaml index 83d9bbb3..63893664 100644 --- a/test/case/ietf_syslog/all.yaml +++ b/test/case/ietf_syslog/all.yaml @@ -13,3 +13,6 @@ - name: Syslog Hostname Filtering case: hostname_filter/test.py + +- name: Syslog Property Filtering + case: property_filter/test.py diff --git a/test/case/ietf_syslog/property_filter/Readme.adoc b/test/case/ietf_syslog/property_filter/Readme.adoc new file mode 120000 index 00000000..ae32c841 --- /dev/null +++ b/test/case/ietf_syslog/property_filter/Readme.adoc @@ -0,0 +1 @@ +test.adoc \ No newline at end of file diff --git a/test/case/ietf_syslog/property_filter/test.adoc b/test/case/ietf_syslog/property_filter/test.adoc new file mode 100644 index 00000000..0a5bd5ee --- /dev/null +++ b/test/case/ietf_syslog/property_filter/test.adoc @@ -0,0 +1,25 @@ +=== Syslog Property Filtering + +ifdef::topdoc[:imagesdir: {topdoc}../../test/case/ietf_syslog/property_filter] + +==== Description + +Verify property-filter feature: filtering syslog messages based on various +message properties with different operators, case-insensitivity, and negation. + +==== Topology + +image::topology.svg[Syslog Property Filtering topology, align=center, scaledwidth=75%] + +==== Sequence + +. Set up topology and attach to target DUT +. Clean up old log files +. Configure syslog with property filters +. Send test messages +. Verify myapp log contains only myapp messages +. Verify not-error log excludes ERROR messages +. Verify case-test log matches case-insensitive 'warning' +. Verify baseline log contains all messages + + diff --git a/test/case/ietf_syslog/property_filter/test.py b/test/case/ietf_syslog/property_filter/test.py new file mode 100755 index 00000000..eb366816 --- /dev/null +++ b/test/case/ietf_syslog/property_filter/test.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""Syslog Property Filtering + +Verify property-filter feature: filtering syslog messages based on various +message properties with different operators, case-insensitivity, and negation. + +""" + +import infamy +import time + +TEST_MESSAGES = [ + ("myapp", "Application startup"), + ("myapp", "Processing request"), + ("otherapp", "Different program"), + ("test", "ERROR: Connection failed"), + ("test", "INFO: Normal message"), + ("test", "WARNING: Check config"), + ("test", "Warning: lowercase"), +] + +with infamy.Test() as test: + with test.step("Set up topology and attach to target DUT"): + env = infamy.Env() + target = env.attach("target", "mgmt") + tgtssh = env.attach("target", "mgmt", "ssh") + + with test.step("Clean up old log files"): + tgtssh.runsh("sudo rm -f /var/log/{myapp,not-error,case-test,baseline}") + + with test.step("Configure syslog with property filters"): + target.put_config_dicts({ + "ietf-syslog": { + "syslog": { + "actions": { + "file": { + "log-file": [{ + "name": "file:myapp", + "infix-syslog:property-filter": { + "property": "programname", + "operator": "isequal", + "value": "myapp" + }, + "facility-filter": { + "facility-list": [{ + "facility": "all", + "severity": "info" + }] + } + }, { + "name": "file:not-error", + "infix-syslog:property-filter": { + "property": "msg", + "operator": "contains", + "value": "ERROR", + "negate": True + }, + "facility-filter": { + "facility-list": [{ + "facility": "all", + "severity": "info" + }] + } + }, { + "name": "file:case-test", + "infix-syslog:property-filter": { + "property": "msg", + "operator": "contains", + "value": "warning", + "case-insensitive": True + }, + "facility-filter": { + "facility-list": [{ + "facility": "all", + "severity": "info" + }] + } + }, { + "name": "file:baseline", + "facility-filter": { + "facility-list": [{ + "facility": "all", + "severity": "info" + }] + } + }] + } + } + } + } + }) + + time.sleep(2) + + with test.step("Send test messages"): + for tag, msg in TEST_MESSAGES: + tgtssh.runsh(f"logger -t {tag} -p daemon.info '{msg}'") + time.sleep(1) + + with test.step("Verify myapp log contains only myapp messages"): + rc = tgtssh.runsh("grep -c 'myapp' /var/log/myapp 2>/dev/null") + count = int(rc.stdout.strip()) if rc.returncode == 0 else 0 + if count != 2: + test.fail(f"Expected 2 myapp messages in /var/log/myapp, got {count}") + + rc = tgtssh.runsh("grep -c 'otherapp' /var/log/myapp 2>/dev/null") + count = int(rc.stdout.strip()) if rc.returncode == 0 else 0 + if count != 0: + test.fail(f"Expected 0 otherapp messages in /var/log/myapp, got {count}") + + with test.step("Verify not-error log excludes ERROR messages"): + rc = tgtssh.runsh("grep -c 'test' /var/log/not-error 2>/dev/null") + count = int(rc.stdout.strip()) if rc.returncode == 0 else 0 + if count != 3: + test.fail(f"Expected 3 non-ERROR messages in /var/log/not-error, got {count}") + + rc = tgtssh.runsh("grep -c 'ERROR' /var/log/not-error 2>/dev/null") + count = int(rc.stdout.strip()) if rc.returncode == 0 else 0 + if count != 0: + test.fail(f"Expected 0 ERROR messages in /var/log/not-error, got {count}") + + with test.step("Verify case-test log matches case-insensitive 'warning'"): + rc = tgtssh.runsh("grep -c 'WARNING\\|Warning' /var/log/case-test 2>/dev/null") + count = int(rc.stdout.strip()) if rc.returncode == 0 else 0 + if count != 2: + test.fail(f"Expected 2 warning messages in /var/log/case-test, got {count}") + + with test.step("Verify baseline log contains all messages"): + for tag, msg in TEST_MESSAGES: + rc = tgtssh.runsh(f"grep -q '{msg}' /var/log/baseline 2>/dev/null") + if rc.returncode != 0: + test.fail(f"Expected message '{msg}' not found in /var/log/baseline") + + test.succeed() diff --git a/test/case/ietf_syslog/property_filter/topology.dot b/test/case/ietf_syslog/property_filter/topology.dot new file mode 120000 index 00000000..02b78869 --- /dev/null +++ b/test/case/ietf_syslog/property_filter/topology.dot @@ -0,0 +1 @@ +../../../infamy/topologies/1x1.dot \ No newline at end of file diff --git a/test/case/ietf_syslog/property_filter/topology.svg b/test/case/ietf_syslog/property_filter/topology.svg new file mode 100644 index 00000000..6fc6f47a --- /dev/null +++ b/test/case/ietf_syslog/property_filter/topology.svg @@ -0,0 +1,33 @@ + + + + + + +1x1 + + + +host + +host + +mgmt + + + +target + +mgmt + +target + + + +host:mgmt--target:mgmt + + + +