Move the handlers into their own dir
And separate out json to its own file.
This commit is contained in:
parent
d4cd98e0b3
commit
48b52d246b
@ -37,6 +37,7 @@ import yaml
|
||||
|
||||
from gabbi import case
|
||||
from gabbi import handlers
|
||||
from gabbi.handlers import jsonhandler
|
||||
from gabbi import httpclient
|
||||
from gabbi import reporter
|
||||
from gabbi import suite as gabbi_suite
|
||||
@ -46,7 +47,7 @@ HANDLERS = [
|
||||
handlers.ForbiddenHeadersResponseHandler,
|
||||
handlers.HeadersResponseHandler,
|
||||
handlers.StringResponseHandler,
|
||||
handlers.JSONHandler,
|
||||
jsonhandler.JSONHandler,
|
||||
]
|
||||
|
||||
|
||||
|
@ -12,10 +12,6 @@
|
||||
# under the License.
|
||||
"""Handlers for processing the body of a response in various ways."""
|
||||
|
||||
import json
|
||||
|
||||
from gabbi import json_parser
|
||||
|
||||
|
||||
class ResponseHandler(object):
|
||||
"""Add functionality for making assertions about an HTTP response.
|
||||
@ -82,6 +78,35 @@ class ResponseHandler(object):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class ContentHandler(object):
|
||||
"""A mixin for ResponseHandlers that adds content handling."""
|
||||
|
||||
@staticmethod
|
||||
def accepts(content_type):
|
||||
"""Return True if this handler can handler this type."""
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def gen_replacer(test):
|
||||
"""Return a function which does RESPONSE replacing."""
|
||||
def replacer_func(match):
|
||||
return match.group('arg')
|
||||
return replacer_func
|
||||
|
||||
@staticmethod
|
||||
def dumps(data, pretty=False):
|
||||
"""Return structured data as a string.
|
||||
|
||||
If pretty is true, prettify.
|
||||
"""
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def loads(data):
|
||||
"""Create structured (Python) data from a stream."""
|
||||
return data
|
||||
|
||||
|
||||
class StringResponseHandler(ResponseHandler):
|
||||
"""Test for matching strings in the the response body."""
|
||||
|
||||
@ -141,99 +166,3 @@ class HeadersResponseHandler(ResponseHandler):
|
||||
test.assertEqual(header_value, response_value,
|
||||
'Expect header %s with value %s, got %s' %
|
||||
(header, header_value, response[header]))
|
||||
|
||||
|
||||
class ContentHandler(object):
|
||||
"""A mixin for ResponseHandlers that add content handling."""
|
||||
|
||||
@staticmethod
|
||||
def accepts(content_type):
|
||||
"""Return True if this handler can handler this type."""
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def gen_replacer(test):
|
||||
"""Return a function which does RESPONSE replacing."""
|
||||
def replacer_func(match):
|
||||
return match.group('arg')
|
||||
return replacer_func
|
||||
|
||||
@staticmethod
|
||||
def dumps(data, pretty=False):
|
||||
"""Return structured data as a string.
|
||||
|
||||
If pretty is true, prettify.
|
||||
"""
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def loads(data):
|
||||
"""Create structured (Python) data from a stream."""
|
||||
return data
|
||||
|
||||
|
||||
class JSONHandler(ResponseHandler, ContentHandler):
|
||||
|
||||
test_key_suffix = 'json_paths'
|
||||
test_key_value = {}
|
||||
|
||||
@staticmethod
|
||||
def accepts(content_type):
|
||||
content_type = content_type.split(';', 1)[0].strip()
|
||||
return (content_type.endswith('+json') or
|
||||
content_type.startswith('application/json'))
|
||||
|
||||
@classmethod
|
||||
def gen_replacer(cls, test):
|
||||
def replacer_func(match):
|
||||
path = match.group('arg')
|
||||
return str(cls.extract_json_path_value(
|
||||
test.prior.response_data, path))
|
||||
return replacer_func
|
||||
|
||||
@staticmethod
|
||||
def dumps(data, pretty=False):
|
||||
if pretty:
|
||||
return json.dumps(data, indent=2, separators=(',', ': '))
|
||||
else:
|
||||
return json.dumps(data)
|
||||
|
||||
@staticmethod
|
||||
def loads(data):
|
||||
return json.loads(data)
|
||||
|
||||
@staticmethod
|
||||
def extract_json_path_value(data, path):
|
||||
"""Extract the value at JSON Path path from the data.
|
||||
|
||||
The input data is a Python datastructure, not a JSON string.
|
||||
"""
|
||||
path_expr = json_parser.parse(path)
|
||||
matches = [match.value for match in path_expr.find(data)]
|
||||
if matches:
|
||||
if len(matches) > 1:
|
||||
return matches
|
||||
else:
|
||||
return matches[0]
|
||||
else:
|
||||
raise ValueError(
|
||||
"JSONPath '%s' failed to match on data: '%s'" % (path, data))
|
||||
|
||||
def action(self, test, path, value=None):
|
||||
"""Test json_paths against json data."""
|
||||
# NOTE: This process has some advantages over other process that
|
||||
# might come along because the JSON data has already been
|
||||
# processed (to provided for the magic template replacing).
|
||||
# Other handlers that want access to data structures will need
|
||||
# to do their own processing.
|
||||
try:
|
||||
match = self.extract_json_path_value(
|
||||
test.response_data, path)
|
||||
except AttributeError:
|
||||
raise AssertionError('unable to extract JSON from test results')
|
||||
except ValueError:
|
||||
raise AssertionError('json path %s cannot match %s' %
|
||||
(path, test.response_data))
|
||||
expected = test.replace_template(value)
|
||||
test.assertEqual(expected, match, 'Unable to match %s as %s, got %s'
|
||||
% (path, expected, match))
|
86
gabbi/handlers/jsonhandler.py
Normal file
86
gabbi/handlers/jsonhandler.py
Normal file
@ -0,0 +1,86 @@
|
||||
#
|
||||
# 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.
|
||||
"""JSON-related content handling."""
|
||||
|
||||
import json
|
||||
|
||||
from gabbi import handlers
|
||||
from gabbi import json_parser
|
||||
|
||||
|
||||
class JSONHandler(handlers.ResponseHandler,
|
||||
handlers.ContentHandler):
|
||||
|
||||
test_key_suffix = 'json_paths'
|
||||
test_key_value = {}
|
||||
|
||||
@staticmethod
|
||||
def accepts(content_type):
|
||||
content_type = content_type.split(';', 1)[0].strip()
|
||||
return (content_type.endswith('+json') or
|
||||
content_type.startswith('application/json'))
|
||||
|
||||
@classmethod
|
||||
def gen_replacer(cls, test):
|
||||
def replacer_func(match):
|
||||
path = match.group('arg')
|
||||
return str(cls.extract_json_path_value(
|
||||
test.prior.response_data, path))
|
||||
return replacer_func
|
||||
|
||||
@staticmethod
|
||||
def dumps(data, pretty=False):
|
||||
if pretty:
|
||||
return json.dumps(data, indent=2, separators=(',', ': '))
|
||||
else:
|
||||
return json.dumps(data)
|
||||
|
||||
@staticmethod
|
||||
def loads(data):
|
||||
return json.loads(data)
|
||||
|
||||
@staticmethod
|
||||
def extract_json_path_value(data, path):
|
||||
"""Extract the value at JSON Path path from the data.
|
||||
|
||||
The input data is a Python datastructure, not a JSON string.
|
||||
"""
|
||||
path_expr = json_parser.parse(path)
|
||||
matches = [match.value for match in path_expr.find(data)]
|
||||
if matches:
|
||||
if len(matches) > 1:
|
||||
return matches
|
||||
else:
|
||||
return matches[0]
|
||||
else:
|
||||
raise ValueError(
|
||||
"JSONPath '%s' failed to match on data: '%s'" % (path, data))
|
||||
|
||||
def action(self, test, path, value=None):
|
||||
"""Test json_paths against json data."""
|
||||
# NOTE: This process has some advantages over other process that
|
||||
# might come along because the JSON data has already been
|
||||
# processed (to provided for the magic template replacing).
|
||||
# Other handlers that want access to data structures will need
|
||||
# to do their own processing.
|
||||
try:
|
||||
match = self.extract_json_path_value(
|
||||
test.response_data, path)
|
||||
except AttributeError:
|
||||
raise AssertionError('unable to extract JSON from test results')
|
||||
except ValueError:
|
||||
raise AssertionError('json path %s cannot match %s' %
|
||||
(path, test.response_data))
|
||||
expected = test.replace_template(value)
|
||||
test.assertEqual(expected, match, 'Unable to match %s as %s, got %s'
|
||||
% (path, expected, match))
|
@ -19,6 +19,7 @@ import unittest
|
||||
from gabbi import case
|
||||
from gabbi import driver
|
||||
from gabbi import handlers
|
||||
from gabbi.handlers import jsonhandler
|
||||
|
||||
|
||||
class HandlersTest(unittest.TestCase):
|
||||
@ -83,7 +84,7 @@ class HandlersTest(unittest.TestCase):
|
||||
self.assertIn(' "location": "house"', msg)
|
||||
|
||||
def test_response_json_paths(self):
|
||||
handler = handlers.JSONHandler(self.test_class)
|
||||
handler = jsonhandler.JSONHandler(self.test_class)
|
||||
self.test.content_type = "application/json"
|
||||
self.test.test_data = {'response_json_paths': {
|
||||
'$.objects[0].name': 'cow',
|
||||
@ -98,7 +99,7 @@ class HandlersTest(unittest.TestCase):
|
||||
self._assert_handler(handler)
|
||||
|
||||
def test_response_json_paths_fail_data(self):
|
||||
handler = handlers.JSONHandler(self.test_class)
|
||||
handler = jsonhandler.JSONHandler(self.test_class)
|
||||
self.test.content_type = "application/json"
|
||||
self.test.test_data = {'response_json_paths': {
|
||||
'$.objects[0].name': 'cow',
|
||||
@ -114,7 +115,7 @@ class HandlersTest(unittest.TestCase):
|
||||
self._assert_handler(handler)
|
||||
|
||||
def test_response_json_paths_fail_path(self):
|
||||
handler = handlers.JSONHandler(self.test_class)
|
||||
handler = jsonhandler.JSONHandler(self.test_class)
|
||||
self.test.content_type = "application/json"
|
||||
self.test.test_data = {'response_json_paths': {
|
||||
'$.objects[1].name': 'cow',
|
||||
|
@ -15,10 +15,10 @@
|
||||
|
||||
import unittest
|
||||
|
||||
from gabbi import handlers
|
||||
from gabbi.handlers import jsonhandler
|
||||
|
||||
|
||||
extract = handlers.JSONHandler.extract_json_path_value
|
||||
extract = jsonhandler.JSONHandler.extract_json_path_value
|
||||
nested_data = {
|
||||
'objects': [
|
||||
{'name': 'one', 'value': 'alpha'},
|
||||
|
Loading…
Reference in New Issue
Block a user