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

Wildcards in keys #313

Closed
felixhammerl opened this issue Aug 30, 2016 · 12 comments
Closed

Wildcards in keys #313

felixhammerl opened this issue Aug 30, 2016 · 12 comments

Comments

@felixhammerl
Copy link

felixhammerl commented Aug 30, 2016

There should be a way to use wildcards on JSON object's keys, as it is possible for values (e.g. strings).

Twitter convo w/ @uglyog on this topic

Background

This is a part of the JSON API we're writing a CDC for:

"articles": [
    {
        "variants": {
            "001": {
                "bundles": {
                    "001-A": {
                        "description": "someDescription",
                        "referencedArticles": [
                            {
                                "bundleId": "someId"
                            }
                        ]
                    }
                }
            }
        }
    }
]

There's one or more objects being used like an array (001, 002, ... and 001-A, 001-B, ...). Not pretty, but not possible to change that.

I need something like this: $.body.articles[*].variants.*.bundles.*.description. Pact-JVM seems to allow wildcards (see README ), but I've not been able to do that in Java via the API. Also, I'm not trying to manually add it to the JSON as it is auto-generated. But the only API that does anything like this is for arrays (.eachLike(), etc.).

@uglyog
Copy link
Member

uglyog commented Sep 10, 2016

I have updated the DSLs to support wildcard keys, but it is not going to be pretty ;-)

To match you JSON requires something like:

    DslPart body = new PactDslJsonBody()
        .eachLike("articles")
          .object("variants")
            .eachKeyLike("001")
              .object("bundles")
                .eachKeyLike("001-A")
                  .stringType("description", "Some Description")
                    .eachLike("referencedArticles")
                      .id("bundleId", 23456L)
                      .closeObject()
                    .closeArray()
                  .closeObject()
                .closeObject()
              .closeObject()
            .closeObject()
          .closeObject()
        .closeArray();

and this generates a pact file with the following body and matchers:

        {
                "body": {
                    "articles": [
                        {
                            "variants": {
                                "001": {
                                    "bundles": {
                                        "001-A": {
                                            "description": "Some Description",
                                            "referencedArticles": [
                                                {
                                                    "bundleId": 23456
                                                }
                                            ]
                                        }
                                    }
                                }
                            }
                        }
                    ]
                },
                "matchingRules": {
                    "$.body.articles": {
                        "min": 0,
                        "match": "type"
                    },
                    "$.body.articles[*].variants.*.bundles.*.referencedArticles": {
                        "min": 0,
                        "match": "type"
                    },
                    "$.body.articles[*].variants.*.bundles.*.description": {
                        "match": "type"
                    },
                    "$.body.articles[*].variants.*.bundles.*.referencedArticles[*].bundleId": {
                        "match": "type"
                    }
                }
        }

@WolfSchlegel
Copy link

Thanks, much appreciated!

@WolfSchlegel
Copy link

Hi Ronald,
we tried the eachKeyLike part of the DSL as described above. It works like a charm with regards to creating the matching rules. However, when verifying the provider against a generated pact, the underlying matcher seems to insist that the actual key has to equal the expected key.

In our test, we generate the following pact:

{
   "provider": {
       "name": "ArticlesProvider"
   },
   "consumer": {
       "name": "ArticlesConsumer"
   },
   "interactions": [
       {
           "description": "retrieving article data",
           "request": {
               "method": "GET",
               "path": "/simple.json"
           },
           "response": {
               "status": 200,
               "headers": {
                   "Content-Type": "application/json"
               },
               "body": {
                   "articles": [
                       {
                           "variants": {
                               "0032": {
                                   "description": "sample description"
                               }
                           }
                       }
                   ]
               },
               "matchingRules": {
                   "$.body.articles[*].variants.*.description": {
                       "match": "type"
                   }
               }
           },
           "providerState": "alex and wolf want to learn pact"
       }
   ],
   "metadata": {
       "pact-specification": {
           "version": "2.0.0"
       },
       "pact-jvm": {
           "version": "3.3.1"
       }
   }
}

The json provided by our simple mock service is:

{
  "articles": [
      {
          "country": "ABC",
          "variants": {
              "1234": {
                  "bar": "bar value",
                  "description": "sample description"
              }
          }
      }
  ]
}

And the test results in failures:

