Merge branch 'master' into fix-pytest-yield
This commit is contained in:
commit
d2175fa89b
@ -269,8 +269,9 @@ flexibility when doing a ``POST`` or ``PUT``. If the value is not a
|
||||
string (that is, it is a sequence or structure) it is treated as a
|
||||
data structure which is turned into a JSON string. If the value is a
|
||||
string that begins with ``<@`` then the rest of the string is treated
|
||||
as the name of a file to be loaded from the same directory as the YAML
|
||||
file. If the value is an undecorated string, that's the value.
|
||||
as a filepath to be loaded. The path is relative to the test directory
|
||||
and may not traverse up into parent directories. If the value is an
|
||||
undecorated string, that's the value.
|
||||
|
||||
When reading from a file care should be taken to ensure that a
|
||||
reasonable content-type is set for the data as this will control if any
|
||||
|
@ -50,3 +50,6 @@ YAML will default to ``ssl: True``.
|
||||
|
||||
If a ``-x`` or ``--failfast`` argument is provided then ``gabbi-run`` will
|
||||
exit after the first test failure.
|
||||
|
||||
Use ``-v`` or ``--verbose`` with a value of ``all``, ``headers`` or ``body``
|
||||
to turn on :ref:`verbosity <metadata>` for all tests being run.
|
||||
|
@ -243,7 +243,13 @@ class HTTPTestCase(testtools.TestCase):
|
||||
|
||||
def _load_data_file(self, filename):
|
||||
"""Read a file from the current test directory."""
|
||||
path = os.path.join(self.test_directory, os.path.basename(filename))
|
||||
path = os.path.join(self.test_directory, filename)
|
||||
has_dir_traversal = os.path.relpath(
|
||||
path, start=self.test_directory).startswith(os.pardir)
|
||||
if has_dir_traversal:
|
||||
raise ValueError(
|
||||
'Attempted loading of data file outside test directory: %s'
|
||||
% filename)
|
||||
with open(path, mode='rb') as data_file:
|
||||
return data_file.read()
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
import argparse
|
||||
from importlib import import_module
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
@ -57,6 +58,9 @@ def run():
|
||||
|
||||
gabbi-run -x example.com:9999 /mountpoint < mytest.yaml
|
||||
|
||||
Use `-v` or `--verbose` with a value of `all`, `headers` or `body` to
|
||||
turn on verbosity for all tests being run.
|
||||
|
||||
Multiple files may be named as arguments, separated from other arguments
|
||||
by a ``--``. Each file will be run as a separate test suite::
|
||||
|
||||
@ -74,18 +78,21 @@ def run():
|
||||
|
||||
handler_objects = initialize_handlers(args.response_handlers)
|
||||
|
||||
verbosity = args.verbosity
|
||||
failfast = args.failfast
|
||||
failure = False
|
||||
|
||||
if not input_files:
|
||||
success = run_suite(sys.stdin, handler_objects, host, port,
|
||||
prefix, force_ssl, failfast)
|
||||
prefix, force_ssl, failfast, verbosity)
|
||||
failure = not success
|
||||
else:
|
||||
for input_file in input_files:
|
||||
with open(input_file, 'r') as fh:
|
||||
data_dir = os.path.dirname(input_file)
|
||||
success = run_suite(fh, handler_objects, host, port,
|
||||
prefix, force_ssl, failfast)
|
||||
prefix, force_ssl, failfast, data_dir,
|
||||
verbosity)
|
||||
if not failure: # once failed, this is considered immutable
|
||||
failure = not success
|
||||
if failure and failfast:
|
||||
@ -95,7 +102,7 @@ def run():
|
||||
|
||||
|
||||
def run_suite(handle, handler_objects, host, port, prefix, force_ssl=False,
|
||||
failfast=False):
|
||||
failfast=False, data_dir='.', verbosity=False):
|
||||
"""Run the tests from the YAML in handle."""
|
||||
data = utils.load_yaml(handle)
|
||||
if force_ssl:
|
||||
@ -103,10 +110,15 @@ def run_suite(handle, handler_objects, host, port, prefix, force_ssl=False,
|
||||
data['defaults']['ssl'] = True
|
||||
else:
|
||||
data['defaults'] = {'ssl': True}
|
||||
if verbosity:
|
||||
if 'defaults' in data:
|
||||
data['defaults']['verbose'] = verbosity
|
||||
else:
|
||||
data['defaults'] = {'verbose': verbosity}
|
||||
|
||||
loader = unittest.defaultTestLoader
|
||||
test_suite = suitemaker.test_suite_from_dict(
|
||||
loader, 'input', data, '.', host, port, None, None, prefix=prefix,
|
||||
loader, 'input', data, data_dir, host, port, None, None, prefix=prefix,
|
||||
handlers=handler_objects)
|
||||
|
||||
result = ConciseTestRunner(
|
||||
@ -194,6 +206,12 @@ def _make_argparser():
|
||||
help='Custom response handler. Should be an import path of the '
|
||||
'form package.module or package.module:class.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-v', '--verbose',
|
||||
dest='verbosity',
|
||||
choices=['all', 'body', 'headers'],
|
||||
help='Turn on test verbosity for all tests run in this session.'
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
|
1
gabbi/tests/gabbits_runner/subdir/sample.json
Normal file
1
gabbi/tests/gabbits_runner/subdir/sample.json
Normal file
@ -0,0 +1 @@
|
||||
{"items": {"house": "blue"}}
|
8
gabbi/tests/gabbits_runner/test_data.yaml
Normal file
8
gabbi/tests/gabbits_runner/test_data.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
tests:
|
||||
|
||||
- name: POST data from file
|
||||
verbose: true
|
||||
POST: /
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data: <@subdir/sample.json
|
8
gabbi/tests/gabbits_runner/verbosity.yaml
Normal file
8
gabbi/tests/gabbits_runner/verbosity.yaml
Normal file
@ -0,0 +1,8 @@
|
||||
tests:
|
||||
|
||||
- name: simple data post
|
||||
POST: /
|
||||
request_headers:
|
||||
content-type: application/json
|
||||
data:
|
||||
cat: poppy
|
77
gabbi/tests/test_load_data_file.py
Normal file
77
gabbi/tests/test_load_data_file.py
Normal file
@ -0,0 +1,77 @@
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""Test loading data from files with <@.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from gabbi import case
|
||||
from six.moves import mock
|
||||
|
||||
|
||||
@mock.patch(
|
||||
'gabbi.case.open',
|
||||
new_callable=mock.mock_open,
|
||||
read_data='dummy content',
|
||||
create=True,
|
||||
)
|
||||
class DataFileTest(unittest.TestCase):
|
||||
"""Reading from local file is only allowed at or below the
|
||||
test_directory level.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.http_case = case.HTTPTestCase('test_request')
|
||||
|
||||
def _assert_content_read(self, filepath):
|
||||
self.assertEqual(
|
||||
'dummy content', self.http_case._load_data_file(filepath))
|
||||
|
||||
def test_load_file(self, m_open):
|
||||
self.http_case.test_directory = '.'
|
||||
self._assert_content_read('data.json')
|
||||
m_open.assert_called_with('./data.json', mode='rb')
|
||||
|
||||
def test_load_file_in_directory(self, m_open):
|
||||
self.http_case.test_directory = '.'
|
||||
self._assert_content_read('a/b/c/data.json')
|
||||
m_open.assert_called_with('./a/b/c/data.json', mode='rb')
|
||||
|
||||
def test_load_file_in_root(self, m_open):
|
||||
self.http_case.test_directory = '.'
|
||||
filepath = '/top-level.private'
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
self.http_case._load_data_file(filepath)
|
||||
self.assertFalse(m_open.called)
|
||||
|
||||
def test_load_file_in_parent_dir(self, m_open):
|
||||
self.http_case.test_directory = '.'
|
||||
filepath = '../file-in-parent-dir.txt'
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
self.http_case._load_data_file(filepath)
|
||||
self.assertFalse(m_open.called)
|
||||
|
||||
def test_load_file_within_test_directory(self, m_open):
|
||||
self.http_case.test_directory = '/a/b/c'
|
||||
self._assert_content_read('../../b/c/file-in-test-dir.txt')
|
||||
m_open.assert_called_with(
|
||||
'/a/b/c/../../b/c/file-in-test-dir.txt', mode='rb')
|
||||
|
||||
def test_load_file_not_within_test_directory(self, m_open):
|
||||
self.http_case.test_directory = '/a/b/c'
|
||||
filepath = '../../b/E/file-in-test-dir.txt'
|
||||
with self.assertRaises(ValueError):
|
||||
self.http_case._load_data_file(filepath)
|
||||
self.assertFalse(m_open.called)
|
@ -22,6 +22,7 @@ from wsgi_intercept.interceptor import Urllib3Interceptor
|
||||
|
||||
from gabbi import exception
|
||||
from gabbi.handlers import base
|
||||
from gabbi.handlers.jsonhandler import JSONHandler
|
||||
from gabbi import runner
|
||||
from gabbi.tests.simple_wsgi import SimpleWsgi
|
||||
|
||||
@ -249,6 +250,77 @@ class RunnerTest(unittest.TestCase):
|
||||
self.assertIn('{\n', output)
|
||||
self.assertIn('}\n', output)
|
||||
|
||||
def test_data_dir_good(self):
|
||||
"""Confirm that data dir is the test file's dir."""
|
||||
sys.argv = ['gabbi-run', 'http://%s:%s/foo' % (self.host, self.port)]
|
||||
|
||||
sys.argv.append('--')
|
||||
sys.argv.append('gabbi/tests/gabbits_runner/test_data.yaml')
|
||||
|
||||
with self.server():
|
||||
try:
|
||||
runner.run()
|
||||
except SystemExit as err:
|
||||
self.assertSuccess(err)
|
||||
|
||||
# Compare the verbose output of tests with pretty printed
|
||||
# data.
|
||||
with open('gabbi/tests/gabbits_runner/subdir/sample.json') as data:
|
||||
data = JSONHandler.loads(data.read())
|
||||
expected_string = JSONHandler.dumps(data, pretty=True)
|
||||
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
self.assertIn(expected_string, output)
|
||||
|
||||
def _run_verbosity_arg(self):
|
||||
sys.argv.append('--')
|
||||
sys.argv.append('gabbi/tests/gabbits_runner/verbosity.yaml')
|
||||
|
||||
with self.server():
|
||||
try:
|
||||
runner.run()
|
||||
except SystemExit as err:
|
||||
self.assertSuccess(err)
|
||||
|
||||
sys.stdout.seek(0)
|
||||
output = sys.stdout.read()
|
||||
return output
|
||||
|
||||
def test_verbosity_arg_none(self):
|
||||
"""Confirm --verbose handling."""
|
||||
sys.argv = ['gabbi-run', 'http://%s:%s/foo' % (self.host, self.port)]
|
||||
|
||||
output = self._run_verbosity_arg()
|
||||
self.assertEqual('', output)
|
||||
|
||||
def test_verbosity_arg_body(self):
|
||||
"""Confirm --verbose handling."""
|
||||
sys.argv = ['gabbi-run', 'http://%s:%s/foo' % (self.host, self.port),
|
||||
'--verbose=body']
|
||||
|
||||
output = self._run_verbosity_arg()
|
||||
self.assertIn('{\n "cat": "poppy"\n}', output)
|
||||
self.assertNotIn('application/json', output)
|
||||
|
||||
def test_verbosity_arg_headers(self):
|
||||
"""Confirm --verbose handling."""
|
||||
sys.argv = ['gabbi-run', 'http://%s:%s/foo' % (self.host, self.port),
|
||||
'--verbose=headers']
|
||||
|
||||
output = self._run_verbosity_arg()
|
||||
self.assertNotIn('{\n "cat": "poppy"\n}', output)
|
||||
self.assertIn('application/json', output)
|
||||
|
||||
def test_verbosity_arg_all(self):
|
||||
"""Confirm --verbose handling."""
|
||||
sys.argv = ['gabbi-run', 'http://%s:%s/foo' % (self.host, self.port),
|
||||
'--verbose=all']
|
||||
|
||||
output = self._run_verbosity_arg()
|
||||
self.assertIn('{\n "cat": "poppy"\n}', output)
|
||||
self.assertIn('application/json', output)
|
||||
|
||||
def assertSuccess(self, exitError):
|
||||
errors = exitError.args[0]
|
||||
if errors:
|
||||
|
Loading…
Reference in New Issue
Block a user