summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/README.testsuite2
-rwxr-xr-xtest/TEST-01-BASIC/test.sh16
-rwxr-xr-xtest/TEST-02-CRYPTSETUP/test.sh7
-rwxr-xr-xtest/TEST-03-JOBS/test-jobs.sh38
-rwxr-xr-xtest/TEST-03-JOBS/test.sh5
l---------test/TEST-04-JOURNAL/Makefile1
-rwxr-xr-xtest/TEST-04-JOURNAL/test-journal.sh62
-rwxr-xr-xtest/TEST-04-JOURNAL/test.sh84
l---------test/TEST-05-RLIMITS/Makefile1
-rwxr-xr-xtest/TEST-05-RLIMITS/test-rlimits.sh16
-rwxr-xr-xtest/TEST-05-RLIMITS/test.sh80
l---------test/TEST-06-SELINUX/Makefile1
-rw-r--r--test/TEST-06-SELINUX/systemd_test.if8
-rw-r--r--test/TEST-06-SELINUX/systemd_test.te50
-rwxr-xr-xtest/TEST-06-SELINUX/test-selinux-checks.sh12
-rwxr-xr-xtest/TEST-06-SELINUX/test.sh135
l---------test/TEST-07-ISSUE-1981/Makefile1
-rwxr-xr-xtest/TEST-07-ISSUE-1981/test-segfault.sh36
-rwxr-xr-xtest/TEST-07-ISSUE-1981/test.sh59
l---------test/TEST-08-ISSUE-2730/Makefile1
-rwxr-xr-xtest/TEST-08-ISSUE-2730/test.sh112
l---------test/TEST-09-ISSUE-2691/Makefile1
-rwxr-xr-xtest/TEST-09-ISSUE-2691/test.sh80
l---------test/TEST-10-ISSUE-2467/Makefile1
-rwxr-xr-xtest/TEST-10-ISSUE-2467/test.sh91
l---------test/TEST-11-ISSUE-3166/Makefile1
-rwxr-xr-xtest/TEST-11-ISSUE-3166/test.sh94
l---------test/TEST-12-ISSUE-3171/Makefile1
-rwxr-xr-xtest/TEST-12-ISSUE-3171/test.sh109
-rw-r--r--test/end.service10
-rw-r--r--test/end.service.in6
-rw-r--r--test/exec-environment-empty.service7
-rw-r--r--test/exec-environment.service6
-rw-r--r--test/exec-group.service6
-rw-r--r--test/exec-umask-0177.service7
-rw-r--r--test/exec-umask-default.service6
-rw-r--r--test/exec-user.service6
-rwxr-xr-xtest/networkd-test.py599
-rw-r--r--test/parent.slice2
l---------test/paths.target1
-rwxr-xr-x[-rw-r--r--]test/sysv-generator-test.py25
-rwxr-xr-xtest/test-efi-create-disk.sh4
-rw-r--r--test/test-execute/exec-capabilityambientset-merge-nfsnobody.service9
-rw-r--r--test/test-execute/exec-capabilityambientset-merge.service9
-rw-r--r--test/test-execute/exec-capabilityambientset-nfsnobody.service8
-rw-r--r--test/test-execute/exec-capabilityambientset.service8
-rw-r--r--test/test-execute/exec-capabilityboundingset-invert.service7
-rw-r--r--test/test-execute/exec-capabilityboundingset-merge.service8
-rw-r--r--test/test-execute/exec-capabilityboundingset-reset.service8
-rw-r--r--test/test-execute/exec-capabilityboundingset-simple.service7
-rw-r--r--test/test-execute/exec-environment-empty.service8
-rw-r--r--test/test-execute/exec-environment-multiple.service (renamed from test/exec-environment-multiple.service)3
-rw-r--r--test/test-execute/exec-environment.service7
-rw-r--r--test/test-execute/exec-environmentfile.service7
-rw-r--r--test/test-execute/exec-group-nfsnobody.service7
-rw-r--r--test/test-execute/exec-group.service7
-rw-r--r--test/test-execute/exec-ignoresigpipe-no.service (renamed from test/exec-ignoresigpipe-no.service)2
-rw-r--r--test/test-execute/exec-ignoresigpipe-yes.service (renamed from test/exec-ignoresigpipe-yes.service)2
-rw-r--r--test/test-execute/exec-inaccessiblepaths-mount-propagation.service7
-rw-r--r--test/test-execute/exec-ioschedulingclass-best-effort.service7
-rw-r--r--test/test-execute/exec-ioschedulingclass-idle.service7
-rw-r--r--test/test-execute/exec-ioschedulingclass-none.service7
-rw-r--r--test/test-execute/exec-ioschedulingclass-realtime.service7
-rw-r--r--test/test-execute/exec-oomscoreadjust-negative.service7
-rw-r--r--test/test-execute/exec-oomscoreadjust-positive.service7
-rw-r--r--test/test-execute/exec-passenvironment-absent.service7
-rw-r--r--test/test-execute/exec-passenvironment-empty.service8
-rw-r--r--test/test-execute/exec-passenvironment-repeated.service8
-rw-r--r--test/test-execute/exec-passenvironment.service7
-rw-r--r--test/test-execute/exec-personality-aarch64.service7
-rw-r--r--test/test-execute/exec-personality-ppc64.service (renamed from test/exec-personality-x86.service)6
-rw-r--r--test/test-execute/exec-personality-ppc64le.service (renamed from test/exec-personality-x86-64.service)6
-rw-r--r--test/test-execute/exec-personality-s390.service7
-rw-r--r--test/test-execute/exec-personality-x86-64.service7
-rw-r--r--test/test-execute/exec-personality-x86.service7
-rw-r--r--test/test-execute/exec-privatedevices-no-capability-mknod.service7
-rw-r--r--test/test-execute/exec-privatedevices-no.service (renamed from test/exec-privatedevices-no.service)2
-rw-r--r--test/test-execute/exec-privatedevices-yes-capability-mknod.service7
-rw-r--r--test/test-execute/exec-privatedevices-yes.service (renamed from test/exec-privatedevices-yes.service)2
-rw-r--r--test/test-execute/exec-privatenetwork-yes.service7
-rw-r--r--test/test-execute/exec-privatetmp-no.service (renamed from test/exec-privatetmp-no.service)2
-rw-r--r--test/test-execute/exec-privatetmp-yes.service (renamed from test/exec-privatetmp-yes.service)2
-rw-r--r--test/test-execute/exec-readonlypaths-mount-propagation.service7
-rw-r--r--test/test-execute/exec-readonlypaths.service7
-rw-r--r--test/test-execute/exec-readwritepaths-mount-propagation.service7
-rw-r--r--test/test-execute/exec-runtimedirectory-mode.service8
-rw-r--r--test/test-execute/exec-runtimedirectory-owner-nfsnobody.service9
-rw-r--r--test/test-execute/exec-runtimedirectory-owner.service9
-rw-r--r--test/test-execute/exec-runtimedirectory.service7
-rw-r--r--test/test-execute/exec-spec-interpolation.service6
-rw-r--r--test/test-execute/exec-systemcallerrornumber.service (renamed from test/exec-systemcallerrornumber.service)3
-rw-r--r--test/test-execute/exec-systemcallfilter-failing.service (renamed from test/exec-systemcallfilter-failing.service)1
-rw-r--r--test/test-execute/exec-systemcallfilter-failing2.service (renamed from test/exec-systemcallfilter-failing2.service)1
-rw-r--r--test/test-execute/exec-systemcallfilter-not-failing.service (renamed from test/exec-systemcallfilter-not-failing.service)1
-rw-r--r--test/test-execute/exec-systemcallfilter-not-failing2.service (renamed from test/exec-systemcallfilter-not-failing2.service)1
-rw-r--r--test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service11
-rw-r--r--test/test-execute/exec-systemcallfilter-system-user.service11
-rw-r--r--test/test-execute/exec-umask-0177.service8
-rw-r--r--test/test-execute/exec-umask-default.service7
-rw-r--r--test/test-execute/exec-user-nfsnobody.service7
-rw-r--r--test/test-execute/exec-user.service7
-rw-r--r--test/test-execute/exec-workingdirectory.service (renamed from test/exec-workingdirectory.service)2
-rw-r--r--test/test-functions242
l---------test/test-path/basic.target1
-rw-r--r--test/test-path/path-changed.path (renamed from test/path-changed.path)0
l---------test/test-path/path-changed.service (renamed from test/path-changed.service)0
-rw-r--r--test/test-path/path-directorynotempty.path (renamed from test/path-directorynotempty.path)0
l---------test/test-path/path-directorynotempty.service (renamed from test/path-directorynotempty.service)0
-rw-r--r--test/test-path/path-exists.path (renamed from test/path-exists.path)0
l---------test/test-path/path-exists.service (renamed from test/path-exists.service)0
-rw-r--r--test/test-path/path-existsglob.path (renamed from test/path-existsglob.path)0
l---------test/test-path/path-existsglob.service (renamed from test/path-existsglob.service)0
-rw-r--r--test/test-path/path-makedirectory.path (renamed from test/path-makedirectory.path)0
l---------test/test-path/path-makedirectory.service (renamed from test/path-makedirectory.service)0
-rw-r--r--test/test-path/path-modified.path (renamed from test/path-modified.path)0
l---------test/test-path/path-modified.service (renamed from test/path-modified.service)0
-rw-r--r--test/test-path/path-mycustomunit.service (renamed from test/path-mycustomunit.service)0
-rw-r--r--test/test-path/path-service.service (renamed from test/path-service.service)0
-rw-r--r--test/test-path/path-unit.path (renamed from test/path-unit.path)0
l---------test/test-path/paths.target1
l---------test/test-path/sysinit.target1
-rwxr-xr-xtest/udev-test.pl80
-rw-r--r--test/unstoppable.service2
123 files changed, 2361 insertions, 131 deletions
diff --git a/test/README.testsuite b/test/README.testsuite
index 5c7aca43a8..fa7e73ce3a 100644
--- a/test/README.testsuite
+++ b/test/README.testsuite
@@ -36,7 +36,7 @@ you can even skip the "clean" and "setup" if you want to run the machine again.
$ sudo make KERNEL_APPEND="systemd.unit=multi-user.target" run
You can specify a different kernel and initramfs with $KERNEL_BIN and $INITRD.
-(Fedora's default kernel path and initramfs are used by default)
+(Fedora's or Debian's default kernel path and initramfs are used by default)
$ sudo make KERNEL_BIN=/boot/vmlinuz-foo INITRD=/boot/initramfs-bar clean check
diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh
index d97fbe24d4..041195dcd8 100755
--- a/test/TEST-01-BASIC/test.sh
+++ b/test/TEST-01-BASIC/test.sh
@@ -11,7 +11,7 @@ check_result_qemu() {
mount ${LOOPDEV}p1 $TESTDIR/root
[[ -e $TESTDIR/root/testok ]] && ret=0
[[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
- [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
umount $TESTDIR/root
[[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
ls -l $TESTDIR/journal/*/*.journal
@@ -25,8 +25,7 @@ test_run() {
else
dwarn "can't run QEMU, skipping"
fi
- if check_nspawn; then
- run_nspawn
+ if run_nspawn; then
check_result_nspawn || return 1
else
dwarn "can't run systemd-nspawn, skipping"
@@ -53,14 +52,21 @@ Description=Testsuite service
After=multi-user.target
[Service]
-ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;'
+ExecStart=/bin/sh -x -c 'systemctl --state=failed --no-legend --no-pager > /failed ; echo OK > /testok'
Type=oneshot
EOF
setup_testsuite
- )
+ ) || return 1
setup_nspawn_root
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
ddebug "umount $TESTDIR/root"
umount $TESTDIR/root
}
diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh
index 4be2365e2f..aea0fc53f6 100755
--- a/test/TEST-02-CRYPTSETUP/test.sh
+++ b/test/TEST-02-CRYPTSETUP/test.sh
@@ -13,7 +13,7 @@ check_result_qemu() {
[[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile
mount /dev/mapper/varcrypt $TESTDIR/root/var
- [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
umount $TESTDIR/root/var
umount $TESTDIR/root
cryptsetup luksClose /dev/mapper/varcrypt
@@ -59,7 +59,7 @@ Description=Testsuite service
After=multi-user.target
[Service]
-ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do systemd-cat echo "testsuite service waiting for /var/log/journal" ; echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;'
+ExecStart=/bin/sh -x -c 'systemctl --state=failed --no-legend --no-pager > /failed ; echo OK > /testok'
Type=oneshot
EOF
@@ -76,8 +76,7 @@ EOF
cat >>$initdir/etc/fstab <<EOF
/dev/mapper/varcrypt /var ext3 defaults 0 1
EOF
- )
- setup_nspawn_root
+ ) || return 1
ddebug "umount $TESTDIR/root/var"
umount $TESTDIR/root/var
diff --git a/test/TEST-03-JOBS/test-jobs.sh b/test/TEST-03-JOBS/test-jobs.sh
index 6f32c240cd..fa6cf4181a 100755
--- a/test/TEST-03-JOBS/test-jobs.sh
+++ b/test/TEST-03-JOBS/test-jobs.sh
@@ -4,9 +4,12 @@
# installed job.
systemctl start --no-block hello-after-sleep.target
-# sleep is now running, hello/start is waiting. Verify that:
+
systemctl list-jobs > /root/list-jobs.txt
-grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1
+while ! grep 'sleep\.service.*running' /root/list-jobs.txt; do
+ systemctl list-jobs > /root/list-jobs.txt
+done
+
grep 'hello\.service.*waiting' /root/list-jobs.txt || exit 1
# This is supposed to finish quickly, not wait for sleep to finish.
@@ -23,7 +26,7 @@ grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1
grep 'hello\.service' /root/list-jobs.txt && exit 1
systemctl stop sleep.service hello-after-sleep.target || exit 1
-# Test for a crash when enqueueing a JOB_NOP when other job already exists
+# Test for a crash when enqueuing a JOB_NOP when other job already exists
systemctl start --no-block hello-after-sleep.target || exit 1
# hello.service should still be waiting, so these try-restarts will collapse
# into NOPs.
@@ -46,5 +49,32 @@ systemctl stop --job-mode=replace-irreversibly unstoppable.service || exit 1
# Shutdown of the container/VM will hang if not.
systemctl start unstoppable.service || exit 1
+# Test waiting for a started unit(s) to terminate again
+cat <<EOF > /run/systemd/system/wait2.service
+[Unit]
+Description=Wait for 2 seconds
+[Service]
+ExecStart=/bin/sh -ec 'sleep 2'
+EOF
+cat <<EOF > /run/systemd/system/wait5fail.service
+[Unit]
+Description=Wait for 5 seconds and fail
+[Service]
+ExecStart=/bin/sh -ec 'sleep 5; false'
+EOF
+
+# wait2 succeeds
+START_SEC=$(date -u '+%s')
+systemctl start --wait wait2.service || exit 1
+END_SEC=$(date -u '+%s')
+ELAPSED=$(($END_SEC-$START_SEC))
+[[ "$ELAPSED" -ge 2 ]] && [[ "$ELAPSED" -le 3 ]] || exit 1
+
+# wait5fail fails, so systemctl should fail
+START_SEC=$(date -u '+%s')
+! systemctl start --wait wait2.service wait5fail.service || exit 1
+END_SEC=$(date -u '+%s')
+ELAPSED=$(($END_SEC-$START_SEC))
+[[ "$ELAPSED" -ge 5 ]] && [[ "$ELAPSED" -le 7 ]] || exit 1
+
touch /testok
-exit 0
diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh
index 41e02e2c8a..ab0de0bfd1 100755
--- a/test/TEST-03-JOBS/test.sh
+++ b/test/TEST-03-JOBS/test.sh
@@ -25,8 +25,7 @@ test_run() {
else
dwarn "can't run QEMU, skipping"
fi
- if check_nspawn; then
- run_nspawn
+ if run_nspawn; then
check_result_nspawn || return 1
else
dwarn "can't run systemd-nspawn, skipping"
@@ -63,7 +62,7 @@ EOF
cp test-jobs.sh $initdir/
setup_testsuite
- )
+ ) || return 1
setup_nspawn_root
ddebug "umount $TESTDIR/root"
diff --git a/test/TEST-04-JOURNAL/Makefile b/test/TEST-04-JOURNAL/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-04-JOURNAL/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh
new file mode 100755
index 0000000000..6646eccfa7
--- /dev/null
+++ b/test/TEST-04-JOURNAL/test-journal.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+set -x
+set -e
+set -o pipefail
+
+# Test stdout stream
+
+# Skip empty lines
+ID=$(journalctl --new-id128 | sed -n 2p)
+>/expected
+printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+ID=$(journalctl --new-id128 | sed -n 2p)
+>/expected
+printf $'<5>\n<6>\n<7>\n' | systemd-cat -t "$ID" --level-prefix true
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+# Remove trailing spaces
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf "Trailing spaces\n">/expected
+printf $'<5>Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix true
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf "Trailing spaces\n">/expected
+printf $'Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix false
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+# Don't remove leading spaces
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf $' \t Leading spaces\n'>/expected
+printf $'<5> \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix true
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+ID=$(journalctl --new-id128 | sed -n 2p)
+printf $' \t Leading spaces\n'>/expected
+printf $' \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix false
+journalctl --sync
+journalctl -b -o cat -t "$ID" >/output
+cmp /expected /output
+
+# Don't lose streams on restart
+systemctl start forever-print-hola
+sleep 3
+systemctl restart systemd-journald
+sleep 3
+systemctl stop forever-print-hola
+[[ ! -f "/i-lose-my-logs" ]]
+
+touch /testok
diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh
new file mode 100755
index 0000000000..3ccf113019
--- /dev/null
+++ b/test/TEST-04-JOURNAL/test.sh
@@ -0,0 +1,84 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="Journal-related tests"
+
+. $TEST_BASE_DIR/test-functions
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ if run_nspawn; then
+ check_result_nspawn || return 1
+ else
+ dwarn "can't run systemd-nspawn, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-journal.sh
+Type=oneshot
+EOF
+
+ cat >$initdir/etc/systemd/system/forever-print-hola.service <<EOF
+[Unit]
+Description=ForeverPrintHola service
+
+[Service]
+Type=simple
+ExecStart=/bin/sh -x -c 'while :; do printf "Hola\n" || touch /i-lose-my-logs; sleep 1; done'
+EOF
+
+ cp test-journal.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-05-RLIMITS/Makefile b/test/TEST-05-RLIMITS/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-05-RLIMITS/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-05-RLIMITS/test-rlimits.sh b/test/TEST-05-RLIMITS/test-rlimits.sh
new file mode 100755
index 0000000000..ba665c5968
--- /dev/null
+++ b/test/TEST-05-RLIMITS/test-rlimits.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -x
+set -e
+set -o pipefail
+
+[[ "$(systemctl show -p DefaultLimitNOFILESoft)" = "DefaultLimitNOFILESoft=10000" ]]
+[[ "$(systemctl show -p DefaultLimitNOFILE)" = "DefaultLimitNOFILE=16384" ]]
+
+[[ "$(systemctl show -p LimitNOFILESoft testsuite.service)" = "LimitNOFILESoft=10000" ]]
+[[ "$(systemctl show -p LimitNOFILE testsuite.service)" = "LimitNOFILE=16384" ]]
+
+[[ "$(ulimit -n -S)" = "10000" ]]
+[[ "$(ulimit -n -H)" = "16384" ]]
+
+touch /testok
diff --git a/test/TEST-05-RLIMITS/test.sh b/test/TEST-05-RLIMITS/test.sh
new file mode 100755
index 0000000000..a5f7e8de0b
--- /dev/null
+++ b/test/TEST-05-RLIMITS/test.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="Resource limits-related tests"
+
+. $TEST_BASE_DIR/test-functions
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ if run_nspawn; then
+ check_result_nspawn || return 1
+ else
+ dwarn "can't run systemd-nspawn, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ cat >$initdir/etc/systemd/system.conf <<EOF
+[Manager]
+DefaultLimitNOFILE=10000:16384
+EOF
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-rlimits.sh
+Type=oneshot
+EOF
+
+ cp test-rlimits.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-06-SELINUX/Makefile b/test/TEST-06-SELINUX/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-06-SELINUX/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-06-SELINUX/systemd_test.if b/test/TEST-06-SELINUX/systemd_test.if
new file mode 100644
index 0000000000..25c91adce9
--- /dev/null
+++ b/test/TEST-06-SELINUX/systemd_test.if
@@ -0,0 +1,8 @@
+template(`systemd_test_base_template', `
+ gen_require(`
+ attribute systemd_test_domain_type;
+ ')
+
+ type $1_t, systemd_test_domain_type;
+ domain_type($1_t)
+')
diff --git a/test/TEST-06-SELINUX/systemd_test.te b/test/TEST-06-SELINUX/systemd_test.te
new file mode 100644
index 0000000000..ff01c09b5e
--- /dev/null
+++ b/test/TEST-06-SELINUX/systemd_test.te
@@ -0,0 +1,50 @@
+policy_module(systemd_test, 0.0.1)
+
+# declarations
+attribute systemd_test_domain_type;
+
+systemd_test_base_template(systemd_test)
+systemd_test_base_template(systemd_test_status)
+systemd_test_base_template(systemd_test_start)
+systemd_test_base_template(systemd_test_stop)
+systemd_test_base_template(systemd_test_reload)
+
+# systemd_test_domain_type
+
+require {
+ role system_r;
+ role unconfined_r;
+ type bin_t;
+ type initrc_t;
+ type systemd_systemctl_exec_t;
+ type unconfined_service_t;
+}
+
+role system_r types systemd_test_domain_type;
+role unconfined_r types systemd_test_domain_type;
+
+allow systemd_test_domain_type bin_t: file entrypoint;
+allow systemd_test_domain_type systemd_systemctl_exec_t: file entrypoint;
+allow initrc_t systemd_test_domain_type: process transition;
+allow unconfined_service_t systemd_test_domain_type: process transition;
+corecmd_exec_bin(systemd_test_domain_type)
+init_signal_script(systemd_test_domain_type)
+init_sigchld_script(systemd_test_domain_type)
+systemd_exec_systemctl(systemd_test_domain_type)
+userdom_use_user_ttys(systemd_test_domain_type)
+userdom_use_user_ptys(systemd_test_domain_type)
+
+optional_policy(`
+ dbus_system_bus_client(systemd_test_domain_type)
+ init_dbus_chat(systemd_test_domain_type)
+')
+
+# systemd_test_*_t
+require {
+ type systemd_unit_file_t;
+}
+
+allow systemd_test_status_t systemd_unit_file_t: service { status };
+allow systemd_test_start_t systemd_unit_file_t: service { start };
+allow systemd_test_stop_t systemd_unit_file_t: service { stop };
+allow systemd_test_reload_t systemd_unit_file_t: service { reload };
diff --git a/test/TEST-06-SELINUX/test-selinux-checks.sh b/test/TEST-06-SELINUX/test-selinux-checks.sh
new file mode 100755
index 0000000000..153fab3aac
--- /dev/null
+++ b/test/TEST-06-SELINUX/test-selinux-checks.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -x
+set -e
+set -o pipefail
+
+echo 1 >/sys/fs/selinux/enforce
+runcon -t systemd_test_start_t systemctl start hola
+runcon -t systemd_test_reload_t systemctl reload hola
+runcon -t systemd_test_stop_t systemctl stop hola
+
+touch /testok
diff --git a/test/TEST-06-SELINUX/test.sh b/test/TEST-06-SELINUX/test.sh
new file mode 100755
index 0000000000..1ae4a7c0d9
--- /dev/null
+++ b/test/TEST-06-SELINUX/test.sh
@@ -0,0 +1,135 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="SELinux tests"
+
+# Requirements:
+# Fedora 23
+# selinux-policy-targeted
+# selinux-policy-devel
+
+. $TEST_BASE_DIR/test-functions
+SETUP_SELINUX=yes
+KERNEL_APPEND="$KERNEL_APPEND selinux=1 security=selinux"
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cat <<EOF >$initdir/etc/systemd/system/testsuite.service
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-selinux-checks.sh
+Type=oneshot
+EOF
+
+ cat <<EOF >$initdir/etc/systemd/system/hola.service
+[Service]
+Type=oneshot
+ExecStart=/bin/echo Start Hola
+ExecReload=/bin/echo Reload Hola
+ExecStop=/bin/echo Stop Hola
+RemainAfterExit=yes
+EOF
+
+ setup_testsuite
+
+ cat <<EOF >$initdir/etc/systemd/system/load-systemd-test-module.service
+[Unit]
+Description=Load systemd-test module
+DefaultDependencies=no
+Requires=local-fs.target
+Conflicts=shutdown.target
+After=local-fs.target
+Before=sysinit.target shutdown.target autorelabel.service
+ConditionSecurity=selinux
+ConditionPathExists=|/.load-systemd-test-module
+
+[Service]
+ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && cd /systemd-test-module && make -f /usr/share/selinux/devel/Makefile load && rm /.load-systemd-test-module'
+Type=oneshot
+TimeoutSec=0
+RemainAfterExit=yes
+EOF
+
+ touch $initdir/.load-systemd-test-module
+ mkdir -p $initdir/etc/systemd/system/basic.target.wants
+ ln -fs load-systemd-test-module.service $initdir/etc/systemd/system/basic.target.wants/load-systemd-test-module.service
+
+ local _modules_dir=/var/lib/selinux
+ rm -rf $initdir/$_modules_dir
+ if ! cp -ar $_modules_dir $initdir/$_modules_dir; then
+ dfatal "Failed to copy $_modules_dir"
+ exit 1
+ fi
+
+ local _policy_headers_dir=/usr/share/selinux/devel
+ rm -rf $initdir/$_policy_headers_dir
+ inst_dir /usr/share/selinux
+ if ! cp -ar $_policy_headers_dir $initdir/$_policy_headers_dir; then
+ dfatal "Failed to copy $_policy_headers_dir"
+ exit 1
+ fi
+
+ mkdir $initdir/systemd-test-module
+ cp systemd_test.te $initdir/systemd-test-module
+ cp systemd_test.if $initdir/systemd-test-module
+ cp test-selinux-checks.sh $initdir
+ dracut_install -o sesearch
+ dracut_install runcon
+ dracut_install checkmodule semodule semodule_package m4 make /usr/libexec/selinux/hll/pp load_policy sefcontext_compile
+ ) || return 1
+
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-07-ISSUE-1981/Makefile b/test/TEST-07-ISSUE-1981/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-07-ISSUE-1981/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-07-ISSUE-1981/test-segfault.sh b/test/TEST-07-ISSUE-1981/test-segfault.sh
new file mode 100755
index 0000000000..48f05d89fb
--- /dev/null
+++ b/test/TEST-07-ISSUE-1981/test-segfault.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -x
+set -e
+
+>/failed
+
+cat <<'EOL' >/lib/systemd/system/my.service
+[Service]
+Type=oneshot
+ExecStart=/bin/echo Timer runs me
+EOL
+
+cat <<'EOL' >/lib/systemd/system/my.timer
+[Timer]
+OnBootSec=10s
+OnUnitInactiveSec=1h
+EOL
+
+systemctl unmask my.timer
+
+systemctl start my.timer
+
+mkdir -p /etc/systemd/system/my.timer.d/
+cat <<'EOL' >/etc/systemd/system/my.timer.d/override.conf
+[Timer]
+OnBootSec=10s
+OnUnitInactiveSec=1h
+EOL
+
+systemctl daemon-reload
+
+systemctl mask my.timer
+
+touch /testok
+rm /failed
diff --git a/test/TEST-07-ISSUE-1981/test.sh b/test/TEST-07-ISSUE-1981/test.sh
new file mode 100755
index 0000000000..2f7f01058e
--- /dev/null
+++ b/test/TEST-07-ISSUE-1981/test.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/1981"
+
+. $TEST_BASE_DIR/test-functions
+
+NSPAWN_TIMEOUT=30s
+
+test_run() {
+ dwarn "skipping QEMU"
+ if run_nspawn; then
+ check_result_nspawn || return 1
+ else
+ dwarn "can't run systemd-nspawn, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-segfault.sh
+Type=oneshot
+EOF
+
+ cp test-segfault.sh $initdir/
+
+ setup_testsuite
+ ) || return 1
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-08-ISSUE-2730/Makefile b/test/TEST-08-ISSUE-2730/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-08-ISSUE-2730/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-08-ISSUE-2730/test.sh b/test/TEST-08-ISSUE-2730/test.sh
new file mode 100755
index 0000000000..44831983b3
--- /dev/null
+++ b/test/TEST-08-ISSUE-2730/test.sh
@@ -0,0 +1,112 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2730"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+QEMU_TIMEOUT=180
+FSTYPE=ext4
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ [ -n "$TIMED_OUT" ] && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/bin/sh -x -c 'mount -o remount,rw /dev/sda1 && echo OK > /testok; systemctl poweroff'
+Type=oneshot
+EOF
+
+ rm $initdir/etc/fstab
+ cat >$initdir/etc/systemd/system/-.mount <<EOF
+[Unit]
+Before=local-fs.target
+
+[Mount]
+What=/dev/sda1
+Where=/
+Type=ext4
+Options=errors=remount-ro,noatime
+
+[Install]
+WantedBy=local-fs.target
+Alias=root.mount
+EOF
+
+ cat >$initdir/etc/systemd/system/systemd-remount-fs.service <<EOF
+[Unit]
+DefaultDependencies=no
+Conflicts=shutdown.target
+After=systemd-fsck-root.service
+Before=local-fs-pre.target local-fs.target shutdown.target
+Wants=local-fs-pre.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/bin/systemctl reload /
+EOF
+
+ setup_testsuite
+ ) || return 1
+
+ ln -s /etc/systemd/system/-.mount $initdir/etc/systemd/system/root.mount
+ mkdir -p $initdir/etc/systemd/system/local-fs.target.wants
+ ln -s /etc/systemd/system/-.mount $initdir/etc/systemd/system/local-fs.target.wants/-.mount
+
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-09-ISSUE-2691/Makefile b/test/TEST-09-ISSUE-2691/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-09-ISSUE-2691/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-09-ISSUE-2691/test.sh b/test/TEST-09-ISSUE-2691/test.sh
new file mode 100755
index 0000000000..8ae02e61ac
--- /dev/null
+++ b/test/TEST-09-ISSUE-2691/test.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2691"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+QEMU_TIMEOUT=90
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ [ -n "$TIMED_OUT" ] && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<'EOF'
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c '>/testok'
+RemainAfterExit=yes
+ExecStop=/bin/sh -c 'kill -SEGV $$$$'
+TimeoutStopSec=180s
+EOF
+
+ setup_testsuite
+ ) || return 1
+
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-10-ISSUE-2467/Makefile b/test/TEST-10-ISSUE-2467/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-10-ISSUE-2467/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-10-ISSUE-2467/test.sh b/test/TEST-10-ISSUE-2467/test.sh
new file mode 100755
index 0000000000..4eca6784bc
--- /dev/null
+++ b/test/TEST-10-ISSUE-2467/test.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2467"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ dracut_install nc true rm
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<'EOF'
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test.socket; echo a | nc -U /run/test.ctl; >/testok'
+TimeoutStartSec=10s
+EOF
+
+ cat >$initdir/etc/systemd/system/test.socket <<'EOF'
+[Socket]
+ListenStream=/run/test.ctl
+EOF
+
+ cat > $initdir/etc/systemd/system/test.service <<'EOF'
+[Unit]
+Requires=test.socket
+ConditionPathExistsGlob=/tmp/nonexistent
+
+[Service]
+ExecStart=/bin/true
+EOF
+
+ setup_testsuite
+ ) || return 1
+
+ # mask some services that we do not want to run in these tests
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+ ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-11-ISSUE-3166/Makefile b/test/TEST-11-ISSUE-3166/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-11-ISSUE-3166/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-11-ISSUE-3166/test.sh b/test/TEST-11-ISSUE-3166/test.sh
new file mode 100755
index 0000000000..0f269c8211
--- /dev/null
+++ b/test/TEST-11-ISSUE-3166/test.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/3166"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+
+check_result_qemu() {
+ ret=1
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+ [[ -e $TESTDIR/root/testok ]] && ret=0
+ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+ cp -a $TESTDIR/root/var/log/journal $TESTDIR
+ umount $TESTDIR/root
+ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+ ls -l $TESTDIR/journal/*/*.journal
+ test -s $TESTDIR/failed && ret=$(($ret+1))
+ return $ret
+}
+
+test_run() {
+ if run_qemu; then
+ check_result_qemu || return 1
+ else
+ dwarn "can't run QEMU, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ dracut_install false touch
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-fail-on-restart.sh
+Type=oneshot
+EOF
+
+ cat >$initdir/etc/systemd/system/fail-on-restart.service <<EOF
+[Unit]
+Description=Fail on restart
+
+[Service]
+Type=simple
+ExecStart=/bin/false
+Restart=always
+EOF
+
+
+ cat >$initdir/test-fail-on-restart.sh <<'EOF'
+#!/bin/bash -x
+
+systemctl start fail-on-restart.service
+active_state=$(systemctl show --property ActiveState fail-on-restart.service)
+while [[ "$active_state" == "ActiveState=activating" || "$active_state" == "ActiveState=active" ]]; do
+ sleep 1
+ active_state=$(systemctl show --property ActiveState fail-on-restart.service)
+done
+systemctl is-failed fail-on-restart.service || exit 1
+touch /testok
+EOF
+
+ chmod 0755 $initdir/test-fail-on-restart.sh
+ setup_testsuite
+ ) || return 1
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-12-ISSUE-3171/Makefile b/test/TEST-12-ISSUE-3171/Makefile
new file mode 120000
index 0000000000..e9f93b1104
--- /dev/null
+++ b/test/TEST-12-ISSUE-3171/Makefile
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile \ No newline at end of file
diff --git a/test/TEST-12-ISSUE-3171/test.sh b/test/TEST-12-ISSUE-3171/test.sh
new file mode 100755
index 0000000000..e20f470143
--- /dev/null
+++ b/test/TEST-12-ISSUE-3171/test.sh
@@ -0,0 +1,109 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/3171"
+
+. $TEST_BASE_DIR/test-functions
+
+test_run() {
+ if run_nspawn; then
+ check_result_nspawn || return 1
+ else
+ dwarn "can't run systemd-nspawn, skipping"
+ fi
+ return 0
+}
+
+test_setup() {
+ create_empty_image
+ mkdir -p $TESTDIR/root
+ mount ${LOOPDEV}p1 $TESTDIR/root
+
+ # Create what will eventually be our root filesystem onto an overlay
+ (
+ LOG_LEVEL=5
+ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+ setup_basic_environment
+ dracut_install cat mv stat nc
+
+ # setup the testsuite service
+ cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-socket-group.sh
+Type=oneshot
+EOF
+
+
+ cat >$initdir/test-socket-group.sh <<'EOF'
+#!/bin/bash
+set -x
+set -e
+set -o pipefail
+
+U=/run/systemd/system/test.socket
+cat <<'EOL' >$U
+[Unit]
+Description=Test socket
+[Socket]
+Accept=yes
+ListenStream=/run/test.socket
+SocketGroup=adm
+SocketMode=0660
+EOL
+
+cat <<'EOL' > /run/systemd/system/test@.service
+[Unit]
+Description=Test service
+[Service]
+StandardInput=socket
+ExecStart=/bin/sh -x -c cat
+EOL
+
+systemctl start test.socket
+systemctl is-active test.socket
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+echo A | nc -U /run/test.socket
+
+mv $U ${U}.disabled
+systemctl daemon-reload
+systemctl is-active test.socket
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+echo B | nc -U /run/test.socket && exit 1
+
+mv ${U}.disabled $U
+systemctl daemon-reload
+systemctl is-active test.socket
+echo C | nc -U /run/test.socket && exit 1
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+
+systemctl restart test.socket
+systemctl is-active test.socket
+echo D | nc -U /run/test.socket
+[[ "$(stat --format='%G' /run/test.socket)" == adm ]]
+
+
+touch /testok
+EOF
+
+ chmod 0755 $initdir/test-socket-group.sh
+ setup_testsuite
+ ) || return 1
+
+ setup_nspawn_root
+
+ ddebug "umount $TESTDIR/root"
+ umount $TESTDIR/root
+}
+
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
+do_test "$@"
diff --git a/test/end.service b/test/end.service
new file mode 100644
index 0000000000..6e1996fd02
--- /dev/null
+++ b/test/end.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=End the test
+After=testsuite.service
+OnFailure=poweroff.target
+OnFailureJobMode=replace-irreversibly
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -x -c 'systemctl poweroff --no-block'
+TimeoutStartSec=5m
diff --git a/test/end.service.in b/test/end.service.in
deleted file mode 100644
index 4857ffe02b..0000000000
--- a/test/end.service.in
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=End the test
-After=testsuite.service
-
-[Service]
-ExecStart=@SYSTEMCTL@ poweroff --no-block
diff --git a/test/exec-environment-empty.service b/test/exec-environment-empty.service
deleted file mode 100644
index 0219ca4fd7..0000000000
--- a/test/exec-environment-empty.service
+++ /dev/null
@@ -1,7 +0,0 @@
-[Unit]
-Description=Test for Environment
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test ! "$VAR1" = "word1 word2") && $(test ! "$VAR2" = word3) && $(test ! "$VAR3" = \'$word 5 6\')'
-Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
-Environment=
diff --git a/test/exec-environment.service b/test/exec-environment.service
deleted file mode 100644
index 4586b4c4a9..0000000000
--- a/test/exec-environment.service
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for Environment
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = \'$word 5 6\')'
-Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
diff --git a/test/exec-group.service b/test/exec-group.service
deleted file mode 100644
index 1aa04b5bd2..0000000000
--- a/test/exec-group.service
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for Group
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test $(id -n -g) = nobody)'
-Group=nobody
diff --git a/test/exec-umask-0177.service b/test/exec-umask-0177.service
deleted file mode 100644
index af9295888e..0000000000
--- a/test/exec-umask-0177.service
+++ /dev/null
@@ -1,7 +0,0 @@
-[Unit]
-Description=Test for UMask
-
-[Service]
-ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "600")'
-UMask=0177
-PrivateTmp=yes
diff --git a/test/exec-umask-default.service b/test/exec-umask-default.service
deleted file mode 100644
index 41e20a60a1..0000000000
--- a/test/exec-umask-default.service
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for UMask default
-
-[Service]
-ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "644")'
-PrivateTmp=yes
diff --git a/test/exec-user.service b/test/exec-user.service
deleted file mode 100644
index 2ca08ebb42..0000000000
--- a/test/exec-user.service
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for User
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test "$USER" = nobody)'
-User=nobody
diff --git a/test/networkd-test.py b/test/networkd-test.py
new file mode 100755
index 0000000000..3091722fc1
--- /dev/null
+++ b/test/networkd-test.py
@@ -0,0 +1,599 @@
+#!/usr/bin/env python3
+#
+# networkd integration test
+# This uses temporary configuration in /run and temporary veth devices, and
+# does not write anything on disk or change any system configuration;
+# but it assumes (and checks at the beginning) that networkd is not currently
+# running.
+#
+# This can be run on a normal installation, in QEMU, nspawn (with
+# --private-network), LXD (with "--config raw.lxc=lxc.aa_profile=unconfined"),
+# or LXC system containers. You need at least the "ip" tool from the iproute
+# package; it is recommended to install dnsmasq too to get full test coverage.
+#
+# ATTENTION: This uses the *installed* networkd, not the one from the built
+# source tree.
+#
+# (C) 2015 Canonical Ltd.
+# Author: Martin Pitt <martin.pitt@ubuntu.com>
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+import time
+import unittest
+import tempfile
+import subprocess
+import shutil
+
+networkd_active = subprocess.call(['systemctl', 'is-active', '--quiet',
+ 'systemd-networkd']) == 0
+have_dnsmasq = shutil.which('dnsmasq')
+
+RESOLV_CONF = '/run/systemd/resolve/resolv.conf'
+
+
+@unittest.skipIf(networkd_active,
+ 'networkd is already active')
+class ClientTestBase:
+ def setUp(self):
+ self.iface = 'test_eth42'
+ self.if_router = 'router_eth42'
+ self.workdir_obj = tempfile.TemporaryDirectory()
+ self.workdir = self.workdir_obj.name
+ self.config = '/run/systemd/network/test_eth42.network'
+
+ # avoid "Failed to open /dev/tty" errors in containers
+ os.environ['SYSTEMD_LOG_TARGET'] = 'journal'
+
+ # determine path to systemd-networkd-wait-online
+ for p in ['/usr/lib/systemd/systemd-networkd-wait-online',
+ '/lib/systemd/systemd-networkd-wait-online']:
+ if os.path.exists(p):
+ self.networkd_wait_online = p
+ break
+ else:
+ self.fail('systemd-networkd-wait-online not found')
+
+ # get current journal cursor
+ out = subprocess.check_output(['journalctl', '-b', '--quiet',
+ '--no-pager', '-n0', '--show-cursor'],
+ universal_newlines=True)
+ self.assertTrue(out.startswith('-- cursor:'))
+ self.journal_cursor = out.split()[-1]
+
+ def tearDown(self):
+ self.shutdown_iface()
+ subprocess.call(['systemctl', 'stop', 'systemd-networkd'])
+
+ def writeConfig(self, fname, contents):
+ os.makedirs(os.path.dirname(fname), exist_ok=True)
+ with open(fname, 'w') as f:
+ f.write(contents)
+ self.addCleanup(os.remove, fname)
+
+ def show_journal(self, unit):
+ '''Show journal of given unit since start of the test'''
+
+ print('---- %s ----' % unit)
+ sys.stdout.flush()
+ subprocess.call(['journalctl', '-b', '--no-pager', '--quiet',
+ '--cursor', self.journal_cursor, '-u', unit])
+
+ def create_iface(self, ipv6=False):
+ '''Create test interface with DHCP server behind it'''
+
+ raise NotImplementedError('must be implemented by a subclass')
+
+ def shutdown_iface(self):
+ '''Remove test interface and stop DHCP server'''
+
+ raise NotImplementedError('must be implemented by a subclass')
+
+ def print_server_log(self):
+ '''Print DHCP server log for debugging failures'''
+
+ raise NotImplementedError('must be implemented by a subclass')
+
+ def do_test(self, coldplug=True, ipv6=False, extra_opts='',
+ online_timeout=10, dhcp_mode='yes'):
+ subprocess.check_call(['systemctl', 'start', 'systemd-resolved'])
+ self.writeConfig(self.config, '''\
+[Match]
+Name=%s
+[Network]
+DHCP=%s
+%s''' % (self.iface, dhcp_mode, extra_opts))
+
+ if coldplug:
+ # create interface first, then start networkd
+ self.create_iface(ipv6=ipv6)
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+ else:
+ # start networkd first, then create interface
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+ self.create_iface(ipv6=ipv6)
+
+ try:
+ subprocess.check_call([self.networkd_wait_online, '--interface',
+ self.iface, '--timeout=%i' % online_timeout])
+
+ if ipv6:
+ # check iface state and IP 6 address; FIXME: we need to wait a bit
+ # longer, as the iface is "configured" already with IPv4 *or*
+ # IPv6, but we want to wait for both
+ for timeout in range(10):
+ out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.iface])
+ if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out:
+ break
+ time.sleep(1)
+ else:
+ self.fail('timed out waiting for IPv6 configuration')
+
+ self.assertRegex(out, b'inet6 2600::.* scope global .*dynamic')
+ self.assertRegex(out, b'inet6 fe80::.* scope link')
+ else:
+ # should have link-local address on IPv6 only
+ out = subprocess.check_output(['ip', '-6', 'a', 'show', 'dev', self.iface])
+ self.assertRegex(out, b'inet6 fe80::.* scope link')
+ self.assertNotIn(b'scope global', out)
+
+ # should have IPv4 address
+ out = subprocess.check_output(['ip', '-4', 'a', 'show', 'dev', self.iface])
+ self.assertIn(b'state UP', out)
+ self.assertRegex(out, b'inet 192.168.5.\d+/.* scope global dynamic')
+
+ # check networkctl state
+ out = subprocess.check_output(['networkctl'])
+ self.assertRegex(out, ('%s\s+ether\s+routable\s+unmanaged' % self.if_router).encode())
+ self.assertRegex(out, ('%s\s+ether\s+routable\s+configured' % self.iface).encode())
+
+ out = subprocess.check_output(['networkctl', 'status', self.iface])
+ self.assertRegex(out, b'Type:\s+ether')
+ self.assertRegex(out, b'State:\s+routable.*configured')
+ self.assertRegex(out, b'Address:\s+192.168.5.\d+')
+ if ipv6:
+ self.assertRegex(out, b'2600::')
+ else:
+ self.assertNotIn(b'2600::', out)
+ self.assertRegex(out, b'fe80::')
+ self.assertRegex(out, b'Gateway:\s+192.168.5.1')
+ self.assertRegex(out, b'DNS:\s+192.168.5.1')
+ except (AssertionError, subprocess.CalledProcessError):
+ # show networkd status, journal, and DHCP server log on failure
+ with open(self.config) as f:
+ print('\n---- %s ----\n%s' % (self.config, f.read()))
+ print('---- interface status ----')
+ sys.stdout.flush()
+ subprocess.call(['ip', 'a', 'show', 'dev', self.iface])
+ print('---- networkctl status %s ----' % self.iface)
+ sys.stdout.flush()
+ subprocess.call(['networkctl', 'status', self.iface])
+ self.show_journal('systemd-networkd.service')
+ self.print_server_log()
+ raise
+
+ for timeout in range(50):
+ with open(RESOLV_CONF) as f:
+ contents = f.read()
+ if 'nameserver 192.168.5.1\n' in contents:
+ break
+ time.sleep(0.1)
+ else:
+ self.fail('nameserver 192.168.5.1 not found in ' + RESOLV_CONF)
+
+ if not coldplug:
+ # check post-down.d hook
+ self.shutdown_iface()
+
+ def test_coldplug_dhcp_yes_ip4(self):
+ # we have a 12s timeout on RA, so we need to wait longer
+ self.do_test(coldplug=True, ipv6=False, online_timeout=15)
+
+ def test_coldplug_dhcp_yes_ip4_no_ra(self):
+ # with disabling RA explicitly things should be fast
+ self.do_test(coldplug=True, ipv6=False,
+ extra_opts='IPv6AcceptRA=False')
+
+ def test_coldplug_dhcp_ip4_only(self):
+ # we have a 12s timeout on RA, so we need to wait longer
+ self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4',
+ online_timeout=15)
+
+ def test_coldplug_dhcp_ip4_only_no_ra(self):
+ # with disabling RA explicitly things should be fast
+ self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4',
+ extra_opts='IPv6AcceptRA=False')
+
+ def test_coldplug_dhcp_ip6(self):
+ self.do_test(coldplug=True, ipv6=True)
+
+ def test_hotplug_dhcp_ip4(self):
+ # With IPv4 only we have a 12s timeout on RA, so we need to wait longer
+ self.do_test(coldplug=False, ipv6=False, online_timeout=15)
+
+ def test_hotplug_dhcp_ip6(self):
+ self.do_test(coldplug=False, ipv6=True)
+
+ def test_route_only_dns(self):
+ self.writeConfig('/run/systemd/network/myvpn.netdev', '''\
+[NetDev]
+Name=dummy0
+Kind=dummy
+MACAddress=12:34:56:78:9a:bc''')
+ self.writeConfig('/run/systemd/network/myvpn.network', '''\
+[Match]
+Name=dummy0
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1
+Domains= ~company''')
+
+ self.do_test(coldplug=True, ipv6=False,
+ extra_opts='IPv6AcceptRouterAdvertisements=False')
+
+ with open(RESOLV_CONF) as f:
+ contents = f.read()
+ # ~company is not a search domain, only a routing domain
+ self.assertNotRegex(contents, 'search.*company')
+ # our global server should appear
+ self.assertIn('nameserver 192.168.5.1\n', contents)
+ # should not have domain-restricted server as global server
+ self.assertNotIn('nameserver 192.168.42.1\n', contents)
+
+ def test_route_only_dns_all_domains(self):
+ with open('/run/systemd/network/myvpn.netdev', 'w') as f:
+ f.write('''[NetDev]
+Name=dummy0
+Kind=dummy
+MACAddress=12:34:56:78:9a:bc''')
+ with open('/run/systemd/network/myvpn.network', 'w') as f:
+ f.write('''[Match]
+Name=dummy0
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1
+Domains= ~company ~.''')
+ self.addCleanup(os.remove, '/run/systemd/network/myvpn.netdev')
+ self.addCleanup(os.remove, '/run/systemd/network/myvpn.network')
+
+ self.do_test(coldplug=True, ipv6=False,
+ extra_opts='IPv6AcceptRouterAdvertisements=False')
+
+ with open(RESOLV_CONF) as f:
+ contents = f.read()
+
+ # ~company is not a search domain, only a routing domain
+ self.assertNotRegex(contents, 'search.*company')
+
+ # our global server should appear
+ self.assertIn('nameserver 192.168.5.1\n', contents)
+ # should have company server as global server due to ~.
+ self.assertIn('nameserver 192.168.42.1\n', contents)
+
+
+@unittest.skipUnless(have_dnsmasq, 'dnsmasq not installed')
+class DnsmasqClientTest(ClientTestBase, unittest.TestCase):
+ '''Test networkd client against dnsmasq'''
+
+ def setUp(self):
+ super().setUp()
+ self.dnsmasq = None
+
+ def create_iface(self, ipv6=False, dnsmasq_opts=None):
+ '''Create test interface with DHCP server behind it'''
+
+ # add veth pair
+ subprocess.check_call(['ip', 'link', 'add', 'name', self.iface, 'type',
+ 'veth', 'peer', 'name', self.if_router])
+
+ # give our router an IP
+ subprocess.check_call(['ip', 'a', 'flush', 'dev', self.if_router])
+ subprocess.check_call(['ip', 'a', 'add', '192.168.5.1/24', 'dev', self.if_router])
+ if ipv6:
+ subprocess.check_call(['ip', 'a', 'add', '2600::1/64', 'dev', self.if_router])
+ subprocess.check_call(['ip', 'link', 'set', self.if_router, 'up'])
+
+ # add DHCP server
+ self.dnsmasq_log = os.path.join(self.workdir, 'dnsmasq.log')
+ lease_file = os.path.join(self.workdir, 'dnsmasq.leases')
+ if ipv6:
+ extra_opts = ['--enable-ra', '--dhcp-range=2600::10,2600::20']
+ else:
+ extra_opts = []
+ if dnsmasq_opts:
+ extra_opts += dnsmasq_opts
+ self.dnsmasq = subprocess.Popen(
+ ['dnsmasq', '--keep-in-foreground', '--log-queries',
+ '--log-facility=' + self.dnsmasq_log, '--conf-file=/dev/null',
+ '--dhcp-leasefile=' + lease_file, '--bind-interfaces',
+ '--interface=' + self.if_router, '--except-interface=lo',
+ '--dhcp-range=192.168.5.10,192.168.5.200'] + extra_opts)
+
+ def shutdown_iface(self):
+ '''Remove test interface and stop DHCP server'''
+
+ if self.if_router:
+ subprocess.check_call(['ip', 'link', 'del', 'dev', self.if_router])
+ self.if_router = None
+ if self.dnsmasq:
+ self.dnsmasq.kill()
+ self.dnsmasq.wait()
+ self.dnsmasq = None
+
+ def print_server_log(self):
+ '''Print DHCP server log for debugging failures'''
+
+ with open(self.dnsmasq_log) as f:
+ sys.stdout.write('\n\n---- dnsmasq log ----\n%s\n------\n\n' % f.read())
+
+ def test_resolved_domain_restricted_dns(self):
+ '''resolved: domain-restricted DNS servers'''
+
+ # create interface for generic connections; this will map all DNS names
+ # to 192.168.42.1
+ self.create_iface(dnsmasq_opts=['--address=/#/192.168.42.1'])
+ self.writeConfig('/run/systemd/network/general.network', '''\
+[Match]
+Name=%s
+[Network]
+DHCP=ipv4
+IPv6AcceptRA=False''' % self.iface)
+
+ # create second device/dnsmasq for a .company/.lab VPN interface
+ # static IPs for simplicity
+ subprocess.check_call(['ip', 'link', 'add', 'name', 'testvpnclient', 'type',
+ 'veth', 'peer', 'name', 'testvpnrouter'])
+ self.addCleanup(subprocess.call, ['ip', 'link', 'del', 'dev', 'testvpnrouter'])
+ subprocess.check_call(['ip', 'a', 'flush', 'dev', 'testvpnrouter'])
+ subprocess.check_call(['ip', 'a', 'add', '10.241.3.1/24', 'dev', 'testvpnrouter'])
+ subprocess.check_call(['ip', 'link', 'set', 'testvpnrouter', 'up'])
+
+ vpn_dnsmasq_log = os.path.join(self.workdir, 'dnsmasq-vpn.log')
+ vpn_dnsmasq = subprocess.Popen(
+ ['dnsmasq', '--keep-in-foreground', '--log-queries',
+ '--log-facility=' + vpn_dnsmasq_log, '--conf-file=/dev/null',
+ '--dhcp-leasefile=/dev/null', '--bind-interfaces',
+ '--interface=testvpnrouter', '--except-interface=lo',
+ '--address=/math.lab/10.241.3.3', '--address=/cantina.company/10.241.4.4'])
+ self.addCleanup(vpn_dnsmasq.wait)
+ self.addCleanup(vpn_dnsmasq.kill)
+
+ self.writeConfig('/run/systemd/network/vpn.network', '''\
+[Match]
+Name=testvpnclient
+[Network]
+IPv6AcceptRA=False
+Address=10.241.3.2/24
+DNS=10.241.3.1
+Domains= ~company ~lab''')
+
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+ subprocess.check_call([self.networkd_wait_online, '--interface', self.iface,
+ '--interface=testvpnclient', '--timeout=20'])
+
+ # ensure we start fresh with every test
+ subprocess.check_call(['systemctl', 'restart', 'systemd-resolved'])
+
+ # test vpnclient specific domains; these should *not* be answered by
+ # the general DNS
+ out = subprocess.check_output(['systemd-resolve', 'math.lab'])
+ self.assertIn(b'math.lab: 10.241.3.3', out)
+ out = subprocess.check_output(['systemd-resolve', 'kettle.cantina.company'])
+ self.assertIn(b'kettle.cantina.company: 10.241.4.4', out)
+
+ # test general domains
+ out = subprocess.check_output(['systemd-resolve', 'megasearch.net'])
+ self.assertIn(b'megasearch.net: 192.168.42.1', out)
+
+ with open(self.dnsmasq_log) as f:
+ general_log = f.read()
+ with open(vpn_dnsmasq_log) as f:
+ vpn_log = f.read()
+
+ # VPN domains should only be sent to VPN DNS
+ self.assertRegex(vpn_log, 'query.*math.lab')
+ self.assertRegex(vpn_log, 'query.*cantina.company')
+ self.assertNotIn('lab', general_log)
+ self.assertNotIn('company', general_log)
+
+ # general domains should not be sent to the VPN DNS
+ self.assertRegex(general_log, 'query.*megasearch.net')
+ self.assertNotIn('megasearch.net', vpn_log)
+
+
+class NetworkdClientTest(ClientTestBase, unittest.TestCase):
+ '''Test networkd client against networkd server'''
+
+ def setUp(self):
+ super().setUp()
+ self.dnsmasq = None
+
+ def create_iface(self, ipv6=False):
+ '''Create test interface with DHCP server behind it'''
+
+ # run "router-side" networkd in own mount namespace to shield it from
+ # "client-side" configuration and networkd
+ (fd, script) = tempfile.mkstemp(prefix='networkd-router.sh')
+ self.addCleanup(os.remove, script)
+ with os.fdopen(fd, 'w+') as f:
+ f.write('''\
+#!/bin/sh -eu
+mkdir -p /run/systemd/network
+mkdir -p /run/systemd/netif
+mount -t tmpfs none /run/systemd/network
+mount -t tmpfs none /run/systemd/netif
+[ ! -e /run/dbus ] || mount -t tmpfs none /run/dbus
+# create router/client veth pair
+cat << EOF > /run/systemd/network/test.netdev
+[NetDev]
+Name=%(ifr)s
+Kind=veth
+
+[Peer]
+Name=%(ifc)s
+EOF
+
+cat << EOF > /run/systemd/network/test.network
+[Match]
+Name=%(ifr)s
+
+[Network]
+Address=192.168.5.1/24
+%(addr6)s
+DHCPServer=yes
+
+[DHCPServer]
+PoolOffset=10
+PoolSize=50
+DNS=192.168.5.1
+EOF
+
+# run networkd as in systemd-networkd.service
+exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=//; p}')
+''' % {'ifr': self.if_router, 'ifc': self.iface, 'addr6': ipv6 and 'Address=2600::1/64' or ''})
+
+ os.fchmod(fd, 0o755)
+
+ subprocess.check_call(['systemd-run', '--unit=networkd-test-router.service',
+ '-p', 'InaccessibleDirectories=-/etc/systemd/network',
+ '-p', 'InaccessibleDirectories=-/run/systemd/network',
+ '-p', 'InaccessibleDirectories=-/run/systemd/netif',
+ '--service-type=notify', script])
+
+ # wait until devices got created
+ for timeout in range(50):
+ out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.if_router])
+ if b'state UP' in out and b'scope global' in out:
+ break
+ time.sleep(0.1)
+
+ def shutdown_iface(self):
+ '''Remove test interface and stop DHCP server'''
+
+ if self.if_router:
+ subprocess.check_call(['systemctl', 'stop', 'networkd-test-router.service'])
+ # ensure failed transient unit does not stay around
+ subprocess.call(['systemctl', 'reset-failed', 'networkd-test-router.service'])
+ subprocess.call(['ip', 'link', 'del', 'dev', self.if_router])
+ self.if_router = None
+
+ def print_server_log(self):
+ '''Print DHCP server log for debugging failures'''
+
+ self.show_journal('networkd-test-router.service')
+
+ @unittest.skip('networkd does not have DHCPv6 server support')
+ def test_hotplug_dhcp_ip6(self):
+ pass
+
+ @unittest.skip('networkd does not have DHCPv6 server support')
+ def test_coldplug_dhcp_ip6(self):
+ pass
+
+ def test_search_domains(self):
+
+ # we don't use this interface for this test
+ self.if_router = None
+
+ self.writeConfig('/run/systemd/network/test.netdev', '''\
+[NetDev]
+Name=dummy0
+Kind=dummy
+MACAddress=12:34:56:78:9a:bc''')
+ self.writeConfig('/run/systemd/network/test.network', '''\
+[Match]
+Name=dummy0
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1
+Domains= one two three four five six seven eight nine ten''')
+
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+
+ for timeout in range(50):
+ with open(RESOLV_CONF) as f:
+ contents = f.read()
+ if ' one' in contents:
+ break
+ time.sleep(0.1)
+ self.assertRegex(contents, 'search .*one two three four')
+ self.assertNotIn('seven\n', contents)
+ self.assertIn('# Too many search domains configured, remaining ones ignored.\n', contents)
+
+ def test_search_domains_too_long(self):
+
+ # we don't use this interface for this test
+ self.if_router = None
+
+ name_prefix = 'a' * 60
+
+ self.writeConfig('/run/systemd/network/test.netdev', '''\
+[NetDev]
+Name=dummy0
+Kind=dummy
+MACAddress=12:34:56:78:9a:bc''')
+ self.writeConfig('/run/systemd/network/test.network', '''\
+[Match]
+Name=dummy0
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1
+Domains={p}0 {p}1 {p}2 {p}3 {p}4'''.format(p=name_prefix))
+
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+
+ for timeout in range(50):
+ with open(RESOLV_CONF) as f:
+ contents = f.read()
+ if ' one' in contents:
+ break
+ time.sleep(0.1)
+ self.assertRegex(contents, 'search .*{p}0 {p}1 {p}2'.format(p=name_prefix))
+ self.assertIn('# Total length of all search domains is too long, remaining ones ignored.', contents)
+
+ def test_dropin(self):
+ # we don't use this interface for this test
+ self.if_router = None
+
+ self.writeConfig('/run/systemd/network/test.netdev', '''\
+[NetDev]
+Name=dummy0
+Kind=dummy
+MACAddress=12:34:56:78:9a:bc''')
+ self.writeConfig('/run/systemd/network/test.network', '''\
+[Match]
+Name=dummy0
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1''')
+ self.writeConfig('/run/systemd/network/test.network.d/dns.conf', '''\
+[Network]
+DNS=127.0.0.1''')
+
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+
+ for timeout in range(50):
+ with open(RESOLV_CONF) as f:
+ contents = f.read()
+ if ' 127.0.0.1' in contents:
+ break
+ time.sleep(0.1)
+ self.assertIn('nameserver 192.168.42.1\n', contents)
+ self.assertIn('nameserver 127.0.0.1\n', contents)
+
+if __name__ == '__main__':
+ unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
+ verbosity=2))
diff --git a/test/parent.slice b/test/parent.slice
index 0222f8eb47..a95f90392d 100644
--- a/test/parent.slice
+++ b/test/parent.slice
@@ -2,4 +2,4 @@
Description=Parent Slice
[Slice]
-BlockIOWeight=200
+IOWeight=200
diff --git a/test/paths.target b/test/paths.target
deleted file mode 120000
index e9939c9801..0000000000
--- a/test/paths.target
+++ /dev/null
@@ -1 +0,0 @@
-../units/paths.target \ No newline at end of file
diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py
index 721e53a4ee..838dd57a6f 100644..100755
--- a/test/sysv-generator-test.py
+++ b/test/sysv-generator-test.py
@@ -1,3 +1,5 @@
+#!/usr/bin/python
+#
# systemd-sysv-generator integration test
#
# (C) 2015 Canonical Ltd.
@@ -23,6 +25,7 @@ import subprocess
import tempfile
import shutil
from glob import glob
+import collections
try:
from configparser import RawConfigParser
@@ -32,6 +35,12 @@ except ImportError:
sysv_generator = os.path.join(os.environ.get('builddir', '.'), 'systemd-sysv-generator')
+class MultiDict(collections.OrderedDict):
+ def __setitem__(self, key, value):
+ if isinstance(value, list) and key in self:
+ self[key].extend(value)
+ else:
+ super(MultiDict, self).__setitem__(key, value)
class SysvGeneratorTest(unittest.TestCase):
def setUp(self):
@@ -77,7 +86,14 @@ class SysvGeneratorTest(unittest.TestCase):
for service in glob(self.out_dir + '/*.service'):
if os.path.islink(service):
continue
- cp = RawConfigParser()
+ try:
+ # for python3 we need here strict=False to parse multiple
+ # lines with the same key
+ cp = RawConfigParser(dict_type=MultiDict, strict=False)
+ except TypeError:
+ # RawConfigParser in python2 does not have the strict option
+ # but it allows multiple lines with the same key by default
+ cp = RawConfigParser(dict_type=MultiDict)
cp.optionxform = lambda o: o # don't lower-case option names
with open(service) as f:
cp.readfp(f)
@@ -224,7 +240,7 @@ class SysvGeneratorTest(unittest.TestCase):
s = self.run_generator()[1]['foo.service']
self.assertEqual(set(s.options('Unit')),
set(['Documentation', 'SourcePath', 'Description', 'After']))
- self.assertEqual(s.get('Unit', 'After'), 'nss-lookup.target rpcbind.target')
+ self.assertEqual(s.get('Unit', 'After').split(), ['nss-lookup.target', 'rpcbind.target'])
def test_lsb_deps(self):
'''LSB header dependencies to other services'''
@@ -381,11 +397,12 @@ class SysvGeneratorTest(unittest.TestCase):
# backup files (not enabled in rcN.d/)
shutil.copy(script, script + '.bak')
shutil.copy(script, script + '.old')
+ shutil.copy(script, script + '.tmp')
+ shutil.copy(script, script + '.new')
err, results = self.run_generator()
print(err)
- self.assertEqual(sorted(results),
- ['foo.bak.service', 'foo.old.service', 'foo.service'])
+ self.assertEqual(sorted(results), ['foo.service', 'foo.tmp.service'])
# ensure we don't try to create a symlink to itself
self.assertNotIn('itself', err)
diff --git a/test/test-efi-create-disk.sh b/test/test-efi-create-disk.sh
index 56dd09abd7..cd4699dc18 100755
--- a/test/test-efi-create-disk.sh
+++ b/test/test-efi-create-disk.sh
@@ -11,8 +11,8 @@ mkfs.vfat -F32 ${LOOP}p1
mkdir -p mnt
mount ${LOOP}p1 mnt
-mkdir -p mnt/EFI/{Boot,systemd}
-cp systemd-bootx64.efi mnt/EFI/Boot/bootx64.efi
+mkdir -p mnt/EFI/{BOOT,systemd}
+cp systemd-bootx64.efi mnt/EFI/BOOT/BOOTX64.efi
[ -e /boot/shellx64.efi ] && cp /boot/shellx64.efi mnt/
diff --git a/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service b/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service
new file mode 100644
index 0000000000..00bec581b5
--- /dev/null
+++ b/test/test-execute/exec-capabilityambientset-merge-nfsnobody.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Test for AmbientCapabilities
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
+Type=oneshot
+User=nfsnobody
+AmbientCapabilities=CAP_NET_ADMIN
+AmbientCapabilities=CAP_NET_RAW
diff --git a/test/test-execute/exec-capabilityambientset-merge.service b/test/test-execute/exec-capabilityambientset-merge.service
new file mode 100644
index 0000000000..64964380e2
--- /dev/null
+++ b/test/test-execute/exec-capabilityambientset-merge.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Test for AmbientCapabilities
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
+Type=oneshot
+User=nobody
+AmbientCapabilities=CAP_NET_ADMIN
+AmbientCapabilities=CAP_NET_RAW
diff --git a/test/test-execute/exec-capabilityambientset-nfsnobody.service b/test/test-execute/exec-capabilityambientset-nfsnobody.service
new file mode 100644
index 0000000000..614cfdd584
--- /dev/null
+++ b/test/test-execute/exec-capabilityambientset-nfsnobody.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for AmbientCapabilities
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
+Type=oneshot
+User=nfsnobody
+AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
diff --git a/test/test-execute/exec-capabilityambientset.service b/test/test-execute/exec-capabilityambientset.service
new file mode 100644
index 0000000000..d63f884ef8
--- /dev/null
+++ b/test/test-execute/exec-capabilityambientset.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for AmbientCapabilities
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"'
+Type=oneshot
+User=nobody
+AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
diff --git a/test/test-execute/exec-capabilityboundingset-invert.service b/test/test-execute/exec-capabilityboundingset-invert.service
new file mode 100644
index 0000000000..fd5d248702
--- /dev/null
+++ b/test/test-execute/exec-capabilityboundingset-invert.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "^Bounding set .*cap_chown"); test -z "$$c"'
+Type=oneshot
+CapabilityBoundingSet=~CAP_CHOWN
diff --git a/test/test-execute/exec-capabilityboundingset-merge.service b/test/test-execute/exec-capabilityboundingset-merge.service
new file mode 100644
index 0000000000..5c7fcaf437
--- /dev/null
+++ b/test/test-execute/exec-capabilityboundingset-merge.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_chown,cap_fowner,cap_kill"'
+Type=oneshot
+CapabilityBoundingSet=CAP_FOWNER
+CapabilityBoundingSet=CAP_KILL CAP_CHOWN
diff --git a/test/test-execute/exec-capabilityboundingset-reset.service b/test/test-execute/exec-capabilityboundingset-reset.service
new file mode 100644
index 0000000000..d7d3320204
--- /dev/null
+++ b/test/test-execute/exec-capabilityboundingset-reset.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set ="'
+Type=oneshot
+CapabilityBoundingSet=CAP_FOWNER CAP_KILL
+CapabilityBoundingSet=
diff --git a/test/test-execute/exec-capabilityboundingset-simple.service b/test/test-execute/exec-capabilityboundingset-simple.service
new file mode 100644
index 0000000000..bf1a7f575a
--- /dev/null
+++ b/test/test-execute/exec-capabilityboundingset-simple.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_fowner,cap_kill"'
+Type=oneshot
+CapabilityBoundingSet=CAP_FOWNER CAP_KILL
diff --git a/test/test-execute/exec-environment-empty.service b/test/test-execute/exec-environment-empty.service
new file mode 100644
index 0000000000..9c92d4bc81
--- /dev/null
+++ b/test/test-execute/exec-environment-empty.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for Environment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
+Type=oneshot
+Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
+Environment=
diff --git a/test/exec-environment-multiple.service b/test/test-execute/exec-environment-multiple.service
index 479005a5d8..b9bc225635 100644
--- a/test/exec-environment-multiple.service
+++ b/test/test-execute/exec-environment-multiple.service
@@ -2,6 +2,7 @@
Description=Test for Environment
[Service]
-ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = foobar)'
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = foobar'
+Type=oneshot
Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
Environment="VAR3=foobar"
diff --git a/test/test-execute/exec-environment.service b/test/test-execute/exec-environment.service
new file mode 100644
index 0000000000..06e77af220
--- /dev/null
+++ b/test/test-execute/exec-environment.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Environment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
diff --git a/test/test-execute/exec-environmentfile.service b/test/test-execute/exec-environmentfile.service
new file mode 100644
index 0000000000..f6b8462719
--- /dev/null
+++ b/test/test-execute/exec-environmentfile.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for EnvironmentFile
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+EnvironmentFile=/tmp/test-exec_environmentfile.conf
diff --git a/test/test-execute/exec-group-nfsnobody.service b/test/test-execute/exec-group-nfsnobody.service
new file mode 100644
index 0000000000..e02100a869
--- /dev/null
+++ b/test/test-execute/exec-group-nfsnobody.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Group
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nfsnobody"'
+Type=oneshot
+Group=nfsnobody
diff --git a/test/test-execute/exec-group.service b/test/test-execute/exec-group.service
new file mode 100644
index 0000000000..be7c796912
--- /dev/null
+++ b/test/test-execute/exec-group.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Group
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nobody"'
+Type=oneshot
+Group=nobody
diff --git a/test/exec-ignoresigpipe-no.service b/test/test-execute/exec-ignoresigpipe-no.service
index 69b2e9d8a8..73addf5f05 100644
--- a/test/exec-ignoresigpipe-no.service
+++ b/test/test-execute/exec-ignoresigpipe-no.service
@@ -2,6 +2,6 @@
Description=Test for IgnoreSIGPIPE=no
[Service]
-ExecStart=/bin/sh -c 'kill -PIPE 0'
+ExecStart=/bin/sh -x -c 'kill -PIPE 0'
Type=oneshot
IgnoreSIGPIPE=no
diff --git a/test/exec-ignoresigpipe-yes.service b/test/test-execute/exec-ignoresigpipe-yes.service
index 877ec8aed0..f81c01719e 100644
--- a/test/exec-ignoresigpipe-yes.service
+++ b/test/test-execute/exec-ignoresigpipe-yes.service
@@ -2,6 +2,6 @@
Description=Test for IgnoreSIGPIPE=yes
[Service]
-ExecStart=/bin/sh -c 'kill -PIPE 0'
+ExecStart=/bin/sh -x -c 'kill -PIPE 0'
Type=oneshot
IgnoreSIGPIPE=yes
diff --git a/test/test-execute/exec-inaccessiblepaths-mount-propagation.service b/test/test-execute/exec-inaccessiblepaths-mount-propagation.service
new file mode 100644
index 0000000000..23c6ff3f93
--- /dev/null
+++ b/test/test-execute/exec-inaccessiblepaths-mount-propagation.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test to make sure that InaccessiblePaths= disconnect mount propagation
+
+[Service]
+InaccessiblePaths=-/i-dont-exist
+ExecStart=/bin/sh -x -c 'mkdir -p /TEST; mount -t tmpfs tmpfs /TEST; grep TEST /proc/self/mountinfo && ! grep TEST /proc/$${PPID}/mountinfo && ! grep TEST /proc/1/mountinfo'
+Type=oneshot
diff --git a/test/test-execute/exec-ioschedulingclass-best-effort.service b/test/test-execute/exec-ioschedulingclass-best-effort.service
new file mode 100644
index 0000000000..29bb8510b4
--- /dev/null
+++ b/test/test-execute/exec-ioschedulingclass-best-effort.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=best-effort
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "best-effort"'
+Type=oneshot
+IOSchedulingClass=best-effort
diff --git a/test/test-execute/exec-ioschedulingclass-idle.service b/test/test-execute/exec-ioschedulingclass-idle.service
new file mode 100644
index 0000000000..87dbed14c1
--- /dev/null
+++ b/test/test-execute/exec-ioschedulingclass-idle.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=idle
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "idle"'
+Type=oneshot
+IOSchedulingClass=idle
diff --git a/test/test-execute/exec-ioschedulingclass-none.service b/test/test-execute/exec-ioschedulingclass-none.service
new file mode 100644
index 0000000000..b6af122a1e
--- /dev/null
+++ b/test/test-execute/exec-ioschedulingclass-none.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=none
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "none"'
+Type=oneshot
+IOSchedulingClass=none
diff --git a/test/test-execute/exec-ioschedulingclass-realtime.service b/test/test-execute/exec-ioschedulingclass-realtime.service
new file mode 100644
index 0000000000..d920d5c687
--- /dev/null
+++ b/test/test-execute/exec-ioschedulingclass-realtime.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=realtime
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "realtime"'
+Type=oneshot
+IOSchedulingClass=realtime
diff --git a/test/test-execute/exec-oomscoreadjust-negative.service b/test/test-execute/exec-oomscoreadjust-negative.service
new file mode 100644
index 0000000000..2234c53c3f
--- /dev/null
+++ b/test/test-execute/exec-oomscoreadjust-negative.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for OOMScoreAdjust
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq -100'
+Type=oneshot
+OOMScoreAdjust=-100
diff --git a/test/test-execute/exec-oomscoreadjust-positive.service b/test/test-execute/exec-oomscoreadjust-positive.service
new file mode 100644
index 0000000000..456a8f80cf
--- /dev/null
+++ b/test/test-execute/exec-oomscoreadjust-positive.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for OOMScoreAdjust
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq 100'
+Type=oneshot
+OOMScoreAdjust=100
diff --git a/test/test-execute/exec-passenvironment-absent.service b/test/test-execute/exec-passenvironment-absent.service
new file mode 100644
index 0000000000..7d5e32a4eb
--- /dev/null
+++ b/test/test-execute/exec-passenvironment-absent.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for PassEnvironment with variables absent from the execution environment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2 VAR3
diff --git a/test/test-execute/exec-passenvironment-empty.service b/test/test-execute/exec-passenvironment-empty.service
new file mode 100644
index 0000000000..c93c197c10
--- /dev/null
+++ b/test/test-execute/exec-passenvironment-empty.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for PassEnvironment and erasing the variable list
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2 VAR3
+PassEnvironment=
diff --git a/test/test-execute/exec-passenvironment-repeated.service b/test/test-execute/exec-passenvironment-repeated.service
new file mode 100644
index 0000000000..5e8c56f26a
--- /dev/null
+++ b/test/test-execute/exec-passenvironment-repeated.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for PassEnvironment with a variable name repeated
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2
+PassEnvironment=VAR1 VAR3
diff --git a/test/test-execute/exec-passenvironment.service b/test/test-execute/exec-passenvironment.service
new file mode 100644
index 0000000000..b4a9909682
--- /dev/null
+++ b/test/test-execute/exec-passenvironment.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for PassEnvironment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2 VAR3
diff --git a/test/test-execute/exec-personality-aarch64.service b/test/test-execute/exec-personality-aarch64.service
new file mode 100644
index 0000000000..40b6d95e3a
--- /dev/null
+++ b/test/test-execute/exec-personality-aarch64.service
@@ -0,0 +1,7 @@
+Unit]
+Description=Test for Personality=aarch64
+
+[Service]
+ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "aarch64")'
+Type=oneshot
+Personality=aarch64
diff --git a/test/exec-personality-x86.service b/test/test-execute/exec-personality-ppc64.service
index 0b370a6480..ccc2c8d83d 100644
--- a/test/exec-personality-x86.service
+++ b/test/test-execute/exec-personality-ppc64.service
@@ -1,7 +1,7 @@
[Unit]
-Description=Test for Personality=x86
+Description=Test for Personality=ppc64
[Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "i686")'
+ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64")'
Type=oneshot
-Personality=x86
+Personality=ppc64
diff --git a/test/exec-personality-x86-64.service b/test/test-execute/exec-personality-ppc64le.service
index 5bb5d910d0..2a7625087d 100644
--- a/test/exec-personality-x86-64.service
+++ b/test/test-execute/exec-personality-ppc64le.service
@@ -1,7 +1,7 @@
[Unit]
-Description=Test for Personality=x86-64
+Description=Test for Personality=ppc64le
[Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "x86_64")'
+ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64le")'
Type=oneshot
-Personality=x86-64
+Personality=ppc64le
diff --git a/test/test-execute/exec-personality-s390.service b/test/test-execute/exec-personality-s390.service
new file mode 100644
index 0000000000..89f7de89d0
--- /dev/null
+++ b/test/test-execute/exec-personality-s390.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Personality=s390
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "s390"'
+Type=oneshot
+Personality=s390
diff --git a/test/test-execute/exec-personality-x86-64.service b/test/test-execute/exec-personality-x86-64.service
new file mode 100644
index 0000000000..433e69a6d1
--- /dev/null
+++ b/test/test-execute/exec-personality-x86-64.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Personality=x86-64
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "x86_64"'
+Type=oneshot
+Personality=x86-64
diff --git a/test/test-execute/exec-personality-x86.service b/test/test-execute/exec-personality-x86.service
new file mode 100644
index 0000000000..a623a08cbe
--- /dev/null
+++ b/test/test-execute/exec-personality-x86.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Personality=x86
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "i686"'
+Type=oneshot
+Personality=x86
diff --git a/test/test-execute/exec-privatedevices-no-capability-mknod.service b/test/test-execute/exec-privatedevices-no-capability-mknod.service
new file mode 100644
index 0000000000..6d39469da8
--- /dev/null
+++ b/test/test-execute/exec-privatedevices-no-capability-mknod.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test CAP_MKNOD capability for PrivateDevices=no
+
+[Service]
+PrivateDevices=no
+ExecStart=/bin/sh -x -c 'capsh --print | grep cap_mknod'
+Type=oneshot
diff --git a/test/exec-privatedevices-no.service b/test/test-execute/exec-privatedevices-no.service
index cf4f275fb6..77aeb951b5 100644
--- a/test/exec-privatedevices-no.service
+++ b/test/test-execute/exec-privatedevices-no.service
@@ -2,6 +2,6 @@
Description=Test for PrivateDev=no
[Service]
-ExecStart=/bin/sh -c 'exit $(test -c /dev/mem)'
+ExecStart=/bin/sh -x -c 'test -c /dev/mem'
Type=oneshot
PrivateDevices=no
diff --git a/test/test-execute/exec-privatedevices-yes-capability-mknod.service b/test/test-execute/exec-privatedevices-yes-capability-mknod.service
new file mode 100644
index 0000000000..fb1fc2875a
--- /dev/null
+++ b/test/test-execute/exec-privatedevices-yes-capability-mknod.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test CAP_MKNOD capability for PrivateDevices=yes
+
+[Service]
+PrivateDevices=yes
+ExecStart=/bin/sh -x -c '! capsh --print | grep cap_mknod'
+Type=oneshot
diff --git a/test/exec-privatedevices-yes.service b/test/test-execute/exec-privatedevices-yes.service
index 85b3f4f981..ab958b646e 100644
--- a/test/exec-privatedevices-yes.service
+++ b/test/test-execute/exec-privatedevices-yes.service
@@ -2,6 +2,6 @@
Description=Test for PrivateDev=yes
[Service]
-ExecStart=/bin/sh -c 'exit $(test ! -c /dev/mem)'
+ExecStart=/bin/sh -c 'test ! -c /dev/mem'
Type=oneshot
PrivateDevices=yes
diff --git a/test/test-execute/exec-privatenetwork-yes.service b/test/test-execute/exec-privatenetwork-yes.service
new file mode 100644
index 0000000000..3df543ec93
--- /dev/null
+++ b/test/test-execute/exec-privatenetwork-yes.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for PrivateNetwork
+
+[Service]
+ExecStart=/bin/sh -x -c 'i=$$(ip link | grep ": " | grep -v ": lo:"); test -z "$$i"'
+Type=oneshot
+PrivateNetwork=yes
diff --git a/test/exec-privatetmp-no.service b/test/test-execute/exec-privatetmp-no.service
index d69e552a63..59f60f4755 100644
--- a/test/exec-privatetmp-no.service
+++ b/test/test-execute/exec-privatetmp-no.service
@@ -2,6 +2,6 @@
Description=Test for PrivateTmp=no
[Service]
-ExecStart=/bin/sh -c 'exit $(test -f /tmp/test-exec_privatetmp)'
+ExecStart=/bin/sh -x -c 'test -f /tmp/test-exec_privatetmp'
Type=oneshot
PrivateTmp=no
diff --git a/test/exec-privatetmp-yes.service b/test/test-execute/exec-privatetmp-yes.service
index 881a040b87..907c291b81 100644
--- a/test/exec-privatetmp-yes.service
+++ b/test/test-execute/exec-privatetmp-yes.service
@@ -2,6 +2,6 @@
Description=Test for PrivateTmp=yes
[Service]
-ExecStart=/bin/sh -c 'exit $(test ! -f /tmp/test-exec_privatetmp)'
+ExecStart=/bin/sh -x -c 'test ! -f /tmp/test-exec_privatetmp'
Type=oneshot
PrivateTmp=yes
diff --git a/test/test-execute/exec-readonlypaths-mount-propagation.service b/test/test-execute/exec-readonlypaths-mount-propagation.service
new file mode 100644
index 0000000000..237cbb2efb
--- /dev/null
+++ b/test/test-execute/exec-readonlypaths-mount-propagation.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test to make sure that passing ReadOnlyPaths= disconnect mount propagation
+
+[Service]
+ReadOnlyPaths=-/i-dont-exist
+ExecStart=/bin/sh -x -c 'mkdir -p /TEST; mount -t tmpfs tmpfs /TEST; grep TEST /proc/self/mountinfo && ! grep TEST /proc/$${PPID}/mountinfo && ! grep TEST /proc/1/mountinfo'
+Type=oneshot
diff --git a/test/test-execute/exec-readonlypaths.service b/test/test-execute/exec-readonlypaths.service
new file mode 100644
index 0000000000..6866fdc700
--- /dev/null
+++ b/test/test-execute/exec-readonlypaths.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for ReadOnlyPaths=
+
+[Service]
+ReadOnlyPaths=/etc -/i-dont-exist /usr
+ExecStart=/bin/sh -x -c 'test ! -w /etc && test ! -w /usr && test ! -e /i-dont-exist && test -w /var'
+Type=oneshot
diff --git a/test/test-execute/exec-readwritepaths-mount-propagation.service b/test/test-execute/exec-readwritepaths-mount-propagation.service
new file mode 100644
index 0000000000..466ce6c747
--- /dev/null
+++ b/test/test-execute/exec-readwritepaths-mount-propagation.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test to make sure that passing ReadWritePaths= disconnect mount propagation
+
+[Service]
+ReadWritePaths=-/i-dont-exist
+ExecStart=/bin/sh -x -c 'mkdir -p /TEST; mount -t tmpfs tmpfs /TEST; grep TEST /proc/self/mountinfo && ! grep TEST /proc/$${PPID}/mountinfo && ! grep TEST /proc/1/mountinfo'
+Type=oneshot
diff --git a/test/test-execute/exec-runtimedirectory-mode.service b/test/test-execute/exec-runtimedirectory-mode.service
new file mode 100644
index 0000000000..842721d5c2
--- /dev/null
+++ b/test/test-execute/exec-runtimedirectory-mode.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for RuntimeDirectoryMode
+
+[Service]
+ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a /tmp/test-exec_runtimedirectory-mode); test "$$mode" = "750"'
+Type=oneshot
+RuntimeDirectory=test-exec_runtimedirectory-mode
+RuntimeDirectoryMode=0750
diff --git a/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service b/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service
new file mode 100644
index 0000000000..e962af8a4b
--- /dev/null
+++ b/test/test-execute/exec-runtimedirectory-owner-nfsnobody.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
+
+[Service]
+ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nfsnobody"'
+Type=oneshot
+Group=nfsnobody
+User=root
+RuntimeDirectory=test-exec_runtimedirectory-owner
diff --git a/test/test-execute/exec-runtimedirectory-owner.service b/test/test-execute/exec-runtimedirectory-owner.service
new file mode 100644
index 0000000000..1f438c182e
--- /dev/null
+++ b/test/test-execute/exec-runtimedirectory-owner.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
+
+[Service]
+ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nobody"'
+Type=oneshot
+Group=nobody
+User=root
+RuntimeDirectory=test-exec_runtimedirectory-owner
diff --git a/test/test-execute/exec-runtimedirectory.service b/test/test-execute/exec-runtimedirectory.service
new file mode 100644
index 0000000000..ec46c9d49b
--- /dev/null
+++ b/test/test-execute/exec-runtimedirectory.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for RuntimeDirectory
+
+[Service]
+ExecStart=/bin/sh -x -c 'test -d /tmp/test-exec_runtimedirectory'
+Type=oneshot
+RuntimeDirectory=test-exec_runtimedirectory
diff --git a/test/test-execute/exec-spec-interpolation.service b/test/test-execute/exec-spec-interpolation.service
new file mode 100644
index 0000000000..3e62662aa9
--- /dev/null
+++ b/test/test-execute/exec-spec-interpolation.service
@@ -0,0 +1,6 @@
+[Unit]
+Description=https://github.com/systemd/systemd/issues/2637
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -x -c "perl -e 'exit(!(qq{%%U} eq qq{\\x25U}))'"
diff --git a/test/exec-systemcallerrornumber.service b/test/test-execute/exec-systemcallerrornumber.service
index 255a8b231a..ff7da3c1a4 100644
--- a/test/exec-systemcallerrornumber.service
+++ b/test/test-execute/exec-systemcallerrornumber.service
@@ -2,6 +2,7 @@
Description=Test for SystemCallErrorNumber
[Service]
-ExecStart=/usr/bin/uname -a
+ExecStart=/bin/sh -x -c 'uname -a'
+Type=oneshot
SystemCallFilter=~uname
SystemCallErrorNumber=EACCES
diff --git a/test/exec-systemcallfilter-failing.service b/test/test-execute/exec-systemcallfilter-failing.service
index c6ce9368c9..5c6422f0fd 100644
--- a/test/exec-systemcallfilter-failing.service
+++ b/test/test-execute/exec-systemcallfilter-failing.service
@@ -3,6 +3,7 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "This should not be seen"
+Type=oneshot
SystemCallFilter=ioperm
SystemCallFilter=~ioperm
SystemCallFilter=ioperm
diff --git a/test/exec-systemcallfilter-failing2.service b/test/test-execute/exec-systemcallfilter-failing2.service
index b7f7c2aff9..3516078e1f 100644
--- a/test/exec-systemcallfilter-failing2.service
+++ b/test/test-execute/exec-systemcallfilter-failing2.service
@@ -3,4 +3,5 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "This should not be seen"
+Type=oneshot
SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST
diff --git a/test/exec-systemcallfilter-not-failing.service b/test/test-execute/exec-systemcallfilter-not-failing.service
index feb206ab6d..c794b67edd 100644
--- a/test/exec-systemcallfilter-not-failing.service
+++ b/test/test-execute/exec-systemcallfilter-not-failing.service
@@ -3,6 +3,7 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "Foo bar"
+Type=oneshot
SystemCallFilter=~read write open execve ioperm
SystemCallFilter=ioctl
SystemCallFilter=read write open execve
diff --git a/test/exec-systemcallfilter-not-failing2.service b/test/test-execute/exec-systemcallfilter-not-failing2.service
index cca469aa3d..a62c81bd48 100644
--- a/test/exec-systemcallfilter-not-failing2.service
+++ b/test/test-execute/exec-systemcallfilter-not-failing2.service
@@ -3,4 +3,5 @@ Description=Test for SystemCallFilter
[Service]
ExecStart=/bin/echo "Foo bar"
+Type=oneshot
SystemCallFilter=
diff --git a/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service b/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service
new file mode 100644
index 0000000000..9393e0a998
--- /dev/null
+++ b/test/test-execute/exec-systemcallfilter-system-user-nfsnobody.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Test for SystemCallFilter in system mode with User set
+
+[Service]
+ExecStart=/bin/echo "Foo bar"
+Type=oneshot
+User=nfsnobody
+SystemCallFilter=~read write open execve ioperm
+SystemCallFilter=ioctl
+SystemCallFilter=read write open execve
+SystemCallFilter=~ioperm
diff --git a/test/test-execute/exec-systemcallfilter-system-user.service b/test/test-execute/exec-systemcallfilter-system-user.service
new file mode 100644
index 0000000000..462f94133d
--- /dev/null
+++ b/test/test-execute/exec-systemcallfilter-system-user.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Test for SystemCallFilter in system mode with User set
+
+[Service]
+ExecStart=/bin/echo "Foo bar"
+Type=oneshot
+User=nobody
+SystemCallFilter=~read write open execve ioperm
+SystemCallFilter=ioctl
+SystemCallFilter=read write open execve
+SystemCallFilter=~ioperm
diff --git a/test/test-execute/exec-umask-0177.service b/test/test-execute/exec-umask-0177.service
new file mode 100644
index 0000000000..a5e8fc4dbc
--- /dev/null
+++ b/test/test-execute/exec-umask-0177.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for UMask
+
+[Service]
+ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "600"'
+Type=oneshot
+UMask=0177
+PrivateTmp=yes
diff --git a/test/test-execute/exec-umask-default.service b/test/test-execute/exec-umask-default.service
new file mode 100644
index 0000000000..487f5e9b94
--- /dev/null
+++ b/test/test-execute/exec-umask-default.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for UMask default
+
+[Service]
+ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "644"'
+Type=oneshot
+PrivateTmp=yes
diff --git a/test/test-execute/exec-user-nfsnobody.service b/test/test-execute/exec-user-nfsnobody.service
new file mode 100644
index 0000000000..aafda3aa26
--- /dev/null
+++ b/test/test-execute/exec-user-nfsnobody.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for User
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$USER" = "nfsnobody"'
+Type=oneshot
+User=nfsnobody
diff --git a/test/test-execute/exec-user.service b/test/test-execute/exec-user.service
new file mode 100644
index 0000000000..0a00c1abc4
--- /dev/null
+++ b/test/test-execute/exec-user.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for User
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$USER" = "nobody"'
+Type=oneshot
+User=nobody
diff --git a/test/exec-workingdirectory.service b/test/test-execute/exec-workingdirectory.service
index 10855d682a..fe3c420d2d 100644
--- a/test/exec-workingdirectory.service
+++ b/test/test-execute/exec-workingdirectory.service
@@ -2,6 +2,6 @@
Description=Test for WorkingDirectory
[Service]
-ExecStart=/bin/sh -c 'echo $PWD; exit $(test $PWD = "/tmp/test-exec_workingdirectory")'
+ExecStart=/bin/sh -x -c 'test "$$PWD" = "/tmp/test-exec_workingdirectory"'
Type=oneshot
WorkingDirectory=/tmp/test-exec_workingdirectory
diff --git a/test/test-functions b/test/test-functions
index 8272e52e17..2a21a64c5c 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -4,16 +4,22 @@
PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH
+LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE" = "debian" ]] && echo yes)
KERNEL_VER=${KERNEL_VER-$(uname -r)}
KERNEL_MODS="/lib/modules/$KERNEL_VER/"
+QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}"
+NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}"
+TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out
+FSTYPE="${FSTYPE:-ext3}"
+UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-no}"
if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
echo "WARNING! Cannot determine rootlibdir from pkg-config, assuming /usr/lib/systemd" >&2
ROOTLIBDIR=/usr/lib/systemd
fi
-BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe"
-DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname"
+BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm"
+DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find"
function find_qemu_bin() {
# SUSE and Red Hat call the binary qemu-kvm
@@ -41,6 +47,8 @@ function find_qemu_bin() {
fi
}
+# Return 0 if QEMU did run (then you must check the result state/logs for actual
+# success), or 1 if QEMU is not available.
run_qemu() {
if [ -f /etc/machine-id ]; then
read MACHINE_ID < /etc/machine-id
@@ -50,42 +58,77 @@ run_qemu() {
&& KERNEL_BIN="/boot/$MACHINE_ID/$KERNEL_VER/linux"
fi
+ default_fedora_initrd=/boot/initramfs-${KERNEL_VER}.img
+ default_debian_initrd=/boot/initrd.img-${KERNEL_VER}
[ "$KERNEL_BIN" ] || KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER
- [ "$INITRD" ] || INITRD=/boot/initramfs-${KERNEL_VER}.img
+ [ "$INITRD" ] || { [ -e "$default_fedora_initrd" ] && INITRD=$default_fedora_initrd; }
+ [ "$INITRD" ] || { [ "$LOOKS_LIKE_DEBIAN" ] && [ -e "$default_debian_initrd" ] && INITRD=$default_debian_initrd; }
[ "$QEMU_SMP" ] || QEMU_SMP=1
find_qemu_bin || return 1
KERNEL_APPEND="root=/dev/sda1 \
-systemd.log_level=debug \
raid=noautodetect \
loglevel=2 \
init=$ROOTLIBDIR/systemd \
ro \
console=ttyS0 \
selinux=0 \
+systemd.unified_cgroup_hierarchy=$UNIFIED_CGROUP_HIERARCHY \
$KERNEL_APPEND \
"
- QEMU_OPTIONS="-machine accel=kvm:tcg \
--smp $QEMU_SMP \
+ QEMU_OPTIONS="-smp $QEMU_SMP \
-net none \
-m 512M \
-nographic \
-kernel $KERNEL_BIN \
+-drive format=raw,cache=unsafe,file=${TESTDIR}/rootdisk.img \
"
- if [ "$INITRD" ]; then
+ if [[ "$INITRD" && "$SKIP_INITRD" != "yes" ]]; then
QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD"
fi
- ( set -x
- $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND" $TESTDIR/rootdisk.img ) || return 1
+ if [ -c /dev/kvm ]; then
+ QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
+ fi
+
+ if [[ "$QEMU_TIMEOUT" != "infinity" ]]; then
+ QEMU_BIN="timeout --foreground $QEMU_TIMEOUT $QEMU_BIN"
+ fi
+ (set -x; $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND")
+ rc=$?
+ if [ "$rc" = 124 ] && [ "$QEMU_TIMEOUT" != "infinity" ]; then
+ derror "test timed out after $QEMU_TIMEOUT s"
+ TIMED_OUT=1
+ else
+ [ "$rc" != 0 ] && derror "QEMU failed with exit code $rc"
+ fi
+ return 0
}
+# Return 0 if nspawn did run (then you must check the result state/logs for actual
+# success), or 1 if nspawn is not available.
run_nspawn() {
- set -x
- ../../systemd-nspawn --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND
+ [[ -d /run/systemd/system ]] || return 1
+
+ local _nspawn_cmd="../../systemd-nspawn --register=no --kill-signal=SIGKILL --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND"
+ if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
+ _nspawn_cmd="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
+ fi
+
+ _nspawn_cmd="env UNIFIED_CGROUP_HIERARCHY=$UNIFIED_CGROUP_HIERARCHY $_nspawn_cmd"
+
+ (set -x; $_nspawn_cmd)
+ rc=$?
+ if [ "$rc" = 124 ] && [ "$NSPAWN_TIMEOUT" != "infinity" ]; then
+ derror "test timed out after $NSPAWN_TIMEOUT s"
+ TIMED_OUT=1
+ else
+ [ "$rc" != 0 ] && derror "nspawn failed with exit code $rc"
+ fi
+ return 0
}
setup_basic_environment() {
@@ -104,21 +147,120 @@ setup_basic_environment() {
install_keymaps
install_terminfo
install_execs
+ install_fsck
install_plymouth
install_debug_tools
install_ld_so_conf
+ setup_selinux
strip_binaries
install_depmod_files
generate_module_dependencies
- # softlink mtab
- ln -fs /proc/self/mounts $initdir/etc/mtab
+}
+
+setup_selinux() {
+ # don't forget KERNEL_APPEND='... selinux=1 ...'
+ if [[ "$SETUP_SELINUX" != "yes" ]]; then
+ ddebug "Don't setup SELinux"
+ return 0
+ fi
+ ddebug "Setup SELinux"
+ local _conf_dir=/etc/selinux
+ local _fixfiles_tools="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles"
+
+ rm -rf $initdir/$_conf_dir
+ if ! cp -ar $_conf_dir $initdir/$_conf_dir; then
+ dfatal "Failed to copy $_conf_dir"
+ exit 1
+ fi
+
+ cat <<EOF >$initdir/etc/systemd/system/autorelabel.service
+[Unit]
+Description=Relabel all filesystems
+DefaultDependencies=no
+Requires=local-fs.target
+Conflicts=shutdown.target
+After=local-fs.target
+Before=sysinit.target shutdown.target
+ConditionSecurity=selinux
+ConditionPathExists=|/.autorelabel
+
+[Service]
+ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot'
+Type=oneshot
+TimeoutSec=0
+RemainAfterExit=yes
+EOF
+
+ touch $initdir/.autorelabel
+ mkdir -p $initdir/etc/systemd/system/basic.target.wants
+ ln -fs autorelabel.service $initdir/etc/systemd/system/basic.target.wants/autorelabel.service
+
+ dracut_install $_fixfiles_tools
+ dracut_install fixfiles
+ dracut_install sestatus
+}
+
+install_valgrind() {
+ if ! type -p valgrind; then
+ dfatal "Failed to install valgrind"
+ exit 1
+ fi
+
+ local _valgrind_bins=$(strace -e execve valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if /^execve\("([^"]+)"/')
+ dracut_install $_valgrind_bins
+
+ local _valgrind_libs=$(LD_DEBUG=files valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if m{calling init: (/.*vgpreload_.*)}')
+ dracut_install $_valgrind_libs
+
+ local _valgrind_dbg_and_supp=$(
+ strace -e open valgrind /bin/true 2>&1 >/dev/null |
+ perl -lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }'
+ )
+ dracut_install $_valgrind_dbg_and_supp
+}
+
+create_valgrind_wrapper() {
+ local _valgrind_wrapper=$initdir/$ROOTLIBDIR/systemd-under-valgrind
+ ddebug "Create $_valgrind_wrapper"
+ cat >$_valgrind_wrapper <<EOF
+#!/bin/bash
+
+mount -t proc proc /proc
+exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@"
+EOF
+ chmod 0755 $_valgrind_wrapper
+}
+
+create_strace_wrapper() {
+ local _strace_wrapper=$initdir/$ROOTLIBDIR/systemd-under-strace
+ ddebug "Create $_strace_wrapper"
+ cat >$_strace_wrapper <<EOF
+#!/bin/bash
+
+exec strace -D -o /strace.out $ROOTLIBDIR/systemd "\$@"
+EOF
+ chmod 0755 $_strace_wrapper
+}
+
+install_fsck() {
+ dracut_install /sbin/fsck*
+ dracut_install -o /bin/fsck*
+
+ # fskc.reiserfs calls reiserfsck. so, install it
+ dracut_install -o reiserfsck
}
install_dmevent() {
instmods dm_crypt =crypto
type -P dmeventd >/dev/null && dracut_install dmeventd
inst_libdir_file "libdevmapper-event.so*"
- inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
+ if [[ "$LOOKS_LIKE_DEBIAN" ]]; then
+ # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu
+ # see https://anonscm.debian.org/cgit/pkg-lvm/lvm2.git/tree/debian/patches/0007-udev.patch
+ inst_rules 55-dm.rules 60-persistent-storage-dm.rules
+ else
+ inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules
+ fi
}
install_systemd() {
@@ -129,28 +271,42 @@ install_systemd() {
# we strip binaries since debug symbols increase binaries size a lot
# and it could fill the available space
strip_binaries
+
+ # enable debug logging in PID1
+ echo LogLevel=debug >> $initdir/etc/systemd/system.conf
+}
+
+get_ldpath() {
+ local _bin="$1"
+ objdump -p "$_bin" 2>/dev/null | awk "/R(UN)?PATH/ { print \"$initdir\" \$2 }" | paste -sd :
}
install_missing_libraries() {
# install possible missing libraries
- for i in $initdir/{sbin,bin}/* $initdir/lib/systemd/*; do
- inst_libs $i
+ for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/*; do
+ LD_LIBRARY_PATH=$(get_ldpath $i) inst_libs $i
done
}
create_empty_image() {
rm -f "$TESTDIR/rootdisk.img"
# Create the blank file to use as a root filesystem
- dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=300
+ dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=400
LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img)
[ -b "$LOOPDEV" ] || return 1
echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
sfdisk "$LOOPDEV" <<EOF
-,290M
+,390M
,
EOF
- mkfs.ext3 -L systemd "${LOOPDEV}p1"
+ local _label="-L systemd"
+ # mkfs.reiserfs doesn't know -L. so, use --label instead
+ [[ "$FSTYPE" == "reiserfs" ]] && _label="--label systemd"
+ if ! mkfs -t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
+ dfatal "Failed to mkfs -t ${FSTYPE}"
+ exit 1
+ fi
}
check_result_nspawn() {
@@ -161,10 +317,15 @@ check_result_nspawn() {
[[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
ls -l $TESTDIR/journal/*/*.journal
test -s $TESTDIR/failed && ret=$(($ret+1))
+ [ -n "$TIMED_OUT" ] && ret=$(($ret+1))
return $ret
}
strip_binaries() {
+ if [[ "$STRIP_BINARIES" = "no" ]]; then
+ ddebug "Don't strip binaries"
+ return 0
+ fi
ddebug "Strip binaries"
find "$initdir" -executable -not -path '*/lib/modules/*.ko' -type f | xargs strip --strip-unneeded | ddebug
}
@@ -179,12 +340,17 @@ EOF
}
install_execs() {
- # install any Execs from the service files
- egrep -ho '^Exec[^ ]*=[^ ]+' $initdir/lib/systemd/system/*.service \
- | while read i; do
- i=${i##Exec*=}; i=${i##-}
- inst $i
- done
+ ddebug "install any Execs from the service files"
+ (
+ export PKG_CONFIG_PATH=$TEST_BASE_DIR/../src/core/
+ systemdsystemunitdir=$(pkg-config --variable=systemdsystemunitdir systemd)
+ systemduserunitdir=$(pkg-config --variable=systemduserunitdir systemd)
+ egrep -ho '^Exec[^ ]*=[^ ]+' $initdir/{$systemdsystemunitdir,$systemduserunitdir}/*.service \
+ | while read i; do
+ i=${i##Exec*=}; i=${i##-}
+ inst $i
+ done
+ )
}
generate_module_dependencies() {
@@ -220,6 +386,7 @@ install_config_files() {
inst /etc/sysconfig/init
inst /etc/passwd
inst /etc/shadow
+ inst /etc/login.defs
inst /etc/group
inst /etc/shells
inst /etc/nsswitch.conf
@@ -234,7 +401,7 @@ install_config_files() {
echo systemd-testsuite > $initdir/etc/hostname
# fstab
cat >$initdir/etc/fstab <<EOF
-LABEL=systemd / ext3 rw 0 1
+LABEL=systemd / ${FSTYPE} rw 0 1
EOF
}
@@ -260,21 +427,33 @@ install_dbus() {
inst $ROOTLIBDIR/system/dbus.service
find \
- /etc/dbus-1 -xtype f \
+ /etc/dbus-1 /usr/share/dbus-1 -xtype f \
| while read file; do
inst $file
done
}
install_pam() {
+ (
+ [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture &>/dev/null && find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f
find \
/etc/pam.d \
/etc/security \
/lib64/security \
/lib/security -xtype f \
- | while read file; do
+ ) | while read file; do
inst $file
done
+
+ # pam_unix depends on unix_chkpwd.
+ # see http://www.linux-pam.org/Linux-PAM-html/sag-pam_unix.html
+ dracut_install -o unix_chkpwd
+
+ [[ "$LOOKS_LIKE_DEBIAN" ]] &&
+ cp /etc/pam.d/systemd-user $initdir/etc/pam.d/
+
+ # set empty root password for easy debugging
+ sed -i 's/^root:x:/root::/' $initdir/etc/passwd
}
install_keymaps() {
@@ -305,7 +484,7 @@ install_terminfo() {
setup_testsuite() {
cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/
- sed "s#@SYSTEMCTL@#$(type -P systemctl)#g" $TEST_BASE_DIR/end.service.in > $initdir/etc/systemd/system/end.service
+ cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/
mkdir -p $initdir/etc/systemd/system/testsuite.target.wants
ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service
@@ -1115,11 +1294,6 @@ inst_libdir_file() {
fi
}
-check_nspawn() {
- [[ -d /sys/fs/cgroup/systemd ]]
-}
-
-
do_test() {
if [[ $UID != "0" ]]; then
echo "TEST: $TEST_DESCRIPTION [SKIPPED]: not root" >&2
diff --git a/test/test-path/basic.target b/test/test-path/basic.target
new file mode 120000
index 0000000000..a882b72cc9
--- /dev/null
+++ b/test/test-path/basic.target
@@ -0,0 +1 @@
+../../units/basic.target \ No newline at end of file
diff --git a/test/path-changed.path b/test/test-path/path-changed.path
index e58bdd925f..e58bdd925f 100644
--- a/test/path-changed.path
+++ b/test/test-path/path-changed.path
diff --git a/test/path-changed.service b/test/test-path/path-changed.service
index 8bdf178830..8bdf178830 120000
--- a/test/path-changed.service
+++ b/test/test-path/path-changed.service
diff --git a/test/path-directorynotempty.path b/test/test-path/path-directorynotempty.path
index 17e599fc0e..17e599fc0e 100644
--- a/test/path-directorynotempty.path
+++ b/test/test-path/path-directorynotempty.path
diff --git a/test/path-directorynotempty.service b/test/test-path/path-directorynotempty.service
index 8bdf178830..8bdf178830 120000
--- a/test/path-directorynotempty.service
+++ b/test/test-path/path-directorynotempty.service
diff --git a/test/path-exists.path b/test/test-path/path-exists.path
index c4c9105af4..c4c9105af4 100644
--- a/test/path-exists.path
+++ b/test/test-path/path-exists.path
diff --git a/test/path-exists.service b/test/test-path/path-exists.service
index 8bdf178830..8bdf178830 120000
--- a/test/path-exists.service
+++ b/test/test-path/path-exists.service
diff --git a/test/path-existsglob.path b/test/test-path/path-existsglob.path
index a058599605..a058599605 100644
--- a/test/path-existsglob.path
+++ b/test/test-path/path-existsglob.path
diff --git a/test/path-existsglob.service b/test/test-path/path-existsglob.service
index 8bdf178830..8bdf178830 120000
--- a/test/path-existsglob.service
+++ b/test/test-path/path-existsglob.service
diff --git a/test/path-makedirectory.path b/test/test-path/path-makedirectory.path
index 9408479c0f..9408479c0f 100644
--- a/test/path-makedirectory.path
+++ b/test/test-path/path-makedirectory.path
diff --git a/test/path-makedirectory.service b/test/test-path/path-makedirectory.service
index 8bdf178830..8bdf178830 120000
--- a/test/path-makedirectory.service
+++ b/test/test-path/path-makedirectory.service
diff --git a/test/path-modified.path b/test/test-path/path-modified.path
index 18363227ba..18363227ba 100644
--- a/test/path-modified.path
+++ b/test/test-path/path-modified.path
diff --git a/test/path-modified.service b/test/test-path/path-modified.service
index 8bdf178830..8bdf178830 120000
--- a/test/path-modified.service
+++ b/test/test-path/path-modified.service
diff --git a/test/path-mycustomunit.service b/test/test-path/path-mycustomunit.service
index 172ac0d0d5..172ac0d0d5 100644
--- a/test/path-mycustomunit.service
+++ b/test/test-path/path-mycustomunit.service
diff --git a/test/path-service.service b/test/test-path/path-service.service
index f8499ec619..f8499ec619 100644
--- a/test/path-service.service
+++ b/test/test-path/path-service.service
diff --git a/test/path-unit.path b/test/test-path/path-unit.path
index 95e572d6d5..95e572d6d5 100644
--- a/test/path-unit.path
+++ b/test/test-path/path-unit.path
diff --git a/test/test-path/paths.target b/test/test-path/paths.target
new file mode 120000
index 0000000000..b402796cb9
--- /dev/null
+++ b/test/test-path/paths.target
@@ -0,0 +1 @@
+../../units/paths.target \ No newline at end of file
diff --git a/test/test-path/sysinit.target b/test/test-path/sysinit.target
new file mode 120000
index 0000000000..9d10e5b2e2
--- /dev/null
+++ b/test/test-path/sysinit.target
@@ -0,0 +1 @@
+../../units/sysinit.target \ No newline at end of file
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 64d7f93444..9723386b23 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -23,14 +23,23 @@ use strict;
my $udev_bin = "./test-udev";
my $valgrind = 0;
my $gdb = 0;
+my $strace = 0;
my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --track-origins=yes --quiet $udev_bin";
my $udev_bin_gdb = "gdb --args $udev_bin";
-my $udev_dev = "test/dev";
+my $udev_bin_strace = "strace -efile $udev_bin";
my $udev_run = "test/run";
+my $udev_tmpfs = "test/tmpfs";
+my $udev_sys = "${udev_tmpfs}/sys";
+my $udev_dev = "${udev_tmpfs}/dev";
my $udev_rules_dir = "$udev_run/udev/rules.d";
my $udev_rules = "$udev_rules_dir/udev-test.rules";
my $EXIT_TEST_SKIP = 77;
+my $rules_10k_tags = "";
+for (my $i = 1; $i <= 10000; ++$i) {
+ $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
+}
+
my @tests = (
{
desc => "no rules",
@@ -1315,6 +1324,25 @@ KERNEL=="sda", IMPORT{builtin}="path_id"
KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
EOF
},
+ {
+ desc => "add and match tag",
+ devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+ exp_name => "found",
+ not_exp_name => "bad" ,
+ rules => <<EOF
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
+TAGS=="green", SYMLINK+="found"
+TAGS=="blue", SYMLINK+="bad"
+EOF
+ },
+ {
+ desc => "don't crash with lots of tags",
+ devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+ exp_name => "found",
+ rules => $rules_10k_tags . <<EOF
+TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
+EOF
+ },
);
sub udev {
@@ -1327,11 +1355,13 @@ sub udev {
close CONF;
if ($valgrind > 0) {
- system("$udev_bin_valgrind $action $devpath");
+ return system("$udev_bin_valgrind $action $devpath");
} elsif ($gdb > 0) {
- system("$udev_bin_gdb $action $devpath");
+ return system("$udev_bin_gdb $action $devpath");
+ } elsif ($strace > 0) {
+ return system("$udev_bin_strace $action $devpath");
} else {
- system("$udev_bin", "$action", "$devpath");
+ return system("$udev_bin", "$action", "$devpath");
}
}
@@ -1401,23 +1431,34 @@ sub major_minor_test {
}
sub udev_setup {
- system("rm", "-rf", "$udev_dev");
+ system("umount", $udev_tmpfs);
+ rmdir($udev_tmpfs);
+ mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
+ system("mount", "-o", "rw,mode=755,nosuid,noexec,nodev", "-t", "tmpfs", "tmpfs", $udev_tmpfs) && die "unable to mount tmpfs";
+
mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
# setting group and mode of udev_dev ensures the tests work
# even if the parent directory has setgid bit enabled.
chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
+ system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
+
system("rm", "-rf", "$udev_run");
}
sub run_test {
my ($rules, $number) = @_;
+ my $rc;
print "TEST $number: $rules->{desc}\n";
print "device \'$rules->{devpath}\' expecting node/link \'$rules->{exp_name}\'\n";
- udev("add", $rules->{devpath}, \$rules->{rules});
+ $rc = udev("add", $rules->{devpath}, \$rules->{rules});
+ if ($rc != 0) {
+ print "$udev_bin add failed with code $rc\n";
+ $error++;
+ }
if (defined($rules->{not_exp_name})) {
if ((-e "$udev_dev/$rules->{not_exp_name}") ||
(-l "$udev_dev/$rules->{not_exp_name}")) {
@@ -1458,7 +1499,11 @@ sub run_test {
return;
}
- udev("remove", $rules->{devpath}, \$rules->{rules});
+ $rc = udev("remove", $rules->{devpath}, \$rules->{rules});
+ if ($rc != 0) {
+ print "$udev_bin remove failed with code $rc\n";
+ $error++;
+ }
if ((-e "$udev_dev/$rules->{exp_name}") ||
(-l "$udev_dev/$rules->{exp_name}")) {
print "remove: error";
@@ -1487,14 +1532,21 @@ sub run_test {
# due to mknod restrictions
if (!($<==0)) {
print "Must have root permissions to run properly.\n";
- exit;
+ exit($EXIT_TEST_SKIP);
+}
+
+# skip the test when running in a chroot
+system("systemd-detect-virt", "-r", "-q");
+if ($? >> 8 == 0) {
+ print "Running in a chroot, skipping the test.\n";
+ exit($EXIT_TEST_SKIP);
}
# skip the test when running in a container
system("systemd-detect-virt", "-c", "-q");
if ($? >> 8 == 0) {
- print "Running in a container, skipping the test.\n";
- exit($EXIT_TEST_SKIP);
+ print "Running in a container, skipping the test.\n";
+ exit($EXIT_TEST_SKIP);
}
udev_setup();
@@ -1509,6 +1561,9 @@ foreach my $arg (@ARGV) {
} elsif ($arg =~ m/--gdb/) {
$gdb = 1;
printf("using gdb\n");
+ } elsif ($arg =~ m/--strace/) {
+ $strace = 1;
+ printf("using strace\n");
} else {
push(@list, $arg);
}
@@ -1536,10 +1591,11 @@ if ($list[0]) {
print "$error errors occurred\n\n";
# cleanup
-system("rm", "-rf", "$udev_dev");
system("rm", "-rf", "$udev_run");
+system("umount", "$udev_tmpfs");
+rmdir($udev_tmpfs);
if ($error > 0) {
- exit(1);
+ exit(1);
}
exit(0);
diff --git a/test/unstoppable.service b/test/unstoppable.service
index 24fb0a25e1..56b72c98f7 100644
--- a/test/unstoppable.service
+++ b/test/unstoppable.service
@@ -1,5 +1,5 @@
[Service]
Type=oneshot
RemainAfterExit=yes
-ExecStart=/bin/echo 'I'm unstoppable!'
+ExecStart=/bin/echo "I'm unstoppable!"
ExecStop=/bin/systemctl start --no-block unstoppable.service