summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClay Gerrard <clay.gerrard@gmail.com>2014-10-24 13:27:13 -0700
committerDaniel Wakefield <daniel.wakefield@hp.com>2014-11-20 14:42:55 +0000
commitd89e08f722f030925495a4180d2fe8422977841d (patch)
tree3d8539d30c8329f7d76b942bca564b675ed77359
parentcfbabe72660b5d0c471584d987665396d78a4958 (diff)
downloadpython-swiftclient-d89e08f722f030925495a4180d2fe8422977841d.tar.gz
Capture test output better
This change adds some new classes to test.unit.utils which wrap up the collection and mocking of the std err and std out. This will make the testing code easier to write and maintain. Change-Id: I50ad2a736b2bb550ab83f6a43fb5a0fb5393573e
-rw-r--r--tests/unit/test_shell.py69
-rw-r--r--tests/unit/utils.py72
2 files changed, 89 insertions, 52 deletions
diff --git a/tests/unit/test_shell.py b/tests/unit/test_shell.py
index bdba193..9d44248 100644
--- a/tests/unit/test_shell.py
+++ b/tests/unit/test_shell.py
@@ -24,10 +24,10 @@ import swiftclient
from swiftclient.service import SwiftError
import swiftclient.shell
import swiftclient.utils
-from swiftclient.multithreading import OutputManager
from os.path import basename, dirname
from tests.unit.test_swiftclient import MockHttpTest
+from tests.unit.utils import CaptureOutput
if six.PY2:
BUILTIN_OPEN = '__builtin__.open'
@@ -562,20 +562,18 @@ class TestSubcommandHelp(unittest.TestCase):
for command in swiftclient.shell.commands:
help_var = 'st_%s_help' % command
self.assertTrue(help_var in vars(swiftclient.shell))
- out = six.StringIO()
- with mock.patch('sys.stdout', out):
+ with CaptureOutput() as out:
argv = ['', command, '--help']
self.assertRaises(SystemExit, swiftclient.shell.main, argv)
expected = vars(swiftclient.shell)[help_var]
- self.assertEqual(out.getvalue().strip('\n'), expected)
+ self.assertEqual(out.strip('\n'), expected)
def test_no_help(self):
- out = six.StringIO()
- with mock.patch('sys.stdout', out):
+ with CaptureOutput() as out:
argv = ['', 'bad_command', '--help']
self.assertRaises(SystemExit, swiftclient.shell.main, argv)
expected = 'no help for bad_command'
- self.assertEqual(out.getvalue().strip('\n'), expected)
+ self.assertEqual(out.strip('\n'), expected)
class TestParsing(unittest.TestCase):
@@ -583,7 +581,7 @@ class TestParsing(unittest.TestCase):
def setUp(self):
super(TestParsing, self).setUp()
self._environ_vars = {}
- keys = os.environ.keys()
+ keys = list(os.environ.keys())
for k in keys:
if (k in ('ST_KEY', 'ST_USER', 'ST_AUTH')
or k.startswith('OS_')):
@@ -790,21 +788,15 @@ class TestParsing(unittest.TestCase):
"tenant_name": "",
"tenant_id": ""}
- out = six.StringIO()
- err = six.StringIO()
- mock_output = _make_output_manager(out, err)
- with mock.patch('swiftclient.shell.OutputManager', mock_output):
+ with CaptureOutput() as output:
args = _make_args("stat", {}, os_opts)
self.assertRaises(SystemExit, swiftclient.shell.main, args)
- self.assertEqual(err.getvalue().strip(), 'No tenant specified')
+ self.assertEqual(output.err.strip(), 'No tenant specified')
- out = six.StringIO()
- err = six.StringIO()
- mock_output = _make_output_manager(out, err)
- with mock.patch('swiftclient.shell.OutputManager', mock_output):
+ with CaptureOutput() as output:
args = _make_args("stat", {}, os_opts, cmd_args=["testcontainer"])
self.assertRaises(SystemExit, swiftclient.shell.main, args)
- self.assertEqual(err.getvalue().strip(), 'No tenant specified')
+ self.assertEqual(output.err.strip(), 'No tenant specified')
def test_no_tenant_name_or_id_v3(self):
os_opts = {"password": "secret",
@@ -813,23 +805,17 @@ class TestParsing(unittest.TestCase):
"tenant_name": "",
"tenant_id": ""}
- out = six.StringIO()
- err = six.StringIO()
- mock_output = _make_output_manager(out, err)
- with mock.patch('swiftclient.shell.OutputManager', mock_output):
+ with CaptureOutput() as output:
args = _make_args("stat", {"auth_version": "3"}, os_opts)
self.assertRaises(SystemExit, swiftclient.shell.main, args)
- self.assertEqual(err.getvalue().strip(),
+ self.assertEqual(output.err.strip(),
'No project name or project id specified.')
- out = six.StringIO()
- err = six.StringIO()
- mock_output = _make_output_manager(out, err)
- with mock.patch('swiftclient.shell.OutputManager', mock_output):
+ with CaptureOutput() as output:
args = _make_args("stat", {"auth_version": "3"},
os_opts, cmd_args=["testcontainer"])
self.assertRaises(SystemExit, swiftclient.shell.main, args)
- self.assertEqual(err.getvalue().strip(),
+ self.assertEqual(output.err.strip(),
'No project name or project id specified.')
def test_insufficient_env_vars_v3(self):
@@ -858,10 +844,8 @@ class TestParsing(unittest.TestCase):
opts = {"help": ""}
os_opts = {}
args = _make_args("stat", opts, os_opts)
- mock_stdout = six.StringIO()
- with mock.patch('sys.stdout', mock_stdout):
+ with CaptureOutput() as out:
self.assertRaises(SystemExit, swiftclient.shell.main, args)
- out = mock_stdout.getvalue()
self.assertTrue(out.find('[--key <api_key>]') > 0)
self.assertEqual(-1, out.find('--os-username=<auth-user-name>'))
@@ -872,20 +856,16 @@ class TestParsing(unittest.TestCase):
# "username": "user",
# "auth_url": "http://example.com:5000/v3"}
args = _make_args("", opts, os_opts)
- mock_stdout = six.StringIO()
- with mock.patch('sys.stdout', mock_stdout):
+ with CaptureOutput() as out:
self.assertRaises(SystemExit, swiftclient.shell.main, args)
- out = mock_stdout.getvalue()
self.assertTrue(out.find('[--key <api_key>]') > 0)
self.assertEqual(-1, out.find('--os-username=<auth-user-name>'))
## --os-help return os options help
opts = {}
args = _make_args("", opts, os_opts)
- mock_stdout = six.StringIO()
- with mock.patch('sys.stdout', mock_stdout):
+ with CaptureOutput() as out:
self.assertRaises(SystemExit, swiftclient.shell.main, args)
- out = mock_stdout.getvalue()
self.assertTrue(out.find('[--key <api_key>]') > 0)
self.assertTrue(out.find('--os-username=<auth-user-name>') > 0)
@@ -1150,18 +1130,3 @@ class TestKeystoneOptions(MockHttpTest):
opts = {'auth-version': '2.0'}
self._test_options(opts, os_opts)
-
-
-def _make_output_manager(stdout, stderr):
- class MockOutputManager(OutputManager):
- # This class is used to mock OutputManager so that we can
- # override stdout and stderr. Mocking sys.stdout & sys.stdout
- # doesn't work because they are argument defaults in the
- # OutputManager constructor and those defaults are pinned to
- # the value of sys.stdout/stderr before we get chance to mock them.
- def __init__(self, print_stream=None, error_stream=None):
- super(MockOutputManager, self).__init__()
- self.print_stream = stdout
- self.error_stream = stderr
-
- return MockOutputManager
diff --git a/tests/unit/utils.py b/tests/unit/utils.py
index c149abf..3cbb160 100644
--- a/tests/unit/utils.py
+++ b/tests/unit/utils.py
@@ -12,11 +12,16 @@
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+import functools
+import sys
from requests import RequestException
from time import sleep
import testtools
+import mock
+import six
from six.moves import reload_module
from swiftclient import client as c
+from swiftclient import shell as s
def fake_get_auth_keystone(os_options, exc=None, **kwargs):
@@ -213,3 +218,70 @@ class MockHttpTest(testtools.TestCase):
def tearDown(self):
super(MockHttpTest, self).tearDown()
reload_module(c)
+
+
+class CaptureStream(object):
+
+ def __init__(self, stream):
+ self.stream = stream
+ self._capture = six.StringIO()
+ self.streams = [self.stream, self._capture]
+
+ def write(self, *args, **kwargs):
+ for stream in self.streams:
+ stream.write(*args, **kwargs)
+
+ def writelines(self, *args, **kwargs):
+ for stream in self.streams:
+ stream.writelines(*args, **kwargs)
+
+ def getvalue(self):
+ return self._capture.getvalue()
+
+
+class CaptureOutput(object):
+
+ def __init__(self):
+ self._out = CaptureStream(sys.stdout)
+ self._err = CaptureStream(sys.stderr)
+
+ WrappedOutputManager = functools.partial(s.OutputManager,
+ print_stream=self._out,
+ error_stream=self._err)
+ self.patchers = [
+ mock.patch('swiftclient.shell.OutputManager',
+ WrappedOutputManager),
+ mock.patch('sys.stdout', self._out),
+ mock.patch('sys.stderr', self._err),
+ ]
+
+ def __enter__(self):
+ for patcher in self.patchers:
+ patcher.start()
+ return self
+
+ def __exit__(self, *args, **kwargs):
+ for patcher in self.patchers:
+ patcher.stop()
+
+ @property
+ def out(self):
+ return self._out.getvalue()
+
+ @property
+ def err(self):
+ return self._err.getvalue()
+
+ # act like the string captured by stdout
+
+ def __str__(self):
+ return self.out
+
+ def __len__(self):
+ return len(self.out)
+
+ def __eq__(self, other):
+ return self.out == other
+
+ def __getattr__(self, name):
+ return getattr(self.out, name)