Repository: cdent/gabbi

Issue:
Error when response content-type is application/jsonlines
If the response is `application/jsonlines` the JSON content handler kicks in and attempts to decode the response from json, which fails as it treats the whole doc as one single json object, not lines of json.

This is because the accept method for the handler is checking for a content type that starts with 'application/json'

So the simple fix is straightforward, but it might make better sense to create a jsonlines response handler and see if we can make a way to jsonpath on those lines.

Discussion:

Patch:
diff --git a/gabbi/handlers/jsonhandler.py b/gabbi/handlers/jsonhandler.py
index 6647f45..6177779 100644
--- a/gabbi/handlers/jsonhandler.py
+++ b/gabbi/handlers/jsonhandler.py
@@ -38,9 +38,14 @@ class JSONHandler(base.ContentHandler):
 
     @staticmethod
     def accepts(content_type):
-        content_type = content_type.split(';', 1)[0].strip()
+        content_type = content_type.lower()
+        parameters = ''
+        if ';' in content_type:
+            content_type, parameters = content_type.split(';', 1)
+        content_type = content_type.strip()
         return (content_type.endswith('+json') or
-                content_type.startswith('application/json'))
+                content_type == 'application/json'
+                and 'stream=' not in parameters)
 
     @classmethod
     def replacer(cls, response_data, match):


Test patch:
diff --git a/gabbi/tests/gabbits_intercept/self.yaml b/gabbi/tests/gabbits_intercept/self.yaml
index bdd0705..14def1c 100644
--- a/gabbi/tests/gabbits_intercept/self.yaml
+++ b/gabbi/tests/gabbits_intercept/self.yaml
@@ -149,22 +149,6 @@ tests:
   response_json_paths:
       $.data[0]: hello
 
-- name: json home content type is json
-  url: /?data=hello
-  method: GET
-  request_headers:
-      accept: application/json-home
-  response_json_paths:
-      $.data[0]: hello
-
-- name: json content type detection case insensitive
-  url: /?data=hello
-  method: GET
-  request_headers:
-      accept: ApPlIcAtIoN/JsOn-hOmE
-  response_json_paths:
-      $.data[0]: hello
-
 - name: xml derived content type
   desc: +xml types should not work for json paths
   xfail: true
diff --git a/gabbi/tests/test_handlers.py b/gabbi/tests/test_handlers.py
index b07e73f..17c753e 100644
--- a/gabbi/tests/test_handlers.py
+++ b/gabbi/tests/test_handlers.py
@@ -444,3 +444,40 @@ class HandlersTest(unittest.TestCase):
         # method and then run its tests to confirm.
         test = self.test('test_request')
         handler(test)
+
+
+class TestJSONHandlerAccept(unittest.TestCase):
+    """Test that the json handler accepts function.
+
+    We need to confirm that it returns True and False at the right
+    times. This is somewhat tricky as there are a fair number of
+    MIME-types that include the string "JSON" but aren't, as a
+    whole document, capable of being decoded.
+    """
+
+    def _test_content_type(self, content_type, expected):
+        if expected:
+            self.assertTrue(
+                jsonhandler.JSONHandler.accepts(content_type),
+                "expected %s to be accepted but it was not!" % content_type)
+        else:
+            self.assertFalse(
+                jsonhandler.JSONHandler.accepts(content_type),
+                "expected %s to not be accepted but it was!" % content_type)
+
+    def test_many_content_types(self):
+        cases = [
+            ("application/json", True),
+            ("application/JSON", True),
+            ("text/plain", False),
+            ("application/jsonlines", False),
+            ("application/json;stream=true", False),
+            ("application/json;streamable=pony", True),
+            ("application/stream+json", True),
+            ("application/xml", False),
+            ("application/json-seq", False),
+            ("application/json-home", False),
+        ]
+        for test in cases:
+            with self.subTest(test[0]):
+                self._test_content_type(*test)