diff options
author | Dylan Baker <baker.dylan.c@gmail.com> | 2015-08-25 16:45:15 -0700 |
---|---|---|
committer | Dylan Baker <baker.dylan.c@gmail.com> | 2015-09-22 14:45:48 -0700 |
commit | 39297fcde745960377fe936dd52bf666b9e08fe8 (patch) | |
tree | ca26dae7f90cc0719ae42aef63661c957a0f20b8 /framework | |
parent | d860fb6f83ab64a99591c8a93d7931d19addb376 (diff) |
framework/results.py: add TestrunResult.from_dict method
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@intel.com>
Diffstat (limited to 'framework')
-rw-r--r-- | framework/backends/json.py | 28 | ||||
-rw-r--r-- | framework/results.py | 32 | ||||
-rw-r--r-- | framework/tests/results_tests.py | 67 | ||||
-rw-r--r-- | 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 fc816f726..b5a38d034 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 dd7fdc0e7..61841b76a 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 9a4b3584f..2f09127e9 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 007771622..6ad2ff0d3 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) |