Modified: trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py (89197 => 89198)
--- trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py 2011-06-18 19:43:47 UTC (rev 89197)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py 2011-06-18 19:45:43 UTC (rev 89198)
@@ -130,30 +130,6 @@
return self._get_modifier_char(test_name)
# override
- def _convert_json_to_current_version(self, results_json):
- archive_version = None
- if self.VERSION_KEY in results_json:
- archive_version = results_json[self.VERSION_KEY]
-
- super(JSONLayoutResultsGenerator,
- self)._convert_json_to_current_version(results_json)
-
- # version 2->3
- if archive_version == 2:
- for results_for_builder in results_json.itervalues():
- try:
- test_results = results_for_builder[self.TESTS]
- except:
- continue
-
- for test in test_results:
- # Make sure all paths are relative
- test_path = self._get_path_relative_to_layout_test_root(test)
- if test_path != test:
- test_results[test_path] = test_results[test]
- del test_results[test]
-
- # override
def _insert_failure_summaries(self, results_for_builder):
summary = self._result_summary
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py (89197 => 89198)
--- trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py 2011-06-18 19:43:47 UTC (rev 89197)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py 2011-06-18 19:45:43 UTC (rev 89198)
@@ -67,6 +67,33 @@
json_string = _JSON_PREFIX + json_data + _JSON_SUFFIX
filesystem.write_text_file(file_path, json_string)
+
+def convert_trie_to_flat_paths(trie, prefix=None):
+ """Converts the directory structure in the given trie to flat paths, prepending a prefix to each."""
+ result = {}
+ for name, data in trie.iteritems():
+ if prefix:
+ name = prefix + "/" + name
+
+ if not "results" in data:
+ result.update(convert_trie_to_flat_paths(data, name))
+ else:
+ result[name] = data
+
+ return result
+
+
+def add_path_to_trie(path, value, trie):
+ """Inserts a single flat directory path and associated value into a directory trie structure."""
+ if not "/" in path:
+ trie[path] = value
+ return
+
+ directory, slash, rest = path.partition("/")
+ if not directory in trie:
+ trie[directory] = {}
+ add_path_to_trie(rest, value, trie[directory])
+
def test_timings_trie(port, individual_test_timings):
"""Breaks a filename into chunks by directory and puts the test time as a value in the lowest part, e.g.
foo/bar/baz.html: 1ms
@@ -88,16 +115,8 @@
# FIXME: Handle this better. Non-layout tests shouldn't be relativized.
test = test_result.filename
- parts = test.split('/')
- current_map = trie
- for i, part in enumerate(parts):
- if i == (len(parts) - 1):
- current_map[part] = int(1000 * test_result.test_run_time)
- break
+ add_path_to_trie(test, int(1000 * test_result.test_run_time), trie)
- if part not in current_map:
- current_map[part] = {}
- current_map = current_map[part]
return trie
# FIXME: We already have a TestResult class in test_results.py
@@ -153,7 +172,7 @@
TestResult.FAILS: FAIL_RESULT,
TestResult.FLAKY: FLAKY_RESULT}
- VERSION = 3
+ VERSION = 4
VERSION_KEY = "version"
RESULTS = "results"
TIMES = "times"
@@ -271,7 +290,8 @@
# Update the all failing tests with result type and time.
tests = results_for_builder[self.TESTS]
all_failing_tests = self._get_failed_test_names()
- all_failing_tests.update(tests.iterkeys())
+ all_failing_tests.update(convert_trie_to_flat_paths(tests))
+
for test in all_failing_tests:
self._insert_test_time_and_result(test, tests)
@@ -512,6 +532,7 @@
int(time.time()),
self.TIME)
+
def _insert_test_time_and_result(self, test_name, tests):
""" Insert a test item with its results to the given tests dictionary.
@@ -522,32 +543,58 @@
result = self._get_result_char(test_name)
time = self._get_test_timing(test_name)
- if test_name not in tests:
- tests[test_name] = self._create_results_and_times_json()
+ this_test = tests
+ for segment in test_name.split("/"):
+ if segment not in this_test:
+ this_test[segment] = {}
+ this_test = this_test[segment]
- thisTest = tests[test_name]
- if self.RESULTS in thisTest:
- self._insert_item_run_length_encoded(result, thisTest[self.RESULTS])
+ if not len(this_test):
+ self._populate_results_and_times_json(this_test)
+
+ if self.RESULTS in this_test:
+ self._insert_item_run_length_encoded(result, this_test[self.RESULTS])
else:
- thisTest[self.RESULTS] = [[1, result]]
+ this_test[self.RESULTS] = [[1, result]]
- if self.TIMES in thisTest:
- self._insert_item_run_length_encoded(time, thisTest[self.TIMES])
+ if self.TIMES in this_test:
+ self._insert_item_run_length_encoded(time, this_test[self.TIMES])
else:
- thisTest[self.TIMES] = [[1, time]]
+ this_test[self.TIMES] = [[1, time]]
def _convert_json_to_current_version(self, results_json):
"""If the JSON does not match the current version, converts it to the
current version and adds in the new version number.
"""
- if (self.VERSION_KEY in results_json and
- results_json[self.VERSION_KEY] == self.VERSION):
- return
+ if self.VERSION_KEY in results_json:
+ archive_version = results_json[self.VERSION_KEY]
+ if archive_version == self.VERSION:
+ return
+ else:
+ archive_version = 3
+ # version 3->4
+ if archive_version == 3:
+ num_results = len(results_json.values())
+ for builder, results in results_json.iteritems():
+ self._convert_tests_to_trie(results)
+
results_json[self.VERSION_KEY] = self.VERSION
- def _create_results_and_times_json(self):
- results_and_times = {}
+ def _convert_tests_to_trie(self, results):
+ if not self.TESTS in results:
+ return
+
+ test_results = results[self.TESTS]
+ test_results_trie = {}
+ for test in test_results.iterkeys():
+ test_path = self._get_path_relative_to_layout_test_root(test)
+ single_test_result = test_results[test]
+ add_path_to_trie(test_path, single_test_result, test_results_trie)
+
+ results[self.TESTS] = test_results_trie
+
+ def _populate_results_and_times_json(self, results_and_times):
results_and_times[self.RESULTS] = []
results_and_times[self.TIMES] = []
return results_and_times
Modified: trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py (89197 => 89198)
--- trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py 2011-06-18 19:43:47 UTC (rev 89197)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py 2011-06-18 19:45:43 UTC (rev 89198)
@@ -156,8 +156,7 @@
if failed_count_map:
tests = buildinfo[JRG.TESTS]
for test_name in failed_count_map.iterkeys():
- self.assertTrue(test_name in tests)
- test = tests[test_name]
+ test = self._find_test_in_trie(test_name, tests)
failed = 0
for result in test[JRG.RESULTS]:
@@ -174,6 +173,14 @@
if fixable_count:
self.assertEqual(sum(buildinfo[JRG.FIXABLE_COUNT]), fixable_count)
+ def _find_test_in_trie(self, path, trie):
+ nodes = path.split("/")
+ sub_trie = trie
+ for node in nodes:
+ self.assertTrue(node in sub_trie)
+ sub_trie = sub_trie[node]
+ return sub_trie
+
def test_json_generation(self):
self._test_json_generation([], [])
self._test_json_generation(['A1', 'B1'], [])
@@ -197,6 +204,10 @@
['FLAKY_B', 'DISABLED_C', 'FAILS_D'],
['A', 'FLAKY_E'])
+ def test_hierarchical_json_generation(self):
+ # FIXME: Re-work tests to be more comprehensible and comprehensive.
+ self._test_json_generation(['foo/A'], ['foo/B', 'bar/C'])
+
def test_test_timings_trie(self):
test_port = test.TestPort()
individual_test_timings = []