Runner cleanup (#141)
Extract methods from the run() method in runner.py to make the processing of information easier to test and easier to assemble. Most methods were kept in runner.py but loading yaml was extracted to utils.py where it can be reused by driver.py.
This commit is contained in:
parent
2013e4ed74
commit
e2964930a9
gabbi
@ -25,18 +25,16 @@ An entire directory of YAML files is a TestSuite of TestSuites.
|
||||
|
||||
import glob
|
||||
import inspect
|
||||
import io
|
||||
import os
|
||||
import unittest
|
||||
from unittest import suite
|
||||
import uuid
|
||||
|
||||
import yaml
|
||||
|
||||
from gabbi import case
|
||||
from gabbi import handlers
|
||||
from gabbi import reporter
|
||||
from gabbi import suitemaker
|
||||
from gabbi import utils
|
||||
|
||||
|
||||
def build_tests(path, loader, host=None, port=8001, intercept=None,
|
||||
@ -79,7 +77,7 @@ def build_tests(path, loader, host=None, port=8001, intercept=None,
|
||||
for test_file in glob.iglob('%s/*.yaml' % path):
|
||||
if intercept:
|
||||
host = str(uuid.uuid4())
|
||||
suite_dict = load_yaml(test_file)
|
||||
suite_dict = utils.load_yaml(yaml_file=test_file)
|
||||
test_base_name = '%s_%s' % (
|
||||
test_loader_name, os.path.splitext(os.path.basename(test_file))[0])
|
||||
|
||||
@ -124,12 +122,6 @@ def py_test_generator(test_dir, host=None, port=8001, intercept=None,
|
||||
yield 'stop_%s' % test._tests[0].__class__.__name__, test.stop
|
||||
|
||||
|
||||
def load_yaml(yaml_file):
|
||||
"""Read and parse any YAML file. Let exceptions flow where they may."""
|
||||
with io.open(yaml_file, encoding='utf-8') as source:
|
||||
return yaml.safe_load(source.read())
|
||||
|
||||
|
||||
def test_suite_from_yaml(loader, test_base_name, test_yaml, test_directory,
|
||||
host, port, fixture_module, intercept, prefix=''):
|
||||
"""Legacy wrapper retained for backwards compatibility."""
|
||||
|
@ -18,12 +18,12 @@ import sys
|
||||
import unittest
|
||||
|
||||
from six.moves.urllib import parse as urlparse
|
||||
import yaml
|
||||
|
||||
from gabbi import case
|
||||
from gabbi import handlers
|
||||
from gabbi.reporter import ConciseTestRunner
|
||||
from gabbi import suitemaker
|
||||
from gabbi import utils
|
||||
|
||||
|
||||
def run():
|
||||
@ -91,39 +91,15 @@ def run():
|
||||
help='Custom response handler. Should be an import path of the '
|
||||
'form package.module or package.module:class.'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
force_ssl = False
|
||||
split_url = urlparse.urlsplit(args.target)
|
||||
if split_url.scheme:
|
||||
target = split_url.netloc
|
||||
prefix = split_url.path
|
||||
if split_url.scheme == 'https':
|
||||
force_ssl = True
|
||||
else:
|
||||
target = args.target
|
||||
prefix = args.prefix
|
||||
|
||||
if ':' in target and '[' not in target:
|
||||
host, port = target.rsplit(':', 1)
|
||||
elif ']:' in target:
|
||||
host, port = target.rsplit(':', 1)
|
||||
else:
|
||||
host = target
|
||||
port = None
|
||||
host = host.replace('[', '').replace(']', '')
|
||||
host, port, prefix, force_ssl = process_target_args(
|
||||
args.target, args.prefix)
|
||||
|
||||
# Initialize response handlers.
|
||||
custom_response_handlers = []
|
||||
for import_path in args.response_handlers or []:
|
||||
for handler in load_response_handlers(import_path):
|
||||
custom_response_handlers.append(handler)
|
||||
for handler in handlers.RESPONSE_HANDLERS + custom_response_handlers:
|
||||
handler(case.HTTPTestCase)
|
||||
initialize_handlers(args.response_handlers)
|
||||
|
||||
data = yaml.safe_load(sys.stdin.read())
|
||||
# Only override the default if we are forcing a change, there may
|
||||
# already be a default.
|
||||
data = utils.load_yaml(handle=sys.stdin)
|
||||
if force_ssl:
|
||||
if 'defaults' in data:
|
||||
data['defaults']['ssl'] = True
|
||||
@ -137,6 +113,40 @@ def run():
|
||||
sys.exit(not result.wasSuccessful())
|
||||
|
||||
|
||||
def process_target_args(target, prefix):
|
||||
"""Turn the argparse args into a host, port and prefix."""
|
||||
force_ssl = False
|
||||
split_url = urlparse.urlparse(target)
|
||||
|
||||
if split_url.scheme:
|
||||
if split_url.scheme == 'https':
|
||||
force_ssl = True
|
||||
return split_url.hostname, split_url.port, split_url.path, force_ssl
|
||||
else:
|
||||
target = target
|
||||
prefix = prefix
|
||||
|
||||
if ':' in target and '[' not in target:
|
||||
host, port = target.rsplit(':', 1)
|
||||
elif ']:' in target:
|
||||
host, port = target.rsplit(':', 1)
|
||||
else:
|
||||
host = target
|
||||
port = None
|
||||
host = host.replace('[', '').replace(']', '')
|
||||
|
||||
return host, port, prefix, force_ssl
|
||||
|
||||
|
||||
def initialize_handlers(response_handlers):
|
||||
custom_response_handlers = []
|
||||
for import_path in response_handlers or []:
|
||||
for handler in load_response_handlers(import_path):
|
||||
custom_response_handlers.append(handler)
|
||||
for handler in handlers.RESPONSE_HANDLERS + custom_response_handlers:
|
||||
handler(case.HTTPTestCase)
|
||||
|
||||
|
||||
def load_response_handlers(import_path):
|
||||
"""Load and return custom response handlers from the given Python package
|
||||
or module.
|
||||
|
@ -14,7 +14,6 @@
|
||||
"""
|
||||
|
||||
import copy
|
||||
import mock
|
||||
import sys
|
||||
import unittest
|
||||
from uuid import uuid4
|
||||
@ -232,38 +231,50 @@ class RunnerTest(unittest.TestCase):
|
||||
|
||||
class RunnerHostArgParse(unittest.TestCase):
|
||||
|
||||
@mock.patch('sys.exit')
|
||||
@mock.patch('sys.stdin')
|
||||
@mock.patch('gabbi.suitemaker.test_suite_from_dict')
|
||||
@mock.patch('yaml.safe_load', return_value={})
|
||||
def _test_hostport(self, url_or_host, expected_host,
|
||||
portmock_yaml, mock_test_suite, mock_read, mock_exit,
|
||||
provided_prefix=None, expected_port=None,
|
||||
expected_prefix=None, expected_data=None):
|
||||
sys.argv = ['gabbi-run', url_or_host]
|
||||
if provided_prefix:
|
||||
sys.argv.append(provided_prefix)
|
||||
runner.run()
|
||||
expected_prefix=None, expected_ssl=False):
|
||||
host, port, prefix, ssl = runner.process_target_args(
|
||||
url_or_host, provided_prefix)
|
||||
|
||||
expected_data = expected_data or {}
|
||||
# normalize hosts, they are case insensitive
|
||||
self.assertEqual(expected_host.lower(), host.lower())
|
||||
# port can be a string or int depending on the inputs
|
||||
self.assertEqual(expected_port, port)
|
||||
self.assertEqual(expected_prefix, prefix)
|
||||
self.assertEqual(expected_ssl, ssl)
|
||||
|
||||
mock_test_suite.assert_called_with(
|
||||
unittest.defaultTestLoader, 'input', expected_data,
|
||||
'.', expected_host, expected_port, None, None,
|
||||
prefix=expected_prefix
|
||||
)
|
||||
def test_plain_url_no_port(self):
|
||||
self._test_hostport('http://foobar.com/news',
|
||||
'foobar.com',
|
||||
expected_port=None,
|
||||
expected_prefix='/news')
|
||||
|
||||
def test_plain_url(self):
|
||||
def test_plain_url_with_port(self):
|
||||
self._test_hostport('http://foobar.com:80/news',
|
||||
'foobar.com',
|
||||
expected_port='80',
|
||||
expected_port=80,
|
||||
expected_prefix='/news')
|
||||
|
||||
def test_ssl_url(self):
|
||||
self._test_hostport('https://foobar.com/news',
|
||||
'foobar.com',
|
||||
expected_prefix='/news',
|
||||
expected_data={'defaults': {'ssl': True}})
|
||||
expected_ssl=True)
|
||||
|
||||
def test_ssl_port80_url(self):
|
||||
self._test_hostport('https://foobar.com:80/news',
|
||||
'foobar.com',
|
||||
expected_prefix='/news',
|
||||
expected_port=80,
|
||||
expected_ssl=True)
|
||||
|
||||
def test_ssl_port_url(self):
|
||||
self._test_hostport('https://foobar.com:999/news',
|
||||
'foobar.com',
|
||||
expected_prefix='/news',
|
||||
expected_port=999,
|
||||
expected_ssl=True)
|
||||
|
||||
def test_simple_hostport(self):
|
||||
self._test_hostport('foobar.com:999',
|
||||
@ -281,14 +292,14 @@ class RunnerHostArgParse(unittest.TestCase):
|
||||
self._test_hostport(
|
||||
'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:999/news',
|
||||
'FEDC:BA98:7654:3210:FEDC:BA98:7654:3210',
|
||||
expected_port='999',
|
||||
expected_port=999,
|
||||
expected_prefix='/news')
|
||||
|
||||
def test_ipv6_url_localhost(self):
|
||||
self._test_hostport(
|
||||
'http://[::1]:999/news',
|
||||
'::1',
|
||||
expected_port='999',
|
||||
expected_port=999,
|
||||
expected_prefix='/news')
|
||||
|
||||
def test_ipv6_host_localhost(self):
|
||||
|
@ -12,8 +12,11 @@
|
||||
# under the License.
|
||||
"""Utility functions grab bag."""
|
||||
|
||||
import io
|
||||
import os
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
try: # Python 3
|
||||
ConnectionRefused = ConnectionRefusedError
|
||||
@ -99,6 +102,21 @@ def get_colorizer(stream):
|
||||
return lambda x, y: y
|
||||
|
||||
|
||||
def load_yaml(handle=None, yaml_file=None):
|
||||
"""Read and parse any YAML file or filehandle.
|
||||
|
||||
Let exceptions flow where they may.
|
||||
|
||||
If no file or handle is provided, read from STDIN.
|
||||
"""
|
||||
if yaml_file:
|
||||
with io.open(yaml_file, encoding='utf-8') as source:
|
||||
return yaml.safe_load(source.read())
|
||||
|
||||
# This will intentionally raise AttributeError if handle is None.
|
||||
return yaml.safe_load(handle.read())
|
||||
|
||||
|
||||
def not_binary(content_type):
|
||||
"""Decide if something is content we'd like to treat as a string."""
|
||||
return (content_type.startswith('text/') or
|
||||
|
Loading…
x
Reference in New Issue
Block a user