~ursinha/ubuntu-ci-services-itself/401-copying-di-check

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
#!/usr/bin/env python
# -*- Mode: python -*-
# Ubuntu CI Engine
# Copyright 2014 Canonical Ltd.

# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License version 3, as
# published by the Free Software Foundation.

# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE.  See the GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""The CI Engine test runner."""

import os
import subunit
import sys

from ucitests import (
    filters,
    loaders,
    runners,
    results,
)


class Cwd(object):
    """Step into a directory temporarily. """

    def __init__(self, path):
        self.old = os.getcwd()
        self.new = path

    def __enter__(self):
        os.chdir(self.new)

    def __exit__(self, *args):
        os.chdir(self.old)


class SysPath(object):
    """Add paths in front of sys.path temporarily."""

    def __init__(self, paths):
        self.paths = paths
        self.orig = sys.path[:]

    def __enter__(self):
        sys.path = self.paths + sys.path

    def __exit__(self, *args):
        sys.path = self.orig


def load_component_tests(loader, component_base_dir):
    """Load tests for a given component.

    A component is organized inside a given base directory containing files
    *and* a python directory with the code and the tests. We care about that
    python directory only.
    """
    # We set the current directory to the component base one and restore it
    # after loading. This could produce duplicate tests if different components
    # define the same python modules but this would be a bug in itself so we
    # just ignore the potential issue.
    suite = loader.suiteClass()
    with SysPath([component_base_dir]):
        sub_loader = loader.SubLoader(root=component_base_dir)
        suite.addTests(sub_loader.loadTestsFromTree('.'))
    return suite


def load_tests(include_regexps, exclude_regexps=None):
    """Load tests matching inclusive and exclusive regexps.

    :param include_regexps: A list of regexps describing the tests to include.

    :param exclude_regexps: A list of regexps describing the tests to exclude.

    :return: The test suite for all collected tests.
    """
    components = ['ci-utils',
                  'branch-source-builder',
                  'image-builder',
                  'lander',
                  # 'ppa-assigner',
                  # 'ticket_system',
                  'test_runner',
                  ]
    loader = loaders.Loader()
    # setuptools tends to leave eggs all over the place
    loader.dir_matcher = loaders.NameMatcher(includes=[r'.*'],
                                             excludes=[r'\.egg$',
                                                       r'\.egg-info$',
                                                       ])
    suite = loader.suiteClass()
    for c in components:
        suite.addTests(load_component_tests(loader, c))
    suite = filters.include_regexps(include_regexps, suite)
    suite = filters.exclude_regexps(exclude_regexps, suite)
    return suite


def main(args=None, stdout=None, stderr=None):
    if args is None:
        args = sys.argv[1:]
    if stdout is None:
        stdout = sys.stdout
    if stderr is None:
        stderr = sys.stderr
    # Interpret user wishes
    parser = runners.RunTestsArgParser()
    ns = parser.parse_args(args)
    # Load the tests, keeping only the ones required by the user
    suite = load_tests(ns.include_regexps, ns.exclude_regexps)
    if ns.list_only:
        # List the tests without running them
        ret = runners.list_tests(suite, stdout)
    else:
        # Run the tests with the required output
        if ns.format == 'text':
            result = results.TextResult(stdout, verbosity=2)
        else:
            result = subunit.TestProtocolClient(stdout)
        ret = runners.run_tests(suite, result)
    return ret


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