[Piglit] [PATCH 20/49] unittests: port dmesg tests to pytest
Dylan Baker
dylan at pnwbakers.com
Fri Jul 29 18:39:06 UTC 2016
This adds a significant number of comments to the tests, it also makes a
very small change to the various dmesg classes, it adds a __repr__
method to each of them to make testing the classes easier.
Signed-off-by: Dylan Baker <dylanx.c.baker at intel.com>
---
framework/dmesg.py | 9 +
unittests/dmesg_tests.py | 337 ----------------------------------
unittests/framework/test_dmesg.py | 374 ++++++++++++++++++++++++++++++++++++++
3 files changed, 383 insertions(+), 337 deletions(-)
delete mode 100644 unittests/dmesg_tests.py
create mode 100644 unittests/framework/test_dmesg.py
diff --git a/framework/dmesg.py b/framework/dmesg.py
index 7761375..f327e92 100644
--- a/framework/dmesg.py
+++ b/framework/dmesg.py
@@ -151,6 +151,9 @@ class BaseDmesg(object):
return result
+ def __repr__(self):
+ return 'BaseDmesg()'
+
class LinuxDmesg(BaseDmesg):
""" Read dmesg on posix systems
@@ -220,6 +223,9 @@ class LinuxDmesg(BaseDmesg):
# Attempt to store the last element of dmesg, unless there was no dmesg
self._last_message = dmesg[-1] if dmesg else None
+ def __repr__(self):
+ return 'LinuxDmesg()'
+
class DummyDmesg(BaseDmesg):
""" An dummy class for dmesg on non unix-like systems
@@ -242,6 +248,9 @@ class DummyDmesg(BaseDmesg):
""" Dummy version of update_result """
return result
+ def __repr__(self):
+ return 'DummyDmesg()'
+
def get_dmesg(not_dummy=True):
""" Return a Dmesg type instance
diff --git a/unittests/dmesg_tests.py b/unittests/dmesg_tests.py
deleted file mode 100644
index 61ae7cc..0000000
--- a/unittests/dmesg_tests.py
+++ /dev/null
@@ -1,337 +0,0 @@
-# Copyright (c) 2015 Intel Corporation
-
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-"""Tests for the dmesg module.
-
-This module makes extensive use of mock to avoid actually calling into dmesg,
-which allows us to test all classes on all platforms, including windows.
-
-"""
-
-from __future__ import (
- absolute_import, division, print_function, unicode_literals
-)
-import re
-import sys
-import warnings
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-import nose.tools as nt
-
-from . import utils
-from framework import dmesg, status, results, exceptions
-
-# pylint: disable=invalid-name,line-too-long,attribute-defined-outside-init
-
-
- at nt.nottest
-class TestDmesg(dmesg.BaseDmesg):
- """Test Dmesg class. stubs update_dmesg and __init__"""
- def update_dmesg(self, *args, **kwargs):
- pass
-
- def __init__(self):
- super(TestDmesg, self).__init__()
- self._new_messages = ['some', 'new', 'messages']
-
-
-class TestBaseDmesg(object):
- """Tests for the BaseDmesg class."""
- @classmethod
- def setup_class(cls):
- cls.dmesg = TestDmesg()
-
- def setup(self):
- self.result = results.TestResult()
- self.result.dmesg = mock.sentinel.dmesg
-
- def test_update_result_dmesg(self):
- """dmesg.BaseDmesg.update_result: records new dmesg content in result"""
- self.dmesg.update_result(self.result)
- nt.assert_is_not(self.result.dmesg, mock.sentinel.dmesg)
-
- def test_update_result_status_unchanged(self):
- """dmesg.BaseDmesg.update_result: Doesn't change status it shouldn't
-
- Only 'pass', 'warn', and 'fail' should be changed.
-
- """
- failed = set()
-
- for stat in status.ALL:
- if stat in ['pass', 'warn', 'fail']:
- continue
- self.result.result = stat
- self.dmesg.update_result(self.result)
- if self.result.result != stat:
- failed.add(stat)
-
- if failed:
- raise AssertionError(
- "The following status(es) were changed which should not have "
- "been:\n"
- "{}\n".format('\n'.join(failed)))
-
- def test_update_result_status_changed(self):
- """dmesg.BaseDmesg.update_result: changes pass fail and warn"""
- failed = set()
-
- for stat in ['pass', 'warn', 'fail']:
- self.result.result = stat
- self.dmesg.update_result(self.result)
- if self.result.result == stat:
- failed.add(stat)
-
- if failed:
- raise AssertionError(
- "The following status(es) were not changed which should not "
- "have been:\n"
- "{}\n".format('\n'.join(failed)))
-
- def test_update_result_subtest_unchanged(self):
- """dmesg.BaseDmesg.update_result: Doesn't change subtests it shouldn't
-
- Only 'pass', 'warn', and 'fail' should be changed.
-
- """
- failed = set()
-
- for stat in status.ALL:
- if stat in ['pass', 'warn', 'fail']:
- continue
- self.result.subtests['foo'] = stat
- self.dmesg.update_result(self.result)
- if self.result.subtests['foo'] != stat:
- failed.add(stat)
-
- if failed:
- raise AssertionError(
- "The following status(es) were changed which should not have "
- "been:\n"
- "{}\n".format('\n'.join(failed)))
-
- def test_update_subtest_changed(self):
- """dmesg.BaseDmesg.update_result: changes subtests pass fail and warn"""
- failed = set()
-
- for stat in status.ALL:
- if stat in ['pass', 'warn', 'fail']:
- continue
- self.result.subtests['foo'] = stat
- self.dmesg.update_result(self.result)
- if self.result.subtests['foo'] != stat:
- failed.add(stat)
-
- if failed:
- raise AssertionError(
- "The following status(es) were changed which should not have "
- "been:\n"
- "{}\n".format('\n'.join(failed)))
-
-
-def test_update_result_regex_no_match():
- """dmesg.BaseDmesg.update_result: if no regex matches don't change status"""
- dmesg_ = TestDmesg()
- dmesg_.regex = re.compile(r'nomatchforthisreally')
- result = results.TestResult('pass')
- dmesg_.update_result(result)
-
- nt.eq_(result.result, 'pass')
-
-
-def test_update_result_regex_match():
- """dmesg.BaseDmesg.update_result: if regex matches change status"""
- dmesg_ = TestDmesg()
- dmesg_.regex = re.compile(r'.*')
- result = results.TestResult('pass')
- dmesg_.update_result(result)
-
- nt.assert_not_equal(result.result, 'pass')
-
-
- at utils.nose.generator
-def test_update_result_specific():
- """Generator that tests specific result mappings."""
- dmesg_ = TestDmesg()
- tests = [
- ('pass', 'dmesg-warn'),
- ('warn', 'dmesg-fail'),
- ('fail', 'dmesg-fail'),
- ]
- description = 'dmesg.BaseDmesg.update_result: replaces {} with {}'
-
- def test(initial, expected):
- result = results.TestResult(initial)
- dmesg_.update_result(result)
- nt.eq_(result.result, expected)
-
- for initial, expected in tests:
- test.description = description.format(initial, expected)
- yield test, initial, expected
-
-
- at utils.nose.generator
-def test_linuxdmesg_gzip_errors():
- """Generator to test exceptions that need to be passed when reading
- config.gz.
-
- """
- exceptions_ = {
- OSError,
- IOError,
- }
- description = "dmesg.LinuxDmesg: Doesn't stop on {} when reading gzip."
-
- @mock.patch('framework.dmesg.LinuxDmesg.update_dmesg', mock.Mock())
- def test(exception):
- try:
- with mock.patch('framework.dmesg.gzip.open',
- mock.Mock(side_effect=exception)):
- with warnings.catch_warnings():
- warnings.simplefilter('error')
- dmesg.LinuxDmesg()
- except (exceptions.PiglitFatalError, RuntimeWarning):
- pass
-
- for exception in exceptions_:
- test.description = description.format(exception.__name__)
- yield test, exception
-
-
- at nt.raises(exceptions.PiglitFatalError)
- at mock.patch('framework.dmesg.gzip.open', mock.Mock(side_effect=IOError))
-def test_linuxdmesg_timestamp():
- """dmesg.LinuxDmesg: If timestamps are not detected raise"""
- with mock.patch('framework.dmesg.subprocess.check_output',
- mock.Mock(return_value=b'foo\nbar\n')):
- with warnings.catch_warnings():
- warnings.simplefilter('error')
- dmesg.LinuxDmesg()
-
-
- at nt.raises(RuntimeWarning)
- at mock.patch('framework.dmesg.gzip.open', mock.Mock(side_effect=IOError))
-def test_linuxdmesg_warn():
- """dmesg.LinuxDmesg: Warn if timestamp support is uncheckable"""
- with mock.patch('framework.dmesg.LinuxDmesg.update_dmesg', mock.Mock()):
- with warnings.catch_warnings():
- warnings.simplefilter('error')
- dmesg.LinuxDmesg()
-
-
-def test_linuxdmesg_update_dmesg_update():
- """dmesg.LinuxDmesg.update_dmesg: calculate dmesg changes correctly with changes"""
- result = results.TestResult('pass')
-
- with mock.patch('framework.dmesg.subprocess.check_output',
- mock.Mock(return_value=b'[1.0]this')):
- dmesg_ = dmesg.LinuxDmesg()
-
- with mock.patch('framework.dmesg.subprocess.check_output',
- mock.Mock(return_value=b'[1.0]this\n[2.0]is\n[3.0]dmesg\n')):
- dmesg_.update_result(result)
-
- nt.eq_(result.dmesg, '[2.0]is\n[3.0]dmesg')
-
-
-def test_linuxdmesg_update_dmesg_update_no_change():
- """dmesg.LinuxDmesg.update_dmesg: calculate dmesg changes correctly with no changes"""
- result = results.TestResult('pass')
- result.dmesg = mock.sentinel.dmesg
-
- with mock.patch('framework.dmesg.subprocess.check_output',
- mock.Mock(return_value=b'[1.0]this')):
- dmesg_ = dmesg.LinuxDmesg()
- dmesg_.update_result(result)
-
- nt.eq_(result.dmesg, mock.sentinel.dmesg)
-
-
-def test_dummydmesg_update_result():
- """dmesg.DummyDmesg.update_result: returns result unmodified"""
- dmesg_ = dmesg.DummyDmesg()
- result = mock.MagicMock(spec=results.TestResult())
- result.dmesg = mock.sentinel.dmesg
- result.result = mock.sentinel.result
- dmesg_.update_result(result)
-
- nt.eq_(result.dmesg, mock.sentinel.dmesg)
- nt.eq_(result.result, mock.sentinel.result)
-
-
-def test_get_dmesg():
- """dmesg.get_dmesg: Returns correct class for platform"""
- ret = dmesg.get_dmesg()
- if sys.platform.startswith('win32'):
- nt.ok_(isinstance(ret, dmesg.DummyDmesg), msg='got {}'.format(type(ret)))
- elif sys.platform.startswith('linux'):
- nt.ok_(isinstance(ret, dmesg.LinuxDmesg), msg='got {}'.format(type(ret)))
-
-
-def test_get_dmesg_dummy():
- """dmesg.get_dmesg: when not_dummy=False a dummy is provided"""
- # Linux was selected since it would normally return LinuxDmesg
- with mock.patch('framework.dmesg.sys.platform', 'linux'):
- ret = dmesg.get_dmesg(False)
- nt.assert_is_instance(ret, dmesg.DummyDmesg)
-
-
-def test_partial_wrap():
- """dmesg.LinuxDmesg.update_dmesg: correctly handles partial wrap
-
- Since dmesg is a ringbuffer (at least on Linux) it can roll over, and we
- need to ensure that we're handling that correctly.
-
- """
- result = results.TestResult()
-
- mock_out = mock.Mock(return_value=b'[1.0]This\n[2.0]is\n[3.0]dmesg')
- with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
- test = dmesg.LinuxDmesg()
-
- mock_out.return_value = b'[3.0]dmesg\n[4.0]whoo!'
- with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
- test.update_result(result)
-
- nt.eq_(result.dmesg, '[4.0]whoo!')
-
-
-def test_complete_wrap():
- """dmesg.LinuxDmesg.update_dmesg: correctly handles complete wrap
-
- Since dmesg is a ringbuffer (at least on Linux) it can roll over, and we
- need to ensure that we're handling that correctly.
-
- """
- result = results.TestResult()
-
- mock_out = mock.Mock(return_value=b'[1.0]This\n[2.0]is\n[3.0]dmesg')
- with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
- test = dmesg.LinuxDmesg()
-
- mock_out.return_value = b'[4.0]whoo!\n[5.0]doggy'
- with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
- test.update_result(result)
-
- nt.eq_(result.dmesg, '[4.0]whoo!\n[5.0]doggy')
diff --git a/unittests/framework/test_dmesg.py b/unittests/framework/test_dmesg.py
new file mode 100644
index 0000000..6305315
--- /dev/null
+++ b/unittests/framework/test_dmesg.py
@@ -0,0 +1,374 @@
+# Copyright (c) 2015-2016 Intel Corporation
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+"""Tests for the dmesg module.
+
+This module makes extensive use of mock to avoid actually calling into dmesg,
+which allows us to test all classes on all platforms, including windows.
+
+"""
+
+from __future__ import (
+ absolute_import, division, print_function, unicode_literals
+)
+import collections
+import re
+try:
+ import mock
+except ImportError:
+ from unittest import mock
+
+import pytest
+import six
+
+from framework import dmesg
+from framework import status
+from framework import results
+from framework import exceptions
+
+from . import skip
+
+# pylint: disable=invalid-name,no-self-use
+
+
+class _DmesgTester(dmesg.BaseDmesg):
+ """Test Dmesg class. stubs update_dmesg and __init__"""
+
+ def __init__(self):
+ super(_DmesgTester, self).__init__()
+ self._new_messages = ['some', 'new', 'messages']
+
+ def update_dmesg(self, *args, **kwargs):
+ pass
+
+
+class TestBaseDmesg(object):
+ """Tests for the BaseDmesg class."""
+
+ result = None
+
+ @classmethod
+ def setup_class(cls):
+ cls.dmesg = _DmesgTester()
+
+ def setup(self):
+ self.result = results.TestResult()
+ self.result.dmesg = mock.sentinel.dmesg
+
+ def test_update_result_dmesg(self):
+ """dmesg.BaseDmesg.update_result: records new dmesg content in result"""
+ self.dmesg.update_result(self.result)
+ assert self.result.dmesg is not mock.sentinel.dmesg
+
+ @pytest.mark.parametrize(
+ "initial,expected",
+ [
+ (status.PASS, status.DMESG_WARN),
+ (status.WARN, status.DMESG_FAIL),
+ (status.FAIL, status.DMESG_FAIL),
+ (status.CRASH, status.CRASH),
+ (status.SKIP, status.SKIP),
+ (status.NOTRUN, status.NOTRUN),
+ (status.TIMEOUT, status.TIMEOUT),
+ ],
+ ids=six.text_type)
+ def test_update_result_status(self, initial, expected):
+ """Test that when update_result is called status change when they
+ should, and don't when they shouldn't.
+ """
+ self.result.result = initial
+ self.dmesg.update_result(self.result)
+ assert self.result.result is expected
+
+ @pytest.mark.parametrize(
+ "initial,expected",
+ [
+ (status.PASS, status.DMESG_WARN),
+ (status.WARN, status.DMESG_FAIL),
+ (status.FAIL, status.DMESG_FAIL),
+ (status.CRASH, status.CRASH),
+ (status.SKIP, status.SKIP),
+ (status.NOTRUN, status.NOTRUN),
+ (status.TIMEOUT, status.TIMEOUT),
+ ],
+ ids=six.text_type)
+ def test_update_result_subtests(self, initial, expected):
+ """Test that when update_result is called subtest statuses change when
+ they should, and don't when they shouldn't.
+ """
+ self.result.subtests['foo'] = initial
+ self.result.subtests['bar'] = initial
+
+ self.dmesg.update_result(self.result)
+
+ assert self.result.subtests['foo'] is expected
+ assert self.result.subtests['bar'] is expected
+
+ def test_update_result_regex_no_match(self):
+ """dmesg.BaseDmesg.update_result: if no regex matches don't change
+ status.
+ """
+ self.dmesg.regex = re.compile(r'nomatchforthisreally')
+ self.result.result = status.PASS
+
+ self.dmesg.update_result(self.result)
+
+ assert self.result.result is status.PASS
+
+ def test_update_result_regex_match(self):
+ """dmesg.BaseDmesg.update_result: if regex matches change status."""
+ self.dmesg.regex = re.compile(r'.*')
+ self.result.result = status.PASS
+
+ self.dmesg.update_result(self.result)
+
+ assert self.result.result is status.DMESG_WARN
+
+
+class TestLinuxDmesgTimestamps(object):
+ """Tests for the LinuxDmesg.__init__ timestampe detection.
+
+ The linux path will try to open /proc/config.gz and look for
+ CONFIG_PRINTK_TIME=y, there are a couple of things that can go wrong it
+ should recover from, in both of the following cases it's expected to go
+ on and fall back to less exact checking.
+
+ The first is that there is no /proc/config.gz in that case we'll get a
+ OSError in python2 or it's descendent FileNotFoundError in python 3.
+
+ The second is that it could get an IOError in python 2.x or
+ PermissionError in python 3.x, if the file cannot be read.
+
+ The fallback path will try read dmesg and see if there's evidence of a
+ timestamp, or warn that it can't find anything.
+
+ """
+ def test_warn(self, mocker):
+ """Test that if /proc/config is not available, and there are no values
+ to check in _last_message a RuntimeWarning should be issued.
+ """
+ # Mocking this will prevent LinuxDmesg._last_message from being
+ # updated, which will force us down the warn path
+ mocker.patch('framework.dmesg.LinuxDmesg.update_dmesg')
+
+ # OSError was picked because it will work for both python2 and python3
+ # (FileNotFoundError is a descendent of OSError)
+ mocker.patch('framework.dmesg.gzip.open', side_effect=OSError)
+
+ with pytest.warns(RuntimeWarning):
+ dmesg.LinuxDmesg()
+
+ # Implementation notes:
+ #
+ # It would seem like a parametrized test would be what we want here, since
+ # these tests share so much state, but FileNotFoundError and
+ # PermissionError don't exist in python 2.x, and the parametrizer will
+ # cause an error. Using a class with a shared method is the next best
+ # solution.
+ @staticmethod
+ def _do_test(error, mocker):
+ # Mocking this will prevent LinuxDmesg._last_message from being
+ # updated, which will force us down the warn path, which is convenient
+ # for assertion puproses.
+ mocker.patch('framework.dmesg.LinuxDmesg.update_dmesg')
+ mocker.patch('framework.dmesg.gzip.open', side_effect=error)
+
+ with pytest.warns(RuntimeWarning):
+ dmesg.LinuxDmesg()
+
+ @skip.PY3
+ def test_config_oserror(self, mocker):
+ """Test that on python 2.x if an OSError is raised by gzip.open
+ operation doesn't stop.
+ """
+ self._do_test(OSError, mocker)
+
+ @skip.PY3
+ def test_config_ioerror(self, mocker):
+ """Test that on python 2.x if an IOError is raised by gzip.open
+ operation doesn't stop.
+ """
+ self._do_test(IOError, mocker)
+
+ @skip.PY2
+ def test_config_filenotfounderror(self, mocker):
+ """Test that on python 3.x if an FileNotFound is raised by gzip.open
+ operation doesn't stop.
+ """
+ self._do_test(FileNotFoundError, mocker)
+
+ @skip.PY2
+ def test_config_permissionerror(self, mocker):
+ """Test that on python 3.x if an PermissionError is raised by gzip.open
+ operation doesn't stop.
+ """
+ self._do_test(PermissionError, mocker)
+
+ def test_not_timestamps(self, mocker):
+ """If _last_message is populated but doesn't have a valid timestamp
+ then an PiglitFatalException shoudl be raised.
+ """
+ mocker.patch('framework.dmesg.subprocess.check_output',
+ mocker.Mock(return_value=b'foo\nbar\n'))
+ # This error will work for python 2.x and 3.x
+ mocker.patch('framework.dmesg.gzip.open', side_effect=OSError)
+
+ with pytest.raises(exceptions.PiglitFatalError):
+ dmesg.LinuxDmesg()
+
+ @skip.linux
+ def test_partial_wrap(self):
+ """dmesg.LinuxDmesg.update_dmesg: correctly handles partial wrap.
+
+ Since dmesg is a ringbuffer it can roll over, and we need to ensure
+ that we're handling that correctly.
+ """
+ result = results.TestResult()
+
+ mock_out = mock.Mock(return_value=b'[1.0]This\n[2.0]is\n[3.0]dmesg')
+ with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
+ test = dmesg.LinuxDmesg()
+
+ mock_out.return_value = b'[3.0]dmesg\n[4.0]whoo!'
+ with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
+ test.update_result(result)
+
+ assert result.dmesg == '[4.0]whoo!'
+
+ @skip.linux
+ def test_complete_wrap(self):
+ """dmesg.LinuxDmesg.update_dmesg: correctly handles complete wrap.
+
+ Since dmesg is a ringbuffer (at least on Linux) it can roll over, and we
+ need to ensure that we're handling that correctly.
+ """
+ result = results.TestResult()
+
+ mock_out = mock.Mock(return_value=b'[1.0]This\n[2.0]is\n[3.0]dmesg')
+ with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
+ test = dmesg.LinuxDmesg()
+
+ mock_out.return_value = b'[4.0]whoo!\n[5.0]doggy'
+ with mock.patch('framework.dmesg.subprocess.check_output', mock_out):
+ test.update_result(result)
+
+ assert result.dmesg == '[4.0]whoo!\n[5.0]doggy'
+
+
+class TestLinuxDmesg(object):
+ """Tests for LinuxDmesg methods."""
+
+ def test_update_result_sets_result_attr(self):
+ """When update_dmesg is called on a value it should set the dmesg
+ attribute of the results.
+ """
+ result = results.TestResult(status.PASS)
+
+ with mock.patch('framework.dmesg.subprocess.check_output',
+ mock.Mock(return_value=b'[1.0]this')):
+ test = dmesg.LinuxDmesg()
+ with mock.patch('framework.dmesg.subprocess.check_output',
+ mock.Mock(
+ return_value=b'[1.0]this\n[2.0]is\n[2.5]dmesg!\n')):
+ test.update_result(result)
+
+ assert result.dmesg == '[2.0]is\n[2.5]dmesg!'
+
+ def test_update_result_no_change(self):
+ """When update_result is called but no changes to dmesg have occured it
+ should not set the dmesg attribute.
+ """
+ result = results.TestResult('pass')
+ result.dmesg = mock.sentinel.dmesg
+
+ with mock.patch('framework.dmesg.subprocess.check_output',
+ mock.Mock(return_value=b'[1.0]this')):
+ test = dmesg.LinuxDmesg()
+ test.update_result(result)
+
+ assert result.dmesg is mock.sentinel.dmesg
+
+ def test_repr(self):
+ with mock.patch('framework.dmesg.subprocess.check_output',
+ mock.Mock(return_value=b'[1.0]this')):
+ assert repr(dmesg.LinuxDmesg()) == 'LinuxDmesg()'
+
+
+class TestDummyDmesg(object):
+ """Tests for the DummyDmesg class."""
+ _Namespace = collections.namedtuple('_Namespace', ['dmesg', 'result'])
+
+ @pytest.fixture
+ def testers(self):
+ # The setter for result.TestResult checks types, rather than trying to
+ # make the sentinel pass that test, just make a mock that mostly acts
+ # like TestResult
+ result = mock.Mock(spec=results.TestResult)
+ result.dmesg = mock.sentinel.dmesg
+ result.result = mock.sentinel.result
+ return self._Namespace(dmesg.DummyDmesg(), result)
+
+ def test_update_result(self, testers):
+ """DummyDmesg.update_results shouldn't do anything."""
+ testers.dmesg.update_result(testers.result)
+ assert testers.result.dmesg is mock.sentinel.dmesg
+ assert testers.result.result is mock.sentinel.result
+
+ def test_repr(self):
+ assert repr(dmesg.DummyDmesg()) == 'DummyDmesg()'
+
+
+def _name_get_dmesg(value):
+ """Function that names TestGetDmesg.test_get_dmesg."""
+ if isinstance(value, bool):
+ return 'real' if not value else 'dummy'
+ elif isinstance(value, six.text_type):
+ return value
+ elif isinstance(value, dmesg.BaseDmesg):
+ return repr(value)
+ else:
+ raise Exception('unreachable')
+
+
+class TestGetDmesg(object):
+ """Tests for get_dmesg factory."""
+
+ @pytest.mark.parametrize(
+ 'platform,dummy,expected',
+ [
+ ('win32', False, dmesg.DummyDmesg),
+ ('win32', True, dmesg.DummyDmesg),
+ skip.linux(('linux', False, dmesg.DummyDmesg)),
+ skip.linux(('linux', True, dmesg.LinuxDmesg)),
+ ],
+ ids=_name_get_dmesg)
+ def test_get_dmesg(self, platform, dummy, expected, mocker):
+ """Test that get_dmesg returns the expected dmesg type on variuos
+ platforms with various configurations.
+ """
+ mocker.patch('framework.dmesg.sys.platform', platform)
+
+ with mock.patch('framework.dmesg.subprocess.check_output',
+ mock.Mock(return_value=b'[1.0]foo')):
+ actual = dmesg.get_dmesg(not_dummy=dummy)
+
+ # We don't want a subclass, we want the *exact* class. This is a
+ # unittest after all
+ assert type(actual) == expected # pylint: disable=unidiomatic-typecheck
--
2.9.0
More information about the Piglit
mailing list