| # Copyright (C) 2017 Apple Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met: |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND |
| # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR |
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| import logging |
| import unittest |
| |
| from webkitpy.common.net.generictestresults import BindingsTestResults |
| from webkitpy.common.net.jsctestresults import JSCTestResults |
| from webkitpy.common.system.executive import ScriptError |
| from webkitpy.tool.bot.patchanalysistask import * |
| from webkitpy.tool.commands.earlywarningsystem import AbstractEarlyWarningSystem |
| from webkitpy.tool.mocktool import MockTool |
| |
| _log = logging.getLogger(__name__) |
| |
| |
| class MockPatchAnalysisTask(PatchAnalysisTask): |
| def __init__(self, delegate, patch, patches_passed_all_tests): |
| self._delegate = delegate |
| self._patch = patch |
| self._script_error = None |
| self._results_archive_from_patch_test_run = None |
| self._results_from_patch_test_run = None |
| self.error = None |
| self._patches_passed_all_tests = patches_passed_all_tests |
| self._test_run_count = 0 |
| self.failure_status_id = 0 |
| |
| def _test(self): |
| self._test_run_count += 1 |
| |
| if self._patches_passed_all_tests.pop() == True: |
| return True |
| self._script_error = ScriptError('Regression test') |
| return False |
| |
| def _build_and_test_without_patch(self): |
| self._test_run_count += 1 |
| return True |
| |
| def validate(self): |
| return True |
| |
| def test_run_count(self): |
| return self._test_run_count |
| |
| |
| # This is the delegate to be used with MockPatchAnalysisTask, above. |
| class MockJSCEarlyWarningSystem(AbstractEarlyWarningSystem): |
| def __init__(self, first_test_results, second_test_results, clean_test_results): |
| AbstractEarlyWarningSystem.__init__(self) |
| self._group = 'jsc' |
| self._results_in_order = [clean_test_results, second_test_results, first_test_results] |
| |
| def test_results(self): |
| return self._results_in_order.pop() |
| |
| |
| class JSCEarlyWarningSystemTest(unittest.TestCase): |
| def _results_indicate_all_passed(self, results): |
| if results == None: |
| return False |
| return results.all_passed() |
| |
| def _create_task(self, first_test_results, second_test_results, clean_test_results): |
| queue = MockJSCEarlyWarningSystem(first_test_results, second_test_results, clean_test_results) |
| tool = MockTool(log_executive=True) |
| patch = tool.bugs.fetch_attachment(10000) |
| patches_passed_all_tests = map(self._results_indicate_all_passed, [second_test_results, first_test_results]) |
| return MockPatchAnalysisTask(queue, patch, patches_passed_all_tests) |
| |
| def test_success_case(self): |
| first_test_results = JSCTestResults(True, []) |
| second_test_results = JSCTestResults(True, []) |
| clean_test_results = JSCTestResults(True, []) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 1) |
| self.assertTrue(return_value) |
| |
| def test_test_failure(self): |
| first_test_results = JSCTestResults(True, ['Fail.js']) |
| second_test_results = JSCTestResults(True, ['Fail.js']) |
| clean_test_results = JSCTestResults(True, []) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| with self.assertRaises(ScriptError): |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 3) |
| |
| def test_fix(self): |
| first_test_results = JSCTestResults(True, []) |
| second_test_results = JSCTestResults(True, []) |
| clean_test_results = JSCTestResults(True, ['Fail.js']) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 1) |
| self.assertTrue(return_value) |
| |
| def test_ineffective_patch(self): |
| first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js']) |
| second_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js']) |
| clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js']) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 3) |
| self.assertTrue(return_value) |
| |
| def test_partially_effective_patch(self): |
| first_test_results = JSCTestResults(True, ['failure2.js']) |
| second_test_results = JSCTestResults(True, ['failure2.js']) |
| clean_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js']) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 3) |
| self.assertTrue(return_value) |
| |
| def test_different_test_failures_in_patch_and_tree(self): |
| first_test_results = JSCTestResults(False, []) |
| second_test_results = JSCTestResults(False, []) |
| clean_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js']) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| with self.assertRaises(ScriptError): |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 3) |
| |
| def test_first_results_could_not_be_read(self): |
| first_test_results = None |
| second_test_results = JSCTestResults(True, []) |
| clean_test_results = JSCTestResults(True, []) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 1) |
| self.assertFalse(return_value) |
| |
| def test_second_results_could_not_be_read(self): |
| first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js']) |
| second_test_results = None |
| clean_test_results = JSCTestResults(True, []) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 2) |
| self.assertFalse(return_value) |
| |
| def test_clean_results_could_not_be_read(self): |
| first_test_results = JSCTestResults(True, ['failure2.js']) |
| second_test_results = JSCTestResults(True, ['failure2.js']) |
| clean_test_results = None |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 3) |
| self.assertFalse(return_value) |
| |
| def test_flaky_results_on_clean_tree_pass(self): |
| first_test_results = JSCTestResults(True, ['failure2.js']) |
| second_test_results = JSCTestResults(True, []) |
| clean_test_results = JSCTestResults(True, []) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertTrue(return_value) |
| self.assertEqual(task.test_run_count(), 2) |
| |
| def test_flaky_results_on_clean_tree_pass_v2(self): |
| first_test_results = JSCTestResults(True, []) |
| second_test_results = JSCTestResults(True, ['failure2.js']) |
| clean_test_results = JSCTestResults(True, []) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertTrue(return_value) |
| self.assertEqual(task.test_run_count(), 1) |
| |
| def test_flaky_results_on_clean_tree_failure(self): |
| first_test_results = JSCTestResults(False, ['failure1.js', 'failure2.js']) |
| second_test_results = JSCTestResults(True, ['failure2.js']) |
| clean_test_results = JSCTestResults(True, []) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| with self.assertRaises(ScriptError): |
| task._test_patch() |
| self.assertEqual(task.test_run_count(), 3) |
| |
| def test_flaky_results_on_red_tree_pass(self): |
| first_test_results = JSCTestResults(True, ['failure1.js']) |
| second_test_results = JSCTestResults(True, ['failure1.js', 'failure2.js']) |
| clean_test_results = JSCTestResults(True, ['failure1.js']) |
| task = self._create_task(first_test_results, second_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertTrue(return_value) |
| self.assertEqual(task.test_run_count(), 3) |
| |
| |
| class MockBindingsEarlyWarningSystem(AbstractEarlyWarningSystem): |
| def __init__(self, first_test_results, clean_test_results): |
| AbstractEarlyWarningSystem.__init__(self) |
| self._group = 'bindings' |
| self._results_in_order = [clean_test_results, first_test_results] |
| |
| def test_results(self): |
| return self._results_in_order.pop() |
| |
| |
| class BindingsEarlyWarningSystemTest(unittest.TestCase): |
| def _results_indicate_all_passed(self, results): |
| if results == None: |
| return False |
| return results.all_passed() |
| |
| def _create_task(self, first_test_results, clean_test_results): |
| queue = MockBindingsEarlyWarningSystem(first_test_results, clean_test_results) |
| tool = MockTool(log_executive=True) |
| patch = tool.bugs.fetch_attachment(10000) |
| patches_passed_all_tests = [self._results_indicate_all_passed(first_test_results)] |
| return MockPatchAnalysisTask(queue, patch, patches_passed_all_tests) |
| |
| def test_success_case(self): |
| first_test_results = BindingsTestResults([]) |
| clean_test_results = BindingsTestResults([]) |
| task = self._create_task(first_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 1) |
| self.assertTrue(return_value) |
| |
| def test_test_failure(self): |
| first_test_results = BindingsTestResults(['TestMapLike.idl']) |
| clean_test_results = BindingsTestResults([]) |
| task = self._create_task(first_test_results, clean_test_results) |
| |
| with self.assertRaises(ScriptError): |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 2) |
| |
| def test_fix(self): |
| first_test_results = BindingsTestResults([]) |
| clean_test_results = BindingsTestResults(['TestMapLike.idl']) |
| task = self._create_task(first_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 1) |
| self.assertTrue(return_value) |
| |
| def test_ineffective_patch(self): |
| first_test_results = BindingsTestResults(['TestMapLike.idl']) |
| clean_test_results = BindingsTestResults(['TestMapLike.idl']) |
| task = self._create_task(first_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 2) |
| self.assertTrue(return_value) |
| |
| def test_partially_effective_patch(self): |
| first_test_results = BindingsTestResults(['TestMapLike.idl']) |
| clean_test_results = BindingsTestResults(['TestMapLike.idl', 'TestNode.idl']) |
| task = self._create_task(first_test_results, clean_test_results) |
| |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 2) |
| self.assertTrue(return_value) |
| |
| def test_different_test_failures_in_patch_and_tree(self): |
| first_test_results = BindingsTestResults(['TestNode.idl']) |
| clean_test_results = BindingsTestResults(['TestMapLike.idl']) |
| task = self._create_task(first_test_results, clean_test_results) |
| |
| with self.assertRaises(ScriptError): |
| return_value = task._test_patch() |
| self.assertEqual(task.test_run_count(), 2) |