Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / Scripts / webkitpy / layout_tests / layout_package / bot_test_expectations_unittest.py
1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 #     * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #     * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #     * Neither the Google name nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 import unittest
30
31 from webkitpy.layout_tests.layout_package import bot_test_expectations
32 from webkitpy.layout_tests.models import test_expectations
33 from webkitpy.layout_tests.port import builders
34
35
36 class BotTestExpectationsFactoryTest(unittest.TestCase):
37     def fake_results_json_for_builder(self, builder):
38         return bot_test_expectations.ResultsJSON(builder, 'Dummy content')
39
40     def test_expectations_for_builder(self):
41         factory = bot_test_expectations.BotTestExpectationsFactory()
42         factory._results_json_for_builder = self.fake_results_json_for_builder
43
44         old_builders = builders._exact_matches
45         builders._exact_matches = {
46             "Dummy builder name": {"port_name": "dummy-port", "specifiers": []},
47         }
48
49         try:
50             self.assertIsNotNone(factory.expectations_for_builder('Dummy builder name'))
51         finally:
52             builders._exact_matches = old_builders
53
54     def test_expectations_for_port(self):
55         factory = bot_test_expectations.BotTestExpectationsFactory()
56         factory._results_json_for_builder = self.fake_results_json_for_builder
57
58         old_builders = builders._exact_matches
59         builders._exact_matches = {
60             "Dummy builder name": {"port_name": "dummy-port", "specifiers": []},
61         }
62
63         try:
64             self.assertIsNotNone(factory.expectations_for_port('dummy-port'))
65         finally:
66             builders._exact_matches = old_builders
67
68
69 class BotTestExpectationsTest(unittest.TestCase):
70     # FIXME: Find a way to import this map from Tools/TestResultServer/model/jsonresults.py.
71     FAILURE_MAP = {"A": "AUDIO", "C": "CRASH", "F": "TEXT", "I": "IMAGE", "O": "MISSING",
72         "N": "NO DATA", "P": "PASS", "T": "TIMEOUT", "Y": "NOTRUN", "X": "SKIP", "Z": "IMAGE+TEXT", "K": "LEAK"}
73
74     # All result_string's in this file expect newest result
75     # on left: "PFF", means it just passed after 2 failures.
76
77     def _assert_is_flaky(self, results_string, should_be_flaky):
78         results_json = self._results_json_from_test_data({})
79         expectations = bot_test_expectations.BotTestExpectations(results_json, set('test'))
80         length_encoded = self._results_from_string(results_string)['results']
81         num_actual_results = len(expectations._flaky_types_in_results(length_encoded, only_ignore_very_flaky=True))
82         if should_be_flaky:
83             self.assertGreater(num_actual_results, 1)
84         else:
85             self.assertEqual(num_actual_results, 1)
86
87     def test_basic_flaky(self):
88         self._assert_is_flaky('PFF', False)  # Used to fail, but now passes.
89         self._assert_is_flaky('FFP', False)  # Just started failing.
90         self._assert_is_flaky('PFPF', True)  # Seen both failures and passes.
91         # self._assert_is_flaky('PPPF', True)  # Should be counted as flaky but isn't yet.
92         self._assert_is_flaky('FPPP', False)  # Just started failing, not flaky.
93         self._assert_is_flaky('PFFP', True)  # Failed twice in a row, still flaky.
94         # Failing 3+ times in a row is unlikely to be flaky, but rather a transient failure on trunk.
95         # self._assert_is_flaky('PFFFP', False)
96         # self._assert_is_flaky('PFFFFP', False)
97
98     def _results_json_from_test_data(self, test_data):
99         test_data[bot_test_expectations.ResultsJSON.FAILURE_MAP_KEY] = self.FAILURE_MAP
100         json_dict = {
101             'builder': test_data,
102         }
103         return bot_test_expectations.ResultsJSON('builder', json_dict)
104
105     def _results_from_string(self, results_string):
106         results_list = []
107         last_char = None
108         for char in results_string:
109             if char != last_char:
110                 results_list.insert(0, [1, char])
111             else:
112                 results_list[0][0] += 1
113         return {'results': results_list}
114
115     def _assert_expectations(self, test_data, expectations_string, only_ignore_very_flaky):
116         results_json = self._results_json_from_test_data(test_data)
117         expectations = bot_test_expectations.BotTestExpectations(results_json, set('test'))
118         self.assertEqual(expectations.flakes_by_path(only_ignore_very_flaky), expectations_string)
119
120     def _assert_unexpected_results(self, test_data, expectations_string):
121         results_json = self._results_json_from_test_data(test_data)
122         expectations = bot_test_expectations.BotTestExpectations(results_json, set('test'))
123         self.assertEqual(expectations.unexpected_results_by_path(), expectations_string)
124
125     def test_basic(self):
126         test_data = {
127             'tests': {
128                 'foo': {
129                     'veryflaky.html': self._results_from_string('FPFP'),
130                     'maybeflaky.html': self._results_from_string('PPFP'),
131                     'notflakypass.html': self._results_from_string('PPPP'),
132                     'notflakyfail.html': self._results_from_string('FFFF'),
133                 }
134             }
135         }
136         self._assert_expectations(test_data, {
137             'foo/veryflaky.html': sorted(["TEXT", "PASS"]),
138         }, only_ignore_very_flaky=True)
139
140         self._assert_expectations(test_data, {
141             'foo/veryflaky.html': sorted(["TEXT", "PASS"]),
142             'foo/maybeflaky.html': sorted(["TEXT", "PASS"]),
143         }, only_ignore_very_flaky=False)
144
145     def test_all_failure_types(self):
146         test_data = {
147             'tests': {
148                 'foo': {
149                     'allfailures.html': self._results_from_string('FPFPCNCNTXTXIZIZOCOCYKYK'),
150                     'imageplustextflake.html': self._results_from_string('ZPZPPPPPPPPPPPPPPPPP'),
151                 }
152             }
153         }
154         self._assert_expectations(test_data, {
155             'foo/imageplustextflake.html': sorted(["IMAGE+TEXT", "PASS"]),
156             'foo/allfailures.html': sorted(["TEXT", "PASS", "IMAGE+TEXT", "TIMEOUT", "CRASH", "IMAGE", "MISSING", "LEAK"]),
157         }, only_ignore_very_flaky=True)
158
159     def test_unexpected_results_no_unexpected(self):
160         test_data = {
161             'tests': {
162                 'foo': {
163                     'pass1.html': {'results': [[4, 'P']]},
164                     'pass2.html': {'results': [[2, 'Z']], 'expected': 'PASS FAIL'},
165                     'fail.html': {'results': [[2, 'P'], [1, 'F']], 'expected': 'PASS FAIL'},
166                     'not_run.html': {'results': []},
167                     'crash.html': {'results': [[2, 'F'], [1, 'C']], 'expected': 'CRASH FAIL WONTFIX'},
168                 }
169             }
170         }
171         self._assert_unexpected_results(test_data, {})
172
173     def test_unexpected_results_all_unexpected(self):
174         test_data = {
175             'tests': {
176                 'foo': {
177                     'pass1.html': {'results': [[4, 'P']], 'expected': 'FAIL'},
178                     'pass2.html': {'results': [[2, 'P']], 'expected': 'IMAGE'},
179                     'fail.html': {'results': [[4, 'F']]},
180                     'f_p.html': {'results': [[1, 'F'], [2, 'P']]},
181                     'crash.html': {'results': [[2, 'F'], [1, 'C']], 'expected': 'WONTFIX'},
182                     'image.html': {'results': [[2, 'F'], [1, 'I']], 'expected': 'CRASH FAIL'},
183                     'i_f.html': {'results': [[1, 'F'], [5, 'I']], 'expected': 'PASS'},
184                     'all.html': self._results_from_string('FPFPCNCNTXTXIZIZOCOCYKYK'),
185                 }
186             }
187         }
188         self.maxDiff = None
189         self._assert_unexpected_results(test_data, {
190             'foo/pass1.html': sorted(["FAIL", "PASS"]),
191             'foo/pass2.html': sorted(["IMAGE", "PASS"]),
192             'foo/fail.html': sorted(["TEXT", "PASS"]),
193             'foo/f_p.html': sorted(["TEXT", "PASS"]),
194             'foo/crash.html': sorted(["WONTFIX", "CRASH", "TEXT"]),
195             'foo/image.html': sorted(["CRASH", "FAIL", "IMAGE"]),
196             'foo/i_f.html': sorted(["PASS", "IMAGE", "TEXT"]),
197             'foo/all.html': sorted(["TEXT", "PASS", "IMAGE+TEXT", "TIMEOUT", "CRASH", "IMAGE", "MISSING", "LEAK"]),
198         })