From 3540ce8587cbd21ce9c2dbec72ea7fa3d1b38a5f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 4 Apr 2023 11:41:55 +0200
Subject: [PATCH] test: validate that fdstore pinning works

Conflict:Adaptation Context.
Reference:https://github.com/systemd/systemd/commit/3540ce8587cbd21ce9c2dbec72ea7fa3d1b38a5f

---
 test/testsuite-80.units/fdstore-nopin.service |  8 +++
 test/testsuite-80.units/fdstore-pin.service   |  8 +++
 test/testsuite-80.units/fdstore-pin.sh        | 47 +++++++++++++++++
 test/testsuite-80.units/fdstore-pin.target    |  3 ++
 test/units/testsuite-80.service               |  2 +
 test/units/testsuite-80.sh                    | 51 +++++++++++++++++++
 6 files changed, 119 insertions(+)
 create mode 100644 test/testsuite-80.units/fdstore-nopin.service
 create mode 100644 test/testsuite-80.units/fdstore-pin.service
 create mode 100755 test/testsuite-80.units/fdstore-pin.sh
 create mode 100644 test/testsuite-80.units/fdstore-pin.target

diff --git a/test/testsuite-80.units/fdstore-nopin.service b/test/testsuite-80.units/fdstore-nopin.service
new file mode 100644
index 0000000..58a687a
--- /dev/null
+++ b/test/testsuite-80.units/fdstore-nopin.service
@@ -0,0 +1,8 @@
+[Service]
+Type=notify
+NotifyAccess=all
+FileDescriptorStoreMax=10
+FileDescriptorStorePreserve=restart
+ExecStart=/usr/lib/systemd/tests/testdata/testsuite-80.units/fdstore-pin.sh 0
+StandardOutput=journal+console
+StandardError=journal+console
diff --git a/test/testsuite-80.units/fdstore-pin.service b/test/testsuite-80.units/fdstore-pin.service
new file mode 100644
index 0000000..bc78ee0
--- /dev/null
+++ b/test/testsuite-80.units/fdstore-pin.service
@@ -0,0 +1,8 @@
+[Service]
+Type=notify
+NotifyAccess=all
+FileDescriptorStoreMax=10
+FileDescriptorStorePreserve=yes
+ExecStart=/usr/lib/systemd/tests/testdata/testsuite-80.units/fdstore-pin.sh 1
+StandardOutput=journal+console
+StandardError=journal+console
diff --git a/test/testsuite-80.units/fdstore-pin.sh b/test/testsuite-80.units/fdstore-pin.sh
new file mode 100755
index 0000000..4cb041a
--- /dev/null
+++ b/test/testsuite-80.units/fdstore-pin.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eux
+set -o pipefail
+
+PINNED="$1"
+COUNTER="/tmp/fdstore-invoked.$PINNED"
+FILE="/tmp/fdstore-data.$PINNED"
+
+# This script is called six times: thrice from a service unit where the fdstore
+# is pinned, and thrice where it isn't. The second iteration of each series is
+# a restart, the third a stop followed by a start
+
+if [ -e "$COUNTER" ] ; then
+    read -r N < "$COUNTER"
+else
+    N=0
+fi
+
+echo "Invocation #$N with PINNED=$PINNED."
+
+if [ "$N" -eq 0 ] ; then
+    # First iteration
+    test "${LISTEN_FDS:-0}" -eq 0
+    test ! -e "$FILE"
+    echo waldi > "$FILE"
+    systemd-notify --fd=3 --fdname="fd-$N-$PINNED" 3< "$FILE"
+elif [ "$N" -eq 1 ] || { [ "$N" -eq 2 ] && [ "$PINNED" -eq 1 ]; } ; then
+    # Second iteration, or iteration with pinning on
+    test "${LISTEN_FDS:-0}" -eq 1
+    # We reopen fd #3 here, so that the read offset is at zero each time (hence no <&3 here…)
+    read -r word < /proc/self/fd/3
+    test "$word" = "waldi"
+else
+    test "${LISTEN_FDS:-0}" -eq 0
+    test -e "$FILE"
+fi
+
+if [ "$N" -ge 2 ] ; then
+    rm "$COUNTER" "$FILE"
+else
+    echo $((N + 1)) > "$COUNTER"
+fi
+
+systemd-notify --ready --status="Ready"
+
+exec sleep infinity
diff --git a/test/testsuite-80.units/fdstore-pin.target b/test/testsuite-80.units/fdstore-pin.target
new file mode 100644
index 0000000..319b7e1
--- /dev/null
+++ b/test/testsuite-80.units/fdstore-pin.target
@@ -0,0 +1,3 @@
+[Unit]
+After=fdstore-pin.service fdstore-nopin.service
+Wants=fdstore-pin.service fdstore-nopin.service
diff --git a/test/units/testsuite-80.service b/test/units/testsuite-80.service
index 4c7f5d5..82b08a1 100644
--- a/test/units/testsuite-80.service
+++ b/test/units/testsuite-80.service
@@ -6,3 +6,5 @@ Description=TEST-80-NOTIFYACCESS
 ExecStartPre=rm -f /failed /testok
 ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
 Type=oneshot
