| Index: scripts/slave/recipe_modules/json/api.py
|
| diff --git a/scripts/slave/recipe_modules/json/api.py b/scripts/slave/recipe_modules/json/api.py
|
| index 487f0320b40f99e22b2ae033e9f992d2b35d6d5b..e891d4b6a4c035a03c7074d36bedf3c4724c8f7e 100644
|
| --- a/scripts/slave/recipe_modules/json/api.py
|
| +++ b/scripts/slave/recipe_modules/json/api.py
|
| @@ -3,13 +3,15 @@
|
| # found in the LICENSE file.
|
|
|
| import functools
|
| +import contextlib
|
| import json
|
| -import os
|
| -import tempfile
|
|
|
| from cStringIO import StringIO
|
|
|
| from slave import recipe_api
|
| +from slave import recipe_util
|
| +
|
| +from .util import TestResults
|
|
|
| class StringListIO(object):
|
| def __init__(self):
|
| @@ -31,55 +33,7 @@ class StringListIO(object):
|
| self.lines[-1] = self.lines[-1].getvalue()
|
|
|
|
|
| -def convert_trie_to_flat_paths(trie, prefix=None):
|
| - # Cloned from webkitpy.layout_tests.layout_package.json_results_generator
|
| - # so that this code can stand alone.
|
| - result = {}
|
| - for name, data in trie.iteritems():
|
| - if prefix:
|
| - name = prefix + "/" + name
|
| -
|
| - if len(data) and not "actual" in data and not "expected" in data:
|
| - result.update(convert_trie_to_flat_paths(data, name))
|
| - else:
|
| - result[name] = data
|
| -
|
| - return result
|
| -
|
| -
|
| -class TestResults(object):
|
| - def __init__(self, jsonish):
|
| - self.raw = jsonish
|
| -
|
| - self.tests = convert_trie_to_flat_paths(jsonish.get('tests', {}))
|
| - self.passes = {}
|
| - self.unexpected_passes = {}
|
| - self.failures = {}
|
| - self.unexpected_failures = {}
|
| - self.flakes = {}
|
| - self.unexpected_flakes = {}
|
| -
|
| - for (test, result) in self.tests.iteritems():
|
| - key = 'unexpected_' if result.get('is_unexpected') else ''
|
| - actual_result = result['actual']
|
| - data = actual_result
|
| - if ' PASS' in actual_result:
|
| - key += 'flakes'
|
| - elif actual_result == 'PASS':
|
| - key += 'passes'
|
| - data = result
|
| - else:
|
| - key += 'failures'
|
| - getattr(self, key)[test] = data
|
| -
|
| - def __getattr__(self, key):
|
| - if key in self.raw:
|
| - return self.raw[key]
|
| - raise AttributeError("'%s' object has no attribute '%s'" %
|
| - (self.__class__, key)) # pragma: no cover
|
| -
|
| -
|
| -class JsonOutputPlaceholder(recipe_api.Placeholder):
|
| +class JsonOutputPlaceholder(recipe_util.Placeholder):
|
| """JsonOutputPlaceholder is meant to be a placeholder object which, when added
|
| to a step's cmd list, will be replaced by annotated_run with the command
|
| parameters --output-json /path/to/file during the evaluation of your recipe
|
| @@ -92,58 +46,36 @@ class JsonOutputPlaceholder(recipe_api.Placeholder):
|
| JSON document, which will be set as the json_output for that step in the
|
| step_history OrderedDict passed to your recipe generator.
|
| """
|
| - # TODO(iannucci): The --output-json was a shortsighted bug. It should be
|
| - # --json-output to generalize to '--<module>-<method>' convention, which is
|
| - # used in multiple places in the recipe ecosystem.
|
| - def __init__(self, name='output', flag='--output-json'):
|
| - self.name = name
|
| - self.flag = flag
|
| - self.output_file = None
|
| + def __init__(self, api):
|
| + self.raw = api.m.raw_io.output('.json')
|
| super(JsonOutputPlaceholder, self).__init__()
|
|
|
| - def render(self, test_data):
|
| - items = [self.flag]
|
| - if test_data is not None:
|
| - items.append('/path/to/tmp/json')
|
| - else: # pragma: no cover
|
| - json_output_fd, self.output_file = tempfile.mkstemp()
|
| - os.close(json_output_fd)
|
| - items.append(self.output_file)
|
| - return items
|
| -
|
| - def step_finished(self, presentation, result_data, test_data):
|
| - assert not hasattr(result_data, self.name)
|
| - if test_data is not None:
|
| - raw_data = json.dumps(test_data.pop(self.name, None))
|
| - else: # pragma: no cover
|
| - assert self.output_file is not None
|
| - with open(self.output_file, 'r') as f:
|
| - raw_data = f.read()
|
| - os.unlink(self.output_file)
|
| + def render(self, test):
|
| + return self.raw.render(test)
|
| +
|
| + def result(self, presentation, test):
|
| + raw_data = self.raw.result(presentation, test)
|
|
|
| valid = False
|
| + ret = None
|
| try:
|
| - setattr(result_data, self.name, json.loads(raw_data))
|
| + ret = json.loads(raw_data)
|
| valid = True
|
| except ValueError: # pragma: no cover
|
| pass
|
|
|
| - key = 'json.' + self.name + ('' if valid else ' (invalid)')
|
| - listio = StringListIO()
|
| - json.dump(getattr(result_data, self.name), listio, indent=2, sort_keys=True)
|
| - listio.close()
|
| + key = self.name + ('' if valid else ' (invalid)')
|
| + with contextlib.closing(StringListIO()) as listio:
|
| + json.dump(ret, listio, indent=2, sort_keys=True)
|
| presentation.logs[key] = listio.lines
|
|
|
| + return ret
|
|
|
| -class TestResultsOutputPlaceholder(JsonOutputPlaceholder):
|
| - def __init__(self):
|
| - super(TestResultsOutputPlaceholder, self).__init__(
|
| - name='test_results', flag='--json-test-results')
|
|
|
| - def step_finished(self, presentation, result_data, test_data):
|
| - super(TestResultsOutputPlaceholder, self).step_finished(
|
| - presentation, result_data, test_data)
|
| - result_data.test_results = TestResults(result_data.test_results)
|
| +class TestResultsOutputPlaceholder(JsonOutputPlaceholder):
|
| + def result(self, presentation, test):
|
| + ret = super(TestResultsOutputPlaceholder, self).result(presentation, test)
|
| + return TestResults(ret)
|
|
|
|
|
| class JsonApi(recipe_api.RecipeApi):
|
| @@ -156,22 +88,23 @@ class JsonApi(recipe_api.RecipeApi):
|
| return json.dumps(*args, **kwargs)
|
| self.dumps = dumps
|
|
|
| + @recipe_util.returns_placeholder
|
| def input(self, data):
|
| """A placeholder which will expand to a file path containing <data>."""
|
| - return recipe_api.InputDataPlaceholder(self.dumps(data), '.json')
|
| + return self.m.raw_io.input(self.dumps(data), '.json')
|
|
|
| - @staticmethod
|
| - def output():
|
| + @recipe_util.returns_placeholder
|
| + def output(self):
|
| """A placeholder which will expand to '--output-json /tmp/file'."""
|
| - return JsonOutputPlaceholder()
|
| + return JsonOutputPlaceholder(self)
|
|
|
| - @staticmethod
|
| - def test_results():
|
| + @recipe_util.returns_placeholder
|
| + def test_results(self):
|
| """A placeholder which will expand to '--json-test-results /tmp/file'.
|
|
|
| The test_results will be an instance of the TestResults class.
|
| """
|
| - return TestResultsOutputPlaceholder()
|
| + return TestResultsOutputPlaceholder(self)
|
|
|
| def property_args(self):
|
| """Return --build-properties and --factory-properties arguments. LEGACY!
|
| @@ -188,4 +121,3 @@ class JsonApi(recipe_api.RecipeApi):
|
| '--factory-properties', prop_str,
|
| '--build-properties', prop_str
|
| ]
|
| -
|
|
|