aboutsummaryrefslogtreecommitdiffstats
path: root/functest/ci/run_tests.py
blob: 4a47ba570d80ede4137a5ef61963e7df7744137c (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#!/usr/bin/python -u
#
# Author: Jose Lausuch (jose.lausuch@ericsson.com)
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
#

import argparse
import datetime
import enum
import importlib
import os
import re
import sys

import functest.ci.generate_report as generate_report
import functest.ci.tier_builder as tb
import functest.core.testcase_base as testcase_base
import functest.utils.functest_logger as ft_logger
import functest.utils.functest_utils as ft_utils
import functest.utils.openstack_clean as os_clean
import functest.utils.openstack_snapshot as os_snapshot
import functest.utils.openstack_utils as os_utils
from functest.utils.constants import CONST


""" logging configuration """
logger = ft_logger.Logger("run_tests").getLogger()


class Result(enum.Enum):
    EX_OK = os.EX_OK
    EX_ERROR = -1


class BlockingTestFailed(Exception):
    pass


class RunTestsParser(object):

    def __init__(self):
        self.parser = argparse.ArgumentParser()
        self.parser.add_argument("-t", "--test", dest="test", action='store',
                                 help="Test case or tier (group of tests) "
                                 "to be executed. It will run all the test "
                                 "if not specified.")
        self.parser.add_argument("-n", "--noclean", help="Do not clean "
                                 "OpenStack resources after running each "
                                 "test (default=false).",
                                 action="store_true")
        self.parser.add_argument("-r", "--report", help="Push results to "
                                 "database (default=false).",
                                 action="store_true")

    def parse_args(self, argv=[]):
        return vars(self.parser.parse_args(argv))


class GlobalVariables:
    EXECUTED_TEST_CASES = []
    OVERALL_RESULT = Result.EX_OK
    CLEAN_FLAG = True
    REPORT_FLAG = False


def print_separator(str, count=45):
    line = ""
    for i in range(0, count - 1):
        line += str
    logger.info("%s" % line)


def source_rc_file():
    rc_file = CONST.openstack_creds
    if not os.path.isfile(rc_file):
        raise Exception("RC file %s does not exist..." % rc_file)
    logger.debug("Sourcing the OpenStack RC file...")
    os_utils.source_credentials(rc_file)
    for key, value in os.environ.iteritems():
        if re.search("OS_", key):
            if key == 'OS_AUTH_URL':
                CONST.OS_AUTH_URL = value
            elif key == 'OS_USERNAME':
                CONST.OS_USERNAME = value
            elif key == 'OS_TENANT_NAME':
                CONST.OS_TENANT_NAME = value
            elif key == 'OS_PASSWORD':
                CONST.OS_PASSWORD = value


def generate_os_snapshot():
    os_snapshot.main()


def cleanup():
    os_clean.main()


def update_test_info(test_name, result, duration):
    for test in GlobalVariables.EXECUTED_TEST_CASES:
        if test['test_name'] == test_name:
            test.update({"result": result,
                         "duration": duration})


def get_run_dict(testname):
    try:
        dict = ft_utils.get_dict_by_test(testname)
        if not dict:
            logger.error("Cannot get {}'s config options".format(testname))
        elif 'run' in dict:
            return dict['run']
        return None
    except Exception:
        logger.exception("Cannot get {}'s config options".format(testname))
        return None


def run_test(test, tier_name, testcases=None):
    result_str = "PASS"
    start = datetime.datetime.now()
    test_name = test.get_name()
    logger.info("\n")  # blank line
    print_separator("=")
    logger.info("Running test case '%s'..." % test_name)
    print_separator("=")
    logger.debug("\n%s" % test)
    source_rc_file()

    if test.needs_clean() and GlobalVariables.CLEAN_FLAG:
        generate_os_snapshot()

    flags = (" -t %s" % (test_name))
    if GlobalVariables.REPORT_FLAG:
        flags += " -r"

    result = testcase_base.TestcaseBase.EX_RUN_ERROR
    run_dict = get_run_dict(test_name)
    if run_dict:
        try:
            module = importlib.import_module(run_dict['module'])
            cls = getattr(module, run_dict['class'])
            test_case = cls()

            try:
                kwargs = run_dict['args']
                result = test_case.run(**kwargs)
            except KeyError:
                result = test_case.run()
            if result == testcase_base.TestcaseBase.EX_OK:
                if GlobalVariables.REPORT_FLAG:
                    test_case.push_to_db()
                result = test_case.check_criteria()
        except ImportError:
            logger.exception("Cannot import module {}".format(
                run_dict['module']))
        except AttributeError:
            logger.exception("Cannot get class {}".format(
                run_dict['class']))
    else:
        raise Exception("Cannot import the class for the test case.")

    if test.needs_clean() and GlobalVariables.CLEAN_FLAG:
        cleanup()

    end = datetime.datetime.now()
    duration = (end - start).seconds
    duration_str = ("%02d:%02d" % divmod(duration, 60))
    logger.info("Test execution time: %s" % duration_str)

    if result != 0:
        logger.error("The test case '%s' failed. " % test_name)
        GlobalVariables.OVERALL_RESULT = Result.EX_ERROR
        result_str = "FAIL"

        if test.is_blocking():
            if not testcases or testcases == "all":
                # if it is a single test we don't print the whole results table
                update_test_info(test_name, result_str, duration_str)
                generate_report.main(GlobalVariables.EXECUTED_TEST_CASES)
            raise BlockingTestFailed("The test case {} failed and is blocking"
                                     .format(test.get_name()))

    update_test_info(test_name, result_str, duration_str)


def run_tier(tier):
    tier_name = tier.get_name()
    tests = tier.get_tests()
    if tests is None or len(tests) == 0:
        logger.info("There are no supported test cases in this tier "
                    "for the given scenario")
        return 0
    logger.info("\n\n")  # blank line
    print_separator("#")
    logger.info("Running tier '%s'" % tier_name)
    print_separator("#")
    logger.debug("\n%s" % tier)
    for test in tests:
        run_test(test, tier_name)


def run_all(tiers):
    summary = ""
    tiers_to_run = []

    for tier in tiers.get_tiers():
        if (len(tier.get_tests()) != 0 and
                re.search(CONST.CI_LOOP, tier.get_ci_loop()) is not None):
            tiers_to_run.append(tier)
            summary += ("\n    - %s:\n\t   %s"
                        % (tier.get_name(),
                           tier.get_test_names()))

    logger.info("Tests to be executed:%s" % summary)
    GlobalVariables.EXECUTED_TEST_CASES = generate_report.init(tiers_to_run)
    for tier in tiers_to_run:
        run_tier(tier)

    generate_report.main(GlobalVariables.EXECUTED_TEST_CASES)


def main(**kwargs):

    CI_INSTALLER_TYPE = CONST.INSTALLER_TYPE
    CI_SCENARIO = CONST.DEPLOY_SCENARIO

    file = CONST.functest_testcases_yaml
    _tiers = tb.TierBuilder(CI_INSTALLER_TYPE, CI_SCENARIO, file)

    if kwargs['noclean']:
        GlobalVariables.CLEAN_FLAG = False

    if kwargs['report']:
        GlobalVariables.REPORT_FLAG = True

    try:
        if kwargs['test']:
            source_rc_file()
            if _tiers.get_tier(kwargs['test']):
                GlobalVariables.EXECUTED_TEST_CASES = generate_report.init(
                    [_tiers.get_tier(kwargs['test'])])
                run_tier(_tiers.get_tier(kwargs['test']))
            elif _tiers.get_test(kwargs['test']):
                run_test(_tiers.get_test(kwargs['test']),
                         _tiers.get_tier(kwargs['test']),
                         kwargs['test'])
            elif kwargs['test'] == "all":
                run_all(_tiers)
            else:
                logger.error("Unknown test case or tier '%s', "
                             "or not supported by "
                             "the given scenario '%s'."
                             % (kwargs['test'], CI_SCENARIO))
                logger.debug("Available tiers are:\n\n%s"
                             % _tiers)
                return Result.EX_ERROR
        else:
            run_all(_tiers)
    except Exception as e:
        logger.error(e)
        GlobalVariables.OVERALL_RESULT = Result.EX_ERROR
    logger.info("Execution exit value: %s" % GlobalVariables.OVERALL_RESULT)
    return GlobalVariables.OVERALL_RESULT


if __name__ == '__main__':
    parser = RunTestsParser()
    args = parser.parse_args(sys.argv[1:])
    sys.exit(main(**args).value)
cp">%endif %{_sbindir}/ripngd %{_sbindir}/ospf6d %if %{with_pimd} %{_sbindir}/pimd %endif %if %{with_isisd} %{_sbindir}/isisd %endif %if %{with_shared} %attr(755,root,root) %{_libdir}/lib*.so %attr(755,root,root) %{_libdir}/lib*.so.* %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %if "%{initsystem}" == "systemd" %config %{_unitdir}/*.service %else %config /etc/rc.d/init.d/zebra %if %{with_watchquagga} %config /etc/rc.d/init.d/watchquagga %endif %config /etc/rc.d/init.d/ripd %config /etc/rc.d/init.d/ospfd %config /etc/rc.d/init.d/bgpd %config /etc/rc.d/init.d/ripngd %config /etc/rc.d/init.d/ospf6d %if %{with_isisd} %config /etc/rc.d/init.d/isisd %endif %if %{with_pimd} %config /etc/rc.d/init.d/pimd %endif %endif %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* %files contrib %defattr(-,root,root) %doc tools %files devel %defattr(-,root,root) %if %{with_ospfclient} %{_sbindir}/ospfclient %endif %{_libdir}/*.a %{_libdir}/*.la %dir %attr(755,root,root) %{_includedir}/%{name} %{_includedir}/%name/*.h %dir %attr(755,root,root) %{_includedir}/%{name}/ospfd %{_includedir}/%name/ospfd/*.h %if %{with_ospfapi} %dir %attr(755,root,root) %{_includedir}/%{name}/ospfapi %{_includedir}/%name/ospfapi/*.h %endif %changelog * Thu Feb 11 2016 Paul Jakma <paul@jakma.org> - remove with_ipv6 conditionals, always build v6 - Fix UTF-8 char in spec changelog - remove quagga.pam.stack, long deprecated. * Thu Oct 22 2015 Martin Winter <mwinter@opensourcerouting.org> - Cleanup configure: remove --enable-ipv6 (default now), --enable-nssa, --enable-netlink - Remove support for old fedora 4/5 - Fix for package nameing - Fix Weekdays of previous changelogs (bogus dates) - Add conditional logic to only build tex footnotes with supported texi2html - Added pimd to files section and fix double listing of /var/lib*/quagga - Numerous fixes to unify upstart/systemd startup into same spec file - Only allow use of watchquagga for non-systemd systems. no need with systemd * Fri Sep 4 2015 Paul Jakma <paul@jakma.org> - buildreq updates - add a default define for with_pimd * Mon Sep 12 2005 Paul Jakma <paul@dishone.st> - Steal some changes from Fedora spec file: - Add with_rtadv variable - Test for groups/users with getent before group/user adding - Readline need not be an explicit prerequisite - install-info delete should be postun, not preun * Wed Jan 12 2005 Andrew J. Schorr <ajschorr@alumni.princeton.edu> - on package upgrade, implement careful, phased restart logic - use gcc -rdynamic flag when linking for better backtraces * Wed Dec 22 2004 Andrew J. Schorr <ajschorr@alumni.princeton.edu> - daemonv6_list should contain only IPv6 daemons * Wed Dec 22 2004 Andrew J. Schorr <ajschorr@alumni.princeton.edu> - watchquagga added - on upgrade, all daemons should be condrestart'ed - on removal, all daemons should be stopped * Mon Nov 08 2004 Paul Jakma <paul@dishone.st> - Use makeinfo --html to generate quagga.html * Sun Nov 07 2004 Paul Jakma <paul@dishone.st> - Fix with_ipv6 set to 0 build * Sat Oct 23 2004 Paul Jakma <paul@dishone.st> - Update to 0.97.2 * Sat Oct 23 2004 Andrew J. Schorr <aschorr@telemetry-investments.com> - Make directories be owned by the packages concerned - Update logrotate scripts to use correct path to killall and use pid files * Fri Oct 08 2004 Paul Jakma <paul@dishone.st> - Update to 0.97.0 * Wed Sep 15 2004 Paul Jakma <paul@dishone.st> - build snmp support by default - build irdp support - build with shared libs - devel subpackage for archives and headers * Thu Jan 08 2004 Paul Jakma <paul@dishone.st> - updated sysconfig files to specify local dir - added ospf_dump.c crash quick fix patch - added ospfd persistent interface configuration patch * Tue Dec 30 2003 Paul Jakma <paul@dishone.st> - sync to CVS - integrate RH sysconfig patch to specify daemon options (RH) - default to have vty listen only to 127.1 (RH) - add user with fixed UID/GID (RH) - create user with shell /sbin/nologin rather than /bin/false (RH) - stop daemons on uninstall (RH) - delete info file on preun, not postun to avoid deletion on upgrade. (RH) - isisd added - cleanup tasks carried out for every daemon * Sun Nov 2 2003 Paul Jakma <paul@dishone.st> - Fix -devel package to include all files - Sync to 0.96.4 * Tue Aug 12 2003 Paul Jakma <paul@dishone.st> - Renamed to Quagga - Sync to Quagga release 0.96 * Thu Mar 20 2003 Paul Jakma <paul@dishone.st> - zebra privileges support * Tue Mar 18 2003 Paul Jakma <paul@dishone.st> - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API - Amir: Fix configure.ac for net-snmp * Sat Mar 1 2003 Paul Jakma <paul@dishone.st> - ospfd IOS prefix to interface matching for 'network' statement - temporary fix for PtP and IPv6 - sync to zebra.org CVS * Mon Jan 20 2003 Paul Jakma <paul@dishone.st> - update to latest cvs - Yon's "show thread cpu" patch - 17217 - walk up tree - 17218 - ospfd NSSA fixes - 16681 - ospfd nsm fixes - 16824 - ospfd OLSA fixes and new feature - 16823 - KAME and ifindex fixes - 16525 - spec file changes to allow redhat files to be in tree * Sat Dec 28 2002 Alexander Hoogerhuis <alexh@ihatent.com> - Added conditionals for building with(out) IPv6, vtysh, RIP, BGP - Fixed up some build requirements (patch) - Added conditional build requirements for vtysh / snmp - Added conditional to files for _bindir depending on vtysh * Mon Nov 11 2002 Paul Jakma <paulj@alphyra.ie> - update to latest CVS - add Greg Troxel's md5 buffer copy/dup fix - add RIPv1 fix - add Frank's multicast flag fix * Wed Oct 09 2002 Paul Jakma <paulj@alphyra.ie> - update to latest CVS - timestamped crypt_seqnum patch - oi->on_write_q fix * Mon Sep 30 2002 Paul Jakma <paulj@alphyra.ie> - update to latest CVS - add vtysh 'write-config (integrated|daemon)' patch - always 'make rebuild' in vtysh/ to catch new commands * Fri Sep 13 2002 Paul Jakma <paulj@alphyra.ie> - update to 0.93b * Wed Sep 11 2002 Paul Jakma <paulj@alphyra.ie> - update to latest CVS - add "/sbin/ip route flush proto zebra" to zebra RH init on startup * Sat Aug 24 2002 Paul Jakma <paulj@alphyra.ie> - update to current CVS - add OSPF point to multipoint patch - add OSPF bugfixes - add BGP hash optimisation patch * Fri Jun 14 2002 Paul Jakma <paulj@alphyra.ie> - update to 0.93-pre1 / CVS - add link state detection support - add generic PtP and RFC3021 support - various bug fixes * Thu Aug 09 2001 Elliot Lee <sopwith@redhat.com> 0.91a-6 - Fix bug #51336 * Wed Aug 1 2001 Trond Eivind Glomsrød <teg@redhat.com> 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) * Fri Jul 27 2001 Elliot Lee <sopwith@redhat.com> 0.91a-4 - Bump the release when rebuilding into the dist. * Tue Feb 6 2001 Tim Powers <timp@redhat.com> - built for Powertools * Sun Feb 4 2001 Pekka Savola <pekkas@netcore.fi> - Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org. - Update to 0.91a - Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc. - Should be quite Red Hat'isque now.