summaryrefslogtreecommitdiffstats
path: root/src/sbin/bcfg2-test
blob: 25476c7b4e39ff3dfcd58d2a7da35697c56ab9a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env python

"""This tool verifies that all clients known to the server build
without failures"""

import os
import sys
import signal
import fnmatch
import logging
import Bcfg2.Logger
import Bcfg2.Server.Core
from nose.core import TestProgram
from nose.suite import LazySuite
from unittest import TestCase


class ClientTest(TestCase):
    """
    A test case representing the build of all of the configuration for
    a single host.  Checks that none of the build config entities has
    had a failure when it is building.  Optionally ignores some config
    files that we know will cause errors (because they are private
    files we don't have access to, for instance)
    """
    __test__ = False  # Do not collect

    def __init__(self, bcfg2_core, client, ignore=None):
        TestCase.__init__(self)
        self.bcfg2_core = bcfg2_core
        self.client = client
        if ignore is None:
            self.ignore = dict()
        else:
            self.ignore = ignore

    def ignore_entry(self, tag, name):
        """ return True if an error on a given entry should be ignored
        """
        if tag in self.ignore:
            if name in self.ignore[tag]:
                return True
            else:
                # try wildcard matching
                for pattern in self.ignore[tag]:
                    if fnmatch.fnmatch(name, pattern):
                        return True
        return False

    def shortDescription(self):
        return "Building configuration for %s" % self.client

    def runTest(self):
        """ run this individual test """
        config = self.bcfg2_core.BuildConfiguration(self.client)

        failures = []
        msg = ["Failures:"]
        for failure in config.xpath('//*[@failure]'):
            if not self.ignore_entry(failure.tag, failure.get('name')):
                failures.append(failure)
                msg.append("%s:%s: %s" % (failure.tag, failure.get("name"),
                                          failure.get("failure")))

        assert len(failures) == 0, "\n".join(msg)

    def __str__(self):
        return "ClientTest(%s)" % self.client

    id = __str__


def get_sigint_handler(core):
    """ Get a function that handles SIGINT/Ctrl-C by shutting down the
    core and exiting properly."""

    def hdlr(sig, frame):  # pylint: disable=W0613
        """ Handle SIGINT/Ctrl-C by shutting down the core and exiting
        properly. """
        core.shutdown()
        os._exit(1)  # pylint: disable=W0212

    return hdlr


def main():
    optinfo = dict(noseopts=Bcfg2.Options.TEST_NOSEOPTS,
                   test_ignore=Bcfg2.Options.TEST_IGNORE,
                   validate=Bcfg2.Options.CFG_VALIDATION)
    optinfo.update(Bcfg2.Options.CLI_COMMON_OPTIONS)
    optinfo.update(Bcfg2.Options.SERVER_COMMON_OPTIONS)
    setup = Bcfg2.Options.OptionParser(optinfo)
    setup.hm = \
        "bcfg2-test [options] [client] [client] [...]\nOptions:\n     %s" % \
        setup.buildHelpMessage()
    setup.parse(sys.argv[1:])

    if setup['debug']:
        level = logging.DEBUG
    elif setup['verbose']:
        level = logging.INFO
    else:
        level = logging.WARNING
    Bcfg2.Logger.setup_logging("bcfg2-test",
                               to_console=setup['verbose'] or setup['debug'],
                               to_syslog=False,
                               to_file=setup['logging'],
                               level=level)
    if (setup['debug'] or setup['verbose']) and "-v" not in setup['noseopts']:
        setup['noseopts'].append("-v")

    core = Bcfg2.Server.Core.BaseCore(setup)
    signal.signal(signal.SIGINT, get_sigint_handler(core))

    ignore = dict()
    for entry in setup['test_ignore']:
        tag, name = entry.split(":")
        try:
            ignore[tag].append(name)
        except KeyError:
            ignore[tag] = [name]

    core.fam.handle_events_in_interval(0.1)

    if setup['args']:
        clients = setup['args']
    else:
        clients = core.metadata.clients

    def run_tests():
        """ Run the test suite """
        for client in clients:
            yield ClientTest(core, client, ignore)

    TestProgram(argv=sys.argv[0:1] + setup['noseopts'],
                suite=LazySuite(run_tests))

    core.shutdown()
    os._exit(0)  # pylint: disable=W0212

if __name__ == "__main__":
    sys.exit(main())