Merge from Chromium at DEPS revision r199464
This commit was generated by merge_to_master.py.
Change-Id: I19655f81f4534807b2fa07bc72b5208501b02896
diff --git a/Tools/Scripts/webkitpy/bindings/main.py b/Tools/Scripts/webkitpy/bindings/main.py
index 887a861..d3115fb 100644
--- a/Tools/Scripts/webkitpy/bindings/main.py
+++ b/Tools/Scripts/webkitpy/bindings/main.py
@@ -60,7 +60,7 @@
exit_code = e.exit_code
return exit_code
- def generate_supplemental_dependency(self, input_directory, supplemental_dependency_file):
+ def generate_supplemental_dependency(self, input_directory, supplemental_dependency_file, window_constructors_file):
idl_files_list = tempfile.mkstemp()
for input_file in os.listdir(input_directory):
(name, extension) = os.path.splitext(input_file)
@@ -73,7 +73,8 @@
'-Ibindings/scripts',
'bindings/scripts/preprocess-idls.pl',
'--idlFilesList', idl_files_list[1],
- '--supplementalDependencyFile', supplemental_dependency_file]
+ '--supplementalDependencyFile', supplemental_dependency_file,
+ '--windowConstructorsFile', window_constructors_file]
exit_code = 0
try:
@@ -147,7 +148,8 @@
input_directory = os.path.join('bindings', 'tests', 'idls')
supplemental_dependency_file = tempfile.mkstemp()[1]
- if self.generate_supplemental_dependency(input_directory, supplemental_dependency_file):
+ window_constructors_file = tempfile.mkstemp()[1]
+ if self.generate_supplemental_dependency(input_directory, supplemental_dependency_file, window_constructors_file):
print 'Failed to generate a supplemental dependency file.'
os.remove(supplemental_dependency_file)
return -1
diff --git a/Tools/Scripts/webkitpy/common/net/resultsjsonparser.py b/Tools/Scripts/webkitpy/common/net/resultsjsonparser.py
index 1a2a70f..581f967 100644
--- a/Tools/Scripts/webkitpy/common/net/resultsjsonparser.py
+++ b/Tools/Scripts/webkitpy/common/net/resultsjsonparser.py
@@ -77,7 +77,7 @@
if not TestExpectations.has_pixel_failures(actual_results):
expected_results = TestExpectations.remove_pixel_failures(expected_results)
for actual_result in actual_results:
- if not TestExpectations.result_was_expected(actual_result, expected_results, False, False):
+ if not TestExpectations.result_was_expected(actual_result, expected_results, False):
return False
return True
diff --git a/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
index eaf16f7..fd35b44 100644
--- a/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
+++ b/Tools/Scripts/webkitpy/layout_tests/models/test_expectations.py
@@ -800,20 +800,19 @@
return cls.EXPECTATIONS.get(string.lower())
@staticmethod
- def result_was_expected(result, expected_results, test_needs_rebaselining, test_is_skipped):
+ def result_was_expected(result, expected_results, test_needs_rebaselining):
"""Returns whether we got a result we were expecting.
Args:
result: actual result of a test execution
expected_results: set of results listed in test_expectations
- test_needs_rebaselining: whether test was marked as REBASELINE
- test_is_skipped: whether test was marked as SKIP"""
+ test_needs_rebaselining: whether test was marked as REBASELINE"""
if result in expected_results:
return True
if result in (TEXT, IMAGE_PLUS_TEXT, AUDIO) and (FAIL in expected_results):
return True
if result == MISSING and test_needs_rebaselining:
return True
- if result == SKIP and test_is_skipped:
+ if result == SKIP:
return True
return False
@@ -924,10 +923,7 @@
expected_results = self._model.get_expectations(test)
if not pixel_tests_are_enabled:
expected_results = self.remove_pixel_failures(expected_results)
- return self.result_was_expected(result,
- expected_results,
- self.is_rebaselining(test),
- self._model.has_modifier(test, SKIP))
+ return self.result_was_expected(result, expected_results, self.is_rebaselining(test))
def is_rebaselining(self, test):
return self._model.has_modifier(test, REBASELINE)
@@ -967,9 +963,7 @@
modified_expectations = []
for expectation in self._expectations:
- if expectation.name != test or expectation.is_flaky() or not expectation.parsed_expectations:
- continue
- if iter(expectation.parsed_expectations).next() not in (FAIL, IMAGE):
+ if expectation.name != test or not expectation.parsed_expectations:
continue
if test_configuration not in expectation.matching_configurations:
continue
diff --git a/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py b/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
index a198cce..8e6ffdd 100644
--- a/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/models/test_expectations_unittest.py
@@ -107,16 +107,15 @@
def test_result_was_expected(self):
# test basics
- self.assertEqual(TestExpectations.result_was_expected(PASS, set([PASS]), test_needs_rebaselining=False, test_is_skipped=False), True)
- self.assertEqual(TestExpectations.result_was_expected(FAIL, set([PASS]), test_needs_rebaselining=False, test_is_skipped=False), False)
+ self.assertEqual(TestExpectations.result_was_expected(PASS, set([PASS]), test_needs_rebaselining=False), True)
+ self.assertEqual(TestExpectations.result_was_expected(FAIL, set([PASS]), test_needs_rebaselining=False), False)
# test handling of SKIPped tests and results
- self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH]), test_needs_rebaselining=False, test_is_skipped=True), True)
- self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH]), test_needs_rebaselining=False, test_is_skipped=False), False)
+ self.assertEqual(TestExpectations.result_was_expected(SKIP, set([CRASH]), test_needs_rebaselining=False), True)
# test handling of MISSING results and the REBASELINE modifier
- self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=True, test_is_skipped=False), True)
- self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=False, test_is_skipped=False), False)
+ self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=True), True)
+ self.assertEqual(TestExpectations.result_was_expected(MISSING, set([PASS]), test_needs_rebaselining=False), False)
def test_remove_pixel_failures(self):
self.assertEqual(TestExpectations.remove_pixel_failures(set([FAIL])), set([FAIL]))
@@ -504,6 +503,26 @@
self.assertEqual("""Bug(y) [ Win Debug ] failures/expected/foo.html [ Crash ]
""", actual_expectations)
+ def test_remove_flaky_line(self):
+ host = MockHost()
+ test_port = host.port_factory.get('test-win-xp', None)
+ test_port.test_exists = lambda test: True
+ test_port.test_isfile = lambda test: True
+
+ test_config = test_port.test_configuration()
+ test_port.expectations_dict = lambda: {'expectations': """Bug(x) [ Win ] failures/expected/foo.html [ Failure Timeout ]
+Bug(y) [ Mac ] failures/expected/foo.html [ Crash ]
+"""}
+ expectations = TestExpectations(test_port)
+
+ actual_expectations = expectations.remove_configuration_from_test('failures/expected/foo.html', test_config)
+ actual_expectations = expectations.remove_configuration_from_test('failures/expected/foo.html', host.port_factory.get('test-win-vista', None).test_configuration())
+ actual_expectations = expectations.remove_configuration_from_test('failures/expected/foo.html', host.port_factory.get('test-win-win7', None).test_configuration())
+
+ self.assertEqual("""Bug(x) [ Win Debug ] failures/expected/foo.html [ Failure Timeout ]
+Bug(y) [ Mac ] failures/expected/foo.html [ Crash ]
+""", actual_expectations)
+
class RebaseliningTest(Base):
"""Test rebaselining-specific functionality."""
diff --git a/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py b/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py
index 3af1224..b2959d0 100644
--- a/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py
+++ b/Tools/Scripts/webkitpy/layout_tests/models/test_run_results.py
@@ -28,6 +28,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import logging
+import time
from webkitpy.layout_tests.models import test_expectations
from webkitpy.layout_tests.models import test_failures
@@ -135,6 +136,7 @@
tbe = initial_results.tests_by_expectation
tbt = initial_results.tests_by_timeline
results['fixable'] = len(tbt[test_expectations.NOW] - tbe[test_expectations.PASS])
+ # FIXME: Remove this. It is redundant with results['num_failures_by_type'].
results['skipped'] = len(tbt[test_expectations.NOW] & tbe[test_expectations.SKIP])
num_passes = 0
@@ -148,6 +150,12 @@
for modifier_string, modifier_enum in test_expectations.TestExpectations.MODIFIERS.iteritems():
keywords[modifier_enum] = modifier_string.upper()
+ num_failures_by_type = {}
+ for expectation in initial_results.tests_by_expectation:
+ num_failures_by_type[keywords[expectation]] = len(initial_results.tests_by_expectation[expectation] & tbt[test_expectations.NOW])
+ # The number of failures by type.
+ results['num_failures_by_type'] = num_failures_by_type
+
tests = {}
for test_name, result in initial_results.results_by_name.iteritems():
@@ -158,10 +166,9 @@
result_type = result.type
actual = [keywords[result_type]]
- if result_type == test_expectations.SKIP:
- continue
-
test_dict = {}
+ test_dict['time'] = result.total_run_time
+
if result.has_stderr:
test_dict['has_stderr'] = True
@@ -173,16 +180,13 @@
if result_type == test_expectations.PASS:
num_passes += 1
- # FIXME: include passing tests that have stderr output.
- if expected == 'PASS':
- continue
elif result_type == test_expectations.CRASH:
if test_name in initial_results.unexpected_results_by_name:
num_regressions += 1
elif result_type == test_expectations.MISSING:
if test_name in initial_results.unexpected_results_by_name:
num_missing += 1
- elif test_name in initial_results.unexpected_results_by_name:
+ elif result_type != test_expectations.SKIP and test_name in initial_results.unexpected_results_by_name:
if retry_results and test_name not in retry_results.unexpected_results_by_name:
actual.extend(expectations.get_expectations_string(test_name).split(" "))
num_flaky += 1
@@ -202,6 +206,13 @@
test_dict['expected'] = expected
test_dict['actual'] = " ".join(actual)
+ def is_expected(actual_result):
+ return expectations.matches_an_expected_result(test_name, result_type, port_obj.get_option('pixel_tests') or result.reftest_type)
+
+ # To avoid bloating the output results json too much, only add an entry for whether the failure is unexpected.
+ if not all(is_expected(actual_result) for actual_result in actual):
+ test_dict['is_unexpected'] = True
+
test_dict.update(_interpret_test_failures(result.failures))
if retry_results:
@@ -231,30 +242,37 @@
current_map = current_map[part]
results['tests'] = tests
+ # FIXME: Remove this. It is redundant with results['num_failures_by_type'].
results['num_passes'] = num_passes
results['num_flaky'] = num_flaky
+ # FIXME: Remove this. It is redundant with results['num_failures_by_type'].
results['num_missing'] = num_missing
results['num_regressions'] = num_regressions
+ # FIXME: This is always true for Blink. We should remove this and update the code in Layouts/fast/harness/results.html that uses this.
results['uses_expectations_file'] = port_obj.uses_test_expectations_file()
results['interrupted'] = initial_results.interrupted # Does results.html have enough information to compute this itself? (by checking total number of results vs. total number of tests?)
results['layout_tests_dir'] = port_obj.layout_tests_dir()
results['has_wdiff'] = port_obj.wdiff_available()
results['has_pretty_patch'] = port_obj.pretty_patch_available()
results['pixel_tests_enabled'] = port_obj.get_option('pixel_tests')
+ results['seconds_since_epoch'] = int(time.time())
+ results['build_number'] = port_obj.get_option('build_number')
+ results['builder_name'] = port_obj.get_option('builder_name')
try:
- # We only use the svn revision for using trac links in the results.html file,
# Don't do this by default since it takes >100ms.
- # FIXME: Do we really need to populate this both here and in the json_results_generator?
+ # It's only used for uploading data to the flakiness dashboard.
if port_obj.get_option("builder_name"):
port_obj.host.initialize_scm()
- results['revision'] = port_obj.host.scm().head_svn_revision()
+ for (name, path) in port_obj.repository_paths():
+ results[name.lower() + '_revision'] = port_obj.host.scm().svn_revision(path)
except Exception, e:
_log.warn("Failed to determine svn revision for checkout (cwd: %s, webkit_base: %s), leaving 'revision' key blank in full_results.json.\n%s" % (port_obj._filesystem.getcwd(), port_obj.path_from_webkit_base(), e))
# Handle cases where we're running outside of version control.
import traceback
_log.debug('Failed to learn head svn revision:')
_log.debug(traceback.format_exc())
- results['revision'] = ""
+ results['chromium_revision'] = ""
+ results['blink_revision'] = ""
return results
diff --git a/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py b/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py
index c0d9265..5c22306 100644
--- a/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/models/test_run_results_unittest.py
@@ -48,7 +48,7 @@
def run_results(port):
tests = ['passes/text.html', 'failures/expected/timeout.html', 'failures/expected/crash.html', 'failures/expected/hang.html',
- 'failures/expected/audio.html']
+ 'failures/expected/audio.html', 'passes/skipped/skip.html']
expectations = test_expectations.TestExpectations(port, tests)
return test_run_results.TestRunResults(expectations, len(tests))
@@ -63,6 +63,9 @@
initial_results.add(get_result('failures/expected/timeout.html', test_expectations.TIMEOUT), expected, test_is_slow)
initial_results.add(get_result('failures/expected/crash.html', test_expectations.CRASH), expected, test_is_slow)
elif passing:
+ skipped_result = get_result('passes/skipped/skip.html')
+ skipped_result.type = test_expectations.SKIP
+ initial_results.add(skipped_result, expected, test_is_slow)
initial_results.add(get_result('passes/text.html'), expected, test_is_slow)
initial_results.add(get_result('failures/expected/audio.html'), expected, test_is_slow)
initial_results.add(get_result('failures/expected/timeout.html'), expected, test_is_slow)
@@ -124,12 +127,34 @@
summary = summarized_results(self.port, expected=False, passing=False, flaky=False)
self.assertNotIn('revision', summary)
+ def test_num_failures_by_type(self):
+ summary = summarized_results(self.port, expected=False, passing=False, flaky=False)
+ self.assertEquals(summary['num_failures_by_type'], {'CRASH': 1, 'MISSING': 0, 'TEXT': 0, 'IMAGE': 0, 'PASS': 0, 'SKIP': 0, 'TIMEOUT': 2, 'IMAGE+TEXT': 0, 'FAIL': 0, 'AUDIO': 1})
+
+ summary = summarized_results(self.port, expected=True, passing=False, flaky=False)
+ self.assertEquals(summary['num_failures_by_type'], {'CRASH': 1, 'MISSING': 0, 'TEXT': 0, 'IMAGE': 0, 'PASS': 1, 'SKIP': 0, 'TIMEOUT': 1, 'IMAGE+TEXT': 0, 'FAIL': 0, 'AUDIO': 1})
+
+ summary = summarized_results(self.port, expected=False, passing=True, flaky=False)
+ self.assertEquals(summary['num_failures_by_type'], {'CRASH': 0, 'MISSING': 0, 'TEXT': 0, 'IMAGE': 0, 'PASS': 4, 'SKIP': 1, 'TIMEOUT': 0, 'IMAGE+TEXT': 0, 'FAIL': 0, 'AUDIO': 0})
+
def test_svn_revision(self):
self.port._options.builder_name = 'dummy builder'
summary = summarized_results(self.port, expected=False, passing=False, flaky=False)
- self.assertNotEquals(summary['revision'], '')
+ self.assertNotEquals(summary['blink_revision'], '')
def test_summarized_results_wontfix(self):
self.port._options.builder_name = 'dummy builder'
summary = summarized_results(self.port, expected=False, passing=False, flaky=False)
self.assertTrue(summary['tests']['failures']['expected']['hang.html']['wontfix'])
+ self.assertTrue(summary['tests']['passes']['text.html']['is_unexpected'])
+
+ def test_summarized_results_expected_pass(self):
+ self.port._options.builder_name = 'dummy builder'
+ summary = summarized_results(self.port, expected=False, passing=True, flaky=False)
+ self.assertTrue(summary['tests']['passes']['text.html'])
+ self.assertTrue('is_unexpected' not in summary['tests']['passes']['text.html'])
+
+ def test_summarized_results_skipped(self):
+ self.port._options.builder_name = 'dummy builder'
+ summary = summarized_results(self.port, expected=False, passing=True, flaky=False)
+ self.assertTrue(summary['tests']['passes']['skipped']['skip.html'])
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 56f7662..82a18be 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -1079,7 +1079,7 @@
# We use LayoutTest directory here because webkit_base isn't a part of WebKit repository in Chromium port
# where turnk isn't checked out as a whole.
- return [('WebKit', self.layout_tests_dir())]
+ return [('blink', self.layout_tests_dir())]
_WDIFF_DEL = '##WDIFF_DEL##'
_WDIFF_ADD = '##WDIFF_ADD##'
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
index ce0564d..be8905b 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
@@ -378,7 +378,7 @@
def repository_paths(self):
repos = super(ChromiumPort, self).repository_paths()
- repos.append(('Chromium', self.path_from_chromium_base('build')))
+ repos.append(('chromium', self.path_from_chromium_base('build')))
return repos
def _get_crash_log(self, name, pid, stdout, stderr, newer_than):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py
index b7f633c..dad7396 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -295,6 +295,7 @@
Bug(test) failures/expected/exception.html [ WontFix ]
Bug(test) failures/unexpected/pass.html [ Failure ]
Bug(test) passes/skipped/skip.html [ Skip ]
+Bug(test) passes/text.html [ Pass ]
""")
filesystem.maybe_make_directory(LAYOUT_TEST_DIR + '/reftests/foo')
diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py
index ee9f86f..ff772ca 100644
--- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py
@@ -186,6 +186,11 @@
# properly on cygwin (bug 63846).
self.should_test_processes = not self._platform.is_win()
+ def assertHasTimeAndOtherValuesEqual(self, actual, expected):
+ self.assertTrue(actual['time'])
+ del actual['time']
+ self.assertEqual(actual, expected)
+
def test_basic(self):
options, args = parse_args(tests_included=True)
logging_stream = StringIO.StringIO()
@@ -496,9 +501,9 @@
tests_included=True, host=host)
file_list = host.filesystem.written_files.keys()
self.assertEqual(details.exit_code, 1)
- expected_token = '"unexpected":{"text-image-checksum.html":{"expected":"PASS","actual":"IMAGE+TEXT","image_diff_percent":1},"missing_text.html":{"expected":"PASS","is_missing_text":true,"actual":"MISSING"}'
json_string = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json')
- self.assertTrue(json_string.find(expected_token) != -1)
+ self.assertTrue(json_string.find('"text-image-checksum.html":{"actual":"IMAGE+TEXT","is_unexpected":true,"expected":"PASS"') != -1)
+ self.assertTrue(json_string.find('"missing_text.html":{"expected":"PASS","is_missing_text":true,"is_unexpected":true,"actual":"MISSING"') != -1)
self.assertTrue(json_string.find('"num_regressions":1') != -1)
self.assertTrue(json_string.find('"num_flaky":0') != -1)
self.assertTrue(json_string.find('"num_missing":1') != -1)
@@ -506,14 +511,14 @@
def test_pixel_test_directories(self):
host = MockHost()
- """Both tests have faling checksum. We include only the first in pixel tests so only that should fail."""
+ """Both tests have failing checksum. We include only the first in pixel tests so only that should fail."""
args = ['--pixel-tests', '--pixel-test-directory', 'failures/unexpected/pixeldir',
'failures/unexpected/pixeldir/image_in_pixeldir.html',
'failures/unexpected/image_not_in_pixeldir.html']
details, err, _ = logging_run(extra_args=args, host=host, tests_included=True)
self.assertEqual(details.exit_code, 1)
- expected_token = '"unexpected":{"pixeldir":{"image_in_pixeldir.html":{"expected":"PASS","actual":"IMAGE"'
+ expected_token = 'pixeldir":{"image_in_pixeldir.html":{"actual":"IMAGE","is_unexpected":true,"expected":"PASS",'
json_string = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json')
self.assertTrue(json_string.find(expected_token) != -1)
@@ -537,7 +542,7 @@
def test_crash_with_stderr(self):
host = MockHost()
_, regular_output, _ = logging_run(['failures/unexpected/crash-with-stderr.html'], tests_included=True, host=host)
- self.assertTrue(host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json').find('{"crash-with-stderr.html":{"expected":"PASS","actual":"CRASH","has_stderr":true}}') != -1)
+ self.assertTrue(host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json').find('{"crash-with-stderr.html":{"expected":"PASS","is_unexpected":true,"actual":"CRASH","has_stderr":true') != -1)
def test_no_image_failure_with_image_diff(self):
host = MockHost()
@@ -666,8 +671,8 @@
self.assertTrue(host.filesystem.exists('/tmp/layout-test-results/retries/failures/unexpected/text-image-checksum-actual.png'))
json_string = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json')
json = parse_full_results(json_string)
- self.assertEqual(json["tests"]["failures"]["unexpected"]["text-image-checksum.html"],
- {"expected": "PASS", "actual": "TEXT IMAGE+TEXT", "image_diff_percent": 1})
+ self.assertHasTimeAndOtherValuesEqual(json["tests"]["failures"]["unexpected"]["text-image-checksum.html"],
+ {"expected": "PASS", "actual": "TEXT IMAGE+TEXT", "image_diff_percent": 1, "is_unexpected": True})
self.assertFalse(json["pixel_tests_enabled"])
self.assertEqual(details.enabled_pixel_tests_in_retry, True)
@@ -749,7 +754,7 @@
host = MockHost()
_, err, _ = logging_run(['--no-show-results', 'reftests/foo/'], tests_included=True, host=host)
json_string = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json')
- self.assertTrue(json_string.find('"unlistedtest.html":{"expected":"PASS","is_missing_text":true,"actual":"MISSING","is_missing_image":true}') != -1)
+ self.assertTrue(json_string.find('"unlistedtest.html":{"actual":"MISSING","is_missing_image":true,"is_unexpected":true,"expected":"PASS","is_missing_text":true') != -1)
self.assertTrue(json_string.find('"num_regressions":4') != -1)
self.assertTrue(json_string.find('"num_flaky":0') != -1)
self.assertTrue(json_string.find('"num_missing":1') != -1)
@@ -847,6 +852,11 @@
class EndToEndTest(unittest.TestCase):
+ def assertHasTimeAndOtherValuesEqual(self, actual, expected):
+ self.assertTrue(actual['time'])
+ del actual['time']
+ self.assertEqual(actual, expected)
+
def test_reftest_with_two_notrefs(self):
# Test that we update expectations in place. If the expectation
# is missing, update the expected generic location.
@@ -856,15 +866,16 @@
json_string = host.filesystem.read_text_file('/tmp/layout-test-results/full_results.json')
json = parse_full_results(json_string)
- self.assertTrue("multiple-match-success.html" not in json["tests"]["reftests"]["foo"])
- self.assertTrue("multiple-mismatch-success.html" not in json["tests"]["reftests"]["foo"])
- self.assertTrue("multiple-both-success.html" not in json["tests"]["reftests"]["foo"])
- self.assertEqual(json["tests"]["reftests"]["foo"]["multiple-match-failure.html"],
- {"expected": "PASS", "actual": "IMAGE", "reftest_type": ["=="], "image_diff_percent": 1})
- self.assertEqual(json["tests"]["reftests"]["foo"]["multiple-mismatch-failure.html"],
- {"expected": "PASS", "actual": "IMAGE", "reftest_type": ["!="]})
- self.assertEqual(json["tests"]["reftests"]["foo"]["multiple-both-failure.html"],
- {"expected": "PASS", "actual": "IMAGE", "reftest_type": ["==", "!="]})
+ self.assertTrue("is_unexpected" not in json["tests"]["reftests"]["foo"]["multiple-match-success.html"])
+ self.assertTrue("is_unexpected" not in json["tests"]["reftests"]["foo"]["multiple-mismatch-success.html"])
+ self.assertTrue("is_unexpected" not in json["tests"]["reftests"]["foo"]["multiple-both-success.html"])
+
+ self.assertHasTimeAndOtherValuesEqual(json["tests"]["reftests"]["foo"]["multiple-match-failure.html"],
+ {"expected": "PASS", "actual": "IMAGE", "reftest_type": ["=="], "image_diff_percent": 1, "is_unexpected": True})
+ self.assertHasTimeAndOtherValuesEqual(json["tests"]["reftests"]["foo"]["multiple-mismatch-failure.html"],
+ {"expected": "PASS", "actual": "IMAGE", "reftest_type": ["!="], "is_unexpected": True})
+ self.assertHasTimeAndOtherValuesEqual(json["tests"]["reftests"]["foo"]["multiple-both-failure.html"],
+ {"expected": "PASS", "actual": "IMAGE", "reftest_type": ["==", "!="], "is_unexpected": True})
class RebaselineTest(unittest.TestCase, StreamTestingMixin):
diff --git a/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results.py b/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results.py
index 3191b84..e7dabab 100644
--- a/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results.py
+++ b/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results.py
@@ -100,10 +100,7 @@
actual = results['actual'].split(" ")
expected = results['expected'].split(" ")
- def is_expected(result):
- return (result in expected) or (result in ('AUDIO', 'TEXT', 'IMAGE+TEXT') and 'FAIL' in expected)
-
- if all(is_expected(actual_result) for actual_result in actual):
+ if 'is_unexpected' not in results or not results['is_unexpected']:
# Don't print anything for tests that ran as expected.
return
diff --git a/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py b/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py
index 5ce15c1..8951a63 100644
--- a/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/views/buildbot_results_unittest.py
@@ -87,7 +87,9 @@
printer, out = self.get_printer()
summary = test_run_results_unittest.summarized_results(port, expected=False, passing=True, flaky=False)
printer.print_unexpected_results(summary)
- self.assertNotEmpty(out)
+ output = out.getvalue()
+ self.assertTrue(output)
+ self.assertTrue(output.find('Skip') == -1)
def test_print_results(self):
port = MockHost().port_factory.get('test')
diff --git a/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_integrationtest.py b/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_integrationtest.py
index 8bc2148..67ca54e 100644
--- a/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_integrationtest.py
+++ b/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_integrationtest.py
@@ -353,7 +353,7 @@
self._test_run_with_json_output(runner, port.host.filesystem, upload_succeeds=True)
self.assertEqual(self._load_output_json(runner), [{
"buildTime": "2013-02-08T15:19:37.460000", "tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
filesystem = port.host.filesystem
self.assertTrue(filesystem.isfile(runner._output_json_path()))
@@ -366,7 +366,7 @@
self.assertEqual(self._load_output_json(runner), [{
"buildTime": "2013-02-08T15:19:37.460000", "description": "some description",
"tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
def create_runner_and_setup_results_template(self, args=[]):
runner, port = self.create_runner(args)
@@ -396,7 +396,7 @@
self.assertEqual(self._load_output_json(runner), [{
"buildTime": "2013-02-08T15:19:37.460000", "tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
self.assertTrue(filesystem.isfile(output_json_path))
self.assertTrue(filesystem.isfile(results_page_path))
@@ -412,7 +412,7 @@
self.assertEqual(self._load_output_json(runner), [{"previous": "results"}, {
"buildTime": "2013-02-08T15:19:37.460000", "tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
self.assertTrue(filesystem.isfile(filesystem.splitext(output_json_path)[0] + '.html'))
def test_run_respects_reset_results(self):
@@ -426,7 +426,7 @@
self.assertEqual(self._load_output_json(runner), [{
"buildTime": "2013-02-08T15:19:37.460000", "tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
self.assertTrue(filesystem.isfile(filesystem.splitext(output_json_path)[0] + '.html'))
pass
@@ -438,7 +438,7 @@
self._test_run_with_json_output(runner, filesystem, results_shown=False)
expected_entry = {"buildTime": "2013-02-08T15:19:37.460000", "tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}
self.maxDiff = None
self.assertEqual(runner._output_json_path(), '/mock-checkout/output.json')
@@ -485,7 +485,7 @@
self._test_run_with_json_output(runner, port.host.filesystem, upload_succeeds=True)
self.assertEqual(self._load_output_json(runner), [{
"buildTime": "2013-02-08T15:19:37.460000", "tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}, "builderKey": "value"}])
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}, "builderKey": "value"}])
def test_run_with_bad_slave_config_json(self):
runner, port = self.create_runner_and_setup_results_template(args=['--output-json-path=/mock-checkout/output.json',
@@ -537,7 +537,7 @@
self.assertEqual(output['buildTime'], '2013-02-08T15:19:37.460000')
self.assertEqual(output['builderName'], 'builder1')
self.assertEqual(output['builderKey'], 'value1')
- self.assertEqual(output['revisions'], {'WebKit': {'revision': '5678', 'timestamp': '2013-02-01 08:48:05 +0000'}})
+ self.assertEqual(output['revisions'], {'blink': {'revision': '5678', 'timestamp': '2013-02-01 08:48:05 +0000'}})
self.assertEqual(output['tests'].keys(), ['Bindings'])
self.assertEqual(sorted(output['tests']['Bindings'].keys()), ['tests', 'url'])
self.assertEqual(output['tests']['Bindings']['url'], 'http://trac.webkit.org/browser/trunk/PerformanceTests/Bindings')
@@ -547,25 +547,26 @@
'metrics': {'Time': {'current': [[1486.0, 1471.0, 1510.0, 1505.0, 1478.0, 1490.0]] * 4}}})
def test_run_with_repeat(self):
+ self.maxDiff = None
runner, port = self.create_runner_and_setup_results_template(args=['--output-json-path=/mock-checkout/output.json',
'--test-results-server=some.host', '--repeat', '5'])
self._test_run_with_json_output(runner, port.host.filesystem, upload_succeeds=True, repeat=5)
self.assertEqual(self._load_output_json(runner), [
{"buildTime": "2013-02-08T15:19:37.460000",
"tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
{"buildTime": "2013-02-08T15:19:37.460000",
"tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
{"buildTime": "2013-02-08T15:19:37.460000",
"tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
{"buildTime": "2013-02-08T15:19:37.460000",
"tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}},
{"buildTime": "2013-02-08T15:19:37.460000",
"tests": self._event_target_wrapper_and_inspector_results,
- "revisions": {"WebKit": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
+ "revisions": {"blink": {"timestamp": "2013-02-01 08:48:05 +0000", "revision": "5678"}}}])
def test_run_with_test_runner_count(self):
runner, port = self.create_runner_and_setup_results_template(args=['--output-json-path=/mock-checkout/output.json',
diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp.py b/Tools/Scripts/webkitpy/style/checkers/cpp.py
index 69df432..5810e9c 100644
--- a/Tools/Scripts/webkitpy/style/checkers/cpp.py
+++ b/Tools/Scripts/webkitpy/style/checkers/cpp.py
@@ -2857,9 +2857,9 @@
'Streams are highly discouraged.')
# Look for specific includes to fix.
- if include.startswith('wtf/') and not is_system:
+ if include.startswith('wtf/') and is_system:
error(line_number, 'build/include', 4,
- 'wtf includes should be <wtf/file.h> instead of "wtf/file.h".')
+ 'wtf includes should be "wtf/file.h" instead of <wtf/file.h>.')
if filename.find('/chromium/') != -1 and include.startswith('cc/CC'):
error(line_number, 'build/include', 4,
diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
index 20a0b79..c0f2da3 100644
--- a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
+++ b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
@@ -2831,14 +2831,14 @@
'#include "foo.h"\n'
'\n'
'#include <wtf/Assertions.h>\n',
- '')
+ 'wtf includes should be "wtf/file.h" instead of <wtf/file.h>.'
+ ' [build/include] [4]')
self.assert_language_rules_check('foo.cpp',
'#include "config.h"\n'
'#include "foo.h"\n'
'\n'
'#include "wtf/Assertions.h"\n',
- 'wtf includes should be <wtf/file.h> instead of "wtf/file.h".'
- ' [build/include] [4]')
+ '')
def test_check_cc_includes(self):
self.assert_language_rules_check('bar/chromium/foo.cpp',
diff --git a/Tools/Scripts/webkitpy/tool/commands/__init__.py b/Tools/Scripts/webkitpy/tool/commands/__init__.py
index 24646fc..57bba31 100644
--- a/Tools/Scripts/webkitpy/tool/commands/__init__.py
+++ b/Tools/Scripts/webkitpy/tool/commands/__init__.py
@@ -4,18 +4,13 @@
from webkitpy.tool.commands.analyzechangelog import AnalyzeChangeLog
from webkitpy.tool.commands.applywatchlistlocal import ApplyWatchListLocal
from webkitpy.tool.commands.bugfortest import BugForTest
-from webkitpy.tool.commands.bugsearch import BugSearch
from webkitpy.tool.commands.chromechannels import ChromeChannels
from webkitpy.tool.commands.download import *
-from webkitpy.tool.commands.earlywarningsystem import *
from webkitpy.tool.commands.findusers import FindUsers
from webkitpy.tool.commands.gardenomatic import GardenOMatic
-from webkitpy.tool.commands.openbugs import OpenBugs
from webkitpy.tool.commands.prettydiff import PrettyDiff
from webkitpy.tool.commands.queries import *
-from webkitpy.tool.commands.queues import *
from webkitpy.tool.commands.rebaseline import Rebaseline
from webkitpy.tool.commands.rebaselineserver import RebaselineServer
-from webkitpy.tool.commands.roll import *
from webkitpy.tool.commands.upload import *
from webkitpy.tool.commands.suggestnominations import *
diff --git a/Tools/Scripts/webkitpy/tool/commands/bugsearch.py b/Tools/Scripts/webkitpy/tool/commands/bugsearch.py
deleted file mode 100644
index a1d74c5..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/bugsearch.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (c) 2010 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-
-
-class BugSearch(AbstractDeclarativeCommand):
- name = "bug-search"
- help_text = "List bugs matching a query"
- argument_names = "QUERY"
- long_help = \
-"""Runs the bugzilla quicksearch QUERY on bugs.webkit.org, and lists all bugs
-returned. QUERY can be as simple as a bug number or a comma delimited list of
-bug numbers.
-See https://bugzilla.mozilla.org/page.cgi?id=quicksearch.html for full
-documentation on the query format."""
-
- def execute(self, options, args, tool):
- search_string = args[0]
- bugs = tool.bugs.queries.fetch_bugs_matching_quicksearch(search_string)
- for bug in bugs:
- print "%5s %s" % (bug.id(), bug.title())
- if not bugs:
- print "No bugs found matching '%s'" % search_string
diff --git a/Tools/Scripts/webkitpy/tool/commands/download.py b/Tools/Scripts/webkitpy/tool/commands/download.py
index 395c913..f6c903e 100644
--- a/Tools/Scripts/webkitpy/tool/commands/download.py
+++ b/Tools/Scripts/webkitpy/tool/commands/download.py
@@ -63,420 +63,9 @@
]
-class Build(AbstractSequencedCommand):
- name = "build"
- help_text = "Update working copy and build"
- steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.Build,
- ]
-
- def _prepare_state(self, options, args, tool):
- options.build = True
-
-
-class BuildAndTest(AbstractSequencedCommand):
- name = "build-and-test"
- help_text = "Update working copy, build, and run the tests"
- steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.Build,
- steps.RunTests,
- ]
-
-
-class Land(AbstractSequencedCommand):
- name = "land"
- help_text = "Land the current working directory diff and updates the associated bug if any"
- argument_names = "[BUGID]"
- show_in_main_help = True
- steps = [
- steps.AddSvnMimetypeForPng,
- steps.UpdateChangeLogsWithReviewer,
- steps.ValidateReviewer,
- steps.ValidateChangeLogs, # We do this after UpdateChangeLogsWithReviewer to avoid not having to cache the diff twice.
- steps.Build,
- steps.RunTests,
- steps.Commit,
- steps.CloseBugForLandDiff,
- ]
- long_help = """land commits the current working copy diff (just as svn or git commit would).
-land will NOT build and run the tests before committing, but you can use the --build option for that.
-If a bug id is provided, or one can be found in the ChangeLog land will update the bug after committing."""
-
- def _prepare_state(self, options, args, tool):
- changed_files = self._tool.scm().changed_files(options.git_commit)
- return {
- "changed_files": changed_files,
- "bug_id": (args and args[0]) or tool.checkout().bug_id_for_this_commit(options.git_commit, changed_files),
- }
-
-
-class LandCowboy(AbstractSequencedCommand):
- name = "land-cowboy"
- help_text = "Prepares a ChangeLog and lands the current working directory diff."
- steps = [
- steps.PrepareChangeLog,
- steps.EditChangeLog,
- steps.CheckStyle,
- steps.ConfirmDiff,
- steps.Build,
- steps.RunTests,
- steps.Commit,
- steps.CloseBugForLandDiff,
- ]
-
- def _prepare_state(self, options, args, tool):
- options.check_style_filter = "-changelog"
-
-
-class LandCowhand(LandCowboy):
- # Gender-blind term for cowboy, see: http://en.wiktionary.org/wiki/cowhand
- name = "land-cowhand"
-
-
class CheckStyleLocal(AbstractSequencedCommand):
name = "check-style-local"
help_text = "Run check-webkit-style on the current working directory diff"
steps = [
steps.CheckStyle,
]
-
-
-class AbstractPatchProcessingCommand(AbstractDeclarativeCommand):
- # Subclasses must implement the methods below. We don't declare them here
- # because we want to be able to implement them with mix-ins.
- #
- # pylint: disable=E1101
- # def _fetch_list_of_patches_to_process(self, options, args, tool):
- # def _prepare_to_process(self, options, args, tool):
- # def _process_patch(self, options, args, tool):
-
- @staticmethod
- def _collect_patches_by_bug(patches):
- bugs_to_patches = {}
- for patch in patches:
- bugs_to_patches[patch.bug_id()] = bugs_to_patches.get(patch.bug_id(), []) + [patch]
- return bugs_to_patches
-
- def execute(self, options, args, tool):
- self._prepare_to_process(options, args, tool)
- patches = self._fetch_list_of_patches_to_process(options, args, tool)
-
- # It's nice to print out total statistics.
- bugs_to_patches = self._collect_patches_by_bug(patches)
- _log.info("Processing %s from %s." % (pluralize("patch", len(patches)), pluralize("bug", len(bugs_to_patches))))
-
- for patch in patches:
- self._process_patch(patch, options, args, tool)
-
-
-class AbstractPatchSequencingCommand(AbstractPatchProcessingCommand):
- prepare_steps = None
- main_steps = None
-
- def __init__(self):
- options = []
- self._prepare_sequence = StepSequence(self.prepare_steps)
- self._main_sequence = StepSequence(self.main_steps)
- options = sorted(set(self._prepare_sequence.options() + self._main_sequence.options()))
- AbstractPatchProcessingCommand.__init__(self, options)
-
- def _prepare_to_process(self, options, args, tool):
- self._prepare_sequence.run_and_handle_errors(tool, options)
-
- def _process_patch(self, patch, options, args, tool):
- state = { "patch" : patch }
- self._main_sequence.run_and_handle_errors(tool, options, state)
-
-
-class ProcessAttachmentsMixin(object):
- def _fetch_list_of_patches_to_process(self, options, args, tool):
- return map(lambda patch_id: tool.bugs.fetch_attachment(patch_id), args)
-
-
-class ProcessBugsMixin(object):
- def _fetch_list_of_patches_to_process(self, options, args, tool):
- all_patches = []
- for bug_id in args:
- patches = tool.bugs.fetch_bug(bug_id).reviewed_patches()
- _log.info("%s found on bug %s." % (pluralize("reviewed patch", len(patches)), bug_id))
- all_patches += patches
- if not all_patches:
- _log.info("No reviewed patches found, looking for unreviewed patches.")
- for bug_id in args:
- patches = tool.bugs.fetch_bug(bug_id).patches()
- _log.info("%s found on bug %s." % (pluralize("patch", len(patches)), bug_id))
- all_patches += patches
- return all_patches
-
-
-class ProcessURLsMixin(object):
- def _fetch_list_of_patches_to_process(self, options, args, tool):
- all_patches = []
- for url in args:
- bug_id = urls.parse_bug_id(url)
- if bug_id:
- patches = tool.bugs.fetch_bug(bug_id).patches()
- _log.info("%s found on bug %s." % (pluralize("patch", len(patches)), bug_id))
- all_patches += patches
-
- attachment_id = urls.parse_attachment_id(url)
- if attachment_id:
- all_patches += tool.bugs.fetch_attachment(attachment_id)
-
- return all_patches
-
-
-class CheckStyle(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
- name = "check-style"
- help_text = "Run check-webkit-style on the specified attachments"
- argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
- main_steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.ApplyPatch,
- steps.CheckStyle,
- ]
-
-
-class BuildAttachment(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
- name = "build-attachment"
- help_text = "Apply and build patches from bugzilla"
- argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
- main_steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.ApplyPatch,
- steps.Build,
- ]
-
-
-class BuildAndTestAttachment(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
- name = "build-and-test-attachment"
- help_text = "Apply, build, and test patches from bugzilla"
- argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
- main_steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.ApplyPatch,
- steps.Build,
- steps.RunTests,
- ]
-
-
-class AbstractPatchApplyingCommand(AbstractPatchSequencingCommand):
- prepare_steps = [
- steps.EnsureLocalCommitIfNeeded,
- steps.CleanWorkingDirectory,
- steps.Update,
- ]
- main_steps = [
- steps.ApplyPatchWithLocalCommit,
- ]
- long_help = """Updates the working copy.
-Downloads and applies the patches, creating local commits if necessary."""
-
-
-class ApplyAttachment(AbstractPatchApplyingCommand, ProcessAttachmentsMixin):
- name = "apply-attachment"
- help_text = "Apply an attachment to the local working directory"
- argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
- show_in_main_help = True
-
-
-class ApplyFromBug(AbstractPatchApplyingCommand, ProcessBugsMixin):
- name = "apply-from-bug"
- help_text = "Apply reviewed patches from provided bugs to the local working directory"
- argument_names = "BUGID [BUGIDS]"
- show_in_main_help = True
-
-
-class ApplyWatchList(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
- name = "apply-watchlist"
- help_text = "Applies the watchlist to the specified attachments"
- argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
- main_steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.ApplyPatch,
- steps.ApplyWatchList,
- ]
- long_help = """"Applies the watchlist to the specified attachments.
-Downloads the attachment, applies it locally, runs the watchlist against it, and updates the bug with the result."""
-
-
-class AbstractPatchLandingCommand(AbstractPatchSequencingCommand):
- main_steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.ApplyPatch,
- steps.ValidateChangeLogs,
- steps.ValidateReviewer,
- steps.Build,
- steps.RunTests,
- steps.Commit,
- steps.ClosePatch,
- steps.CloseBug,
- ]
- long_help = """Checks to make sure builders are green.
-Updates the working copy.
-Applies the patch.
-Builds.
-Runs the layout tests.
-Commits the patch.
-Clears the flags on the patch.
-Closes the bug if no patches are marked for review."""
-
-
-class LandAttachment(AbstractPatchLandingCommand, ProcessAttachmentsMixin):
- name = "land-attachment"
- help_text = "Land patches from bugzilla, optionally building and testing them first"
- argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
- show_in_main_help = True
-
-
-class LandFromBug(AbstractPatchLandingCommand, ProcessBugsMixin):
- name = "land-from-bug"
- help_text = "Land all patches on the given bugs, optionally building and testing them first"
- argument_names = "BUGID [BUGIDS]"
- show_in_main_help = True
-
-
-class LandFromURL(AbstractPatchLandingCommand, ProcessURLsMixin):
- name = "land-from-url"
- help_text = "Land all patches on the given URLs, optionally building and testing them first"
- argument_names = "URL [URLS]"
-
-
-class ValidateChangelog(AbstractSequencedCommand):
- name = "validate-changelog"
- help_text = "Validate that the ChangeLogs and reviewers look reasonable"
- long_help = """Examines the current diff to see whether the ChangeLogs
-and the reviewers listed in the ChangeLogs look reasonable.
-"""
- steps = [
- steps.ValidateChangeLogs,
- steps.ValidateReviewer,
- ]
-
-
-class AbstractRolloutPrepCommand(AbstractSequencedCommand):
- argument_names = "REVISION [REVISIONS] REASON"
-
- def _commit_info(self, revision):
- commit_info = self._tool.checkout().commit_info_for_revision(revision)
- if commit_info and commit_info.bug_id():
- # Note: Don't print a bug URL here because it will confuse the
- # SheriffBot because the SheriffBot just greps the output
- # of create-rollout for bug URLs. It should do better
- # parsing instead.
- _log.info("Preparing rollout for bug %s." % commit_info.bug_id())
- else:
- _log.info("Unable to parse bug number from diff.")
- return commit_info
-
- def _prepare_state(self, options, args, tool):
- revision_list = []
- for revision in str(args[0]).split():
- if revision.isdigit():
- revision_list.append(int(revision))
- else:
- raise ScriptError(message="Invalid svn revision number: " + revision)
- revision_list.sort()
-
- # We use the earliest revision for the bug info
- earliest_revision = revision_list[0]
- state = {
- "revision": earliest_revision,
- "revision_list": revision_list,
- "reason": args[1],
- }
- commit_info = self._commit_info(earliest_revision)
- if commit_info:
- state["bug_id"] = commit_info.bug_id()
- cc_list = sorted([party.bugzilla_email()
- for party in commit_info.responsible_parties()
- if party.bugzilla_email()])
- # FIXME: We should used the list as the canonical representation.
- state["bug_cc"] = ",".join(cc_list)
- return state
-
-
-class PrepareRollout(AbstractRolloutPrepCommand):
- name = "prepare-rollout"
- help_text = "Revert the given revision(s) in the working copy and prepare ChangeLogs with revert reason"
- long_help = """Updates the working copy.
-Applies the inverse diff for the provided revision(s).
-Creates an appropriate rollout ChangeLog, including a trac link and bug link.
-"""
- steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.RevertRevision,
- steps.PrepareChangeLogForRevert,
- ]
-
-
-class CreateRollout(AbstractRolloutPrepCommand):
- name = "create-rollout"
- help_text = "Creates a bug to track the broken SVN revision(s) and uploads a rollout patch."
- steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.RevertRevision,
- steps.CreateBug,
- steps.PrepareChangeLogForRevert,
- steps.PostDiffForRevert,
- ]
-
- def _prepare_state(self, options, args, tool):
- state = AbstractRolloutPrepCommand._prepare_state(self, options, args, tool)
- # Currently, state["bug_id"] points to the bug that caused the
- # regression. We want to create a new bug that blocks the old bug
- # so we move state["bug_id"] to state["bug_blocked"] and delete the
- # old state["bug_id"] so that steps.CreateBug will actually create
- # the new bug that we want (and subsequently store its bug id into
- # state["bug_id"])
- state["bug_blocked"] = state["bug_id"]
- del state["bug_id"]
- state["bug_title"] = "REGRESSION(r%s): %s" % (state["revision"], state["reason"])
- state["bug_description"] = "%s broke the build:\n%s" % (urls.view_revision_url(state["revision"]), state["reason"])
- # FIXME: If we had more context here, we could link to other open bugs
- # that mention the test that regressed.
- if options.parent_command == "sheriff-bot":
- state["bug_description"] += """
-
-This is an automatic bug report generated by the sheriff-bot. If this bug
-report was created because of a flaky test, please file a bug for the flaky
-test (if we don't already have one on file) and dup this bug against that bug
-so that we can track how often these flaky tests case pain.
-
-"Only you can prevent forest fires." -- Smokey the Bear
-"""
- return state
-
-
-class Rollout(AbstractRolloutPrepCommand):
- name = "rollout"
- show_in_main_help = True
- help_text = "Revert the given revision(s) in the working copy and optionally commit the revert and re-open the original bug"
- long_help = """Updates the working copy.
-Applies the inverse diff for the provided revision.
-Creates an appropriate rollout ChangeLog, including a trac link and bug link.
-Opens the generated ChangeLogs in $EDITOR.
-Shows the prepared diff for confirmation.
-Commits the revert and updates the bug (including re-opening the bug if necessary)."""
- steps = [
- steps.DiscardLocalChanges,
- steps.Update,
- steps.RevertRevision,
- steps.PrepareChangeLogForRevert,
- steps.EditChangeLog,
- steps.ConfirmDiff,
- steps.Build,
- steps.Commit,
- steps.ReopenBugAfterRollout,
- ]
diff --git a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
index dbbdf2d..1dc5b4a 100644
--- a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
+++ b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
@@ -36,42 +36,6 @@
from webkitpy.common.checkout.checkout_mock import MockCheckout
-class AbstractRolloutPrepCommandTest(unittest.TestCase):
- def test_commit_info(self):
- command = AbstractRolloutPrepCommand()
- tool = MockTool()
- command.bind_to_tool(tool)
- output = OutputCapture()
-
- expected_logs = "Preparing rollout for bug 50000.\n"
- commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_logs=expected_logs)
- self.assertTrue(commit_info)
-
- mock_commit_info = Mock()
- mock_commit_info.bug_id = lambda: None
- tool._checkout.commit_info_for_revision = lambda revision: mock_commit_info
- expected_logs = "Unable to parse bug number from diff.\n"
- commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_logs=expected_logs)
- self.assertEqual(commit_info, mock_commit_info)
-
- def test_prepare_state(self):
- command = AbstractRolloutPrepCommand()
- mock_commit_info = MockCheckout().commit_info_for_revision(123)
- command._commit_info = lambda revision: mock_commit_info
-
- state = command._prepare_state(None, ["124 123 125", "Reason"], None)
- self.assertEqual(123, state["revision"])
- self.assertEqual([123, 124, 125], state["revision_list"])
-
- self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 r122 123", "Reason"], tool=None)
- self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 foo 123", "Reason"], tool=None)
-
- command._commit_info = lambda revision: None
- state = command._prepare_state(None, ["124 123 125", "Reason"], None)
- self.assertEqual(123, state["revision"])
- self.assertEqual([123, 124, 125], state["revision_list"])
-
-
class DownloadCommandsTest(CommandsTest):
maxDiff = None
@@ -90,267 +54,3 @@
options.test = True
options.update = True
return options
-
- def test_build(self):
- expected_logs = "Updating working directory\nBuilding WebKit\n"
- self.assert_execute_outputs(Build(), [], options=self._default_options(), expected_logs=expected_logs)
-
- def test_build_and_test(self):
- expected_logs = """Updating working directory
-Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-"""
- self.assert_execute_outputs(BuildAndTest(), [], options=self._default_options(), expected_logs=expected_logs)
-
- def test_apply_attachment(self):
- options = self._default_options()
- options.update = True
- options.local_commit = True
- expected_logs = "Updating working directory\nProcessing 1 patch from 1 bug.\nProcessing patch 10000 from bug 50000.\n"
- self.assert_execute_outputs(ApplyAttachment(), [10000], options=options, expected_logs=expected_logs)
-
- def test_apply_from_bug(self):
- options = self._default_options()
- options.update = True
- options.local_commit = True
-
- expected_logs = "Updating working directory\n0 reviewed patches found on bug 50001.\nNo reviewed patches found, looking for unreviewed patches.\n1 patch found on bug 50001.\nProcessing 1 patch from 1 bug.\nProcessing patch 10002 from bug 50001.\n"
- self.assert_execute_outputs(ApplyFromBug(), [50001], options=options, expected_logs=expected_logs)
-
- expected_logs = "Updating working directory\n2 reviewed patches found on bug 50000.\nProcessing 2 patches from 1 bug.\nProcessing patch 10000 from bug 50000.\nProcessing patch 10001 from bug 50000.\n"
- self.assert_execute_outputs(ApplyFromBug(), [50000], options=options, expected_logs=expected_logs)
-
- def test_apply_watch_list(self):
- expected_logs = """Processing 1 patch from 1 bug.
-Updating working directory
-MOCK run_and_throw_if_fail: ['mock-update-webkit'], cwd=/mock-checkout
-Processing patch 10000 from bug 50000.
-MockWatchList: determine_cc_and_messages
-No bug was updated because no id was given.
-Result of watchlist: cc "abarth@webkit.org, eric@webkit.org, levin@chromium.org" messages "Message1.
-
-Message2."
-"""
- self.assert_execute_outputs(ApplyWatchList(), [10000], options=self._default_options(), expected_logs=expected_logs, tool=MockTool(log_executive=True))
-
- def test_land(self):
- expected_logs = """Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Updating bug 50000
-"""
- mock_tool = MockTool()
- mock_tool.scm().create_patch = Mock(return_value="Patch1\nMockPatch\n")
- mock_tool.checkout().modified_changelogs = Mock(return_value=[])
- self.assert_execute_outputs(Land(), [50000], options=self._default_options(), expected_logs=expected_logs, tool=mock_tool)
- # Make sure we're not calling expensive calls too often.
- self.assertEqual(mock_tool.scm().create_patch.call_count, 0)
- self.assertEqual(mock_tool.checkout().modified_changelogs.call_count, 1)
-
- def test_land_cowboy(self):
- expected_logs = """MOCK run_and_throw_if_fail: ['mock-prepare-ChangeLog', '--email=MOCK email', '--merge-base=None', 'MockFile1'], cwd=/mock-checkout
-MOCK run_and_throw_if_fail: ['mock-check-webkit-style', '--git-commit', 'MOCK git commit', '--diff-files', 'MockFile1', '--filter', '-changelog'], cwd=/mock-checkout
-MOCK run_command: ['ruby', '-I', '/mock-checkout/Tools/Scripts/webkitruby/PrettyPatch', '/mock-checkout/Tools/Scripts/webkitruby/PrettyPatch/prettify.rb'], cwd=None, input=Patch1
-MOCK: user.open_url: file://...
-Was that diff correct?
-Building WebKit
-MOCK run_and_throw_if_fail: ['mock-build-webkit'], cwd=/mock-checkout, env={'LC_ALL': 'C', 'MOCK_ENVIRON_COPY': '1'}
-Running Python unit tests
-MOCK run_and_throw_if_fail: ['mock-test-webkitpy'], cwd=/mock-checkout
-Running Perl unit tests
-MOCK run_and_throw_if_fail: ['mock-test-webkitperl'], cwd=/mock-checkout
-Running JavaScriptCore tests
-MOCK run_and_throw_if_fail: ['mock-run-javacriptcore-tests'], cwd=/mock-checkout
-Running bindings generation tests
-MOCK run_and_throw_if_fail: ['mock-run-bindings-tests'], cwd=/mock-checkout
-Running WebKit unit tests
-MOCK run_and_throw_if_fail: ['mock-run-webkit-unit-tests'], cwd=/mock-checkout
-Running run-webkit-tests
-MOCK run_and_throw_if_fail: ['mock-run-webkit-tests', '--quiet'], cwd=/mock-checkout
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-No bug id provided.
-"""
- mock_tool = MockTool(log_executive=True)
- self.assert_execute_outputs(LandCowboy(), [50000], options=self._default_options(), expected_logs=expected_logs, tool=mock_tool)
-
- def test_land_red_builders(self):
- expected_logs = """Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Updating bug 50000
-"""
- mock_tool = MockTool()
- mock_tool.buildbot.light_tree_on_fire()
- self.assert_execute_outputs(Land(), [50000], options=self._default_options(), expected_logs=expected_logs, tool=mock_tool)
-
- def test_check_style(self):
- expected_logs = """Processing 1 patch from 1 bug.
-Updating working directory
-MOCK run_and_throw_if_fail: ['mock-update-webkit'], cwd=/mock-checkout
-Processing patch 10000 from bug 50000.
-MOCK run_and_throw_if_fail: ['mock-check-webkit-style', '--git-commit', 'MOCK git commit', '--diff-files', 'MockFile1'], cwd=/mock-checkout
-"""
- self.assert_execute_outputs(CheckStyle(), [10000], options=self._default_options(), expected_logs=expected_logs, tool=MockTool(log_executive=True))
-
- def test_build_attachment(self):
- expected_logs = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 10000 from bug 50000.\nBuilding WebKit\n"
- self.assert_execute_outputs(BuildAttachment(), [10000], options=self._default_options(), expected_logs=expected_logs)
-
- def test_land_attachment(self):
- # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
- expected_logs = """Processing 1 patch from 1 bug.
-Updating working directory
-Processing patch 10000 from bug 50000.
-Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Not closing bug 50000 as attachment 10000 has review=+. Assuming there are more patches to land from this bug.
-"""
- self.assert_execute_outputs(LandAttachment(), [10000], options=self._default_options(), expected_logs=expected_logs)
-
- def test_land_from_bug(self):
- # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
- expected_logs = """2 reviewed patches found on bug 50000.
-Processing 2 patches from 1 bug.
-Updating working directory
-Processing patch 10000 from bug 50000.
-Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Not closing bug 50000 as attachment 10000 has review=+. Assuming there are more patches to land from this bug.
-Updating working directory
-Processing patch 10001 from bug 50000.
-Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Not closing bug 50000 as attachment 10000 has review=+. Assuming there are more patches to land from this bug.
-"""
- self.assert_execute_outputs(LandFromBug(), [50000], options=self._default_options(), expected_logs=expected_logs)
-
- def test_land_from_url(self):
- # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
- expected_logs = """2 patches found on bug 50000.
-Processing 2 patches from 1 bug.
-Updating working directory
-Processing patch 10000 from bug 50000.
-Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Not closing bug 50000 as attachment 10000 has review=+. Assuming there are more patches to land from this bug.
-Updating working directory
-Processing patch 10001 from bug 50000.
-Building WebKit
-Running Python unit tests
-Running Perl unit tests
-Running JavaScriptCore tests
-Running bindings generation tests
-Running WebKit unit tests
-Running run-webkit-tests
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-Not closing bug 50000 as attachment 10000 has review=+. Assuming there are more patches to land from this bug.
-"""
- self.assert_execute_outputs(LandFromURL(), ["https://bugs.webkit.org/show_bug.cgi?id=50000"], options=self._default_options(), expected_logs=expected_logs)
-
- def test_prepare_rollout(self):
- expected_logs = "Preparing rollout for bug 50000.\nUpdating working directory\n"
- self.assert_execute_outputs(PrepareRollout(), [852, "Reason"], options=self._default_options(), expected_logs=expected_logs)
-
- def test_create_rollout(self):
- expected_logs = """Preparing rollout for bug 50000.
-Updating working directory
-MOCK create_bug
-bug_title: REGRESSION(r852): Reason
-bug_description: http://trac.webkit.org/changeset/852 broke the build:
-Reason
-component: MOCK component
-cc: MOCK cc
-blocked: 50000
-MOCK add_patch_to_bug: bug_id=60001, description=ROLLOUT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
--- Begin comment --
-Any committer can land this patch automatically by marking it commit-queue+. The commit-queue will build and test the patch before landing to ensure that the rollout will be successful. This process takes approximately 15 minutes.
-
-If you would like to land the rollout faster, you can use the following command:
-
- webkit-patch land-attachment ATTACHMENT_ID
-
-where ATTACHMENT_ID is the ID of this attachment.
--- End comment --
-"""
- self.assert_execute_outputs(CreateRollout(), [852, "Reason"], options=self._default_options(), expected_logs=expected_logs)
- self.assert_execute_outputs(CreateRollout(), ["855 852 854", "Reason"], options=self._default_options(), expected_logs=expected_logs)
-
- def test_create_rollout_resolved(self):
- expected_logs = """Preparing rollout for bug 50004.
-Updating working directory
-MOCK create_bug
-bug_title: REGRESSION(r3001): Reason
-bug_description: http://trac.webkit.org/changeset/3001 broke the build:
-Reason
-component: MOCK component
-cc: MOCK cc
-blocked: 50004
-MOCK reopen_bug 50004 with comment 'Re-opened since this is blocked by bug 60001'
-MOCK add_patch_to_bug: bug_id=60001, description=ROLLOUT of r3001, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
--- Begin comment --
-Any committer can land this patch automatically by marking it commit-queue+. The commit-queue will build and test the patch before landing to ensure that the rollout will be successful. This process takes approximately 15 minutes.
-
-If you would like to land the rollout faster, you can use the following command:
-
- webkit-patch land-attachment ATTACHMENT_ID
-
-where ATTACHMENT_ID is the ID of this attachment.
--- End comment --
-"""
- self.assert_execute_outputs(CreateRollout(), [3001, "Reason"], options=self._default_options(), expected_logs=expected_logs)
-
- def test_rollout(self):
- expected_logs = """Preparing rollout for bug 50000.
-Updating working directory
-MOCK: user.open_url: file://...
-Was that diff correct?
-Building WebKit
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-MOCK reopen_bug 50000 with comment 'Reverted r852 for reason:
-
-Reason
-
-Committed r49824: <http://trac.webkit.org/changeset/49824>'
-"""
- self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_logs=expected_logs)
-
diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
deleted file mode 100644
index 90501fc..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
+++ /dev/null
@@ -1,225 +0,0 @@
-# Copyright (c) 2009 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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
-from optparse import make_option
-
-from webkitpy.common.config.committers import CommitterList
-from webkitpy.common.config.ports import DeprecatedPort
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.tool.bot.earlywarningsystemtask import EarlyWarningSystemTask, EarlyWarningSystemTaskDelegate
-from webkitpy.tool.bot.expectedfailures import ExpectedFailures
-from webkitpy.tool.bot.layouttestresultsreader import LayoutTestResultsReader
-from webkitpy.tool.bot.patchanalysistask import UnableToApplyPatch
-from webkitpy.tool.bot.queueengine import QueueEngine
-from webkitpy.tool.commands.queues import AbstractReviewQueue
-
-_log = logging.getLogger(__name__)
-
-
-class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDelegate):
- _build_style = "release"
- # FIXME: Switch _default_run_tests from opt-in to opt-out once more bots are ready to run tests.
- _default_run_tests = False
-
- def __init__(self):
- options = [make_option("--run-tests", action="store_true", dest="run_tests", default=self._default_run_tests, help="Run the Layout tests for each patch")]
- AbstractReviewQueue.__init__(self, options=options)
-
- def begin_work_queue(self):
- AbstractReviewQueue.begin_work_queue(self)
- self._expected_failures = ExpectedFailures()
- self._layout_test_results_reader = LayoutTestResultsReader(self._tool, self._port.results_directory(), self._log_directory())
-
- def _failing_tests_message(self, task, patch):
- results = task.results_from_patch_test_run(patch)
- unexpected_failures = self._expected_failures.unexpected_failures_observed(results)
- if not unexpected_failures:
- return None
- return "New failing tests:\n%s" % "\n".join(unexpected_failures)
-
- def _post_reject_message_on_bug(self, tool, patch, status_id, extra_message_text=None):
- results_link = tool.status_server.results_url_for_status(status_id)
- message = "Attachment %s did not pass %s (%s):\nOutput: %s" % (patch.id(), self.name, self.port_name, results_link)
- if extra_message_text:
- message += "\n\n%s" % extra_message_text
- # FIXME: We might want to add some text about rejecting from the commit-queue in
- # the case where patch.commit_queue() isn't already set to '-'.
- if self.watchers:
- tool.bugs.add_cc_to_bug(patch.bug_id(), self.watchers)
- tool.bugs.set_flag_on_attachment(patch.id(), "commit-queue", "-", message)
-
- def review_patch(self, patch):
- task = EarlyWarningSystemTask(self, patch, self._options.run_tests)
- if not task.validate():
- self._did_error(patch, "%s did not process patch." % self.name)
- return False
- try:
- return task.run()
- except UnableToApplyPatch, e:
- self._did_error(patch, "%s unable to apply patch." % self.name)
- return False
- except ScriptError, e:
- self._post_reject_message_on_bug(self._tool, patch, task.failure_status_id, self._failing_tests_message(task, patch))
- results_archive = task.results_archive_from_patch_test_run(patch)
- if results_archive:
- self._upload_results_archive_for_patch(patch, results_archive)
- self._did_fail(patch)
- # FIXME: We're supposed to be able to raise e again here and have
- # one of our base classes mark the patch as fail, but there seems
- # to be an issue with the exit_code.
- return False
-
- # EarlyWarningSystemDelegate methods
-
- def parent_command(self):
- return self.name
-
- def run_command(self, command):
- self.run_webkit_patch(command + [self._deprecated_port.flag()])
-
- def command_passed(self, message, patch):
- pass
-
- def command_failed(self, message, script_error, patch):
- failure_log = self._log_from_script_error_for_upload(script_error)
- return self._update_status(message, patch=patch, results_file=failure_log)
-
- def expected_failures(self):
- return self._expected_failures
-
- def test_results(self):
- return self._layout_test_results_reader.results()
-
- def archive_last_test_results(self, patch):
- return self._layout_test_results_reader.archive(patch)
-
- def build_style(self):
- return self._build_style
-
- def refetch_patch(self, patch):
- return self._tool.bugs.fetch_attachment(patch.id())
-
- def report_flaky_tests(self, patch, flaky_test_results, results_archive):
- pass
-
- # StepSequenceErrorHandler methods
-
- @classmethod
- def handle_script_error(cls, tool, state, script_error):
- # FIXME: Why does this not exit(1) like the superclass does?
- _log.error(script_error.message_with_output())
-
-
-class GtkEWS(AbstractEarlyWarningSystem):
- name = "gtk-ews"
- port_name = "gtk"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "xan.lopez@gmail.com",
- ]
-
-
-class EflEWS(AbstractEarlyWarningSystem):
- name = "efl-ews"
- port_name = "efl"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "leandro@profusion.mobi",
- "antognolli@profusion.mobi",
- "lucas.demarchi@profusion.mobi",
- "gyuyoung.kim@samsung.com",
- ]
-
-
-class QtEWS(AbstractEarlyWarningSystem):
- name = "qt-ews"
- port_name = "qt"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "webkit-ews@sed.inf.u-szeged.hu",
- ]
-
-
-class QtWK2EWS(AbstractEarlyWarningSystem):
- name = "qt-wk2-ews"
- port_name = "qt"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "webkit-ews@sed.inf.u-szeged.hu",
- ]
-
-
-class WinEWS(AbstractEarlyWarningSystem):
- name = "win-ews"
- port_name = "win"
- _default_run_tests = True
-
-class AbstractChromiumEWS(AbstractEarlyWarningSystem):
- port_name = "chromium"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "dglazkov@chromium.org",
- ]
-
-
-class ChromiumLinuxEWS(AbstractChromiumEWS):
- # FIXME: We should rename this command to cr-linux-ews, but that requires
- # a database migration. :(
- name = "chromium-ews"
- port_name = "chromium-xvfb"
- _default_run_tests = True
-
-
-class ChromiumLinuxDebugEWS(AbstractChromiumEWS):
- name = "cr-linux-debug-ews"
- port_name = "chromium-xvfb"
- _build_style = "debug"
-
-
-class ChromiumWindowsEWS(AbstractChromiumEWS):
- name = "cr-win-ews"
-
-
-class ChromiumAndroidEWS(AbstractChromiumEWS):
- name = "cr-android-ews"
- port_name = "chromium-android"
- watchers = AbstractChromiumEWS.watchers + [
- "peter+ews@chromium.org",
- ]
-
-
-class MacEWS(AbstractEarlyWarningSystem):
- name = "mac-ews"
- port_name = "mac"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "rniwa@webkit.org",
- ]
-
-
-class MacWK2EWS(AbstractEarlyWarningSystem):
- name = "mac-wk2-ews"
- port_name = "mac-wk2"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "rniwa@webkit.org",
- ]
diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py
deleted file mode 100644
index 3ab1cd4..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# Copyright (C) 2009 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.tool.bot.queueengine import QueueEngine
-from webkitpy.tool.commands.earlywarningsystem import *
-from webkitpy.tool.commands.queuestest import QueuesTest
-from webkitpy.tool.mocktool import MockTool, MockOptions
-
-
-class AbstractEarlyWarningSystemTest(QueuesTest):
- def test_failing_tests_message(self):
- # Needed to define port_name, used in AbstractEarlyWarningSystem.__init__
- class TestEWS(AbstractEarlyWarningSystem):
- port_name = "chromium" # Needs to be a port which port/factory understands.
-
- ews = TestEWS()
- ews.bind_to_tool(MockTool())
- ews._options = MockOptions(port=None, confirm=False)
- OutputCapture().assert_outputs(self, ews.begin_work_queue, expected_logs=self._default_begin_work_queue_logs(ews.name))
- ews._expected_failures.unexpected_failures_observed = lambda results: set(["foo.html", "bar.html"])
- task = Mock()
- patch = ews._tool.bugs.fetch_attachment(10000)
- self.assertMultiLineEqual(ews._failing_tests_message(task, patch), "New failing tests:\nbar.html\nfoo.html")
-
-
-class EarlyWarningSytemTest(QueuesTest):
- def _default_expected_logs(self, ews):
- string_replacements = {
- "name": ews.name,
- "port": ews.port_name,
- }
- if ews._default_run_tests:
- run_tests_line = "Running: webkit-patch --status-host=example.com build-and-test --no-clean --no-update --test --non-interactive --port=%(port)s\n" % string_replacements
- else:
- run_tests_line = ""
- string_replacements['run_tests_line'] = run_tests_line
-
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs(ews.name),
- "process_work_item": """Running: webkit-patch --status-host=example.com clean --port=%(port)s
-Running: webkit-patch --status-host=example.com update --port=%(port)s
-Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000 --port=%(port)s
-Running: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=release --port=%(port)s
-%(run_tests_line)sMOCK: update_status: %(name)s Pass
-MOCK: release_work_item: %(name)s 10000
-""" % string_replacements,
- "handle_unexpected_error": "Mock error message\n",
- "handle_script_error": "ScriptError error message\n\nMOCK output\n",
- }
- return expected_logs
-
- def _test_ews(self, ews):
- ews.bind_to_tool(MockTool())
- options = Mock()
- options.port = None
- options.run_tests = ews._default_run_tests
- self.assert_queue_outputs(ews, expected_logs=self._default_expected_logs(ews), options=options)
-
- def _test_ewses(self):
- self._test_ews(MacEWS())
- self._test_ews(MacWK2EWS())
- self._test_ews(ChromiumLinuxEWS())
- self._test_ews(ChromiumWindowsEWS())
- self._test_ews(ChromiumAndroidEWS())
- self._test_ews(QtEWS())
- self._test_ews(QtWK2EWS())
- self._test_ews(GtkEWS())
- self._test_ews(EflEWS())
diff --git a/Tools/Scripts/webkitpy/tool/commands/openbugs.py b/Tools/Scripts/webkitpy/tool/commands/openbugs.py
deleted file mode 100644
index 8c55aba..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/openbugs.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# Copyright (c) 2010 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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 re
-import sys
-
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-
-_log = logging.getLogger(__name__)
-
-
-class OpenBugs(AbstractDeclarativeCommand):
- name = "open-bugs"
- help_text = "Finds all bug numbers passed in arguments (or stdin if no args provided) and opens them in a web browser"
-
- bug_number_regexp = re.compile(r"\b\d{4,6}\b")
-
- def _open_bugs(self, bug_ids):
- for bug_id in bug_ids:
- bug_url = self._tool.bugs.bug_url_for_bug_id(bug_id)
- self._tool.user.open_url(bug_url)
-
- # _find_bugs_in_string mostly exists for easy unit testing.
- def _find_bugs_in_string(self, string):
- return self.bug_number_regexp.findall(string)
-
- def _find_bugs_in_iterable(self, iterable):
- return sum([self._find_bugs_in_string(string) for string in iterable], [])
-
- def execute(self, options, args, tool):
- if args:
- bug_ids = self._find_bugs_in_iterable(args)
- else:
- # This won't open bugs until stdin is closed but could be made to easily. That would just make unit testing slightly harder.
- bug_ids = self._find_bugs_in_iterable(sys.stdin)
-
- _log.info("%s bugs found in input." % len(bug_ids))
-
- self._open_bugs(bug_ids)
diff --git a/Tools/Scripts/webkitpy/tool/commands/openbugs_unittest.py b/Tools/Scripts/webkitpy/tool/commands/openbugs_unittest.py
deleted file mode 100644
index 680e514..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/openbugs_unittest.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2009 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-from webkitpy.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.commands.openbugs import OpenBugs
-
-class OpenBugsTest(CommandsTest):
-
- find_bugs_in_string_expectations = [
- ["123", []],
- ["1234", ["1234"]],
- ["12345", ["12345"]],
- ["123456", ["123456"]],
- ["1234567", []],
- [" 123456 234567", ["123456", "234567"]],
- ]
-
- def test_find_bugs_in_string(self):
- openbugs = OpenBugs()
- for expectation in self.find_bugs_in_string_expectations:
- self.assertEqual(openbugs._find_bugs_in_string(expectation[0]), expectation[1])
-
- def test_args_parsing(self):
- expected_logs = "2 bugs found in input.\nMOCK: user.open_url: http://example.com/12345\nMOCK: user.open_url: http://example.com/23456\n"
- self.assert_execute_outputs(OpenBugs(), ["12345\n23456"], expected_logs=expected_logs)
diff --git a/Tools/Scripts/webkitpy/tool/commands/queues.py b/Tools/Scripts/webkitpy/tool/commands/queues.py
deleted file mode 100644
index b9a78a8..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/queues.py
+++ /dev/null
@@ -1,487 +0,0 @@
-# Copyright (c) 2009 Google Inc. All rights reserved.
-# Copyright (c) 2009 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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 codecs
-import logging
-import os
-import sys
-import time
-import traceback
-
-from datetime import datetime
-from optparse import make_option
-from StringIO import StringIO
-
-from webkitpy.common.config.committervalidator import CommitterValidator
-from webkitpy.common.config.ports import DeprecatedPort
-from webkitpy.common.net.bugzilla import Attachment
-from webkitpy.common.net.statusserver import StatusServer
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.tool.bot.botinfo import BotInfo
-from webkitpy.tool.bot.commitqueuetask import CommitQueueTask, CommitQueueTaskDelegate
-from webkitpy.tool.bot.expectedfailures import ExpectedFailures
-from webkitpy.tool.bot.feeders import CommitQueueFeeder, EWSFeeder
-from webkitpy.tool.bot.flakytestreporter import FlakyTestReporter
-from webkitpy.tool.bot.layouttestresultsreader import LayoutTestResultsReader
-from webkitpy.tool.bot.patchanalysistask import UnableToApplyPatch
-from webkitpy.tool.bot.queueengine import QueueEngine, QueueEngineDelegate
-from webkitpy.tool.bot.stylequeuetask import StyleQueueTask, StyleQueueTaskDelegate
-from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
-from webkitpy.tool.multicommandtool import Command, TryAgain
-
-_log = logging.getLogger(__name__)
-
-
-class AbstractQueue(Command, QueueEngineDelegate):
- watchers = [
- ]
-
- _pass_status = "Pass"
- _fail_status = "Fail"
- _retry_status = "Retry"
- _error_status = "Error"
-
- def __init__(self, options=None): # Default values should never be collections (like []) as default values are shared between invocations
- options_list = (options or []) + [
- make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Do not ask the user for confirmation before running the queue. Dangerous!"),
- make_option("--exit-after-iteration", action="store", type="int", dest="iterations", default=None, help="Stop running the queue after iterating this number of times."),
- ]
- Command.__init__(self, "Run the %s" % self.name, options=options_list)
- self._iteration_count = 0
-
- def _cc_watchers(self, bug_id):
- try:
- self._tool.bugs.add_cc_to_bug(bug_id, self.watchers)
- except Exception, e:
- traceback.print_exc()
- _log.error("Failed to CC watchers.")
-
- def run_webkit_patch(self, args):
- webkit_patch_args = [self._tool.path()]
- # FIXME: This is a hack, we should have a more general way to pass global options.
- # FIXME: We must always pass global options and their value in one argument
- # because our global option code looks for the first argument which does
- # not begin with "-" and assumes that is the command name.
- webkit_patch_args += ["--status-host=%s" % self._tool.status_server.host]
- if self._tool.status_server.bot_id:
- webkit_patch_args += ["--bot-id=%s" % self._tool.status_server.bot_id]
- if self._options.port:
- webkit_patch_args += ["--port=%s" % self._options.port]
- webkit_patch_args.extend(args)
-
- try:
- args_for_printing = list(webkit_patch_args)
- args_for_printing[0] = 'webkit-patch' # Printing our path for each log is redundant.
- _log.info("Running: %s" % self._tool.executive.command_for_printing(args_for_printing))
- command_output = self._tool.executive.run_command(webkit_patch_args, cwd=self._tool.scm().checkout_root)
- except ScriptError, e:
- # Make sure the whole output gets printed if the command failed.
- _log.error(e.message_with_output(output_limit=None))
- raise
- return command_output
-
- def _log_directory(self):
- return os.path.join("..", "%s-logs" % self.name)
-
- # QueueEngineDelegate methods
-
- def queue_log_path(self):
- return os.path.join(self._log_directory(), "%s.log" % self.name)
-
- def work_item_log_path(self, work_item):
- raise NotImplementedError, "subclasses must implement"
-
- def begin_work_queue(self):
- _log.info("CAUTION: %s will discard all local changes in \"%s\"" % (self.name, self._tool.scm().checkout_root))
- if self._options.confirm:
- response = self._tool.user.prompt("Are you sure? Type \"yes\" to continue: ")
- if (response != "yes"):
- _log.error("User declined.")
- sys.exit(1)
- _log.info("Running WebKit %s." % self.name)
- self._tool.status_server.update_status(self.name, "Starting Queue")
-
- def stop_work_queue(self, reason):
- self._tool.status_server.update_status(self.name, "Stopping Queue, reason: %s" % reason)
-
- def should_continue_work_queue(self):
- self._iteration_count += 1
- return not self._options.iterations or self._iteration_count <= self._options.iterations
-
- def next_work_item(self):
- raise NotImplementedError, "subclasses must implement"
-
- def process_work_item(self, work_item):
- raise NotImplementedError, "subclasses must implement"
-
- def handle_unexpected_error(self, work_item, message):
- raise NotImplementedError, "subclasses must implement"
-
- # Command methods
-
- def execute(self, options, args, tool, engine=QueueEngine):
- self._options = options # FIXME: This code is wrong. Command.options is a list, this assumes an Options element!
- self._tool = tool # FIXME: This code is wrong too! Command.bind_to_tool handles this!
- return engine(self.name, self, self._tool.wakeup_event, self._options.seconds_to_sleep).run()
-
- @classmethod
- def _log_from_script_error_for_upload(cls, script_error, output_limit=None):
- # We have seen request timeouts with app engine due to large
- # log uploads. Trying only the last 512k.
- if not output_limit:
- output_limit = 512 * 1024 # 512k
- output = script_error.message_with_output(output_limit=output_limit)
- # We pre-encode the string to a byte array before passing it
- # to status_server, because ClientForm (part of mechanize)
- # wants a file-like object with pre-encoded data.
- return StringIO(output.encode("utf-8"))
-
- @classmethod
- def _update_status_for_script_error(cls, tool, state, script_error, is_error=False):
- message = str(script_error)
- if is_error:
- message = "Error: %s" % message
- failure_log = cls._log_from_script_error_for_upload(script_error)
- return tool.status_server.update_status(cls.name, message, state["patch"], failure_log)
-
-
-class FeederQueue(AbstractQueue):
- name = "feeder-queue"
-
- _sleep_duration = 30 # seconds
-
- # AbstractQueue methods
-
- def begin_work_queue(self):
- AbstractQueue.begin_work_queue(self)
- self.feeders = [
- CommitQueueFeeder(self._tool),
- EWSFeeder(self._tool),
- ]
-
- def next_work_item(self):
- # This really show inherit from some more basic class that doesn't
- # understand work items, but the base class in the heirarchy currently
- # understands work items.
- return "synthetic-work-item"
-
- def process_work_item(self, work_item):
- for feeder in self.feeders:
- feeder.feed()
- time.sleep(self._sleep_duration)
- return True
-
- def work_item_log_path(self, work_item):
- return None
-
- def handle_unexpected_error(self, work_item, message):
- _log.error(message)
-
-
-class AbstractPatchQueue(AbstractQueue):
- def _update_status(self, message, patch=None, results_file=None):
- return self._tool.status_server.update_status(self.name, message, patch, results_file)
-
- def _next_patch(self):
- # FIXME: Bugzilla accessibility should be checked here; if it's unaccessible,
- # it should return None.
- patch = None
- while not patch:
- patch_id = self._tool.status_server.next_work_item(self.name)
- if not patch_id:
- return None
- patch = self._tool.bugs.fetch_attachment(patch_id)
- if not patch:
- # FIXME: Using a fake patch because release_work_item has the wrong API.
- # We also don't really need to release the lock (although that's fine),
- # mostly we just need to remove this bogus patch from our queue.
- # If for some reason bugzilla is just down, then it will be re-fed later.
- fake_patch = Attachment({'id': patch_id}, None)
- self._release_work_item(fake_patch)
- return patch
-
- def _release_work_item(self, patch):
- self._tool.status_server.release_work_item(self.name, patch)
-
- def _did_pass(self, patch):
- self._update_status(self._pass_status, patch)
- self._release_work_item(patch)
-
- def _did_fail(self, patch):
- self._update_status(self._fail_status, patch)
- self._release_work_item(patch)
-
- def _did_retry(self, patch):
- self._update_status(self._retry_status, patch)
- self._release_work_item(patch)
-
- def _did_error(self, patch, reason):
- message = "%s: %s" % (self._error_status, reason)
- self._update_status(message, patch)
- self._release_work_item(patch)
-
- def work_item_log_path(self, patch):
- return os.path.join(self._log_directory(), "%s.log" % patch.bug_id())
-
-
-# Used to share code between the EWS and commit-queue.
-class PatchProcessingQueue(AbstractPatchQueue):
- # Subclasses must override.
- port_name = None
-
- def __init__(self, options=None):
- self._port = None # We can't instantiate port here because tool isn't avaialble.
- AbstractPatchQueue.__init__(self, options)
-
- # FIXME: This is a hack to map between the old port names and the new port names.
- def _new_port_name_from_old(self, port_name, platform):
- # The new port system has no concept of xvfb yet.
- if port_name == 'chromium-xvfb':
- return 'chromium'
- return port_name
-
- def begin_work_queue(self):
- AbstractPatchQueue.begin_work_queue(self)
- if not self.port_name:
- return
- # FIXME: This is only used for self._deprecated_port.flag()
- self._deprecated_port = DeprecatedPort.port(self.port_name)
- # FIXME: This violates abstraction
- self._tool._deprecated_port = self._deprecated_port
- self._port = self._tool.port_factory.get(self._new_port_name_from_old(self.port_name, self._tool.platform))
-
- def _upload_results_archive_for_patch(self, patch, results_archive_zip):
- if not self._port:
- self._port = self._tool.port_factory.get(self._new_port_name_from_old(self.port_name, self._tool.platform))
-
- bot_id = self._tool.status_server.bot_id or "bot"
- description = "Archive of layout-test-results from %s for %s" % (bot_id, self._port.name())
- # results_archive is a ZipFile object, grab the File object (.fp) to pass to Mechanize for uploading.
- results_archive_file = results_archive_zip.fp
- # Rewind the file object to start (since Mechanize won't do that automatically)
- # See https://bugs.webkit.org/show_bug.cgi?id=54593
- results_archive_file.seek(0)
- # FIXME: This is a small lie to always say run-webkit-tests since Chromium uses new-run-webkit-tests.
- # We could make this code look up the test script name off the port.
- comment_text = "The attached test failures were seen while running run-webkit-tests on the %s.\n" % (self.name)
- # FIXME: We could easily list the test failures from the archive here,
- # currently callers do that separately.
- comment_text += BotInfo(self._tool, self._port.name()).summary_text()
- self._tool.bugs.add_attachment_to_bug(patch.bug_id(), results_archive_file, description, filename="layout-test-results.zip", comment_text=comment_text)
-
-
-class CommitQueue(PatchProcessingQueue, StepSequenceErrorHandler, CommitQueueTaskDelegate):
- name = "commit-queue"
- port_name = "chromium-xvfb"
-
- # AbstractPatchQueue methods
-
- def begin_work_queue(self):
- PatchProcessingQueue.begin_work_queue(self)
- self.committer_validator = CommitterValidator(self._tool)
- self._expected_failures = ExpectedFailures()
- self._layout_test_results_reader = LayoutTestResultsReader(self._tool, self._port.results_directory(), self._log_directory())
-
- def next_work_item(self):
- return self._next_patch()
-
- def process_work_item(self, patch):
- self._cc_watchers(patch.bug_id())
- task = CommitQueueTask(self, patch)
- try:
- if task.run():
- self._did_pass(patch)
- return True
- self._did_retry(patch)
- except ScriptError, e:
- validator = CommitterValidator(self._tool)
- validator.reject_patch_from_commit_queue(patch.id(), self._error_message_for_bug(task, patch, e))
- results_archive = task.results_archive_from_patch_test_run(patch)
- if results_archive:
- self._upload_results_archive_for_patch(patch, results_archive)
- self._did_fail(patch)
-
- def _failing_tests_message(self, task, patch):
- results = task.results_from_patch_test_run(patch)
- unexpected_failures = self._expected_failures.unexpected_failures_observed(results)
- if not unexpected_failures:
- return None
- return "New failing tests:\n%s" % "\n".join(unexpected_failures)
-
- def _error_message_for_bug(self, task, patch, script_error):
- message = self._failing_tests_message(task, patch)
- if not message:
- message = script_error.message_with_output()
- results_link = self._tool.status_server.results_url_for_status(task.failure_status_id)
- return "%s\nFull output: %s" % (message, results_link)
-
- def handle_unexpected_error(self, patch, message):
- self.committer_validator.reject_patch_from_commit_queue(patch.id(), message)
-
- # CommitQueueTaskDelegate methods
-
- def run_command(self, command):
- self.run_webkit_patch(command + [self._deprecated_port.flag()])
-
- def command_passed(self, message, patch):
- self._update_status(message, patch=patch)
-
- def command_failed(self, message, script_error, patch):
- failure_log = self._log_from_script_error_for_upload(script_error)
- return self._update_status(message, patch=patch, results_file=failure_log)
-
- def expected_failures(self):
- return self._expected_failures
-
- def test_results(self):
- return self._layout_test_results_reader.results()
-
- def archive_last_test_results(self, patch):
- return self._layout_test_results_reader.archive(patch)
-
- def build_style(self):
- return "release"
-
- def refetch_patch(self, patch):
- return self._tool.bugs.fetch_attachment(patch.id())
-
- def report_flaky_tests(self, patch, flaky_test_results, results_archive=None):
- reporter = FlakyTestReporter(self._tool, self.name)
- reporter.report_flaky_tests(patch, flaky_test_results, results_archive)
-
- def did_pass_testing_ews(self, patch):
- # Currently, chromium-ews is the only testing EWS. Once there are more,
- # should make sure they all pass.
- status = self._tool.status_server.patch_status("chromium-ews", patch.id())
- return status == self._pass_status
-
- # StepSequenceErrorHandler methods
-
- @classmethod
- def handle_script_error(cls, tool, state, script_error):
- # Hitting this error handler should be pretty rare. It does occur,
- # however, when a patch no longer applies to top-of-tree in the final
- # land step.
- _log.error(script_error.message_with_output())
-
- @classmethod
- def handle_checkout_needs_update(cls, tool, state, options, error):
- message = "Tests passed, but commit failed (checkout out of date). Updating, then landing without building or re-running tests."
- tool.status_server.update_status(cls.name, message, state["patch"])
- # The only time when we find out that out checkout needs update is
- # when we were ready to actually pull the trigger and land the patch.
- # Rather than spinning in the master process, we retry without
- # building or testing, which is much faster.
- options.build = False
- options.test = False
- options.update = True
- raise TryAgain()
-
-
-class AbstractReviewQueue(PatchProcessingQueue, StepSequenceErrorHandler):
- """This is the base-class for the EWS queues and the style-queue."""
- def __init__(self, options=None):
- PatchProcessingQueue.__init__(self, options)
-
- def review_patch(self, patch):
- raise NotImplementedError("subclasses must implement")
-
- # AbstractPatchQueue methods
-
- def begin_work_queue(self):
- PatchProcessingQueue.begin_work_queue(self)
-
- def next_work_item(self):
- return self._next_patch()
-
- def process_work_item(self, patch):
- try:
- if not self.review_patch(patch):
- return False
- self._did_pass(patch)
- return True
- except ScriptError, e:
- if e.exit_code != QueueEngine.handled_error_code:
- self._did_fail(patch)
- else:
- # The subprocess handled the error, but won't have released the patch, so we do.
- # FIXME: We need to simplify the rules by which _release_work_item is called.
- self._release_work_item(patch)
- raise e
-
- def handle_unexpected_error(self, patch, message):
- _log.error(message)
-
- # StepSequenceErrorHandler methods
-
- @classmethod
- def handle_script_error(cls, tool, state, script_error):
- _log.error(script_error.output)
-
-
-class StyleQueue(AbstractReviewQueue, StyleQueueTaskDelegate):
- name = "style-queue"
-
- def __init__(self):
- AbstractReviewQueue.__init__(self)
-
- def review_patch(self, patch):
- task = StyleQueueTask(self, patch)
- if not task.validate():
- self._did_error(patch, "%s did not process patch." % self.name)
- return False
- try:
- return task.run()
- except UnableToApplyPatch, e:
- self._did_error(patch, "%s unable to apply patch." % self.name)
- return False
- except ScriptError, e:
- message = "Attachment %s did not pass %s:\n\n%s\n\nIf any of these errors are false positives, please file a bug against check-webkit-style." % (patch.id(), self.name, e.output)
- self._tool.bugs.post_comment_to_bug(patch.bug_id(), message, cc=self.watchers)
- self._did_fail(patch)
- return False
- return True
-
- # StyleQueueTaskDelegate methods
-
- def run_command(self, command):
- self.run_webkit_patch(command)
-
- def command_passed(self, message, patch):
- self._update_status(message, patch=patch)
-
- def command_failed(self, message, script_error, patch):
- failure_log = self._log_from_script_error_for_upload(script_error)
- return self._update_status(message, patch=patch, results_file=failure_log)
-
- def expected_failures(self):
- return None
-
- def refetch_patch(self, patch):
- return self._tool.bugs.fetch_attachment(patch.id())
diff --git a/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py b/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py
deleted file mode 100644
index 929f83e..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py
+++ /dev/null
@@ -1,509 +0,0 @@
-# Copyright (C) 2009 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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 os
-import StringIO
-
-from webkitpy.common.checkout.scm import CheckoutNeedsUpdate
-from webkitpy.common.checkout.scm.scm_mock import MockSCM
-from webkitpy.common.net.bugzilla import Attachment
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.layout_tests.models import test_results
-from webkitpy.layout_tests.models import test_failures
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.commands.queues import *
-from webkitpy.tool.commands.queuestest import QueuesTest
-from webkitpy.tool.commands.stepsequence import StepSequence
-from webkitpy.common.net.statusserver_mock import MockStatusServer
-from webkitpy.tool.mocktool import MockTool, MockOptions
-
-
-class TestCommitQueue(CommitQueue):
- def __init__(self, tool=None):
- CommitQueue.__init__(self)
- if tool:
- self.bind_to_tool(tool)
- self._options = MockOptions(confirm=False, parent_command="commit-queue", port=None)
-
- def begin_work_queue(self):
- output_capture = OutputCapture()
- output_capture.capture_output()
- CommitQueue.begin_work_queue(self)
- output_capture.restore_output()
-
-
-class TestQueue(AbstractPatchQueue):
- name = "test-queue"
-
-
-class TestReviewQueue(AbstractReviewQueue):
- name = "test-review-queue"
-
-
-class TestFeederQueue(FeederQueue):
- _sleep_duration = 0
-
-
-class AbstractQueueTest(CommandsTest):
- def test_log_directory(self):
- self.assertEqual(TestQueue()._log_directory(), os.path.join("..", "test-queue-logs"))
-
- def _assert_run_webkit_patch(self, run_args, port=None):
- queue = TestQueue()
- tool = MockTool()
- tool.status_server.bot_id = "gort"
- tool.executive = Mock()
- queue.bind_to_tool(tool)
- queue._options = Mock()
- queue._options.port = port
-
- queue.run_webkit_patch(run_args)
- expected_run_args = ["echo", "--status-host=example.com", "--bot-id=gort"]
- if port:
- expected_run_args.append("--port=%s" % port)
- expected_run_args.extend(run_args)
- tool.executive.run_command.assert_called_with(expected_run_args, cwd='/mock-checkout')
-
- def test_run_webkit_patch(self):
- self._assert_run_webkit_patch([1])
- self._assert_run_webkit_patch(["one", 2])
- self._assert_run_webkit_patch([1], port="mockport")
-
- def test_iteration_count(self):
- queue = TestQueue()
- queue._options = Mock()
- queue._options.iterations = 3
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertFalse(queue.should_continue_work_queue())
-
- def test_no_iteration_count(self):
- queue = TestQueue()
- queue._options = Mock()
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
-
- def _assert_log_message(self, script_error, log_message):
- failure_log = AbstractQueue._log_from_script_error_for_upload(script_error, output_limit=10)
- self.assertTrue(failure_log.read(), log_message)
-
- def test_log_from_script_error_for_upload(self):
- self._assert_log_message(ScriptError("test"), "test")
- unicode_tor = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
- utf8_tor = unicode_tor.encode("utf-8")
- self._assert_log_message(ScriptError(unicode_tor), utf8_tor)
- script_error = ScriptError(unicode_tor, output=unicode_tor)
- expected_output = "%s\nLast %s characters of output:\n%s" % (utf8_tor, 10, utf8_tor[-10:])
- self._assert_log_message(script_error, expected_output)
-
-
-class FeederQueueTest(QueuesTest):
- def test_feeder_queue(self):
- queue = TestFeederQueue()
- tool = MockTool(log_executive=True)
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("feeder-queue"),
- "process_work_item": """Warning, attachment 10001 on bug 50000 has invalid committer (non-committer@example.com)
-Warning, attachment 10001 on bug 50000 has invalid committer (non-committer@example.com)
-MOCK setting flag 'commit-queue' to '-' on attachment '10001' with comment 'Rejecting attachment 10001 from commit-queue.\n\nnon-committer@example.com does not have committer permissions according to http://trac.webkit.org/browser/trunk/Tools/Scripts/webkitpy/common/config/committers.py.
-
-- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.
-
-- If you have committer rights please correct the error in Tools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed). The commit-queue restarts itself every 2 hours. After restart the commit-queue will correctly respect your committer rights.'
-MOCK: update_work_items: commit-queue [10005, 10000]
-Feeding commit-queue items [10005, 10000]
-Feeding EWS (1 r? patch, 1 new)
-MOCK: submit_to_ews: 10002
-""",
- "handle_unexpected_error": "Mock error message\n",
- }
- self.assert_queue_outputs(queue, tool=tool, expected_logs=expected_logs)
-
-
-class AbstractPatchQueueTest(CommandsTest):
- def test_next_patch(self):
- queue = AbstractPatchQueue()
- tool = MockTool()
- queue.bind_to_tool(tool)
- queue._options = Mock()
- queue._options.port = None
- self.assertIsNone(queue._next_patch())
- tool.status_server = MockStatusServer(work_items=[2, 10000, 10001])
- expected_stdout = "MOCK: fetch_attachment: 2 is not a known attachment id\n" # A mock-only message to prevent us from making mistakes.
- expected_logs = "MOCK: release_work_item: None 2\n"
- patch = OutputCapture().assert_outputs(self, queue._next_patch, expected_stdout=expected_stdout, expected_logs=expected_logs)
- # The patch.id() == 2 is ignored because it doesn't exist.
- self.assertEqual(patch.id(), 10000)
- self.assertEqual(queue._next_patch().id(), 10001)
- self.assertEqual(queue._next_patch(), None) # When the queue is empty
-
-
-class PatchProcessingQueueTest(CommandsTest):
- def test_upload_results_archive_for_patch(self):
- queue = PatchProcessingQueue()
- queue.name = "mock-queue"
- tool = MockTool()
- queue.bind_to_tool(tool)
- queue._options = Mock()
- queue._options.port = None
- patch = queue._tool.bugs.fetch_attachment(10001)
- expected_logs = """MOCK add_attachment_to_bug: bug_id=50000, description=Archive of layout-test-results from bot for chromium-mac-snowleopard filename=layout-test-results.zip mimetype=None
--- Begin comment --
-The attached test failures were seen while running run-webkit-tests on the mock-queue.
-Port: chromium-mac-snowleopard Platform: MockPlatform 1.0
--- End comment --
-"""
- OutputCapture().assert_outputs(self, queue._upload_results_archive_for_patch, [patch, Mock()], expected_logs=expected_logs)
-
-
-class NeedsUpdateSequence(StepSequence):
- def _run(self, tool, options, state):
- raise CheckoutNeedsUpdate([], 1, "", None)
-
-
-class AlwaysCommitQueueTool(object):
- def __init__(self):
- self.status_server = MockStatusServer()
-
- def command_by_name(self, name):
- return CommitQueue
-
-
-class SecondThoughtsCommitQueue(TestCommitQueue):
- def __init__(self, tool=None):
- self._reject_patch = False
- TestCommitQueue.__init__(self, tool)
-
- def run_command(self, command):
- # We want to reject the patch after the first validation,
- # so wait to reject it until after some other command has run.
- self._reject_patch = True
- return CommitQueue.run_command(self, command)
-
- def refetch_patch(self, patch):
- if not self._reject_patch:
- return self._tool.bugs.fetch_attachment(patch.id())
-
- attachment_dictionary = {
- "id": patch.id(),
- "bug_id": patch.bug_id(),
- "name": "Rejected",
- "is_obsolete": True,
- "is_patch": False,
- "review": "-",
- "reviewer_email": "foo@bar.com",
- "commit-queue": "-",
- "committer_email": "foo@bar.com",
- "attacher_email": "Contributer1",
- }
- return Attachment(attachment_dictionary, None)
-
-
-class CommitQueueTest(QueuesTest):
- def _mock_test_result(self, testname):
- return test_results.TestResult(testname, [test_failures.FailureTextMismatch()])
-
- def test_commit_queue(self):
- tool = MockTool()
- tool.filesystem.write_text_file('/tmp/layout-test-results/full_results.json', '') # Otherwise the commit-queue will hit a KeyError trying to read the results from the MockFileSystem.
- tool.filesystem.write_text_file('/tmp/layout-test-results/webkit_unit_tests_output.xml', '')
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("commit-queue"),
- "process_work_item": """Running: webkit-patch --status-host=example.com clean --port=chromium-xvfb
-MOCK: update_status: commit-queue Cleaned working directory
-Running: webkit-patch --status-host=example.com update --port=chromium-xvfb
-MOCK: update_status: commit-queue Updated working directory
-Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000 --port=chromium-xvfb
-MOCK: update_status: commit-queue Applied patch
-Running: webkit-patch --status-host=example.com validate-changelog --non-interactive 10000 --port=chromium-xvfb
-MOCK: update_status: commit-queue ChangeLog validated
-Running: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=release --port=chromium-xvfb
-MOCK: update_status: commit-queue Built patch
-Running: webkit-patch --status-host=example.com build-and-test --no-clean --no-update --test --non-interactive --port=chromium-xvfb
-MOCK: update_status: commit-queue Passed tests
-Running: webkit-patch --status-host=example.com land-attachment --force-clean --non-interactive --parent-command=commit-queue 10000 --port=chromium-xvfb
-MOCK: update_status: commit-queue Landed patch
-MOCK: update_status: commit-queue Pass
-MOCK: release_work_item: commit-queue 10000
-""",
- "handle_script_error": "ScriptError error message\n\nMOCK output\n",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '10000' with comment 'Rejecting attachment 10000 from commit-queue.\n\nMock error message'\n",
- }
- self.assert_queue_outputs(CommitQueue(), tool=tool, expected_logs=expected_logs)
-
- def test_commit_queue_failure(self):
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("commit-queue"),
- "process_work_item": """MOCK: update_status: commit-queue Cleaned working directory
-MOCK: update_status: commit-queue Updated working directory
-MOCK: update_status: commit-queue Patch does not apply
-MOCK setting flag 'commit-queue' to '-' on attachment '10000' with comment 'Rejecting attachment 10000 from commit-queue.\n\nMOCK script error
-Full output: http://dummy_url'
-MOCK: update_status: commit-queue Fail
-MOCK: release_work_item: commit-queue 10000
-""",
- "handle_script_error": "ScriptError error message\n\nMOCK output\n",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '10000' with comment 'Rejecting attachment 10000 from commit-queue.\n\nMock error message'\n",
- }
- queue = CommitQueue()
-
- def mock_run_webkit_patch(command):
- if command[0] == 'clean' or command[0] == 'update':
- # We want cleaning to succeed so we can error out on a step
- # that causes the commit-queue to reject the patch.
- return
- raise ScriptError('MOCK script error')
-
- queue.run_webkit_patch = mock_run_webkit_patch
- self.assert_queue_outputs(queue, expected_logs=expected_logs)
-
- def test_commit_queue_failure_with_failing_tests(self):
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("commit-queue"),
- "process_work_item": """MOCK: update_status: commit-queue Cleaned working directory
-MOCK: update_status: commit-queue Updated working directory
-MOCK: update_status: commit-queue Patch does not apply
-MOCK setting flag 'commit-queue' to '-' on attachment '10000' with comment 'Rejecting attachment 10000 from commit-queue.\n\nNew failing tests:
-mock_test_name.html
-another_test_name.html
-Full output: http://dummy_url'
-MOCK: update_status: commit-queue Fail
-MOCK: release_work_item: commit-queue 10000
-""",
- "handle_script_error": "ScriptError error message\n\nMOCK output\n",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '10000' with comment 'Rejecting attachment 10000 from commit-queue.\n\nMock error message'\n",
- }
- queue = CommitQueue()
-
- def mock_run_webkit_patch(command):
- if command[0] == 'clean' or command[0] == 'update':
- # We want cleaning to succeed so we can error out on a step
- # that causes the commit-queue to reject the patch.
- return
- queue._expected_failures.unexpected_failures_observed = lambda results: ["mock_test_name.html", "another_test_name.html"]
- raise ScriptError('MOCK script error')
-
- queue.run_webkit_patch = mock_run_webkit_patch
- self.assert_queue_outputs(queue, expected_logs=expected_logs)
-
- def test_rollout(self):
- tool = MockTool()
- tool.filesystem.write_text_file('/tmp/layout-test-results/full_results.json', '') # Otherwise the commit-queue will hit a KeyError trying to read the results from the MockFileSystem.
- tool.filesystem.write_text_file('/tmp/layout-test-results/webkit_unit_tests_output.xml', '')
- tool.buildbot.light_tree_on_fire()
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("commit-queue"),
- "process_work_item": """Running: webkit-patch --status-host=example.com clean --port=%(port)s
-MOCK: update_status: commit-queue Cleaned working directory
-Running: webkit-patch --status-host=example.com update --port=%(port)s
-MOCK: update_status: commit-queue Updated working directory
-Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000 --port=%(port)s
-MOCK: update_status: commit-queue Applied patch
-Running: webkit-patch --status-host=example.com validate-changelog --non-interactive 10000 --port=%(port)s
-MOCK: update_status: commit-queue ChangeLog validated
-Running: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=release --port=%(port)s
-MOCK: update_status: commit-queue Built patch
-Running: webkit-patch --status-host=example.com build-and-test --no-clean --no-update --test --non-interactive --port=%(port)s
-MOCK: update_status: commit-queue Passed tests
-Running: webkit-patch --status-host=example.com land-attachment --force-clean --non-interactive --parent-command=commit-queue 10000 --port=%(port)s
-MOCK: update_status: commit-queue Landed patch
-MOCK: update_status: commit-queue Pass
-MOCK: release_work_item: commit-queue 10000
-""" % {"port": CommitQueue.port_name},
- "handle_script_error": "ScriptError error message\n\nMOCK output\n",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '10000' with comment 'Rejecting attachment 10000 from commit-queue.\n\nMock error message'\n",
- }
- self.assert_queue_outputs(CommitQueue(), tool=tool, expected_logs=expected_logs)
-
- def test_rollout_lands(self):
- tool = MockTool()
- tool.buildbot.light_tree_on_fire()
- rollout_patch = tool.bugs.fetch_attachment(10005) # _patch6, a rollout patch.
- assert(rollout_patch.is_rollout())
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("commit-queue"),
- "process_work_item": """Running: webkit-patch --status-host=example.com clean --port=%(port)s
-MOCK: update_status: commit-queue Cleaned working directory
-Running: webkit-patch --status-host=example.com update --port=%(port)s
-MOCK: update_status: commit-queue Updated working directory
-Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10005 --port=%(port)s
-MOCK: update_status: commit-queue Applied patch
-Running: webkit-patch --status-host=example.com validate-changelog --non-interactive 10005 --port=%(port)s
-MOCK: update_status: commit-queue ChangeLog validated
-Running: webkit-patch --status-host=example.com land-attachment --force-clean --non-interactive --parent-command=commit-queue 10005 --port=%(port)s
-MOCK: update_status: commit-queue Landed patch
-MOCK: update_status: commit-queue Pass
-MOCK: release_work_item: commit-queue 10005
-""" % {"port": CommitQueue.port_name},
- "handle_script_error": "ScriptError error message\n\nMOCK output\n",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '10005' with comment 'Rejecting attachment 10005 from commit-queue.\n\nMock error message'\n",
- }
- self.assert_queue_outputs(CommitQueue(), tool=tool, work_item=rollout_patch, expected_logs=expected_logs)
-
- def test_auto_retry(self):
- queue = CommitQueue()
- options = Mock()
- options.parent_command = "commit-queue"
- tool = AlwaysCommitQueueTool()
- sequence = NeedsUpdateSequence(None)
-
- expected_logs = """Commit failed because the checkout is out of date. Please update and try again.
-MOCK: update_status: commit-queue Tests passed, but commit failed (checkout out of date). Updating, then landing without building or re-running tests.
-"""
- state = {'patch': None}
- OutputCapture().assert_outputs(self, sequence.run_and_handle_errors, [tool, options, state], expected_exception=TryAgain, expected_logs=expected_logs)
-
- self.assertTrue(options.update)
- self.assertFalse(options.build)
- self.assertFalse(options.test)
-
- def test_manual_reject_during_processing(self):
- queue = SecondThoughtsCommitQueue(MockTool())
- queue.begin_work_queue()
- queue._tool.filesystem.write_text_file('/tmp/layout-test-results/full_results.json', '') # Otherwise the commit-queue will hit a KeyError trying to read the results from the MockFileSystem.
- queue._tool.filesystem.write_text_file('/tmp/layout-test-results/webkit_unit_tests_output.xml', '')
- queue._options = Mock()
- queue._options.port = None
- expected_logs = """Running: webkit-patch --status-host=example.com clean --port=chromium-xvfb
-MOCK: update_status: commit-queue Cleaned working directory
-Running: webkit-patch --status-host=example.com update --port=chromium-xvfb
-MOCK: update_status: commit-queue Updated working directory
-Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000 --port=chromium-xvfb
-MOCK: update_status: commit-queue Applied patch
-Running: webkit-patch --status-host=example.com validate-changelog --non-interactive 10000 --port=chromium-xvfb
-MOCK: update_status: commit-queue ChangeLog validated
-Running: webkit-patch --status-host=example.com build --no-clean --no-update --build-style=release --port=chromium-xvfb
-MOCK: update_status: commit-queue Built patch
-Running: webkit-patch --status-host=example.com build-and-test --no-clean --no-update --test --non-interactive --port=chromium-xvfb
-MOCK: update_status: commit-queue Passed tests
-MOCK: update_status: commit-queue Retry
-MOCK: release_work_item: commit-queue 10000
-"""
- OutputCapture().assert_outputs(self, queue.process_work_item, [QueuesTest.mock_work_item], expected_logs=expected_logs)
-
- def test_report_flaky_tests(self):
- queue = TestCommitQueue(MockTool())
- expected_logs = """MOCK bug comment: bug_id=50002, cc=None
---- Begin comment ---
-The commit-queue just saw foo/bar.html flake (text diff) while processing attachment 10000 on bug 50000.
-Port: MockPort Platform: MockPlatform 1.0
---- End comment ---
-
-MOCK add_attachment_to_bug: bug_id=50002, description=Failure diff from bot filename=failure.diff mimetype=None
-MOCK bug comment: bug_id=50002, cc=None
---- Begin comment ---
-The commit-queue just saw bar/baz.html flake (text diff) while processing attachment 10000 on bug 50000.
-Port: MockPort Platform: MockPlatform 1.0
---- End comment ---
-
-bar/baz-diffs.txt does not exist in results archive, uploading entire archive.
-MOCK add_attachment_to_bug: bug_id=50002, description=Archive of layout-test-results from bot filename=layout-test-results.zip mimetype=None
-MOCK bug comment: bug_id=50000, cc=None
---- Begin comment ---
-The commit-queue encountered the following flaky tests while processing attachment 10000:
-
-foo/bar.html bug 50002 (author: abarth@webkit.org)
-bar/baz.html bug 50002 (author: abarth@webkit.org)
-The commit-queue is continuing to process your patch.
---- End comment ---
-
-"""
- test_names = ["foo/bar.html", "bar/baz.html"]
- test_results = [self._mock_test_result(name) for name in test_names]
-
- class MockZipFile(object):
- def __init__(self):
- self.fp = StringIO()
-
- def read(self, path):
- return ""
-
- def namelist(self):
- # This is intentionally missing one diffs.txt to exercise the "upload the whole zip" codepath.
- return ['foo/bar-diffs.txt']
-
- OutputCapture().assert_outputs(self, queue.report_flaky_tests, [QueuesTest.mock_work_item, test_results, MockZipFile()], expected_logs=expected_logs)
-
- def test_did_pass_testing_ews(self):
- tool = MockTool()
- patch = tool.bugs.fetch_attachment(10000)
- queue = TestCommitQueue(tool)
- self.assertFalse(queue.did_pass_testing_ews(patch))
-
-
-class StyleQueueTest(QueuesTest):
- def test_style_queue_with_style_exception(self):
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("style-queue"),
- "process_work_item": """Running: webkit-patch --status-host=example.com clean
-MOCK: update_status: style-queue Cleaned working directory
-Running: webkit-patch --status-host=example.com update
-MOCK: update_status: style-queue Updated working directory
-Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000
-MOCK: update_status: style-queue Applied patch
-Running: webkit-patch --status-host=example.com apply-watchlist-local 50000
-MOCK: update_status: style-queue Watchlist applied
-Running: webkit-patch --status-host=example.com check-style-local --non-interactive --quiet
-MOCK: update_status: style-queue Style checked
-MOCK: update_status: style-queue Pass
-MOCK: release_work_item: style-queue 10000
-""",
- "handle_unexpected_error": "Mock error message\n",
- "handle_script_error": "MOCK output\n",
- }
- tool = MockTool(executive_throws_when_run=set(['check-style']))
- self.assert_queue_outputs(StyleQueue(), expected_logs=expected_logs, tool=tool)
-
- def test_style_queue_with_watch_list_exception(self):
- expected_logs = {
- "begin_work_queue": self._default_begin_work_queue_logs("style-queue"),
- "process_work_item": """Running: webkit-patch --status-host=example.com clean
-MOCK: update_status: style-queue Cleaned working directory
-Running: webkit-patch --status-host=example.com update
-MOCK: update_status: style-queue Updated working directory
-Running: webkit-patch --status-host=example.com apply-attachment --no-update --non-interactive 10000
-MOCK: update_status: style-queue Applied patch
-Running: webkit-patch --status-host=example.com apply-watchlist-local 50000
-Exception for ['echo', '--status-host=example.com', 'apply-watchlist-local', 50000]
-
-MOCK command output
-MOCK: update_status: style-queue Unabled to apply watchlist
-Running: webkit-patch --status-host=example.com check-style-local --non-interactive --quiet
-MOCK: update_status: style-queue Style checked
-MOCK: update_status: style-queue Pass
-MOCK: release_work_item: style-queue 10000
-""",
- "handle_unexpected_error": "Mock error message\n",
- "handle_script_error": "MOCK output\n",
- }
- tool = MockTool(executive_throws_when_run=set(['apply-watchlist-local']))
- self.assert_queue_outputs(StyleQueue(), expected_logs=expected_logs, tool=tool)
diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
index c6c4d2a..a2f3b03 100644
--- a/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
+++ b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
@@ -196,6 +196,7 @@
else:
results_url = self._results_url(options.builder)
self._baseline_suffix_list = options.suffixes.split(',')
+
for suffix in self._baseline_suffix_list:
self._rebaseline_test(options.builder, options.test, options.move_overwritten_baselines_to, suffix, results_url)
self._scm_changes['remove-lines'].append({'builder': options.builder, 'test': options.test})
@@ -306,24 +307,26 @@
builders_to_fallback_paths[builder] = fallback_path
return builders_to_fallback_paths.keys()
- def _rebaseline_commands(self, test_list, options):
-
+ def _rebaseline_commands(self, test_prefix_list, options):
path_to_webkit_patch = self._tool.path()
cwd = self._tool.scm().checkout_root
commands = []
- for test in test_list:
- for builder in self._builders_to_fetch_from(test_list[test]):
- suffixes = ','.join(test_list[test][builder])
- cmd_line = [path_to_webkit_patch, 'rebaseline-test-internal', '--suffixes', suffixes, '--builder', builder, '--test', test]
- if options.move_overwritten_baselines:
- move_overwritten_baselines_to = builders.move_overwritten_baselines_to(builder)
- for platform in move_overwritten_baselines_to:
- cmd_line.extend(['--move-overwritten-baselines-to', platform])
- if options.results_directory:
- cmd_line.extend(['--results-directory', options.results_directory])
- if options.verbose:
- cmd_line.append('--verbose')
- commands.append(tuple([cmd_line, cwd]))
+ port = self._tool.port_factory.get()
+
+ for test_prefix in test_prefix_list:
+ for test in port.tests([test_prefix]):
+ for builder in self._builders_to_fetch_from(test_prefix_list[test_prefix]):
+ suffixes = ','.join(test_prefix_list[test_prefix][builder])
+ cmd_line = [path_to_webkit_patch, 'rebaseline-test-internal', '--suffixes', suffixes, '--builder', builder, '--test', test]
+ if options.move_overwritten_baselines:
+ move_overwritten_baselines_to = builders.move_overwritten_baselines_to(builder)
+ for platform in move_overwritten_baselines_to:
+ cmd_line.extend(['--move-overwritten-baselines-to', platform])
+ if options.results_directory:
+ cmd_line.extend(['--results-directory', options.results_directory])
+ if options.verbose:
+ cmd_line.append('--verbose')
+ commands.append(tuple([cmd_line, cwd]))
return commands
def _files_to_add(self, command_results):
@@ -353,12 +356,12 @@
return list(files_to_add), lines_to_remove
- def _optimize_baselines(self, test_list, verbose=False):
+ def _optimize_baselines(self, test_prefix_list, verbose=False):
# We don't run this in parallel because modifying the SCM in parallel is unreliable.
- for test in test_list:
+ for test in test_prefix_list:
all_suffixes = set()
- for builder in self._builders_to_fetch_from(test_list[test]):
- all_suffixes.update(test_list[test][builder])
+ for builder in self._builders_to_fetch_from(test_prefix_list[test]):
+ all_suffixes.update(test_prefix_list[test][builder])
# FIXME: We should propagate the platform options as well.
self._run_webkit_patch(['optimize-baselines', '--suffixes', ','.join(all_suffixes), test], verbose)
@@ -373,13 +376,13 @@
expectationsString = expectations.remove_configuration_from_test(test, test_configuration)
self._tool.filesystem.write_text_file(path, expectationsString)
- def _rebaseline(self, options, test_list):
- for test, builders_to_check in sorted(test_list.items()):
+ def _rebaseline(self, options, test_prefix_list):
+ for test, builders_to_check in sorted(test_prefix_list.items()):
_log.info("Rebaselining %s" % test)
for builder, suffixes in sorted(builders_to_check.items()):
_log.debug(" %s: %s" % (builder, ",".join(suffixes)))
- commands = self._rebaseline_commands(test_list, options)
+ commands = self._rebaseline_commands(test_prefix_list, options)
command_results = self._tool.executive.run_in_parallel(commands)
log_output = '\n'.join(result[2] for result in command_results).replace('\n\n', '\n')
for line in log_output.split('\n'):
@@ -392,7 +395,7 @@
self._update_expectations_files(lines_to_remove)
if options.optimize:
- self._optimize_baselines(test_list, options.verbose)
+ self._optimize_baselines(test_prefix_list, options.verbose)
class RebaselineJson(AbstractParallelRebaselineCommand):
@@ -419,7 +422,7 @@
self.move_overwritten_baselines_option,
self.no_optimize_option,
] + self.platform_options)
- self._test_list = None
+ self._test_prefix_list = None
def _tests_to_rebaseline(self, port):
tests_to_rebaseline = {}
@@ -439,21 +442,21 @@
for test_name, suffixes in tests:
_log.info(" %s (%s)" % (test_name, ','.join(suffixes)))
- if test_name not in self._test_list:
- self._test_list[test_name] = {}
- self._test_list[test_name][builder_name] = suffixes
+ if test_name not in self._test_prefix_list:
+ self._test_prefix_list[test_name] = {}
+ self._test_prefix_list[test_name][builder_name] = suffixes
def execute(self, options, args, tool):
options.results_directory = None
- self._test_list = {}
+ self._test_prefix_list = {}
port_names = tool.port_factory.all_port_names(options.platform)
for port_name in port_names:
self._add_tests_to_rebaseline_for_port(port_name)
- if not self._test_list:
+ if not self._test_prefix_list:
_log.warning("Did not find any tests marked Rebaseline.")
return
- self._rebaseline(options, self._test_list)
+ self._rebaseline(options, self._test_prefix_list)
class Rebaseline(AbstractParallelRebaselineCommand):
@@ -493,17 +496,17 @@
else:
builders_to_check = self._builders_to_pull_from()
- test_list = {}
+ test_prefix_list = {}
suffixes_to_update = options.suffixes.split(",")
for builder in builders_to_check:
tests = args or self._tests_to_update(builder)
for test in tests:
- if test not in test_list:
- test_list[test] = {}
- test_list[test][builder.name()] = suffixes_to_update
+ if test not in test_prefix_list:
+ test_prefix_list[test] = {}
+ test_prefix_list[test][builder.name()] = suffixes_to_update
if options.verbose:
- _log.debug("rebaseline-json: " + str(test_list))
+ _log.debug("rebaseline-json: " + str(test_prefix_list))
- self._rebaseline(options, test_list)
+ self._rebaseline(options, test_prefix_list)
diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
index c982731..b64746a 100644
--- a/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
+++ b/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -112,15 +112,18 @@
self.assertItemsEqual(self.tool.web.urls_fetched, [self.WEB_PREFIX + '/userscripts/another-test-actual.txt'])
def test_rebaseline_test_with_results_directory(self):
+ self._write("userscripts/another-test.html", "test data")
self._write(self.lion_expectations_path, "Bug(x) [ Mac ] userscripts/another-test.html [ ImageOnlyFailure ]\nbug(z) [ Linux ] userscripts/another-test.html [ ImageOnlyFailure ]\n")
self.options.results_directory = '/tmp'
self.command._rebaseline_test_and_update_expectations(self.options)
self.assertItemsEqual(self.tool.web.urls_fetched, ['file:///tmp/userscripts/another-test-actual.txt'])
def test_rebaseline_reftest(self):
+ self._write("userscripts/another-test.html", "test data")
self._write("userscripts/another-test-expected.html", "generic result")
OutputCapture().assert_outputs(self, self.command._rebaseline_test_and_update_expectations, args=[self.options],
expected_logs="Cannot rebaseline reftest: userscripts/another-test.html\n")
+ self.assertDictEqual(self.command._scm_changes, {'add': [], 'remove-lines': []})
def test_rebaseline_test_and_print_scm_changes(self):
self.command._print_scm_changes = True
@@ -306,6 +309,7 @@
def test_rebaseline_all(self):
options = MockOptions(optimize=True, verbose=True, move_overwritten_baselines=False, results_directory=None)
+ self._write("user-scripts/another-test.html", "Dummy test contents")
self.command._rebaseline(options, {"user-scripts/another-test.html": {"MOCK builder": ["txt", "png"]}})
# Note that we have one run_in_parallel() call followed by a run_command()
@@ -315,6 +319,7 @@
def test_rebaseline_debug(self):
options = MockOptions(optimize=True, verbose=True, move_overwritten_baselines=False, results_directory=None)
+ self._write("user-scripts/another-test.html", "Dummy test contents")
self.command._rebaseline(options, {"user-scripts/another-test.html": {"MOCK builder (Debug)": ["txt", "png"]}})
# Note that we have one run_in_parallel() call followed by a run_command()
@@ -324,6 +329,7 @@
def test_move_overwritten(self):
options = MockOptions(optimize=True, verbose=True, move_overwritten_baselines=True, results_directory=None)
+ self._write("user-scripts/another-test.html", "Dummy test contents")
self.command._rebaseline(options, {"user-scripts/another-test.html": {"MOCK builder": ["txt", "png"]}})
# Note that we have one run_in_parallel() call followed by a run_command()
@@ -333,6 +339,7 @@
def test_no_optimize(self):
options = MockOptions(optimize=False, verbose=True, move_overwritten_baselines=False, results_directory=None)
+ self._write("user-scripts/another-test.html", "Dummy test contents")
self.command._rebaseline(options, {"user-scripts/another-test.html": {"MOCK builder (Debug)": ["txt", "png"]}})
# Note that we have only one run_in_parallel() call
@@ -341,6 +348,7 @@
def test_results_directory(self):
options = MockOptions(optimize=False, verbose=True, move_overwritten_baselines=False, results_directory='/tmp')
+ self._write("user-scripts/another-test.html", "Dummy test contents")
self.command._rebaseline(options, {"user-scripts/another-test.html": {"MOCK builder": ["txt", "png"]}})
# Note that we have only one run_in_parallel() call
@@ -401,24 +409,44 @@
self.command._builders_to_pull_from = lambda: [MockBuilder('MOCK builder')]
self.command._tests_to_update = lambda builder: ['mock/path/to/test.html']
+ self._write("mock/path/to/test.html", "Dummy test contents")
+
self._zero_out_test_expectations()
old_exact_matches = builders._exact_matches
- oc = OutputCapture()
try:
builders._exact_matches = {
"MOCK builder": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
}
- oc.capture_output()
self.command.execute(MockOptions(optimize=False, builders=None, suffixes="txt,png", verbose=True, move_overwritten_baselines=False), [], self.tool)
finally:
- oc.restore_output()
builders._exact_matches = old_exact_matches
calls = filter(lambda x: x != ['qmake', '-v'] and x[0] != 'perl', self.tool.executive.calls)
self.assertEqual(calls,
[[['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'mock/path/to/test.html', '--verbose']]])
+ def test_rebaseline_directory(self):
+ self.command._builders_to_pull_from = lambda: [MockBuilder('MOCK builder')]
+ self.command._tests_to_update = lambda builder: ['userscripts']
+
+ self._write("userscripts/first-test.html", "test data")
+ self._write("userscripts/second-test.html", "test data")
+
+ old_exact_matches = builders._exact_matches
+ try:
+ builders._exact_matches = {
+ "MOCK builder": {"port_name": "test-mac-leopard", "specifiers": set(["mock-specifier"])},
+ }
+ self.command.execute(MockOptions(optimize=False, builders=None, suffixes="txt,png", verbose=True, move_overwritten_baselines=False), [], self.tool)
+ finally:
+ builders._exact_matches = old_exact_matches
+
+ calls = filter(lambda x: x != ['qmake', '-v'] and x[0] != 'perl', self.tool.executive.calls)
+ self.assertEqual(calls,
+ [[['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/first-test.html', '--verbose'],
+ ['echo', 'rebaseline-test-internal', '--suffixes', 'txt,png', '--builder', 'MOCK builder', '--test', 'userscripts/second-test.html', '--verbose']]])
+
class TestRebaselineExpectations(_BaseTestCase):
command_constructor = RebaselineExpectations
@@ -433,6 +461,8 @@
self.tool.executive = MockExecutive2()
+ self._write("userscripts/another-test.html", "Dummy test contents")
+ self._write("userscripts/images.svg", "Dummy test contents")
self.command._tests_to_rebaseline = lambda port: {'userscripts/another-test.html': set(['txt']), 'userscripts/images.svg': set(['png'])}
self.command.execute(self.options, [], self.tool)
diff --git a/Tools/Scripts/webkitpy/tool/commands/roll.py b/Tools/Scripts/webkitpy/tool/commands/roll.py
deleted file mode 100644
index 8237319..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/roll.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# Copyright (c) 2011 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
-
-from webkitpy.tool import steps
-
-
-default_changelog_message = "Unreviewed. Rolled DEPS.\n\n"
-
-class RollChromiumDEPS(AbstractSequencedCommand):
- name = "roll-chromium-deps"
- help_text = "Updates Chromium DEPS (LKGR as the revision will use the last-known good revision of Chromium)"
- argument_names = "CHROMIUM_REVISION"
- steps = [
- steps.UpdateChromiumDEPS,
- steps.PrepareChangeLogForDEPSRoll,
- steps.ConfirmDiff,
- steps.Commit,
- ]
-
- def _prepare_state(self, options, args, tool):
- return {
- "chromium_revision": (args and args[0]),
- "changelog_message": default_changelog_message,
- }
-
-
-class PostChromiumDEPSRoll(AbstractSequencedCommand):
- name = "post-chromium-deps-roll"
- help_text = "Posts a patch to update Chromium DEPS (LKGR as the revision will use the last-known good revision of Chromium)"
- argument_names = "CHROMIUM_REVISION CHROMIUM_REVISION_NAME [CHANGELOG_MESSAGE]"
- steps = [
- steps.CleanWorkingDirectory,
- steps.Update,
- steps.UpdateChromiumDEPS,
- steps.PrepareChangeLogForDEPSRoll,
- steps.CreateBug,
- steps.PostDiff,
- ]
-
- def _prepare_state(self, options, args, tool):
- options.review = False
- options.request_commit = True
-
- chromium_revision = args[0]
- chromium_revision_name = args[1]
- changelog_message = args[2] if len(args) >= 3 else default_changelog_message
- return {
- "chromium_revision": chromium_revision,
- "changelog_message": changelog_message,
- "bug_title": "Roll Chromium DEPS to %s" % chromium_revision_name,
- "bug_description": "A DEPS roll a day keeps the build break away.",
- }
diff --git a/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py b/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py
deleted file mode 100644
index 9e805dd..0000000
--- a/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) 2011 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.commands.roll import *
-from webkitpy.tool.mocktool import MockOptions, MockTool
-
-
-class RollCommandsTest(CommandsTest):
- def test_update_chromium_deps(self):
- expected_logs = """Updating Chromium DEPS to 6764
-MOCK: MockDEPS.write_variable(chromium_rev, 6764)
-MOCK: user.open_url: file://...
-Was that diff correct?
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-"""
- options = MockOptions(non_interactive=False)
- self.assert_execute_outputs(RollChromiumDEPS(), [6764], options=options, expected_logs=expected_logs)
-
- def test_update_chromium_deps_older_revision(self):
- options = MockOptions(non_interactive=False)
- expected_logs = """Current Chromium DEPS revision 6564 is newer than 5764.
-Unable to update Chromium DEPS.
-"""
- self.assert_execute_outputs(RollChromiumDEPS(), [5764], options=options, expected_logs=expected_logs, expected_exception=SystemExit)
-
-
-class PostRollCommandsTest(CommandsTest):
- def test_prepare_state(self):
- postroll = PostChromiumDEPSRoll()
- options = MockOptions()
- tool = MockTool()
- lkgr_state = postroll._prepare_state(options, [None, "last-known good revision"], tool)
- self.assertIsNone(lkgr_state["chromium_revision"])
- self.assertEqual("Roll Chromium DEPS to last-known good revision", lkgr_state["bug_title"])
- self.assertEqual("Unreviewed. Rolled DEPS.\n\n", lkgr_state["changelog_message"])
- revision_state = postroll._prepare_state(options, ["1234", "r1234", "test message"], tool)
- self.assertEqual("1234", revision_state["chromium_revision"])
- self.assertEqual("Roll Chromium DEPS to r1234", revision_state["bug_title"])
- self.assertEqual("test message", revision_state["changelog_message"])
diff --git a/Tools/Scripts/webkitpy/tool/steps/__init__.py b/Tools/Scripts/webkitpy/tool/steps/__init__.py
index 709de5b..96ac98f 100644
--- a/Tools/Scripts/webkitpy/tool/steps/__init__.py
+++ b/Tools/Scripts/webkitpy/tool/steps/__init__.py
@@ -50,7 +50,6 @@
from webkitpy.tool.steps.options import Options
from webkitpy.tool.steps.postdiff import PostDiff
from webkitpy.tool.steps.postdiffforcommit import PostDiffForCommit
-from webkitpy.tool.steps.postdiffforrevert import PostDiffForRevert
from webkitpy.tool.steps.preparechangelog import PrepareChangeLog
from webkitpy.tool.steps.preparechangelogfordepsroll import PrepareChangeLogForDEPSRoll
from webkitpy.tool.steps.preparechangelogforrevert import PrepareChangeLogForRevert
diff --git a/Tools/Scripts/webkitpy/tool/steps/postdiffforrevert.py b/Tools/Scripts/webkitpy/tool/steps/postdiffforrevert.py
deleted file mode 100644
index 2900eb3..0000000
--- a/Tools/Scripts/webkitpy/tool/steps/postdiffforrevert.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2010 Google 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:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
-# OWNER OR 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.
-
-from webkitpy.common.net.bugzilla import Attachment
-from webkitpy.tool.steps.abstractstep import AbstractStep
-
-
-class PostDiffForRevert(AbstractStep):
- def run(self, state):
- comment_text = "Any committer can land this patch automatically by \
-marking it commit-queue+. The commit-queue will build and test \
-the patch before landing to ensure that the rollout will be \
-successful. This process takes approximately 15 minutes.\n\n\
-If you would like to land the rollout faster, you can use the \
-following command:\n\n\
- webkit-patch land-attachment ATTACHMENT_ID\n\n\
-where ATTACHMENT_ID is the ID of this attachment."
- self._tool.bugs.add_patch_to_bug(
- state["bug_id"],
- self.cached_lookup(state, "diff"),
- "%s%s" % (Attachment.rollout_preamble, state["revision"]),
- comment_text=comment_text,
- mark_for_review=False,
- mark_for_commit_queue=True)