pact-foundation / pact-php

PHP 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
Apache License 2.0
272 stars 92 forks source link

Pact-PHP <=9.x.x - Verification failed when the query has nested keys #222

Open mark-onenetwork opened 3 years ago

mark-onenetwork commented 3 years ago

Hi All,

I encountered a weird issue: verification failed when the query has nested keys key_a[]=1&key_b[1]=2, key_a is an array, key_b is a hash.

Here is the output:

W, [2021-09-28T01:44:25.107664 #4532]  WARN -- : Verifying - actual interactions do not match expected interactions.
Incorrect requests:
        GET /api/products/my_endpoint?travel_date=2021-04-10&key_b[1]=2&key_a[]=1 (request query did not match)

Diff with interaction: "A get request to /api/products/my_endpoint" given "Resource 112 exists, and is available on 2021-05-21"
Diff
--------------------------------------
Key: - is expected
     + is actual
Matching keys and values are not shown

 {
   "query": {
-    "key_a": [
+    "key_a[]": [
       "1"
     ]

Description of differences
--------------------------------------
* Could not find key "key_a" (keys present are: key_b[1], key_a[]) at $.query
* Did not expect the key "key_a[]" to exist at $.query

I debug code and got some clues:

  1. When parsing the expected interaction, the query string: key_a[]=1&key_b[1]=2 is covert to key_a=1&key_b[1]=2 because of the logic here.
  2. However when trying to match the candidate interactions with actual request, the square brackets in the actual query key key_a[]=1 is not removed as in expected interaction key_a=1, which causes the inconsistency between expected interaction and actual interaction.

I'm wondering if it's a bug.

bethesque commented 3 years ago

The query matching logic is a nightmare, because there are many different ways a query can be parsed. I'm afraid you'll need to try using a string query expectation in this case.

mark-onenetwork commented 3 years ago

@bethesque Thanks for the quick response. Then it's a "know issue". Could you please explain a bit more on using string query expectation instead? Would be appreciated, I'm not Ruby expert.

bethesque commented 3 years ago

Can you please copy your Pact expectation code into a comment.

mark-onenetwork commented 3 years ago
$request = new ConsumerRequest();
$request
    ->setMethod('GET')
    ->setPath('/api/products/my_endpoint?key_a[]=1&key_b[1]=2')
    ->addHeader('Content-Type', 'application/json');

It's in PHP, probably no way to do that.

bethesque commented 3 years ago

Ah, it's already a string. Is there no separate method to set the query? In the other languages, the path and the query are set separately, so that suggests to me that something in the php is splitting them out.

mark-onenetwork commented 3 years ago

Yes, there is a separate method to set the query.

$request = new ConsumerRequest();
$request
    ->setMethod('GET')
    ->setPath('/api/products/my_endpoint')
    ->setQuery('key_a[]=1&key_b[1]=2')
    ->addHeader('Content-Type', 'application/json');
YOU54F commented 1 month ago

Needs retesting in pact-php 10.x which utilises the pact reference core in rust via ffi, rather than the pact ruby project