+StandardOutput=journal+console
+StandardError=journal+console
diff --git a/test/units/testsuite-80.sh b/test/units/testsuite-80.sh
index 43647a7..9a979b9 100755
--- a/test/units/testsuite-80.sh
+++ b/test/units/testsuite-80.sh
@@ -48,5 +48,56 @@ assert_eq "$(systemctl show notify.service -p NotifyAccess --value)" "all"
 
 rm /tmp/syncfifo1 /tmp/syncfifo2
 
+# Now test basic fdstore behaviour
+
+systemd-analyze log-level debug
+
+# Test fdstore pinning (this will pull in fdstore-pin.service fdstore-nopin.service)
+systemctl start fdstore-pin.target
+
+assert_eq "$(systemctl show fdstore-pin.service -P FileDescriptorStorePreserve)" yes
+assert_eq "$(systemctl show fdstore-nopin.service -P FileDescriptorStorePreserve)" restart
+assert_eq "$(systemctl show fdstore-pin.service -P SubState)" running
+assert_eq "$(systemctl show fdstore-nopin.service -P SubState)" running
+assert_eq "$(systemctl show fdstore-pin.service -P NFileDescriptorStore)" 1
+assert_eq "$(systemctl show fdstore-nopin.service -P NFileDescriptorStore)" 1
+
+# The file descriptor store should survive service restarts
+systemctl restart fdstore-pin.service fdstore-nopin.service
+
+assert_eq "$(systemctl show fdstore-pin.service -P NFileDescriptorStore)" 1
+assert_eq "$(systemctl show fdstore-nopin.service -P NFileDescriptorStore)" 1
+assert_eq "$(systemctl show fdstore-pin.service -P SubState)" running
+assert_eq "$(systemctl show fdstore-nopin.service -P SubState)" running
+
+# It should not survive the service stop plus a later start (unless pinned)
+systemctl stop fdstore-pin.service fdstore-nopin.service
+
+assert_eq "$(systemctl show fdstore-pin.service -P NFileDescriptorStore)" 1
+assert_eq "$(systemctl show fdstore-nopin.service -P NFileDescriptorStore)" 0
+assert_eq "$(systemctl show fdstore-pin.service -P SubState)" dead-resources-pinned
+assert_eq "$(systemctl show fdstore-nopin.service -P SubState)" dead
+
+systemctl start fdstore-pin.service fdstore-nopin.service
+
+assert_eq "$(systemctl show fdstore-pin.service -P NFileDescriptorStore)" 1
+assert_eq "$(systemctl show fdstore-nopin.service -P NFileDescriptorStore)" 0
+assert_eq "$(systemctl show fdstore-pin.service -P SubState)" running
+assert_eq "$(systemctl show fdstore-nopin.service -P SubState)" running
+
+systemctl stop fdstore-pin.service fdstore-nopin.service
+
+assert_eq "$(systemctl show fdstore-pin.service -P NFileDescriptorStore)" 1
+assert_eq "$(systemctl show fdstore-nopin.service -P NFileDescriptorStore)" 0
+assert_eq "$(systemctl show fdstore-pin.service -P SubState)" dead-resources-pinned
+assert_eq "$(systemctl show fdstore-nopin.service -P SubState)" dead
+
+systemctl clean fdstore-pin.service --what=fdstore
+
+assert_eq "$(systemctl show fdstore-pin.service -P NFileDescriptorStore)" 0
+assert_eq "$(systemctl show fdstore-nopin.service -P NFileDescriptorStore)" 0
+assert_eq "$(systemctl show fdstore-pin.service -P SubState)" dead
+assert_eq "$(systemctl show fdstore-nopin.service -P SubState)" dead
+
 touch /testok
 rm /failed
 
-- 
2.33.0

