~kelemeng/checkbox/bug868571

« back to all changes in this revision

Viewing changes to plugins/suites_prompt.py

Introduced job_prompt plugin to treat all jobs (suites, tests, etc.) as composites.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
# You should have received a copy of the GNU General Public License
17
17
# along with Checkbox.  If not, see <http://www.gnu.org/licenses/>.
18
18
#
19
 
import re
 
19
import copy
20
20
 
21
21
from checkbox.lib.iterator import IteratorExclude
 
22
from checkbox.lib.resolver import Resolver
22
23
 
23
24
from checkbox.job import JobIterator
24
 
from checkbox.properties import List, Path, String
 
25
from checkbox.properties import List, String
25
26
from checkbox.plugin import Plugin
26
27
 
27
28
from gettext import gettext as _
29
30
 
30
31
class SuitesPrompt(Plugin):
31
32
 
32
 
    # Plugin default for running suite types
33
 
    plugin_default = String(default="external")
34
 
 
35
 
    # Plugin priorities for running suites
 
33
    # Plugin priorities for running jobs
36
34
    plugin_priorities = List(String(), default_factory=lambda:"internal")
37
35
 
38
 
    # Space separated list of directories where suite files are stored.
39
 
    directories = List(Path(),
40
 
        default_factory=lambda:"%(checkbox_share)s/suites")
41
 
 
42
 
    # List of suites to blacklist
43
 
    blacklist = List(String(), default_factory=lambda:"")
44
 
 
45
 
    # List of suites to whitelist
46
 
    whitelist = List(String(), default_factory=lambda:"")
47
 
 
48
 
    def _suites_compare(self, a, b):
49
 
        priorities = self.plugin_priorities
50
 
        if a["plugin"] in priorities:
51
 
            if b["plugin"] in priorities:
52
 
                ia = priorities.index(a["plugin"])
53
 
                ib = priorities.index(b["plugin"])
54
 
                if ia != ib:
55
 
                    return cmp(ia, ib)
56
 
            else:
57
 
                return -1
58
 
        elif b["plugin"] in priorities:
59
 
            return 1
60
 
 
61
 
        return cmp(a["name"], b["name"])
62
 
 
63
 
    def _suites_exclude(self, suite):
64
 
        suites_ignore = self.persist.get("ignore", [])
65
 
        if "description" in suite and suite["description"] in suites_ignore:
66
 
            return True
67
 
 
68
 
        return False
69
 
 
70
36
    def register(self, manager):
71
37
        super(SuitesPrompt, self).register(manager)
72
38
        self._iterator = None
73
 
        self._suite = None
 
39
        self._ignore = []
74
40
        self._suites = {}
75
41
        self._tests = {}
76
42
 
77
43
        for (rt, rh) in [
78
 
             ("gather", self.gather),
79
44
             ("gather-persist", self.gather_persist),
 
45
             ("ignore-jobs", self.ignore_jobs),
80
46
             ("report-suite", self.report_suite),
81
 
             ("prompt-suite", self.prompt_suite),
 
47
             ("report-test", self.report_test),
82
48
             ("prompt-suites", self.prompt_suites)]:
83
49
            self._manager.reactor.call_on(rt, rh)
84
50
 
85
51
        self._manager.reactor.call_on("prompt-gather", self.prompt_gather, 100)
86
 
        self._manager.reactor.call_on("report-(attachment|test)",
87
 
            self.report_attachment_or_test, -100)
88
 
 
89
 
    def gather(self):
90
 
        for directory in self.directories:
91
 
            self._manager.reactor.fire("message-directory", directory)
92
52
 
93
53
    def gather_persist(self, persist):
94
54
        self.persist = persist.root_at("suites_prompt")
95
55
 
96
 
    def report_attachment_or_test(self, element):
97
 
        if self._suite:
98
 
            element.setdefault("suite", self._suite["name"])
99
 
            if element["plugin"] != "attachment":
100
 
                self._tests.setdefault(self._suite["name"], [])
101
 
                self._tests[self._suite["name"]].append(element["name"])
 
56
    def ignore_jobs(self, jobs):
 
57
        self._ignore = jobs
102
58
 
103
59
    def report_suite(self, suite):
104
 
        whitelist_patterns = [re.compile(r"^%s$" % r) for r in self.whitelist if r]
105
 
        blacklist_patterns = [re.compile(r"^%s$" % r) for r in self.blacklist if r]
106
 
 
107
60
        name = suite["name"]
108
 
        if whitelist_patterns:
109
 
            if not [name for p in whitelist_patterns if p.match(name)]:
110
 
                return
111
 
        elif blacklist_patterns:
112
 
            if [name for p in blacklist_patterns if p.match(name)]:
113
 
                return
 
61
        suite.update(self._suites.get(name, {}))
 
62
        suite.setdefault("type", "suite")
 
