Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MalformedJsonException is thrown is thrown if a response does not have Content-Type header #1013

Open
flexfrank opened this issue Feb 4, 2020 · 12 comments

Comments

@flexfrank
Copy link

I test a API that does not have Content-Type header by pact.
ProviderClient treats its response body as application/json and failed to parse.
I think the should be treated as application/octet-stream by default.

0 - com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 7 path $
com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 7 path $
	at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1564)
	at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1405)
	at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:543)
	at com.google.gson.stream.JsonReader.peek(JsonReader.java:426)
	at com.google.gson.JsonParser.parseReader(JsonParser.java:61)
	at com.google.gson.JsonParser.parseString(JsonParser.java:47)
	at com.google.gson.JsonParser.parse(JsonParser.java:98)
	at au.com.dius.pact.provider.ResponseComparison$Companion.generateFullDiff(ResponseComparison.kt:91)
	at au.com.dius.pact.provider.ResponseComparison$Companion.access$generateFullDiff(ResponseComparison.kt:85)
	at au.com.dius.pact.provider.ResponseComparison.bodyResult(ResponseComparison.kt:79)
	at au.com.dius.pact.provider.ResponseComparison$Companion.compareResponse(ResponseComparison.kt:124)
	at au.com.dius.pact.provider.ProviderVerifier.verifyRequestResponsePact(ProviderVerifier.kt:476)
	at au.com.dius.pact.provider.junit5.PactVerificationContext.validateTestExecution(PactJUnit5VerificationProvider.kt:96)
	at au.com.dius.pact.provider.junit5.PactVerificationContext.verifyInteraction(PactJUnit5VerificationProvider.kt:77)

https://github.com/DiUS/pact-jvm/blob/master/provider/pact-jvm-provider/src/main/kotlin/au/com/dius/pact/provider/ProviderClient.kt#L363-L367

@PabloThiele
Copy link

PabloThiele commented Feb 7, 2020

Adding some support on the discussion: HTTP RFC Item 7.2.1
The problem is that seems to change a previous default behavior can be treated as major change.

@uglyog
Copy link
Member

uglyog commented Feb 22, 2020

This is a regression, it should treat it as text/plain. Although application/octet-stream is the default in the RFC, we will need to treat it as text to be able to compare it.

@uglyog
Copy link
Member

uglyog commented Mar 8, 2020

Version 4.0.7 has been released with this change

@flexfrank
Copy link
Author

@uglyog
In au.com.dius.pact.core.model.Request class, application/json is still default Content-Type.
My tests throw AssertionError with 4.0.7 like:

0 - Expected a response type of 'application/json' but the actual type was 'text/plain'
java.lang.AssertionError: 
0 - Expected a response type of 'application/json' but the actual type was 'text/plain'
	at au.com.dius.pact.provider.junit5.PactVerificationContext.verifyInteraction(PactJUnit5VerificationProvider.kt:85)

https://github.com/DiUS/pact-jvm/blob/05ca602/core/model/src/main/kotlin/au/com/dius/pact/core/model/Request.kt#L116

@wieslawmlynarski
Copy link
Contributor

wieslawmlynarski commented Mar 12, 2020

This change 4.0.6 -> 4.0.7 resulted that the tests started to fail.
The reason is that in the contract there is no content type. before was default was "application/json" now is text/plain which results in a 415 status code.
Do you have an idea how you can go around it?

wieslawmlynarski added a commit to wieslawmlynarski/pact-jvm that referenced this issue Mar 12, 2020
…e is not provided

When the body is of type json use the application/json content type
Breaking change was between pact 4.0.6 -> 4.0.7
uglyog pushed a commit that referenced this issue Mar 21, 2020
…t-content-type

#1013 - Fix to issue when in pact contract content type is not provided
@uglyog
Copy link
Member

uglyog commented Mar 22, 2020

4.0.8 released

uglyog pushed a commit that referenced this issue Apr 29, 2020
When the body is of type json use the application/json content type
Breaking change was between pact 4.0.6 -> 4.0.7

(cherry picked from commit d1b192a)
@stardust20
Copy link

stardust20 commented Mar 5, 2021

