pact-foundation / pact-jvm

JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://docs.pact.io
Apache License 2.0
1.08k stars 480 forks source link

XML matching rules incorrect in version 4.0.11 #1186

Open mefellows opened 4 years ago

mefellows commented 4 years ago

Matching rules in junit5 consumer tests appear to produce an invalid contract, when manually adjusted to what I believe are correct matching rules, the provider is still matching on exact values.

Versions

Versions

Repro

Problem 1: consumer produces invalid matching rules

Given a test that produces (expects) this XML Document:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ns:projects id="1234" xmlns:ns="http://some.namespace/and/more/stuff">
    <project due="2016-02-11T09:46:56.023Z" id="100" name="Project 1" type="activity">
        <tasks>
            <task done="true" id="100" name="Task 1"/>
            <task done="true" id="100" name="Task 1"/>
            <task done="true" id="100" name="Task 1"/>
            <task done="true" id="100" name="Task 1"/>
        </tasks>
    </project>
</ns:projects>

It produces this pact file:

{
  "provider": {
    "name": "pactflow-example-provider-java-soap"
  },
  "consumer": {
    "name": "pactflow-example-consumer-java-soap"
  },
  "interactions": [
    {
      "description": "a request for projects in XML",
      "request": {
        "method": "GET",
        "path": "/projects",
        "headers": {
          "Accept": "application/xml"
        },
        "query": {
          "from": [
            "today"
          ]
        }
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/xml"
        },
        "body": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<ns:projects id=\"1234\" xmlns:ns=\"http://some.namespace/and/more/stuff\">\n    <project due=\"2016-02-11T09:46:56.023Z\" id=\"100\" name=\"Project 1\" type=\"activity\">\n        <tasks>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n        </tasks>\n    </project>\n    <project due=\"2016-02-11T09:46:56.023Z\" id=\"100\" name=\"Project 1\" type=\"activity\">\n        <tasks>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n            <task done=\"true\" id=\"100\" name=\"Task 1\"/>\n        </tasks>\n    </project>\n</ns:projects>\n",
        "matchingRules": {
          "body": {
            "$.projects.project.['@due']": {
              "matchers": [
                {
                  "match": "timestamp",
                  "timestamp": "yyyy-MM-dd'T'HH:mm:ss.SSSX"
                }
              ],
              "combine": "AND"
            },
            "$.projects.project.['@name']": {
              "matchers": [
                {
                  "match": "type"
                }
              ],
              "combine": "AND"
            },
            "$.projects.project.['@id']": {
              "matchers": [
                {
                  "match": "integer"
                }
              ],
              "combine": "AND"
            },
            "$.projects.project.tasks.task.['@name']": {
              "matchers": [
                {
                  "match": "type"
                }
              ],
              "combine": "AND"
            },
            "$.projects.project.tasks.task.['@id']": {
              "matchers": [
                {
                  "match": "integer"
                }
              ],
              "combine": "AND"
            },
            "$.projects.project.tasks.task.['@done']": {
              "matchers": [
                {
                  "match": "type"
                }
              ],
              "combine": "AND"
            }
          }
        },
        "generators": {
          "body": {
            "$.projects.project.['@id']": {
              "type": "RandomInt",
              "min": 0,
              "max": 2147483647
            },
            "$.projects.project.tasks.task.['@id']": {
              "type": "RandomInt",
              "min": 0,
              "max": 2147483647
            }
          }
        }
      },
      "providerStates": [
        {
          "name": "i have a list of projects"
        }
      ]
    }
  ],
  "metadata": {
    "pactSpecification": {
      "version": "3.0.0"
    },
    "pact-jvm": {
      "version": "4.0.10"
    }
  }
}

When verifying on the provider, the following error is observed:

Expected either a "*" or path identifier in path expression "$.projects.project.['@due']" at index 19

Problem 2: Provider only matches exact values

I worked around this temporarily by adjusting all of the incorrect $.projects.project.['@id'] type problems to -> $.projects.project['@id']. This allowed the provider to progress further, but the matching rules aren't applied and thus exact values are required for a test to pass.

uglyog commented 4 years ago

4.1.7 has been released