diff options
Diffstat (limited to 'test')
85 files changed, 956 insertions, 94 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..6963d8c88d 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 @@ -53,14 +53,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 --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..242090c761 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 --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..4252a9a75d 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. diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh index 41e02e2c8a..83393435f0 100755 --- a/test/TEST-03-JOBS/test.sh +++ b/test/TEST-03-JOBS/test.sh @@ -63,7 +63,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..3a05619ad5 --- /dev/null +++ b/test/TEST-04-JOURNAL/test-journal.sh @@ -0,0 +1,63 @@ +#!/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 +exit 0 diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh new file mode 100755 index 0000000000..1a14f76060 --- /dev/null +++ b/test/TEST-04-JOURNAL/test.sh @@ -0,0 +1,85 @@ +#!/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 check_nspawn; then + run_nspawn + 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..54000ecefb --- /dev/null +++ b/test/TEST-05-RLIMITS/test-rlimits.sh @@ -0,0 +1,17 @@ +#!/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 +exit 0 diff --git a/test/TEST-05-RLIMITS/test.sh b/test/TEST-05-RLIMITS/test.sh new file mode 100755 index 0000000000..6eaa0b8f34 --- /dev/null +++ b/test/TEST-05-RLIMITS/test.sh @@ -0,0 +1,81 @@ +#!/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 check_nspawn; then + run_nspawn + 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/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..d76ab507d2 --- /dev/null +++ b/test/networkd-test.py @@ -0,0 +1,371 @@ +#!/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, or LXC. +# 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') + + +@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' + os.makedirs(os.path.dirname(self.config), exist_ok=True) + + # 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() + if os.path.exists(self.config): + os.unlink(self.config) + subprocess.call(['systemctl', 'stop', 'systemd-networkd']) + + 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'): + with open(self.config, 'w') as f: + f.write('''[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 + + # verify resolv.conf if it gets dynamically managed + if os.path.islink('/etc/resolv.conf'): + for timeout in range(50): + with open('/etc/resolv.conf') as f: + contents = f.read() + if 'nameserver 192.168.5.1\n' in contents: + break + # resolv.conf can have at most three nameservers; if we already + # have three different ones, that's also okay + if contents.count('nameserver ') >= 3: + break + time.sleep(0.1) + else: + self.fail('nameserver 192.168.5.1 not found in /etc/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='IPv6AcceptRouterAdvertisements=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='IPv6AcceptRouterAdvertisements=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) + + +@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): + '''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 = [] + 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()) + + +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 + + +if __name__ == '__main__': + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, + verbosity=2)) 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..aca5f1eec6 100644 --- a/test/sysv-generator-test.py +++ b/test/sysv-generator-test.py @@ -23,6 +23,7 @@ import subprocess import tempfile import shutil from glob import glob +import collections try: from configparser import RawConfigParser @@ -32,6 +33,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 +84,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 +238,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''' 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.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.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-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-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/exec-personality-x86-64.service b/test/test-execute/exec-personality-x86-64.service index 5bb5d910d0..433e69a6d1 100644 --- a/test/exec-personality-x86-64.service +++ b/test/test-execute/exec-personality-x86-64.service @@ -2,6 +2,6 @@ Description=Test for Personality=x86-64 [Service] -ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "x86_64")' +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "x86_64"' Type=oneshot Personality=x86-64 diff --git a/test/exec-personality-x86.service b/test/test-execute/exec-personality-x86.service index 0b370a6480..a623a08cbe 100644 --- a/test/exec-personality-x86.service +++ b/test/test-execute/exec-personality-x86.service @@ -2,6 +2,6 @@ Description=Test for Personality=x86 [Service] -ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "i686")' +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "i686"' Type=oneshot Personality=x86 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/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/exec-runtimedirectory-mode.service b/test/test-execute/exec-runtimedirectory-mode.service index ba6d7ee39f..842721d5c2 100644 --- a/test/exec-runtimedirectory-mode.service +++ b/test/test-execute/exec-runtimedirectory-mode.service @@ -2,7 +2,7 @@ Description=Test for RuntimeDirectoryMode [Service] -ExecStart=/bin/sh -c 's=$(stat -c %a /tmp/test-exec_runtimedirectory-mode); echo $s; exit $(test $s = "750")' +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/exec-runtimedirectory-owner.service b/test/test-execute/exec-runtimedirectory-owner.service index 077e08d1c5..1f438c182e 100644 --- a/test/exec-runtimedirectory-owner.service +++ b/test/test-execute/exec-runtimedirectory-owner.service @@ -2,7 +2,7 @@ Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set) [Service] -ExecStart=/bin/sh -c 'f=/tmp/test-exec_runtimedirectory-owner;g=$(stat -c %G $f); echo "$g"; exit $(test $g = "nobody")' +ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nobody"' Type=oneshot Group=nobody User=root diff --git a/test/exec-runtimedirectory.service b/test/test-execute/exec-runtimedirectory.service index c12a6c63d6..ec46c9d49b 100644 --- a/test/exec-runtimedirectory.service +++ b/test/test-execute/exec-runtimedirectory.service @@ -2,6 +2,6 @@ Description=Test for RuntimeDirectory [Service] -ExecStart=/bin/sh -c 'exit $(test -d /tmp/test-exec_runtimedirectory)' +ExecStart=/bin/sh -x -c 'test -d /tmp/test-exec_runtimedirectory' Type=oneshot RuntimeDirectory=test-exec_runtimedirectory 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-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.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..961a6254d8 100644 --- a/test/test-functions +++ b/test/test-functions @@ -4,6 +4,7 @@ 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/" @@ -12,7 +13,7 @@ if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then ROOTLIBDIR=/usr/lib/systemd fi -BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe" +BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee" 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" function find_qemu_bin() { @@ -50,8 +51,11 @@ 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 @@ -67,8 +71,7 @@ selinux=0 \ $KERNEL_APPEND \ " - QEMU_OPTIONS="-machine accel=kvm:tcg \ --smp $QEMU_SMP \ + QEMU_OPTIONS="-smp $QEMU_SMP \ -net none \ -m 512M \ -nographic \ @@ -79,13 +82,17 @@ $KERNEL_APPEND \ QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD" fi + if [ -c /dev/kvm ]; then + QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host" + fi + ( set -x $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND" $TESTDIR/rootdisk.img ) || return 1 } run_nspawn() { set -x - ../../systemd-nspawn --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND + ../../systemd-nspawn --register=no --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND } setup_basic_environment() { @@ -104,21 +111,61 @@ setup_basic_environment() { install_keymaps install_terminfo install_execs + install_fsck install_plymouth install_debug_tools install_ld_so_conf strip_binaries install_depmod_files generate_module_dependencies - # softlink mtab - ln -fs /proc/self/mounts $initdir/etc/mtab +} + +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 + +exec valgrind --leak-check=full --log-file=/valgrind.out $ROOTLIBDIR/systemd "\$@" +EOF + chmod 0755 $_valgrind_wrapper +} + +install_fsck() { + dracut_install /sbin/fsck* + dracut_install -o /bin/fsck* } 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() { @@ -141,12 +188,12 @@ install_missing_libraries() { 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 @@ -165,6 +212,10 @@ check_result_nspawn() { } 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 +230,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 +276,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 @@ -260,21 +317,26 @@ 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 + + [[ "$LOOKS_LIKE_DEBIAN" ]] && + cp /etc/pam.d/systemd-user $initdir/etc/pam.d/ } install_keymaps() { @@ -305,7 +367,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 @@ -1116,7 +1178,7 @@ inst_libdir_file() { } check_nspawn() { - [[ -d /sys/fs/cgroup/systemd ]] + [[ -d /run/systemd/system ]] } 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/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 |