mock-server / mockserver

MockServer enables easy mocking of any system you integrate with via HTTP or HTTPS with clients written in Java, JavaScript and Ruby. MockServer also includes a proxy that introspects all proxied traffic including encrypted SSL traffic and supports Port Forwarding, Web Proxying (i.e. HTTP proxy), HTTPS Tunneling Proxying (using HTTP CONNECT) and SOCKS Proxying (i.e. dynamic port forwarding).
http://mock-server.com
Apache License 2.0
4.52k stars 1.06k forks source link

JSON String body. Double quotes in verification is ignored/JSON String body unwrapping in verification #1870

Open pctF opened 2 months ago

pctF commented 2 months ago

Describe the issue Seems like parser of verification is unwrapping JSON String and it leads to failed verification of body.

Creating verification from java API org.mockserver.model.HttpRequest#withBody(org.mockserver.model.JsonBody.json("\"test json string value\"")) will lead to same behaviour.

It is extreamly similar to: https://github.com/mock-server/mockserver/issues/1101

What you are trying to do Sending request to mockserver with JSON String body: "example string JSON Value". Then trying to verify that request with this body was sent.

MockServer version 5.13.2, 5.15.0 (examples showed on docker deployment of image mockserver/mockserver:5.15.0)

To Reproduce

Clear mockserver:

curl -X PUT --location "http://localhost:32860/mockserver/clear?type=all"

Send request with JSON String body:

curl -X POST --location "http://localhost:32860/test/str" \
    -H "Content-Type: application/json" \
    -d '"test json string value"'

Verify manually that request is in logs:

curl -X PUT --location "http://localhost:32860/mockserver/retrieve?format=log_entries&type=requests"
[
  {
    "logLevel" : "INFO",
    "timestamp" : "2024-05-03 13:04:58.146",
    "type" : "RECEIVED_REQUEST",
    "httpRequest" : {
      "method" : "POST",
      "path" : "/test/str",
      "headers" : {
        "User-Agent" : [
          "curl/7.81.0"
        ],
        "Host" : [
          "localhost:32860"
        ],
        "Content-Type" : [
          "application/json"
        ],
        "Content-Length" : [
          "24"
        ],
        "Accept" : [
          "*/*"
        ]
      },
      "keepAlive" : true,
      "secure" : false,
      "protocol" : "HTTP_1_1",
      "localAddress" : "172.17.0.2:1080",
      "remoteAddress" : "172.17.0.1:57072",
      "body" : "test json string value"
    },
    "message" : [
      "received request:",
      "",
      "   {",
      "      \"method\" : \"POST\",",
      "      \"path\" : \"/test/str\",",
      "      \"headers\" : {",
      "         \"User-Agent\" : [ \"curl/7.81.0\" ],",
      "         \"Host\" : [ \"localhost:32860\" ],",
      "         \"Content-Type\" : [ \"application/json\" ],",
      "         \"Content-Length\" : [ \"24\" ],",
      "         \"Accept\" : [ \"*/*\" ]",
      "      },",
      "      \"keepAlive\" : true,",
      "      \"secure\" : false,",
      "      \"protocol\" : \"HTTP_1_1\",",
      "      \"localAddress\" : \"172.17.0.2:1080\",",
      "      \"remoteAddress\" : \"172.17.0.1:57072\",",
      "      \"body\" : \"test json string value\"",
      "   }"
    ]
  }

Run verification of request with same body:

curl -X PUT --location "http://localhost:32860/mockserver/verify" \\
    -H "Content-Type: application/json" \
    -d '{
          "httpRequest": {
            "method": "POST",
            "path": "/test/str",
            "body": {
              "type": "JSON",
              "json": "test json string value",
              "contentType": "application/json"
            },
            "headers": [
              {
                "name": "Content-Type",
                "values": [
                  "application/json"
                ]
              }
            ]
          },
          "times": {
            "atLeast": 1,
            "atMost": 1
          }
        }'
Request not found exactly once, expected:<{
  "body" : {
    "contentType" : "application/json",
    "type" : "JSON",
    "rawBytes" : "dGVzdCBqc29uIHN0cmluZyB2YWx1ZQ=="
  },
  "headers" : {
    "Content-Type" : [ "application/json" ]
  },
  "method" : "POST",
  "path" : "/test/str"
}> but was:<{
  "body" : {
    "contentType" : "application/json",
    "type" : "JSON",
    "json" : "test json string value",
    "rawBytes" : "InRlc3QganNvbiBzdHJpbmcgdmFsdWUi"
  },
  "headers" : {
    "Accept" : [ "*/*" ],
    "User-Agent" : [ "curl/7.81.0" ],
    "Host" : [ "localhost:32860" ],
    "Content-Length" : [ "24" ],
    "Content-Type" : [ "application/json" ]
  },
  "keepAlive" : true,
  "method" : "POST",
  "path" : "/test/str",
  "secure" : false
}

