[Piglit] [PATCH 03/26] framework/results.py: add TestrunResult.from_dict method
Dylan Baker
baker.dylan.c at gmail.com
Fri Sep 11 15:55:29 PDT 2015
This allows us to easily restore from json serialization, it also
removes the type hint that we've added in the to_json method.
Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
---
framework/backends/json.py | 28 +++++++++++------
framework/results.py | 32 +++++++++++++++++++
framework/tests/results_tests.py | 67 ++++++++++++++++++++++++++++++++++++++++
framework/tests/utils.py | 1 +
4 files changed, 118 insertions(+), 10 deletions(-)
diff --git a/framework/backends/json.py b/framework/backends/json.py
index fc816f7..b5a38d0 100644
--- a/framework/backends/json.py
+++ b/framework/backends/json.py
@@ -47,6 +47,13 @@ CURRENT_JSON_VERSION = 6
# The level to indent a final file
INDENT = 4
+_DECODER_TABLE = {
+ 'Subtests': results.Subtests,
+ 'TestResult': results.TestResult,
+ 'TestrunResult': results.TestrunResult,
+ 'Totals': results.Totals,
+}
+
def piglit_encoder(obj):
""" Encoder for piglit that can transform additional classes into json
@@ -66,10 +73,10 @@ def piglit_encoder(obj):
def piglit_decoder(obj):
"""Json decoder for piglit that can load TestResult objects."""
if isinstance(obj, dict):
- if obj.get('__type__', '') == 'TestResult':
- return results.TestResult.from_dict(obj)
- elif obj.get('__type__', '') == 'Subtests':
- return results.Subtests.from_dict(obj)
+ try:
+ return _DECODER_TABLE[obj['__type__']].from_dict(obj)
+ except KeyError:
+ pass
return obj
@@ -141,11 +148,13 @@ class JSONBackend(FileBackend):
# writing worked and is valid or it didn't work.
try:
with open(test, 'r') as f:
- data['tests'].update(json.load(f))
+ data['tests'].update(json.load(f, object_hook=piglit_decoder))
except ValueError:
pass
assert data['tests']
+ data = results.TestrunResult.from_dict(data)
+
# write out the combined file. Use the compression writer from the
# FileBackend
with self._write_final(os.path.join(self._dest, 'results.json')) as f:
@@ -221,18 +230,17 @@ def _load(results_file):
This function converts an existing, fully completed json run.
"""
- result = results.TestrunResult()
- result.results_version = 0 # This should get overwritten
try:
- result.__dict__.update(
- json.load(results_file, object_hook=piglit_decoder))
+ result = json.load(results_file, object_hook=piglit_decoder)
except ValueError as e:
raise exceptions.PiglitFatalError(
'While loading json results file: "{}",\n'
'the following error occured:\n{}'.format(results_file.name,
str(e)))
- return result
+ if isinstance(result, results.TestrunResult):
+ return result
+ return results.TestrunResult.from_dict(result, _no_totals=True)
def _resume(results_dir):
diff --git a/framework/results.py b/framework/results.py
index dd7fdc0..61841b7 100644
--- a/framework/results.py
+++ b/framework/results.py
@@ -204,6 +204,11 @@ class Totals(dict):
result['__type__'] = 'Totals'
return result
+ @classmethod
+ def from_dict(cls, dict_):
+ """Convert a dictionary into a Totals object."""
+ return cls(dict_)
+
class TestrunResult(object):
"""The result of a single piglit run."""
@@ -246,3 +251,30 @@ class TestrunResult(object):
rep = copy.copy(self.__dict__)
rep['__type__'] = 'TestrunResult'
return rep
+
+ @classmethod
+ def from_dict(cls, dict_, _no_totals=False):
+ """Convert a dictionary into a TestrunResult.
+
+ This method is meant to be used for loading results from json or
+ similar formats
+
+ _no_totals is not meant to be used externally, it allows us to control
+ the generation of totals when loading old results formats.
+
+ """
+ res = cls()
+ for name in ['name', 'uname', 'options', 'glxinfo', 'wglinfo', 'lspci',
+ 'tests', 'totals', 'results_version']:
+ value = dict_.get(name)
+ if value:
+ setattr(res, name, value)
+
+ # This could be replaced with a getter/setter property
+ time = dict_.get('time_elapsed')
+ res.time_elapsed = None if time is None else float(time)
+
+ if not res.totals and not _no_totals:
+ res.calculate_group_totals()
+
+ return res
diff --git a/framework/tests/results_tests.py b/framework/tests/results_tests.py
index 9a4b358..2f09127 100644
--- a/framework/tests/results_tests.py
+++ b/framework/tests/results_tests.py
@@ -498,3 +498,70 @@ class TestTestrunResultToJson(object):
def test_type(self):
"""results.TestrunResult.to_json: __type__ is added"""
nt.eq_(self.test['__type__'], 'TestrunResult')
+
+
+class TestTestrunResultFromDict(object):
+ """Tests for TestrunResult.from_dict."""
+ @classmethod
+ def setup_class(cls):
+ subtest = results.TestResult('fail')
+ subtest.subtests['foo'] = 'pass'
+
+ test = results.TestrunResult()
+ test.name = 'name'
+ test.uname = 'this is uname'
+ test.options = {'some': 'option'}
+ test.glxinfo = 'glxinfo'
+ test.wglinfo = 'wglinfo'
+ test.lspci = 'this is lspci'
+ test.time_elapsed = 1.23
+ test.tests = {
+ 'a test': results.TestResult('pass'),
+ 'subtest': subtest,
+ }
+ test.results_version = 100000 # This will never be less than current
+
+ cls.baseline = test
+ cls.test = results.TestrunResult.from_dict(test.to_json())
+
+ @utils.nose_generator
+ def test_basic(self):
+ """Generate tests for basic attributes"""
+
+ def test(baseline, test):
+ nt.eq_(baseline, test)
+
+ for attrib in ['name', 'uname', 'glxinfo', 'wglinfo', 'lspci',
+ 'time_elapsed', 'results_version']:
+ test.description = ('results.TestrunResult.from_dict: '
+ '{} is restored correctly'.format(attrib))
+ yield (test,
+ getattr(self.baseline, attrib),
+ getattr(self.test, attrib))
+
+ def test_tests(self):
+ """results.TestrunResult.from_dict: tests is restored correctly"""
+ nt.eq_(self.test.tests['a test'].result,
+ self.baseline.tests['a test'].result)
+
+ def test_test_type(self):
+ """results.TestrunResult.from_dict: tests is restored correctly"""
+ nt.ok_(isinstance(self.test.tests['a test'].result, status.Status),
+ msg='Tests should be type Status, but was "{}"'.format(
+ type(self.test.tests['a test'].result)))
+
+ def test_totals(self):
+ """results.TestrunResult.from_dict: totals is restored correctly"""
+ nt.assert_dict_equal(self.baseline.totals, self.test.totals)
+
+ def test_subtests(self):
+ """results.TestrunResult.from_dict: subtests are restored correctly"""
+ nt.eq_(self.test.tests['subtest'].subtests['foo'],
+ self.baseline.tests['subtest'].subtests['foo'])
+
+ def test_subtest_type(self):
+ """results.TestrunResult.from_dict: subtests are Status instances"""
+ nt.ok_(isinstance(self.test.tests['subtest'].subtests['foo'],
+ status.Status),
+ msg='Subtests should be type Status, but was "{}"'.format(
+ type(self.test.tests['subtest'].subtests['foo'])))
diff --git a/framework/tests/utils.py b/framework/tests/utils.py
index 0077716..6ad2ff0 100644
--- a/framework/tests/utils.py
+++ b/framework/tests/utils.py
@@ -234,6 +234,7 @@ def resultfile():
data = copy.deepcopy(JSON_DATA)
data['tests']['sometest'] = results.TestResult('pass')
data['tests']['sometest'].time = 1.2
+ data = results.TestrunResult.from_dict(data)
with tempfile_.NamedTemporaryFile(delete=False) as f:
json.dump(data, f, default=backends.json.piglit_encoder)
--
2.5.1
More information about the Piglit
mailing list