summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--oslotest/base.py16
-rw-r--r--oslotest/tests/unit/test_timeout.py48
-rw-r--r--oslotest/timeout.py22
-rw-r--r--releasenotes/notes/timeout-scaling-52741beadde528e5.yaml10
4 files changed, 91 insertions, 5 deletions
diff --git a/oslotest/base.py b/oslotest/base.py
index 144e72e..fb4b02d 100644
--- a/oslotest/base.py
+++ b/oslotest/base.py
@@ -40,6 +40,15 @@ class BaseTestCase(testtools.TestCase):
individual test cases can run. This lets tests fail for taking too
long, and prevents deadlocks from completely hanging test runs.
+ The class variable ``DEFAULT_TIMEOUT`` can be set to configure
+ a test suite default test value for cases in which ``OS_TEST_TIMEOUT``
+ is not set. It defaults to ``0``, which means no timeout.
+
+ The class variable ``TIMEOUT_SCALING_FACTOR`` can be set on an
+ individual test class for tests that reasonably take longer than
+ the rest of the test suite so that the overall timeout can be
+ kept small. It defaults to ``1``.
+
If the environment variable ``OS_STDOUT_CAPTURE`` is set, a fake
stream replaces ``sys.stdout`` so the test can look at the output
it produces.
@@ -75,6 +84,8 @@ class BaseTestCase(testtools.TestCase):
.. _fixtures: https://pypi.org/project/fixtures
"""
+ DEFAULT_TIMEOUT = 0
+ TIMEOUT_SCALING_FACTOR = 1
def __init__(self, *args, **kwds):
super(BaseTestCase, self).__init__(*args, **kwds)
@@ -112,7 +123,10 @@ class BaseTestCase(testtools.TestCase):
self.useFixture(fixtures.TempHomeDir())
def _set_timeout(self):
- self.useFixture(timeout.Timeout())
+ self.useFixture(timeout.Timeout(
+ default_timeout=self.DEFAULT_TIMEOUT,
+ scaling_factor=self.TIMEOUT_SCALING_FACTOR,
+ ))
def _fake_output(self):
self.output_fixture = self.useFixture(output.CaptureOutput())
diff --git a/oslotest/tests/unit/test_timeout.py b/oslotest/tests/unit/test_timeout.py
index 1ba5bed..38c7a3d 100644
--- a/oslotest/tests/unit/test_timeout.py
+++ b/oslotest/tests/unit/test_timeout.py
@@ -43,3 +43,51 @@ class TimeoutTestCase(testtools.TestCase):
env_get_mock.assert_called_once_with('OS_TEST_TIMEOUT', 0)
self.assertEqual(0, fixture_timeout_mock.call_count)
self.assertEqual(0, fixture_mock.call_count)
+
+ @mock.patch('os.environ.get')
+ @mock.patch.object(timeout.Timeout, 'useFixture')
+ @mock.patch('fixtures.Timeout')
+ def test_timeout_default(
+ self, fixture_timeout_mock, fixture_mock, env_get_mock):
+ env_get_mock.return_value = 5
+ tc = timeout.Timeout(default_timeout=5)
+ tc.setUp()
+ env_get_mock.assert_called_once_with('OS_TEST_TIMEOUT', 5)
+ fixture_timeout_mock.assert_called_once_with(5, gentle=True)
+ self.assertEqual(1, fixture_mock.call_count)
+
+ @mock.patch('os.environ.get')
+ @mock.patch.object(timeout.Timeout, 'useFixture')
+ @mock.patch('fixtures.Timeout')
+ def test_timeout_bad_default(
+ self, fixture_timeout_mock, fixture_mock, env_get_mock):
+ env_get_mock.return_value = 'invalid'
+ tc = timeout.Timeout(default_timeout='invalid')
+ tc.setUp()
+ env_get_mock.assert_called_once_with('OS_TEST_TIMEOUT', 0)
+ self.assertEqual(0, fixture_timeout_mock.call_count)
+ self.assertEqual(0, fixture_mock.call_count)
+
+ @mock.patch('os.environ.get')
+ @mock.patch.object(timeout.Timeout, 'useFixture')
+ @mock.patch('fixtures.Timeout')
+ def test_timeout_scaling(
+ self, fixture_timeout_mock, fixture_mock, env_get_mock):
+ env_get_mock.return_value = 2
+ tc = timeout.Timeout(scaling_factor=1.5)
+ tc.setUp()
+ env_get_mock.assert_called_once_with('OS_TEST_TIMEOUT', 0)
+ fixture_timeout_mock.assert_called_once_with(3, gentle=True)
+ self.assertEqual(1, fixture_mock.call_count)
+
+ @mock.patch('os.environ.get')
+ @mock.patch.object(timeout.Timeout, 'useFixture')
+ @mock.patch('fixtures.Timeout')
+ def test_timeout_bad_scaling(
+ self, fixture_timeout_mock, fixture_mock, env_get_mock):
+ env_get_mock.return_value = 2
+ tc = timeout.Timeout(scaling_factor='invalid')
+ tc.setUp()
+ env_get_mock.assert_called_once_with('OS_TEST_TIMEOUT', 0)
+ fixture_timeout_mock.assert_called_once_with(2, gentle=True)
+ self.assertEqual(1, fixture_mock.call_count)
diff --git a/oslotest/timeout.py b/oslotest/timeout.py
index a9286d3..69d08ad 100644
--- a/oslotest/timeout.py
+++ b/oslotest/timeout.py
@@ -22,13 +22,27 @@ class Timeout(fixtures.Fixture):
"""
+ def __init__(self, default_timeout=0, scaling_factor=1):
+ super(Timeout, self).__init__()
+ try:
+ self._default_timeout = int(default_timeout)
+ except ValueError:
+ # If timeout value is invalid do not set a timeout.
+ self._default_timeout = 0
+ self._scaling_factor = scaling_factor
+
def setUp(self):
super(Timeout, self).setUp()
- test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
+ test_timeout = os.environ.get('OS_TEST_TIMEOUT', self._default_timeout)
try:
test_timeout = int(test_timeout)
except ValueError:
# If timeout value is invalid do not set a timeout.
- test_timeout = 0
- if test_timeout > 0:
- self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
+ test_timeout = self._default_timeout
+ try:
+ scaled_timeout = int(test_timeout * self._scaling_factor)
+ except ValueError:
+ # If scaling factor is invalid, use the basic test timeout.
+ scaled_timeout = test_timeout
+ if scaled_timeout > 0:
+ self.useFixture(fixtures.Timeout(scaled_timeout, gentle=True))
diff --git a/releasenotes/notes/timeout-scaling-52741beadde528e5.yaml b/releasenotes/notes/timeout-scaling-52741beadde528e5.yaml
new file mode 100644
index 0000000..ad9f047
--- /dev/null
+++ b/releasenotes/notes/timeout-scaling-52741beadde528e5.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ New class variable, ``TIMEOUT_SCALING_FACTOR`` was added that allows
+ modifying a test class to have a longer timeout than other tests in the
+ suite without having to raise the default timeout for all tests.
+ - |
+ New class varable, ``DEFAULT_TIMEOUT`` was added that lets test suite
+ authors override the default value of ``OS_TEST_TIMEOUT`` at the
+ test suite level.