Expected behaviour Verification should match request. Or at least should be stated that while JSON structures in /httpRequest/body/json treated as JSONs, strings will be parsed as raw json input.

MockServer Log (rerun of same verification)

2024-05-03T13:25:42.236775144Z 2024-05-03 13:25:42 5.15.0 INFO exception:
2024-05-03T13:25:42.236806164Z 
2024-05-03T13:25:42.236810663Z   Unrecognized token 'test': was expecting (JSON String, Number (or 'NaN'/'INF'/'+INF'), Array, Object or token 'null', 'true' or 'false')
2024-05-03T13:25:42.236814450Z    at [Source: (String)"test json string value"; line: 1, column: 5]
2024-05-03T13:25:42.236818047Z 
2024-05-03T13:25:42.236821414Z  while deserialising jsonBody with json:
2024-05-03T13:25:42.236824911Z 
2024-05-03T13:25:42.236828197Z   test json string value
2024-05-03T13:25:42.236831674Z  
2024-05-03T13:25:42.236835000Z com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'test': was expecting (JSON String, Number (or 'NaN'/'INF'/'+INF'), Array, Object or token 'null', 'true' or 'false')
2024-05-03T13:25:42.236838567Z  at [Source: (String)"test json string value"; line: 1, column: 5]
2024-05-03T13:25:42.236842285Z  at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2418)
2024-05-03T13:25:42.236846072Z  at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:759)
2024-05-03T13:25:42.236861622Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:3038)
2024-05-03T13:25:42.236865199Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:3016)
2024-05-03T13:25:42.236868556Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._matchToken(ReaderBasedJsonParser.java:2790)
2024-05-03T13:25:42.236872033Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._matchTrue(ReaderBasedJsonParser.java:2744)
2024-05-03T13:25:42.236875429Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:767)
2024-05-03T13:25:42.236878826Z  at com.fasterxml.jackson.databind.ObjectMapper._readTreeAndClose(ObjectMapper.java:4759)
2024-05-03T13:25:42.236882203Z  at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:3124)
2024-05-03T13:25:42.236885619Z  at org.mockserver.serialization.serializers.body.JsonBodySerializer.serialize(JsonBodySerializer.java:48)
2024-05-03T13:25:42.236889116Z  at org.mockserver.serialization.serializers.body.JsonBodySerializer.serialize(JsonBodySerializer.java:19)
2024-05-03T13:25:42.236892463Z  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
2024-05-03T13:25:42.236895849Z  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
2024-05-03T13:25:42.236899296Z  at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:3208)
2024-05-03T13:25:42.236903534Z  at com.fasterxml.jackson.core.base.GeneratorBase.writeObject(GeneratorBase.java:389)
2024-05-03T13:25:42.236906941Z  at com.fasterxml.jackson.core.JsonGenerator.writeObjectField(JsonGenerator.java:2408)
2024-05-03T13:25:42.236910327Z  at org.mockserver.serialization.serializers.request.HttpRequestSerializer.serialize(HttpRequestSerializer.java:67)
2024-05-03T13:25:42.236913734Z  at org.mockserver.serialization.serializers.request.HttpRequestSerializer.serialize(HttpRequestSerializer.java:15)
2024-05-03T13:25:42.236917111Z  at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:733)
2024-05-03T13:25:42.236920527Z  at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774)
2024-05-03T13:25:42.236923924Z  at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
2024-05-03T13:25:42.236927321Z  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
2024-05-03T13:25:42.236930717Z  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
2024-05-03T13:25:42.236934134Z  at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1572)
2024-05-03T13:25:42.236937511Z  at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1273)
2024-05-03T13:25:42.236945576Z  at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1140)
2024-05-03T13:25:42.236948963Z  at org.mockserver.model.ObjectWithJsonToString.toString(ObjectWithJsonToString.java:17)
2024-05-03T13:25:42.236952319Z  at java.base/java.lang.String.valueOf(String.java:4218)
2024-05-03T13:25:42.236955636Z  at org.mockserver.formatting.StringFormatter.indentAndToString(StringFormatter.java:39)
2024-05-03T13:25:42.236959023Z  at org.mockserver.formatting.StringFormatter.formatLogMessage(StringFormatter.java:51)
2024-05-03T13:25:42.236962369Z  at org.mockserver.formatting.StringFormatter.formatLogMessage(StringFormatter.java:46)
2024-05-03T13:25:42.236965726Z  at org.mockserver.log.model.LogEntry.getMessage(LogEntry.java:340)
2024-05-03T13:25:42.236969072Z  at org.mockserver.logging.MockServerLogger.writeToSystemOut(MockServerLogger.java:110)
2024-05-03T13:25:42.236972389Z  at org.mockserver.log.MockServerEventLog.processLogEntry(MockServerEventLog.java:156)
2024-05-03T13:25:42.236975735Z  at org.mockserver.log.MockServerEventLog.lambda$startRingBuffer$7(MockServerEventLog.java:142)
2024-05-03T13:25:42.236979082Z  at com.lmax.disruptor.BatchEventProcessor.processEvents(BatchEventProcessor.java:168)
2024-05-03T13:25:42.236982629Z  at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:125)
2024-05-03T13:25:42.236986075Z  at java.base/java.lang.Thread.run(Thread.java:833)
2024-05-03T13:25:42.236990855Z 
2024-05-03T13:25:42.237021955Z 2024-05-03 13:25:42 5.15.0 INFO 1080 verifying requests that match:
2024-05-03T13:25:42.237029190Z 
2024-05-03T13:25:42.237032736Z   {
2024-05-03T13:25:42.237035562Z     "httpRequest" : {
2024-05-03T13:25:42.237038438Z       "method" : "POST",
2024-05-03T13:25:42.237041323Z       "path" : "/test/str",
2024-05-03T13:25:42.237044169Z       "headers" : {
2024-05-03T13:25:42.237046854Z         "Content-Type" : [ "application/json" ]
2024-05-03T13:25:42.237049649Z       },
2024-05-03T13:25:42.237052335Z       "body" : {
2024-05-03T13:25:42.237054980Z         "contentType" : "application/json",
2024-05-03T13:25:42.237057705Z         "type" : "JSON"
2024-05-03T13:25:42.237060410Z       }
2024-05-03T13:25:42.237063026Z     },
2024-05-03T13:25:42.237065661Z     "times" : {
2024-05-03T13:25:42.237068316Z       "atLeast" : 1,
2024-05-03T13:25:42.237071021Z       "atMost" : 1
2024-05-03T13:25:42.237073646Z     }
2024-05-03T13:25:42.237076241Z   }
2024-05-03T13:25:42.237078856Z  
2024-05-03T13:25:42.239269483Z 2024-05-03 13:25:42 5.15.0 INFO exception:
2024-05-03T13:25:42.239307908Z 
2024-05-03T13:25:42.239311615Z   Unrecognized token 'test': was expecting (JSON String, Number (or 'NaN'/'INF'/'+INF'), Array, Object or token 'null', 'true' or 'false')
2024-05-03T13:25:42.239314581Z    at [Source: (String)"test json string value"; line: 1, column: 5]
2024-05-03T13:25:42.239317577Z 
2024-05-03T13:25:42.239320262Z  while deserialising JsonBodyDTO with json:
2024-05-03T13:25:42.239322967Z 
2024-05-03T13:25:42.239325542Z   test json string value
2024-05-03T13:25:42.239328238Z  
2024-05-03T13:25:42.239330883Z com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'test': was expecting (JSON String, Number (or 'NaN'/'INF'/'+INF'), Array, Object or token 'null', 'true' or 'false')
2024-05-03T13:25:42.239333738Z  at [Source: (String)"test json string value"; line: 1, column: 5]
2024-05-03T13:25:42.239336424Z  at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2418)
2024-05-03T13:25:42.239339450Z  at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:759)
2024-05-03T13:25:42.239342285Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:3038)
2024-05-03T13:25:42.239345010Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:3016)
2024-05-03T13:25:42.239347736Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._matchToken(ReaderBasedJsonParser.java:2790)
2024-05-03T13:25:42.239351062Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._matchTrue(ReaderBasedJsonParser.java:2744)
2024-05-03T13:25:42.239353858Z  at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:767)
2024-05-03T13:25:42.239356583Z  at com.fasterxml.jackson.databind.ObjectMapper._readTreeAndClose(ObjectMapper.java:4759)
2024-05-03T13:25:42.239359278Z  at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:3124)
2024-05-03T13:25:42.239361994Z  at org.mockserver.serialization.serializers.body.JsonBodyDTOSerializer.serialize(JsonBodyDTOSerializer.java:49)
2024-05-03T13:25:42.239364709Z  at org.mockserver.serialization.serializers.body.JsonBodyDTOSerializer.serialize(JsonBodyDTOSerializer.java:20)
2024-05-03T13:25:42.239367434Z  at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:733)
2024-05-03T13:25:42.239370149Z  at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774)
2024-05-03T13:25:42.239372885Z  at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
2024-05-03T13:25:42.239376141Z  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
2024-05-03T13:25:42.239378917Z  at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
2024-05-03T13:25:42.239387844Z  at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1572)
2024-05-03T13:25:42.239392303Z  at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1273)
2024-05-03T13:25:42.239395098Z  at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1140)
2024-05-03T13:25:42.239397894Z  at org.mockserver.serialization.RequestDefinitionSerializer.serialize(RequestDefinitionSerializer.java:59)
2024-05-03T13:25:42.239400599Z  at org.mockserver.log.MockServerEventLog.lambda$null$34(MockServerEventLog.java:497)
2024-05-03T13:25:42.239403324Z  at org.mockserver.log.MockServerEventLog.lambda$retrieveAllRequests$16(MockServerEventLog.java:313)
2024-05-03T13:25:42.239406050Z  at org.mockserver.log.MockServerEventLog.lambda$retrieveLogEntries$29(MockServerEventLog.java:432)
2024-05-03T13:25:42.239408745Z  at org.mockserver.log.MockServerEventLog.lambda$startRingBuffer$7(MockServerEventLog.java:144)
2024-05-03T13:25:42.239411500Z  at com.lmax.disruptor.BatchEventProcessor.processEvents(BatchEventProcessor.java:168)
2024-05-03T13:25:42.239414266Z  at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:125)
2024-05-03T13:25:42.239416931Z  at java.base/java.lang.Thread.run(Thread.java:833)
2024-05-03T13:25:42.239419586Z 
2024-05-03T13:25:42.240781565Z 2024-05-03 13:25:42 5.15.0 INFO request not found exactly once, expected:
2024-05-03T13:25:42.240797456Z 
2024-05-03T13:25:42.240802105Z   {
2024-05-03T13:25:42.240804950Z     "method" : "POST",
2024-05-03T13:25:42.240807816Z     "path" : "/test/str",
2024-05-03T13:25:42.240810672Z     "headers" : {
2024-05-03T13:25:42.240813387Z       "Content-Type" : [ "application/json" ]
2024-05-03T13:25:42.240816132Z     },
2024-05-03T13:25:42.240818978Z     "body" : "test json string value"
2024-05-03T13:25:42.240822044Z   }
2024-05-03T13:25:42.240824679Z 
2024-05-03T13:25:42.240827284Z  but was:
2024-05-03T13:25:42.240829899Z 
2024-05-03T13:25:42.240832444Z   {
2024-05-03T13:25:42.240835019Z     "method" : "POST",
2024-05-03T13:25:42.240837714Z     "path" : "/test/str",
2024-05-03T13:25:42.240840500Z     "headers" : {
2024-05-03T13:25:42.240843175Z       "host" : [ "localhost:32861" ],
2024-05-03T13:25:42.240845880Z       "User-Agent" : [ "IntelliJ HTTP Client/IntelliJ IDEA 2024.1" ],
2024-05-03T13:25:42.240848616Z       "Content-Type" : [ "application/json" ],
2024-05-03T13:25:42.240851311Z       "Content-Length" : [ "24" ],
2024-05-03T13:25:42.240853996Z       "Accept-Encoding" : [ "br, deflate, gzip, x-gzip" ],
2024-05-03T13:25:42.240865899Z       "Accept" : [ "*/*" ]
2024-05-03T13:25:42.240868715Z     },
2024-05-03T13:25:42.240871300Z     "keepAlive" : true,
2024-05-03T13:25:42.240873965Z     "secure" : false,
2024-05-03T13:25:42.240876620Z     "protocol" : "HTTP_1_1",
2024-05-03T13:25:42.240879396Z     "localAddress" : "172.17.0.2:1080",
2024-05-03T13:25:42.240882081Z     "remoteAddress" : "172.17.0.1:42990",
2024-05-03T13:25:42.240884766Z     "body" : "test json string value"
2024-05-03T13:25:42.240887472Z   }
2024-05-03T13:25:42.240890047Z