Convert json_results_generator.py to output version 4 JSON.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Jul 2011 22:48:15 +0000 (22:48 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Jul 2011 22:48:15 +0000 (22:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=60869

Patch by Alice Boxhall <aboxhall@chromium.org> on 2011-07-11
Reviewed by Ojan Vafai.

* Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
* Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
* Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@90789 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py

index 7b4227a..21f55ef 100644 (file)
@@ -1,3 +1,14 @@
+2011-07-11  Alice Boxhall  <aboxhall@chromium.org>
+
+        Convert json_results_generator.py to output version 4 JSON.
+        https://bugs.webkit.org/show_bug.cgi?id=60869
+
+        Reviewed by Ojan Vafai.
+
+        * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+        * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+        * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+
 2011-07-11  Martin Robinson  <mrobinson@igalia.com>
 
         [GTK] [NRWT] Pixel tests do not work
index 690b8c9..44310cd 100644 (file)
@@ -125,30 +125,6 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase
         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
 
index e7287ba..bf5e749 100644 (file)
@@ -66,6 +66,33 @@ def write_json(filesystem, json_object, file_path):
     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 len(data) and 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 test name into chunks by directory and puts the test time as a value in the lowest part, e.g.
     foo/bar/baz.html: 1ms
@@ -83,16 +110,8 @@ def test_timings_trie(port, individual_test_timings):
     for test_result in individual_test_timings:
         test = test_result.test_name
 
-        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
@@ -147,7 +166,7 @@ class JSONResultsGeneratorBase(object):
                         TestResult.FAILS: FAIL_RESULT,
                         TestResult.FLAKY: FLAKY_RESULT}
 
-    VERSION = 3
+    VERSION = 4
     VERSION_KEY = "version"
     RESULTS = "results"
     TIMES = "times"
@@ -265,7 +284,8 @@ class JSONResultsGeneratorBase(object):
         # 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)
 
@@ -516,32 +536,57 @@ class JSONResultsGeneratorBase(object):
         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():
+            single_test_result = test_results[test]
+            add_path_to_trie(test, 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
index 51a0755..6adbf94 100644 (file)
@@ -155,8 +155,7 @@ class JSONGeneratorTest(unittest.TestCase):
         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]:
@@ -173,6 +172,14 @@ class JSONGeneratorTest(unittest.TestCase):
         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'], [])
@@ -196,6 +203,10 @@ class JSONGeneratorTest(unittest.TestCase):
             ['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 = []