Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / typ / typ / json_results.py
1 # Copyright 2014 Google Inc. All rights reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 from collections import OrderedDict
16
17 import json
18
19
20 class ResultType(object):
21     Pass = 'Pass'
22     Failure = 'Failure'
23     ImageOnlyFailure = 'ImageOnlyFailure'
24     Timeout = 'Timeout'
25     Crash = 'Crash'
26     Skip = 'Skip'
27
28     values = (Pass, Failure, ImageOnlyFailure, Timeout, Crash, Skip)
29
30
31 class Result(object):
32     # too many instance attributes  pylint: disable=R0902
33     # too many arguments  pylint: disable=R0913
34
35     def __init__(self, name, actual, started, took, worker,
36                  expected=None, unexpected=False,
37                  flaky=False, code=0, out='', err='', pid=0):
38         self.name = name
39         self.actual = actual
40         self.started = started
41         self.took = took
42         self.worker = worker
43         self.expected = expected or [ResultType.Pass]
44         self.unexpected = unexpected
45         self.flaky = flaky
46         self.code = code
47         self.out = out
48         self.err = err
49         self.pid = pid
50
51
52 class ResultSet(object):
53
54     def __init__(self):
55         self.results = []
56
57     def add(self, result):
58         self.results.append(result)
59
60
61 TEST_SEPARATOR = '.'
62
63
64 def make_full_results(metadata, seconds_since_epoch, all_test_names, results):
65     """Convert the typ results to the Chromium JSON test result format.
66
67     See http://www.chromium.org/developers/the-json-test-results-format
68     """
69
70     # We use OrderedDicts here so that the output is stable.
71     full_results = OrderedDict()
72     full_results['version'] = 3
73     full_results['interrupted'] = False
74     full_results['path_delimiter'] = TEST_SEPARATOR
75     full_results['seconds_since_epoch'] = seconds_since_epoch
76
77     for md in metadata:
78         key, val = md.split('=', 1)
79         full_results[key] = val
80
81     passing_tests = _passing_test_names(results)
82     failed_tests = failed_test_names(results)
83     skipped_tests = set(all_test_names) - passing_tests - failed_tests
84
85     full_results['num_failures_by_type'] = OrderedDict()
86     full_results['num_failures_by_type']['FAIL'] = len(failed_tests)
87     full_results['num_failures_by_type']['PASS'] = len(passing_tests)
88     full_results['num_failures_by_type']['SKIP'] = len(skipped_tests)
89
90     full_results['tests'] = OrderedDict()
91
92     for test_name in all_test_names:
93         value = OrderedDict()
94         if test_name in skipped_tests:
95             value['expected'] = 'SKIP'
96             value['actual'] = 'SKIP'
97         else:
98             value['expected'] = 'PASS'
99             value['actual'] = _actual_results_for_test(test_name, results)
100             if value['actual'].endswith('FAIL'):
101                 value['is_unexpected'] = True
102         _add_path_to_trie(full_results['tests'], test_name, value)
103
104     return full_results
105
106
107 def make_upload_request(test_results_server, builder, master, testtype,
108                         full_results):
109     url = 'http://%s/testfile/upload' % test_results_server
110     attrs = [('builder', builder),
111              ('master', master),
112              ('testtype', testtype)]
113     content_type, data = _encode_multipart_form_data(attrs, full_results)
114     return url, content_type, data
115
116
117 def exit_code_from_full_results(full_results):
118     return 1 if num_failures(full_results) else 0
119
120
121 def num_failures(full_results):
122     return full_results['num_failures_by_type']['FAIL']
123
124
125 def failed_test_names(results):
126     names = set()
127     for r in results.results:
128         if r.actual == ResultType.Failure:
129             names.add(r.name)
130         elif (r.actual == ResultType.Pass and r.name in names):
131             names.remove(r.name)
132     return names
133
134
135 def _passing_test_names(results):
136     return set(r.name for r in results.results if r.actual == ResultType.Pass)
137
138
139 def _actual_results_for_test(test_name, results):
140     actuals = []
141     for r in results.results:
142         if r.name == test_name:
143             if r.actual == ResultType.Failure:
144                 actuals.append('FAIL')
145             elif r.actual == ResultType.Pass:
146                 actuals.append('PASS')
147
148     assert actuals, 'We did not find any result data for %s.' % test_name
149     return ' '.join(actuals)
150
151
152 def _add_path_to_trie(trie, path, value):
153     if TEST_SEPARATOR not in path:
154         trie[path] = value
155         return
156     directory, rest = path.split(TEST_SEPARATOR, 1)
157     if directory not in trie:
158         trie[directory] = {}
159     _add_path_to_trie(trie[directory], rest, value)
160
161
162 def _encode_multipart_form_data(attrs, test_results):
163     # Cloned from webkitpy/common/net/file_uploader.py
164     BOUNDARY = '-J-S-O-N-R-E-S-U-L-T-S---B-O-U-N-D-A-R-Y-'
165     CRLF = '\r\n'
166     lines = []
167
168     for key, value in attrs:
169         lines.append('--' + BOUNDARY)
170         lines.append('Content-Disposition: form-data; name="%s"' % key)
171         lines.append('')
172         lines.append(value)
173
174     lines.append('--' + BOUNDARY)
175     lines.append('Content-Disposition: form-data; name="file"; '
176                  'filename="full_results.json"')
177     lines.append('Content-Type: application/json')
178     lines.append('')
179     lines.append(json.dumps(test_results))
180
181     lines.append('--' + BOUNDARY + '--')
182     lines.append('')
183     body = CRLF.join(lines)
184     content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
185     return content_type, body