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
|
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
|
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
|
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
|
as a filepath to be loaded. The path is relative to the test directory
|
||||||
file. If the value is an undecorated string, that's the value.
|
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
|
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
|
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
|
If a ``-x`` or ``--failfast`` argument is provided then ``gabbi-run`` will
|
||||||
exit after the first test failure.
|
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):
|
def _load_data_file(self, filename):
|
||||||
"""Read a file from the current test directory."""
|
"""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:
|
with open(path, mode='rb') as data_file:
|
||||||
return data_file.read()
|
return data_file.read()
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@ -57,6 +58,9 @@ def run():
|
|||||||
|
|
||||||
gabbi-run -x example.com:9999 /mountpoint < mytest.yaml
|
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
|
Multiple files may be named as arguments, separated from other arguments
|
||||||
by a ``--``. Each file will be run as a separate test suite::
|
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)
|
handler_objects = initialize_handlers(args.response_handlers)
|
||||||
|
|
||||||
|
verbosity = args.verbosity
|
||||||
failfast = args.failfast
|
failfast = args.failfast
|
||||||
failure = False
|
failure = False
|
||||||
|
|
||||||
if not input_files:
|
if not input_files:
|
||||||
success = run_suite(sys.stdin, handler_objects, host, port,
|
success = run_suite(sys.stdin, handler_objects, host, port,
|
||||||
prefix, force_ssl, failfast)
|
prefix, force_ssl, failfast, verbosity)
|
||||||
failure = not success
|
failure = not success
|
||||||
else:
|
else:
|
||||||
for input_file in input_files:
|
for input_file in input_files:
|
||||||
with open(input_file, 'r') as fh:
|
with open(input_file, 'r') as fh:
|
||||||
|
data_dir = os.path.dirname(input_file)
|
||||||
success = run_suite(fh, handler_objects, host, port,
|
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
|
if not failure: # once failed, this is considered immutable
|
||||||
failure = not success
|
failure = not success
|
||||||
if failure and failfast:
|
if failure and failfast:
|
||||||
@ -95,7 +102,7 @@ def run():
|
|||||||
|
|
||||||
|
|
||||||
def run_suite(handle, handler_objects, host, port, prefix, force_ssl=False,
|
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."""
|
"""Run the tests from the YAML in handle."""
|
||||||
data = utils.load_yaml(handle)
|
data = utils.load_yaml(handle)
|
||||||
if force_ssl:
|
if force_ssl:
|
||||||
@ -103,10 +110,15 @@ def run_suite(handle, handler_objects, host, port, prefix, force_ssl=False,
|
|||||||
data['defaults']['ssl'] = True
|
data['defaults']['ssl'] = True
|
||||||
else:
|
else:
|
||||||
data['defaults'] = {'ssl': True}
|
data['defaults'] = {'ssl': True}
|
||||||
|
if verbosity:
|
||||||
|
if 'defaults' in data:
|
||||||
|
data['defaults']['verbose'] = verbosity
|
||||||
|
else:
|
||||||
|
data['defaults'] = {'verbose': verbosity}
|
||||||
|
|
||||||
loader = unittest.defaultTestLoader
|
loader = unittest.defaultTestLoader
|
||||||
test_suite = suitemaker.test_suite_from_dict(
|
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)
|
handlers=handler_objects)
|
||||||
|
|
||||||
result = ConciseTestRunner(
|
result = ConciseTestRunner(
|
||||||
@ -194,6 +206,12 @@ def _make_argparser():
|
|||||||
help='Custom response handler. Should be an import path of the '
|
help='Custom response handler. Should be an import path of the '
|
||||||
'form package.module or package.module:class.'
|
'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
|
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 import exception
|
||||||
from gabbi.handlers import base
|
from gabbi.handlers import base
|
||||||
|
from gabbi.handlers.jsonhandler import JSONHandler
|
||||||
from gabbi import runner
|
from gabbi import runner
|
||||||
from gabbi.tests.simple_wsgi import SimpleWsgi
|
from gabbi.tests.simple_wsgi import SimpleWsgi
|
||||||
|
|
||||||
@ -249,6 +250,77 @@ class RunnerTest(unittest.TestCase):
|
|||||||
self.assertIn('{\n', output)
|
self.assertIn('{\n', output)
|
||||||
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):
|
def assertSuccess(self, exitError):
|
||||||
errors = exitError.args[0]
|
errors = exitError.args[0]
|
||||||
if errors:
|
if errors:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user