From 702710be94ad7a5505c13bc11fd691bfdffdfa74 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Wed, 17 Jun 2015 12:04:25 +0100 Subject: [PATCH] Add the concept of a 'prefix' A prefix is applied to all the unqualifed URLs in a suite of tests. This is useful for testing live applications that are mounted at different points under a wsgi server. Fixes #46 --- docs/source/runner.rst | 9 +++++++++ gabbi/driver.py | 25 ++++++++++++++++++++++--- gabbi/runner.py | 14 +++++++++++++- gabbi/tests/test_driver.py | 24 +++++++++++++++++++----- gabbi/tests/test_gabbits/sample.yaml | 6 ++++++ gabbi/tests/test_gabbits/single.yaml | 4 ---- 6 files changed, 69 insertions(+), 13 deletions(-) create mode 100644 gabbi/tests/test_gabbits/sample.yaml delete mode 100644 gabbi/tests/test_gabbits/single.yaml diff --git a/docs/source/runner.rst b/docs/source/runner.rst index 6ba1f84..9a9135d 100644 --- a/docs/source/runner.rst +++ b/docs/source/runner.rst @@ -14,3 +14,12 @@ expressed directly in the YAML file or provided on the command line:: gabbi-run [host[:port]] < /my/test.yaml + +To facilitate using the same tests against the application mounted +in different locations in a WSGI server, a `prefix` may be provided +as a second argument:: + + gabbi-run host[:port] [prefix] < /my/test.yaml + +The value of prefix will be prepended to path porition of URLs that +are not fully qualified. diff --git a/gabbi/driver.py b/gabbi/driver.py index 62d0c6f..bced3d8 100644 --- a/gabbi/driver.py +++ b/gabbi/driver.py @@ -33,6 +33,7 @@ from unittest import suite import uuid import six +from six.moves.urllib import parse as urlparse import yaml from gabbi import case @@ -59,10 +60,22 @@ class TestBuilder(type): def build_tests(path, loader, host=None, port=8001, intercept=None, test_loader_name=None, fixture_module=None, - response_handlers=None): + response_handlers=None, prefix=None): """Read YAML files from a directory to create tests. Each YAML file represents an ordered sequence of HTTP requests. + + :param path: The directory where yaml files are located. + :param loader: The TestLoader. + :param host: The host to test against. Do not used with ``intercept``. + :param port: The port to test against. Used with ``host``. + :param intercept: WSGI app factory for wsgi-intercept. + :param test_loader_name: Base name for test classes. Rarely used. + :param fixture_module: Python module containing fixture classes. + :param response_handers: ResponseHandler classes. + :type response_handlers: List of ResponseHandler classes. + :param prefix: A URL prefix for all URLs that are not fully qualified. + :rtype: TestSuite containing TestSuites (one for each YAML file). """ if not (bool(host) ^ bool(intercept)): @@ -93,7 +106,7 @@ def build_tests(path, loader, host=None, port=8001, intercept=None, os.path.basename(test_file))[0]) file_suite = test_suite_from_yaml(loader, test_name, test_yaml, path, host, port, fixture_module, - intercept) + intercept, prefix) top_suite.addTest(file_suite) return top_suite @@ -118,7 +131,7 @@ def test_update(orig_dict, new_dict): def test_suite_from_yaml(loader, test_base_name, test_yaml, test_directory, - host, port, fixture_module, intercept): + host, port, fixture_module, intercept, prefix=None): """Generate a TestSuite from YAML data.""" file_suite = gabbi_suite.GabbiSuite() @@ -153,6 +166,12 @@ def test_suite_from_yaml(loader, test_base_name, test_yaml, test_directory, raise AssertionError('Test url missing in test %s.' % test_name) + if prefix: + # Only add prefix to urls that have no scheme or netloc + parsed_url = urlparse.urlsplit(test['url']) + if not (parsed_url[0] and parsed_url[1]): + test['url'] = '%s%s' % (prefix, test['url']) + test_key_set = set(test.keys()) if test_key_set != base_test_key_set: raise AssertionError( diff --git a/gabbi/runner.py b/gabbi/runner.py index f852da8..bc05888 100644 --- a/gabbi/runner.py +++ b/gabbi/runner.py @@ -36,6 +36,11 @@ def run(): gabbi-run example.com:9999 < mytest.yaml + If is also possible to provide a URL prefix which can be useful if the + target application might be mounted in different locations. An example: + + gabbi-run example.com:9999 /mountpoint < mytest.yaml + Output is formatted as unittest summary information. """ try: @@ -47,6 +52,12 @@ def run(): port = None except IndexError: host, port = 'stub', None + + try: + prefix = sys.argv[2] + except IndexError: + prefix = None + loader = unittest.defaultTestLoader # Initialize the extensions for response handling. @@ -55,7 +66,8 @@ def run(): data = yaml.safe_load(sys.stdin.read()) suite = driver.test_suite_from_yaml(loader, 'input', data, '.', - host, port, None, None) + host, port, None, None, + prefix=prefix) result = unittest.TextTestRunner(verbosity=2).run(suite) sys.exit(not result.wasSuccessful()) diff --git a/gabbi/tests/test_driver.py b/gabbi/tests/test_driver.py index 299082c..7cda438 100644 --- a/gabbi/tests/test_driver.py +++ b/gabbi/tests/test_driver.py @@ -30,16 +30,30 @@ class DriverTest(unittest.TestCase): self.loader = unittest.defaultTestLoader self.test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR) - def test_driver_loads_one_test(self): + def test_driver_loads_two_tests(self): suite = driver.build_tests(self.test_dir, self.loader, host='localhost', port=8001) self.assertEqual(1, len(suite._tests), 'top level suite contains one suite') - self.assertEqual(1, len(suite._tests[0]._tests), - 'contained suite contains one test') - self.assertEqual('test_driver_single_one', - suite._tests[0]._tests[0].__class__.__name__, + self.assertEqual(2, len(suite._tests[0]._tests), + 'contained suite contains two tests') + the_one_test = suite._tests[0]._tests[0] + self.assertEqual('test_driver_sample_one', + the_one_test.__class__.__name__, 'test class name maps') + self.assertEqual('one', + the_one_test.test_data['name']) + self.assertEqual('/', the_one_test.test_data['url']) + + def test_driver_prefix(self): + suite = driver.build_tests(self.test_dir, self.loader, + host='localhost', port=8001, + prefix='/mountpoint') + the_one_test = suite._tests[0]._tests[0] + the_two_test = suite._tests[0]._tests[1] + self.assertEqual('/mountpoint/', the_one_test.test_data['url']) + self.assertEqual('http://example.com/moo', + the_two_test.test_data['url']) def test_build_requires_host_or_intercept(self): with self.assertRaises(AssertionError): diff --git a/gabbi/tests/test_gabbits/sample.yaml b/gabbi/tests/test_gabbits/sample.yaml new file mode 100644 index 0000000..185e378 --- /dev/null +++ b/gabbi/tests/test_gabbits/sample.yaml @@ -0,0 +1,6 @@ + +tests: + - name: one + url: / + - name: two + url: http://example.com/moo diff --git a/gabbi/tests/test_gabbits/single.yaml b/gabbi/tests/test_gabbits/single.yaml deleted file mode 100644 index d4674eb..0000000 --- a/gabbi/tests/test_gabbits/single.yaml +++ /dev/null @@ -1,4 +0,0 @@ - -tests: - - name: one - url: /