0) retrieving article data returns a response which has a matching body
      $.body.articles.0.variants -> Expected 0032=Map(description -> sample description) but was missing

      Diff:

      @3
              {
      +            "country": "ABC",
                  "variants": {

      @4
                  "variants": {
      -                "0032": {
      +                "1234": {
      +                    "bar": "bar value",
                          "description": "sample description"

The key below "variants" is matched based on its value "0032". Is there a way to match it based on its type only? We started looking into au.com.dius.pact.matchers.JsonBodyMatcher and au.com.dius.pact.matchers.Matchers to understand where the equality matching is happening.

Could you please point us into the right direction where to adapt the matcher?

Thank you,
Wolf and Alex (pairing)

@uglyog
Copy link
Member

uglyog commented Sep 14, 2016

Aah, yeah, sorry I missed that. I'll need to have another look, probably
will have to add another matcher from the consumer test and then maybe
update the matching logic in JsonBodyMatcher.

The line that needs to change is
https://github.com/DiUS/pact-jvm/blob/master/pact-jvm-matchers/src/main/scala/au/com/dius/pact/matchers/JsonBodyMatcher.scala#L118
but it needs an update to the DSL first.

On 14 September 2016 at 01:16, Wolf Schlegel notifications@github.com
wrote:

Hi Ronald,
we tried the eachKeyLike part of the DSL as described above. It works like
a charm with regards to creating the matching rules. However, when
verifying the provider against a generated pact, the underlying matcher
seems to insist that the actual key has to equal the expected key.

In our test, we generate the following pact:

{
"provider": {
"name": "ArticlesProvider"
},
"consumer": {
"name": "ArticlesConsumer"
},
"interactions": [
{
"description": "retrieving article data",
"request": {
"method": "GET",
"path": "/simple.json"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
"articles": [
{
"variants": {
"0032": {
"description": "sample description"
}
}
}
]
},
"matchingRules": {
"$.body.articles[].variants..description": {
"match": "type"
}
}
},
"providerState": "alex and wolf want to learn pact"
}
],
"metadata": {
"pact-specification": {
"version": "2.0.0"
},
"pact-jvm": {
"version": "3.3.1"
}
}
}

The json provided by our simple mock service is:

{
"articles": [
{
"country": "ABC",
"variants": {
"1234": {
"bar": "bar value",
"description": "sample description"
}
}
}
]
}

And the test results in failures:

  1. retrieving article data returns a response which has a matching body
    $.body.articles.0.variants -> Expected 0032=Map(description -> sample description) but was missing
  Diff:

  @3
          {
  +            "country": "ABC",
              "variants": {

  @4
              "variants": {
  -                "0032": {
  +                "1234": {
  +                    "bar": "bar value",
                      "description": "sample description"

The key below "variants" is matched based on its value "0032". Is there a
way to match it based on its type only? We started looking into
au.com.dius.pact.matchers.JsonBodyMatcher and au.com.dius.pact.matchers.
Matchers to understand where the equality matching is happening.

Could you please point us into the right direction where to adapt the
matcher?

Thank you,
Wolf and Alex (pairing)


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#313 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AA0tslrerBA0iMEm1f5qTcnD-N7Azh1gks5qpr43gaJpZM4Jwgod
.

uglyog pushed a commit that referenced this issue Sep 14, 2016
@uglyog
Copy link
Member

uglyog commented Sep 15, 2016

Ok, should work for you now. That was more complex than I initially envisioned, but I think we now have a good implementation.

@ghost
Copy link

ghost commented Sep 19, 2016

Hi Ronald,

thanks for working on the issue and for your prompt answers! Unfortunately our test case still does not work. We created a pull request (#318) with the exact test setup mentioned by @WolfSchlegel above.

Could you please have a look? Thanks.

Best regards,
Alex & Alexandra (pairing)

@uglyog
Copy link
Member

uglyog commented Sep 21, 2016

I got your tests passing (it just needed a really small change), sorry for the inconvience.

@ghost
Copy link

ghost commented Sep 23, 2016

Hi Ronald,

thanks a lot for your changes; they fixed the test for us as well.
The issue is resolved from our side.

Have a nice weekend!

Best regards,
Alex

@uglyog uglyog closed this as completed Oct 3, 2016
@maxant
Copy link

maxant commented Apr 10, 2017

Please see #401

@sureshmaruthirao
Copy link

Please see #500

@sureshmaruthirao
Copy link

Parallel nested object mapping i am trying on that one please see the issue #500

@joelgithub
Copy link

Yes, please look at #500

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

6 participants