63
        self._suites[name] = suite
114
64
 
115
 
        if suite["name"] not in self._suites:
116
 
            suite.setdefault("plugin", self.plugin_default)
117
 
            self._suites[suite["name"]] = self._suite = suite
 
65
    def report_test(self, test):
 
66
        name = test["name"]
 
67
        self._tests[name] = test
118
68
 
119
69
    def prompt_gather(self, interface):
120
 
        if len(self._suites) > 1:
121
 
            suites_tree = dict((s["description"], self._tests.get(s["name"], []))
122
 
                for s in self._suites.values() if "description" in s)
123
 
            suites_default = self.persist.get("default")
124
 
            if suites_default is None:
125
 
                suites_default = dict(suites_tree)
126
 
 
127
 
            suites_results = interface.show_tree(
128
 
                _("Select the suites to test"),
129
 
                suites_tree, suites_default)
130
 
            self.persist.set("default", suites_results)
131
 
 
132
 
            ignore_tests = []
133
 
            for suite, tests in suites_tree.items():
134
 
                if suite not in suites_results:
135
 
                    ignore_tests.extend(tests)
136
 
 
137
 
                else:
138
 
                    for test in tests:
139
 
                        if test not in suites_results[suite]:
140
 
                            ignore_tests.append(test)
141
 
 
142
 
            self._manager.reactor.fire("ignore-tests", ignore_tests)
143
 
 
144
 
    def prompt_suite(self, interface, suite):
145
 
        self._manager.reactor.fire("prompt-%s" % suite["plugin"],
146
 
            interface, suite)
 
70
        # Resolve dependencies
 
71
        compare = lambda a, b: cmp(a["name"], b["name"])
 
72
        resolver = Resolver(compare=compare, key=lambda e: e["name"])
 
73
        jobs = dict((k, v) for k, v in self._suites.items() + self._tests.items())
 
74
        for job in jobs.values():
 
75
            depends = [jobs[job["suite"]]] if "suite" in job else []
 
76
            resolver.add(job, *depends)
 
77
 
 
78
        # Build options
 
79
        options = {}
 
80
        for job in resolver.get_dependents():
 
81
            suboptions = options
 
82
            dependencies = resolver.get_dependencies(job)
 
83
            for dependency in dependencies:
 
84
                if dependency.get("type") == "suite":
 
85
                    attribute = "description"
 
86
                else:
 
87
                    attribute = "name"
 
88
 
 
89
                suboptions = suboptions.setdefault(dependency[attribute], {})
 
90
 
 
91
        # Builds defaults
 
92
        defaults = self.persist.get("default")
 
93
        if defaults is None:
 
94
            defaults = copy.deepcopy(options)
 
95
 
 
96
        # Get results
 
97
        results = interface.show_tree(_("Select the suites to test"),
 
98
            options, defaults)
 
99
        self.persist.set("default", results)
 
100
 
 
101
        # Get tests to ignore
 
102
        def get_ignore_jobs(options, results):
 
103
            jobs = []
 
104
            for k, v in options.iteritems():
 
105
                if not v and k not in results:
 
106
                    jobs.append(k)
 
107
 
 
108
                else:
 
109
                    jobs.extend(get_ignore_jobs(options[k], results.get(k, {})))
 
110
 
 
111
            return jobs
 
112
 
 
113
        ignore_jobs = get_ignore_jobs(options, results)
 
114
        self._manager.reactor.fire("ignore-jobs", ignore_jobs)
147
115
 
148
116
    def prompt_suites(self, interface):
149
117
        if not self._iterator:
154
122
 
155
123
        while True:
156
124
            try:
157
 
                self._suite = self._iterator.go(interface.direction)
 
125
                suite = self._iterator.go(interface.direction)
158
126
            except StopIteration:
159
127
                break
160
128
 
161
 
            self._manager.reactor.fire("prompt-suite", interface, self._suite)
 
129
            self._manager.reactor.fire("prompt-job", interface, suite)
 
130
 
 
131
    def _suites_compare(self, a, b):
 
132
        priorities = self.plugin_priorities
 
133
        if a["plugin"] in priorities:
 
134
            if b["plugin"] in priorities:
 
135
                ia = priorities.index(a["plugin"])
 
136
                ib = priorities.index(b["plugin"])
 
137
                if ia != ib:
 
138
                    return cmp(ia, ib)
 
139
            else:
 
140
                return -1
 
141
        elif b["plugin"] in priorities:
 
142
            return 1
 
143
 
 
144
        return cmp(a["name"], b["name"])
 
145
 
 
146
    def _suites_exclude(self, suite):
 
147
        if "description" in suite and suite["description"] in self._ignore:
 
148
            return True
 
149
 
 
150
        return False
162
151
 
163
152
 
164
153
factory = SuitesPrompt