I'm having a very similar issue when the response type produced by the mock controller is not a JSON but a text/csv.

I'm using pact-jvm 4.1.6 version.

java.lang.AssertionError: 
Failures:

1) Request method

    1.1)       com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 5 path $

	at au.com.dius.pact.provider.spring.target.MockMvcTarget.testInteraction(MockMvcTarget.kt:86)
	at au.com.dius.pact.provider.junit.InteractionRunner$interactionBlock$statement$1.evaluate(InteractionRunner.kt:226)
	at au.com.dius.pact.provider.junit.RunStateChanges.evaluate(RunStateChanges.kt:30)
	at au.com.dius.pact.provider.junit.InteractionRunner.run(InteractionRunner.kt:162)
	at au.com.dius.pact.provider.junit.PactRunner.runChild(PactRunner.kt:150)
	at au.com.dius.pact.provider.junit.PactRunner.runChild(PactRunner.kt:56)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

Any idea how to solve this?

@uglyog
Copy link
Member

uglyog commented Mar 6, 2021

@stardust20 you need to provide the content type of the body if it is not JSON.

@stardust20
Copy link

stardust20 commented Mar 8, 2021

I'm sending the accept header, I tried text/plain and text/csv but it doesn't make a difference. The contract in this case looks like the following:
Upon receiving:

{
  "method": "GET",
  "path": "/api/v1/url/csv"
  "headers": {
    "Accept": "text/csv"
}

And the response that looks as follows:

{
  "status": 200,
  "headers": {
    "Content-Type": "text/csv"
}
  "body": "NAME,EMAIL\nSome name, email@email.com\nOther name, otheremail@email.com\n"
}

The method in the controller I'm mocking has the following mapping:

@GetMapping("/api/v1/url/csv", produces = ["text/csv"])

@stardust20
Copy link

stardust20 commented Mar 8, 2021

I think the issue here is that the mock controller is not setting up the response content-type, and that causes the error with pact:

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Disposition:"attachment; filename=csv-file.csv"]
     Content type = null
             Body = NAME,EMAIL\nSome name, email@email.com\nOther name, otheremail@email.com\n

And then the error:

1.1)       com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 5 path $



	at au.com.dius.pact.provider.spring.target.MockMvcTarget.testInteraction(MockMvcTarget.kt:86)
	at au.com.dius.pact.provider.junit.InteractionRunner$interactionBlock$statement$1.evaluate(InteractionRunner.kt:226)
	at au.com.dius.pact.provider.junit.RunStateChanges.evaluate(RunStateChanges.kt:30)
	at au.com.dius.pact.provider.junit.InteractionRunner.run(InteractionRunner.kt:162)
	at au.com.dius.pact.provider.junit.PactRunner.runChild(PactRunner.kt:150)
	at au.com.dius.pact.provider.junit.PactRunner.runChild(PactRunner.kt:56)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

@uglyog
Copy link
Member

uglyog commented Mar 13, 2021

@stardust20 I can't replicate that error. My test works if the controller sets the content type, and fails if it does not. It looks like Springboot is setting the content type to application/json if the controller does not.

See https://github.com/pact-foundation/pact-jvm/blob/v4.1.x/provider/spring/src/test/java/au/com/dius/pact/provider/spring/BookController.java#L46 and https://github.com/pact-foundation/pact-jvm/blob/v4.1.x/provider/spring/src/test/resources/pacts/readers-contract.json#L82

@stardust20
Copy link

@stardust20 I can't replicate that error. My test works if the controller sets the content type, and fails if it does not. It looks like Springboot is setting the content type to application/json if the controller does not.

See https://github.com/pact-foundation/pact-jvm/blob/v4.1.x/provider/spring/src/test/java/au/com/dius/pact/provider/spring/BookController.java#L46 and https://github.com/pact-foundation/pact-jvm/blob/v4.1.x/provider/spring/src/test/resources/pacts/readers-contract.json#L82

My controller had a very similar configuration to that one, with the produces = {"text/csv"} in the definition but it didn't work. I ended up changing it and adding that part inside the function like response.setHeader("Content-Type"...

I don't understand why it didn't work with the other setup. In any case, thanks for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants