summaryrefslogtreecommitdiff
path: root/test/sysv-generator-test.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/sysv-generator-test.py')
-rw-r--r--test/sysv-generator-test.py391
1 files changed, 0 insertions, 391 deletions
diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py
deleted file mode 100644
index cf7d467368..0000000000
--- a/test/sysv-generator-test.py
+++ /dev/null
@@ -1,391 +0,0 @@
-# systemd-sysv-generator integration test
-#
-# (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 unittest
-import sys
-import os
-import subprocess
-import tempfile
-import shutil
-from glob import glob
-
-try:
- from configparser import RawConfigParser
-except ImportError:
- # python 2
- from ConfigParser import RawConfigParser
-
-sysv_generator = os.path.join(os.environ.get('builddir', '.'), 'systemd-sysv-generator')
-
-
-class SysvGeneratorTest(unittest.TestCase):
- def setUp(self):
- self.workdir = tempfile.mkdtemp(prefix='sysv-gen-test.')
- self.init_d_dir = os.path.join(self.workdir, 'init.d')
- os.mkdir(self.init_d_dir)
- self.rcnd_dir = self.workdir
- self.unit_dir = os.path.join(self.workdir, 'systemd')
- os.mkdir(self.unit_dir)
- self.out_dir = os.path.join(self.workdir, 'output')
- os.mkdir(self.out_dir)
-
- def tearDown(self):
- shutil.rmtree(self.workdir)
-
- #
- # Helper methods
- #
-
- def run_generator(self, expect_error=False):
- '''Run sysv-generator.
-
- Fail if stderr contains any "Fail", unless expect_error is True.
- Return (stderr, filename -> ConfigParser) pair with ouput to stderr and
- parsed generated units.
- '''
- env = os.environ.copy()
- env['SYSTEMD_LOG_LEVEL'] = 'debug'
- env['SYSTEMD_SYSVINIT_PATH'] = self.init_d_dir
- env['SYSTEMD_SYSVRCND_PATH'] = self.rcnd_dir
- env['SYSTEMD_UNIT_PATH'] = self.unit_dir
- gen = subprocess.Popen(
- [sysv_generator, 'ignored', 'ignored', self.out_dir],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- universal_newlines=True, env=env)
- (out, err) = gen.communicate()
- if not expect_error:
- self.assertFalse('Fail' in err, err)
- self.assertEqual(gen.returncode, 0, err)
-
- results = {}
- for service in glob(self.out_dir + '/*.service'):
- if os.path.islink(service):
- continue
- cp = RawConfigParser()
- cp.optionxform = lambda o: o # don't lower-case option names
- with open(service) as f:
- cp.readfp(f)
- results[os.path.basename(service)] = cp
-
- return (err, results)
-
- def add_sysv(self, fname, keys, enable=False, prio=1):
- '''Create a SysV init script with the given keys in the LSB header
-
- There are sensible default values for all fields.
- If enable is True, links will be created in the rcN.d dirs. In that
- case, the priority can be given with "prio" (default to 1).
-
- Return path of generated script.
- '''
- name_without_sh = fname.endswith('.sh') and fname[:-3] or fname
- keys.setdefault('Provides', name_without_sh)
- keys.setdefault('Required-Start', '$local_fs')
- keys.setdefault('Required-Stop', keys['Required-Start'])
- keys.setdefault('Default-Start', '2 3 4 5')
- keys.setdefault('Default-Stop', '0 1 6')
- keys.setdefault('Short-Description', 'test %s service' %
- name_without_sh)
- keys.setdefault('Description', 'long description for test %s service' %
- name_without_sh)
- script = os.path.join(self.init_d_dir, fname)
- with open(script, 'w') as f:
- f.write('#!/bin/init-d-interpreter\n### BEGIN INIT INFO\n')
- for k, v in keys.items():
- if v is not None:
- f.write('#%20s %s\n' % (k + ':', v))
- f.write('### END INIT INFO\ncode --goes here\n')
- os.chmod(script, 0o755)
-
- if enable:
- def make_link(prefix, runlevel):
- d = os.path.join(self.rcnd_dir, 'rc%s.d' % runlevel)
- if not os.path.isdir(d):
- os.mkdir(d)
- os.symlink('../init.d/' + fname, os.path.join(d, prefix + fname))
-
- for rl in keys['Default-Start'].split():
- make_link('S%02i' % prio, rl)
- for rl in keys['Default-Stop'].split():
- make_link('K%02i' % (99 - prio), rl)
-
- return script
-
- def assert_enabled(self, unit, targets):
- '''assert that a unit is enabled in precisely the given targets'''
-
- all_targets = ['multi-user', 'graphical']
-
- # should be enabled
- for target in all_targets:
- link = os.path.join(self.out_dir, '%s.target.wants' % target, unit)
- if target in targets:
- unit_file = os.readlink(link)
- self.assertTrue(os.path.exists(unit_file))
- self.assertEqual(os.path.basename(unit_file), unit)
- else:
- self.assertFalse(os.path.exists(link),
- '%s unexpectedly exists' % link)
-
- #
- # test cases
- #
-
- def test_nothing(self):
- '''no input files'''
-
- results = self.run_generator()[1]
- self.assertEqual(results, {})
- self.assertEqual(os.listdir(self.out_dir), [])
-
- def test_simple_disabled(self):
- '''simple service without dependencies, disabled'''
-
- self.add_sysv('foo', {}, enable=False)
- err, results = self.run_generator()
- self.assertEqual(len(results), 1)
-
- # no enablement links or other stuff
- self.assertEqual(os.listdir(self.out_dir), ['foo.service'])
-
- s = results['foo.service']
- self.assertEqual(s.sections(), ['Unit', 'Service'])
- self.assertEqual(s.get('Unit', 'Description'), 'LSB: test foo service')
- # $local_fs does not need translation, don't expect any dependency
- # fields here
- self.assertEqual(set(s.options('Unit')),
- set(['Documentation', 'SourcePath', 'Description']))
-
- self.assertEqual(s.get('Service', 'Type'), 'forking')
- init_script = os.path.join(self.init_d_dir, 'foo')
- self.assertEqual(s.get('Service', 'ExecStart'),
- '%s start' % init_script)
- self.assertEqual(s.get('Service', 'ExecStop'),
- '%s stop' % init_script)
-
- self.assertNotIn('Overwriting', err)
-
- def test_simple_enabled_all(self):
- '''simple service without dependencies, enabled in all runlevels'''
-
- self.add_sysv('foo', {}, enable=True)
- err, results = self.run_generator()
- self.assertEqual(list(results), ['foo.service'])
- self.assert_enabled('foo.service', ['multi-user', 'graphical'])
- self.assertNotIn('Overwriting', err)
-
- def test_simple_enabled_some(self):
- '''simple service without dependencies, enabled in some runlevels'''
-
- self.add_sysv('foo', {'Default-Start': '2 4'}, enable=True)
- err, results = self.run_generator()
- self.assertEqual(list(results), ['foo.service'])
- self.assert_enabled('foo.service', ['multi-user'])
-
- def test_lsb_macro_dep_single(self):
- '''single LSB macro dependency: $network'''
-
- self.add_sysv('foo', {'Required-Start': '$network'})
- s = self.run_generator()[1]['foo.service']
- self.assertEqual(set(s.options('Unit')),
- set(['Documentation', 'SourcePath', 'Description', 'After', 'Wants']))
- self.assertEqual(s.get('Unit', 'After'), 'network-online.target')
- self.assertEqual(s.get('Unit', 'Wants'), 'network-online.target')
-
- def test_lsb_macro_dep_multi(self):
- '''multiple LSB macro dependencies'''
-
- self.add_sysv('foo', {'Required-Start': '$named $portmap'})
- 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')
-
- def test_lsb_deps(self):
- '''LSB header dependencies to other services'''
-
- # also give symlink priorities here; they should be ignored
- self.add_sysv('foo', {'Required-Start': 'must1 must2',
- 'Should-Start': 'may1 ne_may2'},
- enable=True, prio=40)
- self.add_sysv('must1', {}, enable=True, prio=10)
- self.add_sysv('must2', {}, enable=True, prio=15)
- self.add_sysv('may1', {}, enable=True, prio=20)
- # do not create ne_may2
- err, results = self.run_generator()
- self.assertEqual(sorted(results),
- ['foo.service', 'may1.service', 'must1.service', 'must2.service'])
-
- # foo should depend on all of them
- self.assertEqual(sorted(results['foo.service'].get('Unit', 'After').split()),
- ['may1.service', 'must1.service', 'must2.service', 'ne_may2.service'])
-
- # other services should not depend on each other
- self.assertFalse(results['must1.service'].has_option('Unit', 'After'))
- self.assertFalse(results['must2.service'].has_option('Unit', 'After'))
- self.assertFalse(results['may1.service'].has_option('Unit', 'After'))
-
- def test_symlink_prio_deps(self):
- '''script without LSB headers use rcN.d priority'''
-
- # create two init.d scripts without LSB header and enable them with
- # startup priorities
- for prio, name in [(10, 'provider'), (15, 'consumer')]:
- with open(os.path.join(self.init_d_dir, name), 'w') as f:
- f.write('#!/bin/init-d-interpreter\ncode --goes here\n')
- os.fchmod(f.fileno(), 0o755)
-
- d = os.path.join(self.rcnd_dir, 'rc2.d')
- if not os.path.isdir(d):
- os.mkdir(d)
- os.symlink('../init.d/' + name, os.path.join(d, 'S%02i%s' % (prio, name)))
-
- err, results = self.run_generator()
- self.assertEqual(sorted(results), ['consumer.service', 'provider.service'])
- self.assertFalse(results['provider.service'].has_option('Unit', 'After'))
- self.assertEqual(results['consumer.service'].get('Unit', 'After'),
- 'provider.service')
-
- def test_multiple_provides(self):
- '''multiple Provides: names'''
-
- self.add_sysv('foo', {'Provides': 'foo bar baz'})
- err, results = self.run_generator()
- self.assertEqual(list(results), ['foo.service'])
- self.assertEqual(set(results['foo.service'].options('Unit')),
- set(['Documentation', 'SourcePath', 'Description']))
- # should create symlinks for the alternative names
- for f in ['bar.service', 'baz.service']:
- self.assertEqual(os.readlink(os.path.join(self.out_dir, f)),
- 'foo.service')
- self.assertNotIn('Overwriting', err)
-
- def test_same_provides_in_multiple_scripts(self):
- '''multiple init.d scripts provide the same name'''
-
- self.add_sysv('foo', {'Provides': 'foo common'}, enable=True, prio=1)
- self.add_sysv('bar', {'Provides': 'bar common'}, enable=True, prio=2)
- err, results = self.run_generator()
- self.assertEqual(sorted(results), ['bar.service', 'foo.service'])
- # should create symlink for the alternative name for either unit
- self.assertIn(os.readlink(os.path.join(self.out_dir, 'common.service')),
- ['foo.service', 'bar.service'])
-
- def test_provide_other_script(self):
- '''init.d scripts provides the name of another init.d script'''
-
- self.add_sysv('foo', {'Provides': 'foo bar'}, enable=True)
- self.add_sysv('bar', {'Provides': 'bar'}, enable=True)
- err, results = self.run_generator()
- self.assertEqual(sorted(results), ['bar.service', 'foo.service'])
- # we do expect an overwrite here, bar.service should overwrite the
- # alias link from foo.service
- self.assertIn('Overwriting', err)
-
- def test_nonexecutable_script(self):
- '''ignores non-executable init.d script'''
-
- os.chmod(self.add_sysv('foo', {}), 0o644)
- err, results = self.run_generator()
- self.assertEqual(results, {})
-
- def test_sh_suffix(self):
- '''init.d script with .sh suffix'''
-
- self.add_sysv('foo.sh', {}, enable=True)
- err, results = self.run_generator()
- s = results['foo.service']
-
- self.assertEqual(s.sections(), ['Unit', 'Service'])
- # should not have a .sh
- self.assertEqual(s.get('Unit', 'Description'), 'LSB: test foo service')
-
- # calls correct script with .sh
- init_script = os.path.join(self.init_d_dir, 'foo.sh')
- self.assertEqual(s.get('Service', 'ExecStart'),
- '%s start' % init_script)
- self.assertEqual(s.get('Service', 'ExecStop'),
- '%s stop' % init_script)
-
- self.assert_enabled('foo.service', ['multi-user', 'graphical'])
-
- def test_sh_suffix_with_provides(self):
- '''init.d script with .sh suffix and Provides:'''
-
- self.add_sysv('foo.sh', {'Provides': 'foo bar'})
- err, results = self.run_generator()
- # ensure we don't try to create a symlink to itself
- self.assertNotIn(err, 'itself')
- self.assertEqual(list(results), ['foo.service'])
- self.assertEqual(results['foo.service'].get('Unit', 'Description'),
- 'LSB: test foo service')
-
- # should create symlink for the alternative name
- self.assertEqual(os.readlink(os.path.join(self.out_dir, 'bar.service')),
- 'foo.service')
-
- def test_hidden_files(self):
- '''init.d script with hidden file suffix'''
-
- script = self.add_sysv('foo', {}, enable=True)
- # backup files (not enabled in rcN.d/)
- shutil.copy(script, script + '.dpkg-new')
- shutil.copy(script, script + '.dpkg-dist')
- shutil.copy(script, script + '.swp')
- shutil.copy(script, script + '.rpmsave')
-
- err, results = self.run_generator()
- self.assertEqual(list(results), ['foo.service'])
-
- self.assert_enabled('foo.service', ['multi-user', 'graphical'])
-
- def test_backup_file(self):
- '''init.d script with backup file'''
-
- script = self.add_sysv('foo', {}, enable=True)
- # backup files (not enabled in rcN.d/)
- shutil.copy(script, script + '.bak')
- shutil.copy(script, script + '.old')
-
- err, results = self.run_generator()
- print(err)
- self.assertEqual(sorted(results),
- ['foo.bak.service', 'foo.old.service', 'foo.service'])
-
- # ensure we don't try to create a symlink to itself
- self.assertNotIn(err, 'itself')
-
- self.assert_enabled('foo.service', ['multi-user', 'graphical'])
- self.assert_enabled('foo.bak.service', [])
- self.assert_enabled('foo.old.service', [])
-
- def test_existing_native_unit(self):
- '''existing native unit'''
-
- with open(os.path.join(self.unit_dir, 'foo.service'), 'w') as f:
- f.write('[Unit]\n')
-
- self.add_sysv('foo.sh', {'Provides': 'foo bar'}, enable=True)
- err, results = self.run_generator()
- self.assertEqual(list(results), [])
- # no enablement or alias links, as native unit is disabled
- self.assertEqual(os.listdir(self.out_dir), [])
-
-
-if __name__ == '__main__':
- unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))