I have slapped together a small test suite for the functionality implemented in PATCH 0051. Obviously it requires this patch to work.

It also requires PATCH 0052 to pass all tests.

https://fedorahosted.org/freeipa/ticket/4517

--
Martin^3 Babinsky
From d09a4f1134a0e0535b1cab6989b41929f793d33c Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Wed, 22 Jul 2015 13:54:44 +0200
Subject: [PATCH] test suite for configuration of installers based on
 ConfigureTool

Tests for new functionality introduced in
https://fedorahosted.org/freeipa/ticket/4517
---
 ipatests/test_install/test_installer_config.py | 440 +++++++++++++++++++++++++
 1 file changed, 440 insertions(+)
 create mode 100644 ipatests/test_install/test_installer_config.py

diff --git a/ipatests/test_install/test_installer_config.py b/ipatests/test_install/test_installer_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..48c43d06161e9b1612c718be6833f9a24030e2b5
--- /dev/null
+++ b/ipatests/test_install/test_installer_config.py
@@ -0,0 +1,440 @@
+#
+# Copyright (C) 2015  FreeIPA Contributors see COPYING for license
+#
+
+"""
+tests for passing options to new-style installer from CLI and config file
+"""
+
+from ConfigParser import RawConfigParser
+from csv import writer, QUOTE_NONE
+from cStringIO import StringIO
+import os
+
+import pytest
+
+from ipapython.install import cli, common, core
+
+class MockInstaller(common.Installable, common.Interactive, core.Composite):
+
+    bool_opt = core.Knob(
+        bool,
+        False,
+        cli_short_name='b',
+        description='boolean option'
+    )
+
+    str_opt = core.Knob(
+        str,
+        'string',
+        cli_short_name='s',
+        description='string option'
+    )
+
+    int_opt = core.Knob(
+        int,
+        1,
+        cli_short_name='i',
+        description='integer option'
+    )
+
+    list_ints_opt = core.Knob(
+        (list, int),
+        None,
+        cli_short_name='l',
+        description='option storing list of integers'
+    )
+    list_strings_opt = core.Knob(
+        (list, str),
+        None,
+        cli_short_name='t',
+        description='option storing list of strings'
+    )
+
+    validated_int_opt = core.Knob(
+        int,
+        0,
+        cli_short_name='o',
+        description='option with custom validator'
+    )
+
+    @validated_int_opt.validator
+    def validated_int_opt(self, value):
+        if value < 0 or value > 10:
+            raise ValueError('invalid value {0}'.format(value))
+
+    no_default_opt = core.Knob(
+        int,
+        cli_short_name='n',
+        description='option with no default'
+    )
+
+@pytest.mark.usefixtures('configs')
+@pytest.mark.skipif(os.geteuid() != 0,
+                    reason="Must be root to run installer tests")
+class TestInstallerConfiguration(object):
+    valid_section = 'global'
+    invalid_section = 'glebl'
+
+    configs = {
+        'simple.txt': {
+            valid_section: dict(
+                bool_opt=False,
+                int_opt=3,
+                str_opt='test_string',
+                no_default_opt=1
+            )
+        },
+        'multivalue_int.txt': {
+            valid_section: dict(
+                bool_opt=False,
+                int_opt=5,
+                list_ints_opt=[1, 2, 3],
+                no_default_opt=1
+            )
+        },
+        'multivalue_string.txt': {
+            valid_section: dict(
+                bool_opt=True,
+                int_opt=4,
+                list_strings_opt=['value1', 'value2', 'value3'],
+                no_default_opt=1
+            )
+        },
+        'multivalue_string_with_comma.txt': {
+            valid_section: dict(
+                    bool_opt=False,
+                    list_strings_opt=['value1', 'value,2', 'value3'],
+                    no_default_opt=1
+                )
+        },
+        'multiline_string.txt': {
+            valid_section: dict(
+                bool_opt=True,
+                str_opt='value1\nvalue2',
+                no_default_opt=1
+            )
+        },
+        'validated_int.txt': {
+            valid_section: dict(
+                bool_opt=True,
+                validated_int_opt=4,
+                no_default_opt=1
+            )
+        },
+        'invalid_bool.txt': {
+            valid_section: dict(
+                bool_opt='trve',
+                no_default_opt=1
+            )
+        },
+        'invalid_int.txt': {
+            valid_section: dict(
+                bool_opt=True,
+                int_opt='fwefghhe',
+                no_default_opt=1
+            )
+        },
+        'invalid_list_ints.txt': {
+            valid_section: dict(
+                int_opt=4,
+                list_ints_opt=[1, 'two', 3],
+                no_default_opt=1
+            )
+        },
+        'invalid_validated.txt': {
+            valid_section: dict(
+                bool_opt=True,
+                validated_int_opt=14,
+                no_default_opt=1
+            )
+        },
+        'invalid_section.txt': {
+            invalid_section: dict(
+                bool_opt=True,
+                no_default_opt=1
+            )
+        },
+        'no_default_opt.txt': {
+            valid_section: dict(
+                bool_opt=False,
+                list_ints_opt=[1, 2, 3]
+            )
+        },
+        'unknown_options.txt': {
+            valid_section: dict(
+                bool_opt=True,
+                unknown1=1,
+                invalid=True,
+                wrong=3
+            )
+        }
+    }
+
+    @classmethod
+    def write_config(cls, config_filename):
+        cp = RawConfigParser()
+        config_dict = cls.configs[config_filename]
+
+        for section in config_dict:
+            cp.add_section(section)
+
+            for option in config_dict[section]:
+                if isinstance(config_dict[section][option], list):
+                    # format the output as CSV string
+                    outp_string = StringIO()
+                    csv_writer = writer(outp_string, quoting=QUOTE_NONE,
+                                        escapechar='\\', lineterminator='')
+                    csv_writer.writerow(config_dict[section][option])
+                    cp.set(section, option, outp_string.getvalue())
+                    outp_string.close()
+                else:
+                    cp.set(section, option, config_dict[section][option])
+
+        with open(config_filename, 'w') as f:
+            cp.write(f)
+
+    @classmethod
+    def run_installer(cls, installer, capsys, config=None, args=[]):
+        cmd_args = [installer.command_name, '-q']
+        cmd_args.extend(args)
+
+        if config is not None:
+            cmd_args.extend(['-c', config])
+
+        installer.make_parser()
+        options, args = installer.option_parser.parse_args(cmd_args[1:])
+        command_class = installer.get_command_class(options, args)
+        command = command_class(options, args)
+        ret = command.execute()
+
+        if ret:
+            out, err = capsys.readouterr()
+            raise RuntimeError(err)
+
+        knob_values = {}
+        for (owner_cls, name) in command.cfgr.knobs():
+            knob_values[name] = getattr(command.cfgr, name)
+
+        return knob_values
+
+    @classmethod
+    def assert_options(cls, config_options, knob_values, **overrides):
+
+        for section in config_options:
+            for option in config_options[section]:
+                if option in overrides:
+                    assert overrides[option] == knob_values[option]
+                else:
+                    assert (config_options[section][option]
+                            == knob_values[option])
+
+    @classmethod
+    def assert_error(cls, exc_class, expected_err, command, *args, **kwargs):
+        with pytest.raises(exc_class) as exc_info:
+            command(*args, **kwargs)
+
+        dir(exc_info)
+        assert expected_err in exc_info.value.message
+
+    def test_no_config(self, installer, capsys):
+        self.assert_options(
+            {},
+            self.run_installer(
+                installer, capsys,
+                args=['-b', '-i', '4', '-s', 'test', '-n', '2']
+            ),
+            bool_opt=True,
+            int_opt=4,
+            str_opt='test',
+            no_default_opt=2
+        )
+
+    def test_simple_config(self, installer, capsys):
+        self.assert_options(
+            self.configs['simple.txt'],
+            self.run_installer(installer, capsys, config='simple.txt')
+        )
+
+    def test_multivalue_int_config(self, installer, capsys):
+        self.assert_options(
+            self.configs['multivalue_int.txt'],
+            self.run_installer(installer, capsys, config='multivalue_int.txt')
+        )
+
+    def test_multivalue_string_config(self, installer, capsys):
+        self.assert_options(
+            self.configs['multivalue_string.txt'],
+            self.run_installer(installer, capsys, config='multivalue_string.txt')
+        )
+
+    def test_multivalue_comma_string_config(self, installer, capsys):
+        self.assert_options(
+            self.configs['multivalue_string_with_comma.txt'],
+            self.run_installer(installer, capsys,
+                               config='multivalue_string_with_comma.txt')
+        )
+
+    def test_multiline_string(self, installer, capsys):
+        self.assert_options(
+            self.configs['multiline_string.txt'],
+            self.run_installer(installer, capsys,
+                               config='multiline_string.txt')
+        )
+
+    def test_validated_int(self, installer, capsys):
+        self.assert_options(
+            self.configs['validated_int.txt'],
+            self.run_installer(installer, capsys,
+                               config='validated_int.txt')
+        )
+
+    def test_nonexistent_config(self, installer, capsys):
+        config = 'nonexistent_config.txt'
+
+        self.assert_error(
+            RuntimeError,
+            "[Errno 2] No such file or directory: '{0}'".format(
+                config),
+            self.run_installer,
+            installer,
+            capsys,
+            config=config
+        )
+
+    def test_invalid_config_section(self, installer, capsys):
+        config = 'invalid_section.txt'
+        self.assert_error(
+            RuntimeError,
+            "No section: '{0}'".format(self.valid_section),
+            self.run_installer,
+            installer,
+            capsys,
+            config=config
+        )
+
+    def test_invalid_bool_config(self, installer, capsys):
+        config = 'invalid_bool.txt'
+        self.assert_error(
+            RuntimeError,
+            "{0}: Not a boolean: {1}".format(
+                config,
+                self.configs[config]['global']['bool_opt']
+            ),
+            self.run_installer,
+            installer,
+            capsys,
+            config=config
+        )
+
+    def test_invalid_int_config(self, installer, capsys):
+        config = 'invalid_int.txt'
+        self.assert_error(
+            RuntimeError,
+            "{0}: invalid integer value: '{1}'".format(
+                config,
+                self.configs[config]['global']['int_opt']
+            ),
+            self.run_installer,
+            installer,
+            capsys,
+            config=config
+        )
+
+    def test_invalid_list_ints(self, installer, capsys):
+        config = 'invalid_list_ints.txt'
+        self.assert_error(
+            RuntimeError,
+            "{0}: invalid integer value: '{1}'".format(
+                config,
+                self.configs[config]['global']['list_ints_opt'][1]
+            ),
+            self.run_installer,
+            installer,
+            capsys,
+            config=config
+        )
+
+    def test_invalid_validated(self, installer, capsys):
+        config = 'invalid_validated.txt'
+        self.assert_error(
+            RuntimeError,
+            "option --{0}: invalid value {1}".format(
+                'validated-int-opt',
+                self.configs[config][self.valid_section]['validated_int_opt']
+            ),
+            self.run_installer,
+            installer,
+            capsys,
+            config=config,
+        )
+
+    def test_unknown_options(self, installer, capsys):
+        config = 'unknown_options.txt'
+        self.assert_error(
+            RuntimeError,
+            '{0}: Unrecognized options: {1}'.format(
+                config, ', '.join(sorted(['unknown1', 'invalid', 'wrong']))
+            ),
+            self.run_installer,
+            installer,
+            capsys,
+            config=config,
+        )
+
+    def test_override_int(self, installer, capsys):
+        self.assert_options(
+            self.configs['simple.txt'],
+            self.run_installer(installer, capsys, config='simple.txt',
+                               args=['-i', '9']),
+            int_opt=9
+        )
+
+    def test_override_bool(self, installer, capsys):
+        self.assert_options(
+            self.configs['simple.txt'],
+            self.run_installer(installer, capsys, config='simple.txt',
+                               args=['-b']),
+            bool_opt=True
+        )
+
+    def test_override_list(self, installer, capsys):
+        self.assert_options(
+            self.configs['multivalue_int.txt'],
+            self.run_installer(installer, capsys, config='multivalue_int.txt',
+                               args=['-l', '4', '-l', '5']),
+            list_ints_opt=[4, 5]
+        )
+
+    def test_override_string(self, installer, capsys):
+        self.assert_options(
+            self.configs['simple.txt'],
+            self.run_installer(installer, capsys, config='simple.txt',
+                               args=['-s', 'override_string']),
+            str_opt='override_string'
+        )
+
+    def test_override_invalid_validated_int(self, installer, capsys):
+        self.assert_options(
+            self.configs['invalid_validated.txt'],
+            self.run_installer(installer, capsys,
+                               config='invalid_validated.txt',
+                               args=['-o', '4']),
+            validated_int_opt=4
+        )
+
+@pytest.fixture()
+def installer(request):
+    installer = cli.install_tool(MockInstaller, 'mock-installer', None)
+    return installer
+
+@pytest.fixture(scope='class')
+def configs(request):
+    for c in request.cls.configs:
+        request.cls.write_config(c)
+
+    def finalize():
+        for c in request.cls.configs:
+            if os.path.exists(c):
+                os.remove(c)
+    request.addfinalizer(finalize)
-- 
2.4.3

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to