| OLD | NEW |
| 1 # Copyright (C) 2010 Google Inc. All rights reserved. | 1 # Copyright (C) 2010 Google Inc. All rights reserved. |
| 2 # | 2 # |
| 3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
| 5 # met: | 5 # met: |
| 6 # | 6 # |
| 7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | 28 |
| 29 import json | 29 import json |
| 30 import logging | 30 import logging |
| 31 | 31 |
| 32 _log = logging.getLogger(__name__) | 32 _log = logging.getLogger(__name__) |
| 33 | 33 |
| 34 _JSON_PREFIX = "ADD_RESULTS(" | 34 _JSON_PREFIX = 'ADD_RESULTS(' |
| 35 _JSON_SUFFIX = ");" | 35 _JSON_SUFFIX = ');' |
| 36 | 36 |
| 37 | 37 |
| 38 def has_json_wrapper(string): | 38 def has_json_wrapper(string): |
| 39 return string.startswith(_JSON_PREFIX) and string.endswith(_JSON_SUFFIX) | 39 return string.startswith(_JSON_PREFIX) and string.endswith(_JSON_SUFFIX) |
| 40 | 40 |
| 41 | 41 |
| 42 def strip_json_wrapper(json_content): | 42 def strip_json_wrapper(json_content): |
| 43 # FIXME: Kill this code once the server returns json instead of jsonp. | 43 # FIXME: Kill this code once the server returns json instead of jsonp. |
| 44 if has_json_wrapper(json_content): | 44 if has_json_wrapper(json_content): |
| 45 return json_content[len(_JSON_PREFIX):len(json_content) - len(_JSON_SUFF
IX)] | 45 return json_content[len(_JSON_PREFIX):len(json_content) - len(_JSON_SUFF
IX)] |
| 46 return json_content | 46 return json_content |
| 47 | 47 |
| 48 | 48 |
| 49 def load_json(filesystem, file_path): | 49 def load_json(filesystem, file_path): |
| 50 content = filesystem.read_text_file(file_path) | 50 content = filesystem.read_text_file(file_path) |
| 51 content = strip_json_wrapper(content) | 51 content = strip_json_wrapper(content) |
| 52 return json.loads(content) | 52 return json.loads(content) |
| 53 | 53 |
| 54 | 54 |
| 55 def write_json(filesystem, json_object, file_path, callback=None): | 55 def write_json(filesystem, json_object, file_path, callback=None): |
| 56 # Specify separators in order to get compact encoding. | 56 # Specify separators in order to get compact encoding. |
| 57 json_string = json.dumps(json_object, separators=(',', ':')) | 57 json_string = json.dumps(json_object, separators=(',', ':')) |
| 58 if callback: | 58 if callback: |
| 59 json_string = callback + "(" + json_string + ");" | 59 json_string = callback + '(' + json_string + ');' |
| 60 filesystem.write_text_file(file_path, json_string) | 60 filesystem.write_text_file(file_path, json_string) |
| 61 | 61 |
| 62 | 62 |
| 63 def convert_trie_to_flat_paths(trie, prefix=None): | 63 def convert_trie_to_flat_paths(trie, prefix=None): |
| 64 """Converts the directory structure in the given trie to flat paths, prepend
ing a prefix to each.""" | 64 """Converts the directory structure in the given trie to flat paths, prepend
ing a prefix to each.""" |
| 65 result = {} | 65 result = {} |
| 66 for name, data in trie.iteritems(): | 66 for name, data in trie.iteritems(): |
| 67 if prefix: | 67 if prefix: |
| 68 name = prefix + "/" + name | 68 name = prefix + '/' + name |
| 69 | 69 |
| 70 if len(data) and not "results" in data: | 70 if len(data) and not 'results' in data: |
| 71 result.update(convert_trie_to_flat_paths(data, name)) | 71 result.update(convert_trie_to_flat_paths(data, name)) |
| 72 else: | 72 else: |
| 73 result[name] = data | 73 result[name] = data |
| 74 | 74 |
| 75 return result | 75 return result |
| 76 | 76 |
| 77 | 77 |
| 78 def add_path_to_trie(path, value, trie): | 78 def add_path_to_trie(path, value, trie): |
| 79 """Inserts a single flat directory path and associated value into a director
y trie structure.""" | 79 """Inserts a single flat directory path and associated value into a director
y trie structure.""" |
| 80 if not "/" in path: | 80 if not '/' in path: |
| 81 trie[path] = value | 81 trie[path] = value |
| 82 return | 82 return |
| 83 | 83 |
| 84 directory, slash, rest = path.partition("/") | 84 directory, slash, rest = path.partition('/') |
| 85 if not directory in trie: | 85 if not directory in trie: |
| 86 trie[directory] = {} | 86 trie[directory] = {} |
| 87 add_path_to_trie(rest, value, trie[directory]) | 87 add_path_to_trie(rest, value, trie[directory]) |
| 88 | 88 |
| 89 | 89 |
| 90 def test_timings_trie(individual_test_timings): | 90 def test_timings_trie(individual_test_timings): |
| 91 """Breaks a test name into chunks by directory and puts the test time as a v
alue in the lowest part, e.g. | 91 """Breaks a test name into chunks by directory and puts the test time as a v
alue in the lowest part, e.g. |
| 92 foo/bar/baz.html: 1ms | 92 foo/bar/baz.html: 1ms |
| 93 foo/bar/baz1.html: 3ms | 93 foo/bar/baz1.html: 3ms |
| 94 | 94 |
| 95 becomes | 95 becomes |
| 96 foo: { | 96 foo: { |
| 97 bar: { | 97 bar: { |
| 98 baz.html: 1, | 98 baz.html: 1, |
| 99 baz1.html: 3 | 99 baz1.html: 3 |
| 100 } | 100 } |
| 101 } | 101 } |
| 102 """ | 102 """ |
| 103 trie = {} | 103 trie = {} |
| 104 for test_result in individual_test_timings: | 104 for test_result in individual_test_timings: |
| 105 test = test_result.test_name | 105 test = test_result.test_name |
| 106 | 106 |
| 107 add_path_to_trie(test, int(1000 * test_result.test_run_time), trie) | 107 add_path_to_trie(test, int(1000 * test_result.test_run_time), trie) |
| 108 | 108 |
| 109 return trie | 109 return trie |
| 110 | 110 |
| 111 | 111 |
| 112 # FIXME: We already have a TestResult class in test_results.py | 112 # FIXME: We already have a TestResult class in test_results.py |
| 113 class TestResult(object): | 113 class TestResult(object): |
| 114 |
| 114 """A simple class that represents a single test result.""" | 115 """A simple class that represents a single test result.""" |
| 115 | 116 |
| 116 # Test modifier constants. | 117 # Test modifier constants. |
| 117 (NONE, FAILS, FLAKY, DISABLED) = range(4) | 118 (NONE, FAILS, FLAKY, DISABLED) = range(4) |
| 118 | 119 |
| 119 def __init__(self, test, failed=False, elapsed_time=0): | 120 def __init__(self, test, failed=False, elapsed_time=0): |
| 120 self.test_name = test | 121 self.test_name = test |
| 121 self.failed = failed | 122 self.failed = failed |
| 122 self.test_run_time = elapsed_time | 123 self.test_run_time = elapsed_time |
| 123 | 124 |
| 124 test_name = test | 125 test_name = test |
| 125 try: | 126 try: |
| 126 test_name = test.split('.')[1] | 127 test_name = test.split('.')[1] |
| 127 except IndexError: | 128 except IndexError: |
| 128 _log.warn("Invalid test name: %s.", test) | 129 _log.warn('Invalid test name: %s.', test) |
| 129 pass | 130 pass |
| 130 | 131 |
| 131 if test_name.startswith('FAILS_'): | 132 if test_name.startswith('FAILS_'): |
| 132 self.modifier = self.FAILS | 133 self.modifier = self.FAILS |
| 133 elif test_name.startswith('FLAKY_'): | 134 elif test_name.startswith('FLAKY_'): |
| 134 self.modifier = self.FLAKY | 135 self.modifier = self.FLAKY |
| 135 elif test_name.startswith('DISABLED_'): | 136 elif test_name.startswith('DISABLED_'): |
| 136 self.modifier = self.DISABLED | 137 self.modifier = self.DISABLED |
| 137 else: | 138 else: |
| 138 self.modifier = self.NONE | 139 self.modifier = self.NONE |
| 139 | 140 |
| 140 def fixable(self): | 141 def fixable(self): |
| 141 return self.failed or self.modifier == self.DISABLED | 142 return self.failed or self.modifier == self.DISABLED |
| OLD | NEW |