I guess it’ll be something like this, but with the...
# protobufs
m
I guess it’ll be something like this, but with the async package: https://github.com/pact-foundation/pact-go/blob/2.x.x/examples/grpc/grpc_consumer_test.go#L52
y
So basically you should decode from
AsynchronousMessage.Contents
manually to protobuf and then verify that?
It looks like once you used the plugin (
WithPlugin
), you can’t use
AsType
and
ConsumedBy
m
AsType
makes sense, because how would the framework know how to arbitrary convert a plugin’s contents to a narrow type?
ConsumedBy
is replaced by
ExecuteTest
I can’t remember why I changed that now I’m sorry. There was possibly a good reason for it though 🙂
y
I see that makes sense, it might worth marking
ConsumedBy
with
// Deprecated: Use ExecuteTest instead.
then to avoid confusions.
m
It’s not deprecated though, it’s still available for non-plugin requests.
👍 1
y
Following up on this thread: So in async protobuf provider test, it looks like we need to have the provider implement this message handler func: (i was using pact-go)
Copy code
func(states []models.ProviderState) (message.Body, message.Metadata, error)
Here
message.Body
is an interface — what shall I give here? I tried both the proto Golang body, and deserialized
[]byte
, they both throw
I’m guessing that the verifier doesn’t know it should be using the protobuf plugin to parse my provider message, what am I missing here?
Following up here, it looks like pact-go verifier is setting the provider proxy to return message as
application/json; charset=utf-8
, while pact expects it to be something like
application/protobuf; message=ProtoMessageExample
. I guess it means protobuf plugin won’t work with provider verification through message handler?
Also, even after I updated the line above to return the proper content type, pact doesn’t seems to be able to find the protobuf matcher:
Copy code
2023-05-31T19:49:05.104537Z DEBUG ThreadId(01) verify_interaction{interaction="XXX"}: pact_matching: No content matcher defined for content type 'application/protobuf;message=SessionStatusResponse', using core matcher implementation
Copy code
2023-05-31T19:49:05.104581Z DEBUG ThreadId(01) verify_interaction{interaction="async health information"}: pact_matching: No body matcher defined for content type 'application/protobuf;message=SessionStatusResponse', using plain text matcher
Digging deeper here, seems the async protobuf contract generated on the consumer side (through
AddAsynchronousMessage
) is missing plugin information. Unlike sync message, the async message doesn’t have
plugins
and raw proto desciptors under
metadata
. Also,
pactSpecification.version
is
3.0
for async contract, (instead of
4.0
for sync grpc contracts). That might be why the provider side can’t find the matcher from the plugin I guess.
m
Thanks for the digging Yu. So the last point, this PR should address it: https://github.com/pact-foundation/pact-go/pull/292 It was failing due to an upstream issue, but I’ve reverted the changes for the upstream dependency and will merge this shortly.
Copy code
2023-05-31T19:49:05.104537Z DEBUG ThreadId(01) verify_interaction{interaction="XXX"}: pact_matching: No content matcher defined for content type 'application/protobuf;message=SessionStatusResponse', using core matcher implementation
hmm interesting. I suspect the plugin only registers
application/protobuf
and because of the additional field it’s mis matching (guess). What happens if you hard code
application/protobuf
as the content type? I wonder if that goes a little further (but then probably fails due to the missing qualifier).
Copy code
func(states []models.ProviderState) (message.Body, message.Metadata, error)
Hmm good point. I think we will need a variation on this that allows a
[]byte
to be returned here, and if a plugin is being used in an interaction, we use the different typed interface to signal that we require a byte array. We may also need to capture a content type here (or elsewhere) that is used to set the response mime type
Could you please raise an issue? Or - and this would be amazing - a PR that demonstrates how you get it to work? We can then pair through a solution to this problem
y
I actually didn’t get this working. I tried force returning
application/protobuf
and message name as content type header. But eventually, pact is still falling back to plain text matcher which obviously doesn’t work. My guess is it’s because the generated contract doesn’t even include any plugin information and proto details on the consumer side
So the sync grpc version of generated contract looks like this to me:
Copy code
{
  "metadata": {
    "pactRust": {
      "ffi": "0.4.1",
      "mockserver": "1.0.0",
      "models": "1.0.4"
    },
    "pactSpecification": {
      "version": "4.0"
    },
    "plugins": [
      {
        "name": "protobuf",
        "version": "0.3.0",
        "configuration": "..."
      }
    ]
  }
}
While the async generated contract has metadata like this:
Copy code
"metadata": {
    "pactRust": {
      "ffi": "0.4.1",
      "models": "1.0.4"
    },
    "pactSpecification": {
      "version": "3.0.0"
    }
  }
In addition to spec version being 3.0.0, it also misses plugin information
On the consumer side I’m doing this to generate:
Copy code
p.AddAsynchronousMessage().
GivenWithParameter(...).
ExpectsToReceive("...").
UsingPlugin(message.PluginConfig{
	Plugin:  "protobuf",
	Version: "0.3.0",
}).
WithContents("...", "application/protobuf").
ExecuteTest(...)
m
Oh, sorry, did you pull the latest with the spec serialisation fix? Then if you try hard coding the content type again let's see how far you get
👀 1
I'll aim to create an example next week to test it out myself
Btw part of the underlying issue is https://github.com/pact-foundation/pact-go/issues/265 I think
y
I’ll aim to create an example next week to test it out myself
@Matt (pactflow.io / pact-js / pact-go) Checking back on this thread — is there an e2e working example now?
m
Sorry I missed this - I’ve updated the issue. Can you please let me know if it addresses your issue?
gratitude thank you 1
y
No worries, I’ll report back once I get a chance to try again.s
👍 1
Thanks for the fix
thankyou 1