matt.fellows
2022-10-24 12:35
has joined #pact-plugins

matt.fellows
2022-10-24 12:35
set the channel description: Forum to discuss building plugins

yousafn
2022-10-24 12:35
has joined #pact-plugins

uglyog
2022-10-24 12:35
has joined #pact-plugins

glenn
2022-10-24 12:35
has joined #pact-plugins

ali.ustek
2022-10-24 12:35
has joined #pact-plugins

matt.fellows
2022-10-24 12:36
Just getting a place for us to discuss the creation of plugins. I?m heading off for the night, but will pop back in here tomorrow with some goodies on next steps :slightly_smiling_face:


yousafn
2022-10-24 12:37
Thanks Matt! Looking forward to welcoming newcomers and old faces to a world of possibilities :slightly_smiling_face:

jaswanth.ooty
2022-11-15 00:17
has joined #pact-plugins

jason.taylor2
2022-11-15 18:01
has joined #pact-plugins

orbit
2022-12-01 15:45
has joined #pact-plugins

yousafn
2022-12-01 17:58
set the channel topic: Docs:- https://docs.pact.io/plugins

aforeman
2022-12-05 02:26
has joined #pact-plugins

sameena9010
2022-12-06 11:38
has joined #pact-plugins

tjones
2022-12-06 11:50
has joined #pact-plugins

yousafn
2022-12-06 12:11
Hey @sameena9010, I saw your question in general, had a go at answering a few below https://pact-foundation.slack.com/archives/C5F4KFKR8/p1670325812233529 Thanks for joining the channel. You asked say 4 q's 1. Can you automate testing of gRPC with Pact a. Yes. with the Pact-protobuf-plugin. https://github.com/pactflow/pact-protobuf-plugin 2. Can you test Kafka with Pact. a. We have some examples with the existing Pact framework (some are Pactflow branded but work with the OSS broker) i. https://docs.pact.io/recipes/kafka ii. https://docs.pactflow.io/docs/examples/kafka/js/consumer iii. https://docs.pactflow.io/docs/examples/kafka/java/consumer iv. https://docs.pactflow.io/docs/examples/kafka/java/provider b. We do not currently have a Kafka plugin, You can request or vote for one of our Canny feature request board https://pact.canny.io/ 3. gRPC testing is only available through plugins - https://docs.pact.io/plugins 4. Plugins will be supported by any Pact implementation using the underlying Rust framework, that supports V4 Pact specification (and utilses plugins) a. There is some small amount of work to do, to introduce plugin support to pact-net. We can help provide advice to yourself to aid the main maintainer Adam Rodgers. b. If the language doesn't support it, but is capable of supporting FFI calls, a user could build out a Pact framework with support for plugins. I am fairly new to the world of gRPC and haven't used Kafka in production, but always happy to learn new things and help you along

sameena9010
2022-12-06 12:16
Thanks @yousafn for the detailed info, i just started looking in to these implementations. I will post my future questions in this channel if i see any issues while doing a poc

yousafn
2022-12-06 12:20
Please do! We look forward to following your journey and wish you all the success

matt.fellows
2022-12-06 20:47
It should be noted that we don?t yet have support in Pact .NET (C#), but as we produce more developer/maintainer material we?d hope to work with the language maintainers to adopt the framework/feature

phil.vint
2022-12-08 12:47
has joined #pact-plugins

manishmitraba
2022-12-13 03:50
has joined #pact-plugins

sambhavi.chinnu
2022-12-13 04:35
has joined #pact-plugins

dmitrij.bogomyakov
2022-12-13 16:19
has joined #pact-plugins

sameena9010
2022-12-15 06:16
Hi I want to explore on the gRPC plugin with maven example, so i installed the protobuf plugin and now im trying to run consumer test its failing with below reason. Can someone help me what i am missing here ```<<< FAILURE! - in io.pact.example.grpc.maven.PactConsumerTest calculateRectangleArea{MockServer, SynchronousMessages} Time elapsed: 1.542 s <<< ERROR! kotlin.UninitializedPropertyAccessException: lateinit property process has not been initialized at io.pact.example.grpc.maven.PactConsumerTest.calculateRectangleArea(PactConsumerTest.java:45)```

uglyog
2022-12-15 06:34
`lateinit property process has not been initialized` means there is a property that has to be initialized before the object can be used. What do you have at `PactConsumerTest.java:45`?

sameena9010
2022-12-15 06:35
which plugin to use ```.usingPlugin("protobuf","0.2.1")```

uglyog
2022-12-15 06:37
Hmm, try plugin version "0.2.2" as "0.2.1" is not good.

sameena9010
2022-12-15 06:48
yeah this one worked

nathan.deamer
2022-12-19 09:41
has joined #pact-plugins

sameena9010
2022-12-20 08:25
I created a repo with go plugin template and made the changes following readme, now when I try to install it i'm getting below error ```pact-plugin-cli.exe install https://github.com/sameena-ops/pact-sample-plugin/releases/tag/v0.0.5 Installing plugin pact-sample-plugin version 0.0.4 ? Plugin with name 'pact-sample-plugin' and version '0.0.4' already exists. Overwrite it? · Yes Error: Did not find a matching file pattern on GitHub to install```

matt.fellows
2022-12-20 08:59
Try adding the verbose flag, it should show what targets it's trying to find

matt.fellows
2022-12-20 09:01
Aha it looks like the version in the plugin json is incorrect :thinking_face:(still 0.0.4) I wonder if there is a bug in the code that updates that?

sameena9010
2022-12-20 09:07
yeah right i missed updating to 0.0.5 in plugin json, let me change and check

sameena9010
2022-12-20 09:10
but still its looking for 0.0.4 ```Installing plugin pact-sample-plugin version 0.0.4 ? Plugin with name 'pact-sample-plugin' and version '0.0.4' already exists. Overwrite it? · Yes 2022-12-20T09:09:22.400911Z INFO pact_plugin_cli::install: Deleting contents of plugin directory 2022-12-20T09:09:22.408563Z INFO pact_plugin_cli::install: Writing plugin manifest file 2022-12-20T09:09:22.415874Z DEBUG pact_plugin_cli::install: Detected OS: Windows 10.0.19044 (Windows 10 Enterprise) [64-bit] 2022-12-20T09:09:22.417143Z DEBUG pact_plugin_cli::install: Checking existence of file from https://github.com/sameena-ops/pact-sample-plugin/releases/download/v0.0.5/pact-pact-sample-plugin-plugin-windows-x86_64.exe.gz 2022-12-20T09:09:22.420079Z DEBUG hyper::client::pool: reuse idle connection for ("https", http://github.com) 2022-12-20T09:09:22.420977Z DEBUG Connection{peer=Client}: h2::codec::framed_write: send frame=Headers { stream_id: StreamId(5), flags: (0x5: END_HEADERS | END_STREAM) } 2022-12-20T09:09:22.635027Z DEBUG Connection{peer=Client}: h2::codec::framed_read: received frame=Headers { stream_id: StreamId(5), flags: (0x5: END_HEADERS | END_STREAM) } 2022-12-20T09:09:22.636942Z DEBUG hyper::client::client: client connection error: connection error: broken pipe Error: Did not find a matching file pattern on GitHub to install```

sameena9010
2022-12-20 09:15
If I change plugin json later then do I need to publish the new version of plugin with the same version in plugin json?

sameena9010
2022-12-20 09:21
And also its taking the gz file path as https://github.com/sameena-ops/pact-sample-plugin/releases/download/v0.0.5/*pact*-pact-sample-*plugin*-plugin-windows-x86_64.exe.gz does it mean the entry point or somewhere i should give only sample instead of full project name.?

matt.fellows
2022-12-20 09:30
in your `pact-plugin.json` file, the name of your plugin shouldn?t be `pact-sample-plugin` but just `sample`


matt.fellows
2022-12-20 09:32
the make actions should set the name of the plugin in `pact-plugin.json` based on the value of `PROJECT` in `Makefile`

matt.fellows
2022-12-20 09:32
It?s possible there is a bug in that though, given it didn?t seem to update the version in the `pact-plugin.json`. If you can track down what happened and raise an issue, that would be great

sameena9010
2022-12-20 09:32
yeah looks same what i have is ```{ "pluginInterfaceVersion": 1, "name": "sample", "version": "0.0.5", "executableType": "exec", "minimumRequiredVersion": null, "entryPoint": "pact-sample-plugin", "entryPoints": {}, "dependencies": null, "pluginConfig": {}}```


matt.fellows
2022-12-20 09:33
what does your makefile look like?

sameena9010
2022-12-20 09:35
yeah version mismatch is there in make file # Update this version VERSION=0.0.4 # Update to your project name PROJECT=pact-sample-plugin

matt.fellows
2022-12-20 09:35
yep, the project name is wrong too (see above)

matt.fellows
2022-12-20 09:35
it should just be `sample`

matt.fellows
2022-12-20 09:35
TL;DR - you shouldn?t need to manually touch `pact-plugin.json`


sahoo.skumar
2022-12-20 13:46
has joined #pact-plugins

sahoo.skumar
2022-12-20 13:49
We are using pact-protobuf-plugin version : v-0.2.3, The protobuf under contract test imports another protobuf, could you please help me out how we can pass multiple protobuf into V4Pact builder

uglyog
2022-12-21 00:26
For the moment, you need to add the additional import directories in the plugin manifest file. See https://github.com/pactflow/pact-protobuf-plugin#additionalincludes-string-or-liststring

uglyog
2022-12-21 00:27
We are currently working on allowing it to be configured in the test

yousafn
2022-12-21 11:01
Protodoc is a pretty cool tool for visualising your proto files. Here is an example with our plugin.proto file https://gist.github.com/YOU54F/5a1ac48da75bea30a2cf019d9d1929a1

yousafn
2022-12-21 11:08
I noted that in a consumer pact test we need to specify the version of the pact plug-in, at least in pact-js If we do, we use the latest version of the plug-in in the plug-in directory, regardless of the version specified in the test. This means the pact gets encoded with the protobuf plug-in later version than specified. On the provider side, the provider test reads the required plug-in version from the file. I had ran my provider test after deleting the latest plug-in from my plug-in folder, which causes my provider test to fail. It might be nice for 1. Use the specified version always, or inform user that you are using a later on on consumer side 2. Provider side - should it alert if it can?t find the correct version plug-in, should it automatically try and download it, if it doesn?t exist Otherwise how do we easily make it visible to a provider, which plugins they require in order to run a particular set of pact verifications. Could there be an ability to retrieve the plugins used for a specific verification, same could be extended to provider states. I could do something with some api calls, get pacts for verification, pull down contents, filter through for provider states and pact plugin entries and print back to the user

matt.fellows
2022-12-21 11:47
I think a user specified semver option might be a way to go. I think Ron uses a semver library under the hood so that behaviour could possibly be improved.

matt.fellows
2022-12-21 11:48
Also, if the framework could auto install that would be really cool

uglyog
2022-12-21 22:30
The idea was to use the specified version or a later semver compatible one. But the logic hasn't been tested, so it may not work.

uglyog
2022-12-21 22:32
To auto-install a plugin, the framework needs a way to know where the plugin installation files are. We have had this idea of a plugin repository that can be queried for that info.

tjones
2022-12-22 03:00
Why not just use the package manager of whatever ecosystem is being used? The need to manage the versions ourselves seems like a strange design choice to me.

uglyog
2022-12-22 03:08
You mean the plugin author should package their plugins using every package manager out there? I.e. Maven repo, NPM, Rust crate, Cocopod, homebrew, ...

tjones
2022-12-22 03:12
No, just the ones we support :wink:

tjones
2022-12-22 03:12
otherwise, where are they going to get them from?

tjones
2022-12-22 03:13
You could even script it into a pact-plugin-publish CLI or something

sahoo.skumar
2022-12-22 03:30
We are unable to make it work with protobuf-config and additionalIncludes. The test is a simple messaging test. The code block look like as

sahoo.skumar
2022-12-22 03:30
```@Pact(consumer = "test-consumer") V4Pact configureInteractionMessage(PactBuilder builder) { return builder .usingPlugin("protobuf") .expectsToReceive("State Interaction message", "core/interaction/message") .with(Map.of( "message.contents", Map.of( "pact:proto", filePath("target/test-resources/com/ap/proto/v1/health.proto"), "pact:message-type", "DeviceHealth", "pact:content-type", "application/protobuf", "pact:protobuf-config", Map.of( "additionalIncludes", List.of( filePath("target/test-resources/com/ap/proto/v1/enums.proto") ) ) ) )) .toPact(); }```

sahoo.skumar
2022-12-22 03:31
health.proto referencing enums.proto

uglyog
2022-12-22 03:31
`additionalIncludes` must be the directory, not the file

sahoo.skumar
2022-12-22 03:40
Thanks, still we dont have any luck, we are using latest v0.2.4, any hint if you could see we are missing something ?

sahoo.skumar
2022-12-22 03:42
or any sample example would be great, Thanks


sahoo.skumar
2022-12-25 03:32
can we have an example of message interaction instead of GRPC, it seems the "pact:protobuf-config" is not working with only message type interaction.

sahoo.skumar
2022-12-25 03:33
```@Pact(consumer = "test-consumer") V4Pact configureInteractionMessage(PactBuilder builder) { return builder .usingPlugin("protobuf") .expectsToReceive("State Interaction message", "core/interaction/message") .with(Map.of( "message.contents", Map.of( "pact:proto", filePath("target/test-resources/com/ap/proto/v1/health.proto"), "pact:message-type", "DeviceHealth", "pact:content-type", "application/protobuf", "pact:protobuf-config", Map.of( "additionalIncludes", List.of( filePath("target/test-resources/com/ap/proto/v1") ) ) ) )) .toPact(); }```

sahoo.skumar
2022-12-25 03:34
The trace we have

sahoo.skumar
2022-12-25 03:34
org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [http://au.com.dius.pact.core.model.V4Interaction$AsynchronousMessage message] in method [void com.aruba.contract.consumer.ConsumerMessagePactTest.consumeConfigureInteractionPersonMessage(http://au.com.dius.pact.core.model.V4Interaction$AsynchronousMessage) throws com.google.protobuf.InvalidProtocolBufferException]: Failed to set the interaction: Failed to process protobuf: Failed to invoke protoc binary: exit code exit status: 1 at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameter(ExecutableInvoker.java:239) at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameters(ExecutableInvoker.java:183) at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameters(ExecutableInvoker.java:144) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:96) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) Caused by: http://au.com.dius.pact.consumer.dsl.InteractionConfigurationError: Failed to set the interaction: Failed to process protobuf: Failed to invoke protoc binary: exit code exit status: 1 at http://au.com.dius.pact.consumer.dsl.PactBuilder.setupMessageContents(PactBuilder.kt:276) at http://au.com.dius.pact.consumer.dsl.PactBuilder.with(PactBuilder.kt:182) at com.aruba.contract.consumer.ConsumerMessagePactTest.configureInteractionPersonMessage(ConsumerMessagePactTest.java:34) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688) at org.junit.platform.commons.support.ReflectionSupport.invokeMethod(ReflectionSupport.java:198) at http://au.com.dius.pact.consumer.junit5.PactConsumerTestExt.lookupPact(PactConsumerTestExt.kt:415) at http://au.com.dius.pact.consumer.junit5.PactConsumerTestExt.resolveParameterForProvider(PactConsumerTestExt.kt:132) at http://au.com.dius.pact.consumer.junit5.PactConsumerTestExt.resolveParameter(PactConsumerTestExt.kt:108) at org.junit.jupiter.engine.execution.ExecutableInvoker.resolveParameter(ExecutableInvoker.java:216) ... 52 more

sahoo.skumar
2022-12-25 03:35
Any help on this would be appreciable.

anandhiemail
2022-12-29 18:25
has joined #pact-plugins

fabio.rodrigues
2023-01-03 11:34
has joined #pact-plugins

mario.pires
2023-01-03 11:42
has joined #pact-plugins

fabio.rodrigues
2023-01-04 15:24
Hi all In relation to pact plugins, we at OutSystems are trying to check if we can write a plugin to do contract testing that use NATS as the delivery system of messages between systems to test. That is the services communicate via message exchange with NATS (https://nats.io/) (that messages are json payload to a specific topic). That made us checking the plugins documentation and examples and some questions were raised: ? Can we currently do a plugin that would connect to Nats like a client and subscribe to topic to either receive or publish messages, and verify the content of those messages (like Grpc or protobuf or kafka) ? Can we use .Net for creating the plugin? If not, since pact-net is a wrapper for the Rust common engine, do we need to use Rust. Or can we use Kotlin? ? Does pact-net already support plugin usage like pact-rust or pact-jvm? And if not, when can we expect that to happen, if at all? ? How does contract visualization occur on the pactflow site? ? What kind of support can we expect from Pactflow/Smartbear team for this endeavor?

uglyog
2023-01-05 00:14
Hi @fabio.rodrigues I'll try answer all the questions: ? Can we currently do a plugin that would connect to Nats like a client and subscribe to topic to either receive or publish messages, and verify the content of those messages (like Grpc or protobuf or kafka) This is what the plugin framework was designed to do. We tried to make it as generic as possible to support all the different use cases that we are aware of. However, the general strategy we are aiming for is to emulate systems like Nats. I.e., with Grpc the plugin provides a mock server to use, and with Kafka we don't actually connect to a real Kafka topic during the tests. ? Can we use .Net for creating the plugin? If not, since pact-net is a wrapper for the Rust common engine, do we need to use Rust. Or can we use Kotlin? Currently plugin support is available with Pact-JVM, Pact-Rust and Pact-Go, so you will need to write the tests in a language supported by one of those frameworks. So Rust or Kotlin will work. ? Does pact-net already support plugin usage like pact-rust or pact-jvm? And if not, when can we expect that to happen, if at all? I think Pact-JS is the next target, and the support for it is in development. Once that is released, Pact-Net will probably be the next framework to target. I would imagine that work on that will start around middle of 2023. ? How does contract visualization occur on the pactflow site? Pactflow does not currently support the plugin and V4 Pact formats, so will try render it in a very basic manor. Plugin support was scheduled to begin Q1 2023, so that work should kick off shortly. ? What kind of support can we expect from Pactflow/Smartbear team for this endeavor? Plugins is on the Pactflow feature roadmap, so new features for it are supported by the budget from Smartbear for Pactflow features. For maintenance and issues with Pact frameworks, Smartbear allows the engineering teams to spend up to about 20% of their budgets on OSS maintenance. So with those constraints, we will try to support any plugin work as it is important to us.

jeroen.vandijk
2023-01-10 09:07
has joined #pact-plugins

james_fraser
2023-01-23 09:43
has joined #pact-plugins

jwang
2023-01-27 23:35
has joined #pact-plugins

joseph.joyce
2023-03-15 09:20
has joined #pact-plugins

adam.cox
2023-03-15 09:58
has joined #pact-plugins

tien.xuan.vo
2023-03-16 02:52
has joined #pact-plugins

adam.cox
2023-03-21 12:05
Hello Pact, I am still working on trying to get a WebSockets plugin (rust) up and running and are hitting some issues. We have implemented the start_mock_server and stop_mock_server requests and when invoked manually using gRPC and calling the enpoints the WS server starts up and can be interacted with. Calling the Shutdown RPC then closes all connections and returns the match results (of which there are none). We are now trying to implement the consumer test so that it submits the interactions to the server. This is where we are struggling a bit: 1. The pact is being sent to the plugin successfully. The interaction we are setting up is present and looks correct. However when we decode the JSON to a v4 Pact the transport value is always None - does this matter? 2. When running the consumer test the start mock server request is sent and the server is stood up. However the plugin immediately starts shutting down, we get no configure_interaction request and there is a panic on main where the shutdown request was sent but the plugin has already gone away. 3. When we pact_builder.synchronous_messages() in the consumer test the vector is always empty, we therefore cannot loop to perform the tests. Switching to sending the message manually doesn?t fix the problem highlighted in 2. We are trying to follow the pact-plugin-protobuf from the pactflow repo and everything looks the setup the same. But obviously we are missing something here. Is it possible to get some pointers with this? Thanks,

adam.cox
2023-03-21 13:56
I think I have solved some of this actually. Previously our code looked like this: ```let mut pact_builder = PactBuilder::new_v4("message-consumer", "message-provider"); // Define the message consumer and provider by name let mock_server = pact_builder .using_plugin("websockets", None) .await // Adds an interaction given the message description and type. .synchronous_message_interaction("Mallory Message", |mut i| async move { /// ... }) .await .start_mock_server_async(Some("websockets/transport/websockets")) .await; pact_builder .synchronous_messages() .collect::<Vec<SynchronousMessage>>().len() // 0```

adam.cox
2023-03-21 13:57
However if I change it to: ```let mut pact_builder = PactBuilder::new_v4("message-consumer", "message-provider"); // Define the message consumer and provider by name let mut pact_builder_async = pact_builder.using_plugin("websockets", None).await; let mock_server = pact_builder_async .synchronous_message_interaction("Mallory Message", |mut i| async move { // ... }) .await .start_mock_server_async(Some("websockets/transport/websockets")) .await; pact_builder_async .synchronous_messages() .collect::<Vec<SynchronousMessage>>() .len() // 0 ```

adam.cox
2023-03-21 13:59
Then the interactions vector has 1 element and also the server does not go away and the shutdown method is called and is successful. I guess the original PactBuilder becomes redundant once we do `using_plugin` and get the PactBuilderAsync. The async one then becomes the one we need to work with and keeping the reference to it in stop is what stops the server from shutting down

adam.cox
2023-03-21 14:05
We still do not get configure_interaction requests though. When should we expect to get thosE?

yousafn
2023-03-21 17:38
Hey Adam, Thanks for posting up and bravo for jumping in to the world of Pact plugins! I saw in general you have already spoken to a couple of the core maintainers! They are based over in Aus so will catch up with this overnight. Is there a shareable codebase? It would help the maintainers and myself in additional investigations (no worries if not) I'll try my best to answer you questions when I get some free time but feel free to keep posting as you work along, as we will support you as best as we can! We are totally invested in bringing more plugins and plugin authors to the fold :)

uglyog
2023-03-21 22:19
Oh, that could be a trap for lots of people. I'll need to think of a way to get the first builder to hold the reference to the second one.

adam.cox
2023-03-22 09:05
@yousafn I?m not sure about shareable codebase. I realise that makes things very difficult but its currently hosted in Comcast Sky?s GitHub org and is private. I?ll have a chat with the powers that be and see what would be best for getting code in front of you guys as its basically impossible to help without looking at the code yourself. I certainly know how that is :smile:

adam.cox
2023-03-22 09:07
> Oh, that could be a trap for lots of people. I?ll need to think of a way to get the first builder to hold the reference to the second one. For the signature of use_plugin could you just do `self` instead of `&self` and move the ownership?

adam.cox
2023-03-22 09:10
A different question, are `configure_interaction`, `generate_content` and `compare_contents` only relevant if we are adding new Generator and Matcher catalogue entries? We aren?t adding those so do we need to worry much about their implementation. btw, I think the plugin architecture is a brilliant idea and bravo for moving everything to Rust. The tooling is so much more portable and extensible this way and it allows us to get things done as we need to. Great job!

oloruntobi.ayilara
2023-03-22 09:25
has joined #pact-plugins

haiyang.huang
2023-03-22 10:30
has joined #pact-plugins

uglyog
2023-03-22 22:14
> A different question, are configure_interaction, generate_content and compare_contents only relevant if we are adding new Generator and Matcher catalogue entries? We aren?t adding those so do we need to worry much about their implementation. Yes, that is correct. You should be able to just ignore anything you don't need, and if your plugin never provides catalogue entries for those types of things, they will never be called.

praveen.em
2023-03-24 08:15
has joined #pact-plugins

tien.xuan.vo
2023-03-25 04:07
Hi, Can I reify protobuf message (async message) like a normal message? I expect to able to get message object without any matching and pass it to a callback/handler.


tjones
2023-03-25 07:53
Oh wait, sorry, I misread the question. I don?t actually know - but I would assume you can


tien.xuan.vo
2023-03-25 09:11
when I call ffi method `pactffi_message_reify` I cant get something that I can decode into original object

matt.fellows
2023-03-25 09:59
There is a way to get it Tien, when I'm at my computer I'll check. There is a message iterator you can use to get the raw btye array, which you can use to pass it back on to the test without matchers etc

tien.xuan.vo
2023-03-25 15:58
Never mind. I think I went to the wrong direction. After adding `debug!` and compiling `rust_ffi` I think `assume you can` from Timothy is the correct answer for now. I got an error before I can confirm. I will ask in another thread.

tien.xuan.vo
2023-03-25 16:02
I got this error when working with protobuf plugin: ```pact_ffi::plugins: Failed to call out to plugin - Request to configure interaction failed: Failed to process protobuf: Failed to invoke protoc binary: exit code exit status: 1``` According to this https://github.com/pactflow/pact-protobuf-plugin#logging, how can I set env `LOG_LEVEL` exactly? I checked `/path/to/plugins/protobuf/log/*.log.Y-M-D` , all files are empty, and I can't see the real problem. I tried this but it doesn't work: ```LOG_LEVEL=debug PACT_LOGLEVEL=trace phpunit example/async-message/consumer/tests/Contract/```

tien.xuan.vo
2023-03-27 01:02
I can confirm the answer is `yes`

tien.xuan.vo
2023-03-27 01:46
Is it a good idea to support loading plugins from multiple directories? e.g. Support multiple values for `PACT_PLUGIN_DIR` , or introduce new var `PACT_PLUGIN_DIRS`

uglyog
2023-03-27 02:03
This needs to be configured in the Pact-PHP integration. The default is to use the `LOG_LEVEL` environment variable, but just note that this is a Node.js/Ruby specific way. But there are FFI functions to setup the logging.

uglyog
2023-03-27 02:04
But, even then, `Failed to invoke protoc binary: exit code exit status: 1` means the protoc command failed with an error, and the log level will not control that tools output. I think it writes to stderr.

uglyog
2023-03-27 02:05
Why would you want this?

matt.fellows
2023-03-27 02:24
So yes, you can get them via the message iterator, i.e. these messages ```pactffi_pact_handle_get_message_iter pactffi_pact_message_iter_next pactffi_message_get_contents_length pactffi_message_get_contents_bin```

matt.fellows
2023-03-27 02:25
There are two `sync` versions of the iterator also.

matt.fellows
2023-03-27 02:25
Is that right @uglyog?

matt.fellows
2023-03-27 02:25
(or rather, that?s what I?m doing - I hope it?s right)

tien.xuan.vo
2023-03-27 02:39
Because (currently it's only me, these reasons doesn't represent the entire pact-php team, because my PRs are not reviewed and merged yet): 1. `pact-php` project only contains "core" features (http + v3 async message), it doesn't include any code that support plugins 2. Instead of supporting all plugins in `pact-php` project like I did before, I split into multiple projects: `pact-php-csv` , `pact-php-protobuf` . The reasons are: a. Not everybody want and use plugins to test their project b. Download binaries need time, and disk storage. c. Support all plugins in `pact-php` only make the code base bigger and bigger overtime 3. Each projects has it own `PACT_PLUGIN_DIR` . For example: `/path/to/pact-php-csv/bin/pact-plugins/csv` and `/another/path/to/pact-php-protobuf/bin/pact-plugins/protobuf` 4. While writing consumer test, setting `PACT_PLUGIN_DIR` before each test is enough for running the test. 5. But when verifying provider, currently only set 1 value for `PACT_PLUGIN_DIR` , so only verify pacts for 1 plugin.

tien.xuan.vo
2023-03-27 02:44
I don't need to call those ffi methods. I just need to call `pactffi_message_reify` . The reason it doesn't work before is I went to the wrong direction (typo in pact:proto, missing content type `application/protobuf`, wrong matching format...)

tien.xuan.vo
2023-03-27 02:50
Currently in Pact-PHP I only call `pactffi_init_with_log_level('debug')` . I don't know what I am missing.

uglyog
2023-03-27 02:51
That will enable debug logs to standout, but not change the protoc error output. You can try trace to see if it makes a difference.

tien.xuan.vo
2023-03-27 02:53
I did try `trace` before but it doesn't help.

tien.xuan.vo
2023-03-27 02:53
btw, don't worry about the error `Failed to invoke protoc binary: exit code exit status: 1` . It's just because a typo that make the path to proto file invalid

tien.xuan.vo
2023-03-27 02:54
Currently `/path/to/plugins/protobuf/log/*.log.Y-M-D files are empty` is the problem I am facing

uglyog
2023-03-27 02:56
I can see the protoc entries in

tien.xuan.vo
2023-03-27 02:57
yes, me too, but all of them are empty

uglyog
2023-03-27 03:01
Something is going wrong with the log level then, it is meant to set the `LOG_LEVEL` for the plugin process based on what you have setup. Do you see any entries in the console for the tests?

tien.xuan.vo
2023-03-27 03:06
> it is meant to set the `LOG_LEVEL` for the plugin process based on what you have setup ahhh, yess?? I am wondering how to do that


matt.fellows
2023-03-27 03:16
on wow, that returns back the byte array? I thought I tried that and it didn?t work. that?s MUCH easier :laughing:

matt.fellows
2023-03-27 03:17
I guess the type declaration is `char*`, but that?s just an array of bytes

tien.xuan.vo
2023-03-27 03:21
It return json like this https://github.com/tienvx/pact-php-protobuf/blob/main/example/async-message/broker/pacts/protobufMessageConsumer-protobufMessageProvider.json#L7 All I need to do is `base64_decode` and merge to object then pass to callback

tien.xuan.vo
2023-03-27 07:08
Another idea is adding `--filter-plugin=NAME` and `--filter-no-plugin` to pact verifier

tien.xuan.vo
2023-03-27 09:16
I will try creating hooks to copy/symlink plugins into 1 places so pact verifier can use it

tien.xuan.vo
2023-03-31 14:12
The solution above has been implemented. Pact plugin directories has been symlinked into single directory, and the path to that directory will be set as value of `PACT_PLUGIN_DIR`

tien.xuan.vo
2023-04-03 05:06
About csv plugin https://docs.pact.io/implementation_guides/pact_plugins/plugins/csv#csv-matching-definitions: If we use headers, mock server will response with columns that are sorted by column's name in ascending order. For example: ```$response ->setStatus(200) ->setBody([ 'csvHeaders' => true, 'column:id' => "matching(regex, '^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$','{$id}')", 'column:name' => "matching(type,'{$name}')", 'column:gender' => "matching(regex, 'male|female|other','{$gender}')", ]) ->setContentType('text/csv') ;``` Mock server will return: ```gender,id,name $gender,$id,$name``` Is this expected behavior?

uglyog
2023-04-03 05:12
You mean, was this planned behaviour? No, I don't think so, but it kind of makes sense.

tien.xuan.vo
2023-04-03 05:22
It makes sense to me also. Currently I'm fine with it because the order of columns isn't important to me. But I think checking for the order of columns is important for some users. I'm thinking about this solution: Add `"csvColumns": "id,name,gender"` so: ? Mock server will return columns in this order ? Provider verifier will verify csv's columns in this order What do you think?

uglyog
2023-04-03 05:24
You are probably right

tien.xuan.vo
2023-04-03 05:26
I will create a minor ticket for this improvement so we can discuss more about it in that ticket


tien.xuan.vo
2023-04-03 05:51
Currently when provider verifier can't find the required plugin, it simply shutdown without any error message: ```PACT_LOGLEVEL=debug phpunit example/provider/ 12:41:36 Xdebug: [Step Debug] Could not connect to debugging client. Tried: 127.0.0.1:9003 (through xdebug.client_host/xdebug.client_port). PHPUnit 9.5.20 #StandWithUkraine 2023-04-03T05:41:46.951993Z DEBUG ThreadId(01) pact_ffi::verifier: pact_ffi::verifier::pactffi_verifier_add_directory_source FFI function invoked 2023-04-03T05:41:46.952030Z DEBUG ThreadId(01) pact_ffi::verifier: pact_ffi::verifier::pactffi_verifier_execute FFI function invoked 2023-04-03T05:41:46.952033Z DEBUG ThreadId(01) pact_ffi::verifier::handle: Pact source to verify = Dir(/home/myname/Projects/pact-php-csv/example/provider/tests/Contract/../../../broker/pacts) 2023-04-03T05:41:46.952639Z DEBUG ThreadId(01) pact_plugin_driver::catalogue_manager: Updated catalogue entries: core/content-generator/binary core/content-generator/json core/content-matcher/json core/content-matcher/multipart-form-data core/content-matcher/text core/content-matcher/xml 2023-04-03T05:41:46.952667Z DEBUG ThreadId(01) pact_plugin_driver::catalogue_manager: Updated catalogue entries: core/matcher/v1-equality core/matcher/v2-max-type core/matcher/v2-min-type core/matcher/v2-minmax-type core/matcher/v2-regex core/matcher/v2-type core/matcher/v3-content-type core/matcher/v3-date core/matcher/v3-datetime core/matcher/v3-decimal-type core/matcher/v3-includes core/matcher/v3-integer-type core/matcher/v3-null core/matcher/v3-number-type core/matcher/v3-time core/matcher/v4-array-contains core/matcher/v4-equals-ignore-order core/matcher/v4-max-equals-ignore-order core/matcher/v4-min-equals-ignore-order core/matcher/v4-minmax-equals-ignore-order core/matcher/v4-not-empty core/matcher/v4-semver 2023-04-03T05:41:46.952718Z DEBUG ThreadId(01) pact_verifier: Scanning "/home/myname/Projects/pact-php-csv/example/provider/tests/Contract/../../../broker/pacts" 2023-04-03T05:41:46.952871Z INFO ThreadId(01) pact_verifier: Pact file requires plugins, will load those now 2023-04-03T05:41:46.952881Z DEBUG ThreadId(01) pact_plugin_driver::plugin_manager: Loading plugin PluginDependency { name: "csv", version: Some("0.0"), dependency_type: Plugin } 2023-04-03T05:41:46.952894Z DEBUG ThreadId(01) pact_plugin_driver::plugin_manager: Did not find plugin, will start it 2023-04-03T05:41:46.952896Z DEBUG ThreadId(01) pact_plugin_driver::plugin_manager: Loading plugin manifest for plugin PluginDependency { name: "csv", version: Some("0.0"), dependency_type: Plugin } 2023-04-03T05:41:46.952902Z DEBUG ThreadId(01) pact_plugin_driver::plugin_manager: Looking for plugin in "/home/myname/.pact/plugins" 2023-04-03T05:41:46.953001Z DEBUG ThreadId(01) pact_ffi::verifier: pact_ffi::verifier::pactffi_verifier_shutdown FFI function invoked F 1 / 1 (100%) Time: 00:00.080, Memory: 28.32 MB There was 1 failure: 1) App\Provider\Tests\Contract\PactVerifyTest::testPactVerifyConsumer Failed asserting that false is true. /home/myname/Projects/pact-php-csv/example/provider/tests/Contract/PactVerifyTest.php:58 FAILURES! Tests: 1, Assertions: 1, Failures: 1.``` I think it should log an error message like: ```Can't find plugin csv in /home/myname/.pact/plugins``` Do you think so?


uglyog
2023-04-03 05:56
Oh, this is during verification

tien.xuan.vo
2023-04-03 05:57
yes, during verification


uglyog
2023-04-03 05:58
Oops!

tien.xuan.vo
2023-04-03 06:01
I will create a ticket for this improvement then


yousafn
2023-04-03 11:08
Good spot @tien.xuan.vo

jordan.brooks
2023-04-18 13:15
has joined #pact-plugins

jordan.brooks
2023-04-18 13:23
Hey :wave: Is anyone here aware of the status of plugins for pact ruby? I don't see it on the roadmap https://github.com/pact-foundation/pact-ruby/blob/master/ROADMAP.md and we have a use case for pact that would require us to be able to use plugins from ruby.

yousafn
2023-04-18 13:33
Hi, It isn't currently on the roadmap (mainly due to maintainer capacity, rather than a lack of wanting to support it) but it is possible to write your own lanaguage implementation, by utilising the pact-reference core (written in rust) - https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/README.md exposed via an FFI (c shared libraries) There are simple implementation examples in a few languages in the repo ? https://github.com/pact-foundation/pact-reference/tree/master/javascript ? https://github.com/pact-foundation/pact-reference/tree/master/php ? https://github.com/pact-foundation/pact-reference/tree/master/ruby I created my own examples a little while back https://github.com/YOU54F/pact-ruby-ffi/blob/main/examples/area_calculator/spec/pactffi_create_plugin_pact_spec.rb https://github.com/YOU54F/pact-ruby-ffi/blob/main/lib/pact_ruby_ffi.rb Maybe you could use that as a source of inspiration to at least get you moving, and share it back with the community

yousafn
2023-04-18 13:36
There are some other examples of loading the shared libraries with Ruby here https://github.com/YOU54F/hello_ffi/tree/main/ruby and tested with GH actions here https://github.com/YOU54F/hello_ffi/blob/6f36442dc52c0624d7c6e146426c50b233db210b/.github/workflows/action.yml#L9-L31 I fix to 2.7.6 of Ruby for gRPC support, as it currently isn't in Ruby 3.x The FFI libs worked with Ruby 3.x when I tested it last

yousafn
2023-04-18 13:38
I also hacked about a ffi interface generator for Deno, to generate the same for Ruby https://github.com/YOU54F/deno-ffigen/commit/52635a822339f3715e694b6f72806820fa2cebc9 which is pretty neat for being able to pull in the appropriate methods in a more automated fashion, than mapping manually

jordan.brooks
2023-04-18 13:46
Awesome - thanks for the link, will see if we would be willing to go that route.

adam.cox
2023-04-28 14:18
Hello again, I have another query about plugins that provide a transport. With the WebSocket plugin that we are creating we need to be able to support `ws` and `wss` connections, mostly to providers at the moment but it may be that we need it for consumers also. Currently our plugin just adds one "transport" to the catalogue: `websockets`. But this means that when verifying contracts there is no way to tell the pact-standalone-verifier to use a `wss` scheme when connecting to the provider server. We noticed that the `ProviderInfo` struct has a `scheme` field which looks like it would be perfect for our use case but the pact-standalone-verifier does not expose this option. Looking at the source code here [1] it looks like it used to, but this is not listed in the docs a the top. We considered having the plugin create two transports `ws` and `wss` but this then meant that the consumer would have to determine which transport to choose so that it is written into the contract. We weren't sure if this was correct as it doesn't really matter for the contract contents if the connection is secure or not. Also we wanted to avoid consumer users from having to create self-signed certs to create contracts unless they really wanted to test with the mock server over wss. Guidance as to the intended approach would be most appreciated :slightly_smiling_face: Side, but related, note: in pact-consumer it looks like `tls` is hard-coded to false [2]. Why is that? Has this not been implemented yet or are secure connections supposed to be solved a different way? [1] https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_verifier_cli/src/main.rs#L673 [2] https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_consumer/src/mock_server/plugin_mock_server.rs#L64

matt.fellows
2023-05-01 08:28
Interesting. I didn?t quite get why you needed `wss` though, is that because your providers only run on TLS? I usually don?t consider TLS a helpful thing in contract testing (i.e. we don?t learn anything new usually), but I know a lot of tooling is making it harder / the default to use TLS so it?s something to consider. @uglyog might be able to answer tomorrow (he?s just returned from PTO, so bare with him as he wades through the inevitable pile of emails/slack messages :laughing: )

uglyog
2023-05-01 23:07
TLS doesn't provide any benefit, but adds a whole bunch of complexity (needing to then deal with keystores/truststores, self-signed certs, custom root CAs, etc). It is not as easy as just saying tls=true. We have support for it for where people have no other option, but it is not currently well supported (at the moment it only supports the use of self-signed certs).

uglyog
2023-05-01 23:09
The way the use transports are designed, the plugin can support as many as required, and the consumer test then specifies the transport that is required, and then there is a new attribute added to the V4 interaction to store this.

uglyog
2023-05-01 23:13
The `ProviderInfo` struct doesn't have a scheme field? It does have a list of transports. ```/// Information about the Provider to verify #[derive(Debug, Clone)] pub struct ProviderInfo { /// Provider Name pub name: String, /// Provider protocol, defaults to HTTP #[deprecated(note = "Use transports instead")] pub protocol: String, /// Hostname of the provider pub host: String, /// Port the provider is running on, defaults to 8080 #[deprecated(note = "Use transports instead")] pub port: Option<u16>, /// Base path for the provider, defaults to / #[deprecated(note = "Use transports instead")] pub path: String, /// Transports configured for the provider pub transports: Vec<ProviderTransport> }```


matt.fellows
2023-05-02 00:49
Ah, yes!

adam.cox
2023-05-02 11:35
This is coming from a scenario we currently face where a consumer has submitted a contract using the `websockets` transport and we are trying to verify it against a provider. This provider only accepts `wss` TLS connections but another provider we have supports only `ws` connections. We didn't want the consumer to have to decide if the provider would be tested with or without TLS because, as you say, it doesn't change the contract and it adds a lot of complications in creating, trusting and using self-signed certs. So it felt odd for the consumer to say "this contract is for wss", "this contract is for ws" as really we only care about this when verifying the contract. What we landed on for now is to use a plugin config item "useSecureSocket" which when set to true will set the mock WS server hostname to `localhost` and send messages over `wss` instead of `ws` which allows a provider to choose whether or not to test using TLS. The problem then becomes verifying two providers on the same host (or rather same CI build container image) which want different config values as it needs to be changed / configured before running the verification. So the recommendation would be the following? ? Do not support using TLS during consumer testing ? Have the plugin offer two transports - `ws` and `wss` ? Have the consumer specify whether or not to use `wss` or `ws` when creating the consumer contract ? Verify the provider according to the transport in the contract. I am not sure if this would be better to the plugin config method or not :thinking_face:

matt.fellows
2023-05-05 11:39
I think you could let the contract record `ws` or `wss` but let both sides choose whether or not to use the secure variant. A config seems a reasonable option to expose that, but i?d default to non-secure for most people (because of the reasons listed by Ron above)

matt.fellows
2023-05-05 11:40
I think it?s OK to expose both options. But even in regular Pact world, I?ve rarely seen the SSL variant used (it?s mostly only needed when you?re testing against a real endpoint, and that real endpoint has a stupid self-signed certificate on it so you need to be able to disable or configure the transport).

adam.cox
2023-05-05 12:09
If the user will set config and decide whether or not to use a secure connection then we do not really need to expose two transports do we? We can just expose the transport `websockets` as we are now and hide the scheme choice from the users. I think consumer side TLS/SSL is going to be an extremely rare or even non-existent use case but secure providers is something that will (has) come up because the binaries we are testing (and will deploy) use self-signed certificates for inter component communication on a device. We are testing against binaries that will be deployed to devices and they are configured in this way. The cert is embedded in the provider and the host running the tests is configured to trust it. We currently have the config value default to false

matt.fellows
2023-05-08 00:39
yes, that makes sense to me!

adam.cox
2023-05-09 13:28
How can we add plugin config to a contract for a given interaction when that interaction uses a core matcher? We are using JSON-RPC payloads over a WebSocket connection so the content matching is done with the core JSON matcher. However on a given interaction we need to be able to set the following: ? Path to connect to the WS server on. e.g. `` - specifically the `/jsonrpc` bit ? Headers to send in the connection request ? Message payload encoding as text or binary We are using synchronous message contracts to do the verification and we are trying to extend the plugin so that these metadata properties can be set, however we are struggling to find the code path that allows plugin config to be added to the contract files when a core matcher is being used. Advice/guidance on how to achieve this would be greatly appreciated

adam.cox
2023-05-09 16:47
I think I have been approaching this from the wrong angle. If we ignore the message encoding (which for now can always be text anyway) then I can just use the ProviderInfo.transports.path and customHeaders. Then when verifying contracts these just need to be passed to the verifier. I guess if some contracts are using Sec-WebSocket-Protocol header and path different to other contracts then this information should be in the contract itself (or maybe these are 2 providers in that case??) but for now we can just take it from the verifier CLI args. I just need to implement support for those args in the verification side of the plugin.

adam.cox
2023-05-10 08:03
One concern with adding the headers and path only when doing verification is that it does not ensure the client implements these details - specifically the header - which is required for the implementation to work.

yousafn
2023-05-10 11:32
when you say core matcher, are you talking about traditional matchers used in http and message pact tests, not the plugin matchers? https://docs.pact.io/implementation_guides/pact_plugins/docs/matching-rule-definition-expressions

adam.cox
2023-05-10 12:23
Yes that is what I mean

adam.cox
2023-05-10 12:23
Our plugin is not adding any new matchers

adam.cox
2023-05-10 12:26
Also, looking at the pact_verifier it doesn't look like the `path` property of the ProviderInfo is being added to the verifyInteraction request. I can only see host and port being sent in the config


yousafn
2023-05-10 12:31
the pact plugin framework only support the matchers in my linked document at the moment

adam.cox
2023-05-10 12:38
I think I mean Content Matcher :thinking_face:

adam.cox
2023-05-10 12:40
Maybe I am phrasing my question/intention incorrectly. We have a consumer that communicates with a provider over WS so we have created a plugin that adds the WS transport. When the consumer interacts with the provider they need to provide a base path and an appropriate header to establish the WS connection. We are using synchronous message interactions to capture the contracts. The messages are JSON payloads. We the consumer to be able to specify the base-path and header in the contract so that during verification they can be sent to the provider. Currently it does not look possible to any of the following: ? Add custom data in the consumer contract for use with a transport plugin ? Specify path / headers / metadata for sync message contracts ? Pass the path property for a transport from the verifier API over to a plugin handling verification requests

yousafn
2023-05-10 15:34
Ok so I think you need to define your own interaction type, and you can set your own properties, your code just needs to know to look for them, and then write the appropriate values https://github.com/pact-foundation/pact-plugins/blob/bfb1fa52506ec42add5abda5e824533c8af0e252/plugins/protobuf/src/main/kotlin/io/pact/protobuf/plugin/PluginApp.kt#L314-L323 your provider side, will expect those keys and can do whatever you need You can define your own shape of your plugin interaction, it may just align to the async/sync message and http specs shapes defined by the v4 spec

yousafn
2023-05-10 15:34
don't know if that helps

yousafn
2023-05-10 15:35
> ? Add custom data in the consumer contract for use with a transport plugin Your consumers can add whatever they want in, ideally to a known spec, so the plugin knows where to read it

yousafn
2023-05-10 15:36
> ? Specify path / headers / metadata for sync message contracts only if you are adhering to the pact specification, the idea with plugins is you can step outside these bounds

yousafn
2023-05-10 15:37
> ? Pass the path property for a transport from the verifier API over to a plugin handling verification requests Your verifier side of the plugin needs to aware of the key in the contract, which is can use to do whatever it needs to do, to get in the right state

yousafn
2023-05-10 15:39
> I guess if some contracts are using Sec-WebSocket-Protocol header and path different to other contracts then this information should be in the contract itself (or maybe these are 2 providers in that case??) could that header be optional? and therefore the plugin verifier is agnostic so it being set or not, if it is set use it, if the path differs from normal use that, otherwise ignore the header and path? maybe some diagrams might help our mentalmodel :slightly_smiling_face:

adam.cox
2023-05-11 09:30
*Consumer Custom Data* If I look in the whole pact-reference code base I cannot find "message-type" anywhere. If I look at https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_consumer/src/builders/sync_message_builder.rs#L139 which can be used for a consumer to set up a sync interaction the `add_plugin_data` function is only called when the content matcher is not a core matcher. So are we saying here that we need our plugin to add a new content matcher which is essentially the same as the core application/json one but it facilitates us adding the custom plugin data fields? On the verifier side I can see how to read the content from the plugin data in the contract but I cannot work out how to get it in the contract using the pact_consumer library. *Consumer Contract Metadata* Again, looking at the https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_consumer/src/builders/sync_message_builder.rs#L147 for defining consumer contracts it doesn't look like a metadata field is supported for either core or plugin based content types. We can set the request and response bodies but not much else. *Pact Verifier* ProviderInfo struct has a https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_verifier/src/lib.rs#L197 which contains the transports and their config. We have a websockets transport in here with a port number. The ProviderTransport struct has a https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_verifier/src/lib.rs#L153. However it seems impossible to set the path property when using the pact-standalone-verifier and even if we could set it it doesn't get sent over to the plugin at any point. Only the host and port get sent as part of the "config" in the verifyInteraction request. https://github.com/pact-foundation/pact-reference/blob/46628a8bf6b4d514adcb317d749fb8a79130b472/rust/pact_verifier/src/lib.rs#L459 https://github.com/pact-foundation/pact-reference/blob/46628a8bf6b4d514adcb317d749fb8a79130b472/rust/pact_verifier/src/lib.rs#LL427C25-L427C25 https://github.com/pact-foundation/pact-plugins/blob/main/drivers/rust/driver/src/plugin_manager.rs#L579 From looking at this code I cannot work out how to get the additional info we need into the config in the contract in order for it to be sent to the provider when doing the verifications. *Diagrams* Let me see if I can put something together to help illustrate what we are trying to do. Thank you very much for taking the time to assist us with this.

adam.cox
2023-05-11 10:32
I have a simple diagram here which (hopefully!) illustrates the use case. 1. The consumer (C) sends a HTTP request to the WS server (P). This request is on a specific path on the server and requires the Sec-WebSocket-Protocol header to be sent. If the path is wrong or the header is missing / value is wrong the connection will not be established. 2. The WS server responds that the protocol can switched over WS and a connection is established 3. The client sends a JSON payload to the server 4. The server processes the payload and sends a response Currently our contract just has the JSON payloads from 3 + 4 in it. However when verifying the contract it fails as the messages are being sent to the server base path (e.g. localhost:9998 - no base path) and without the correct header. This meant that the WS connection was never established and so the payloads from the contract could not be sent.

adam.cox
2023-05-11 10:42
I guess there are a few questions on how best to handle this: 1. Should the path and header be on the contract at all? I'm torn because if these details are missed by the consumer then the integration won't work in prod. But maybe this should be tested elsewhere? 2. If not in the contract how can we configure the provider verification to establish the connection in the correct place? 3. If multiple request/response interactions are happing over a single connection (rather than a connection created for each interaction) does the connection info even belong in the contract and should the plugin setup the connection before verifying the interactions? If so where would this connection be best made in the verification workflow

yousafn
2023-05-12 11:35
Hey Adam, I have read this and super appreciative for the diagrams. I will invite @uglyog in for some noodling as he is our plugin Jedi. I don't think I'll be super valuable at the moment as I am generally newish to the plugin framework, know nothing about websockets/json-rpc so you are well further ahead in the field that I am on both fronts :slightly_smiling_face:

adam.cox
2023-05-12 14:51
Thanks @yousafn. I think your questions have lead me to outline the thoughts/problems much better so I really appreciate your input on this so far :slightly_smiling_face:

uglyog
2023-05-15 03:11
Any data required should be stored in the metadata associated with the interaction. This is up to the plugin to decide how these are interpreted. I.e., you can maybe add a headers key to the metadata.

uglyog
2023-05-15 03:14
The Pact provider verifier won't know how to verify these interactions or interpret those values. This is why the plugin needs to implement `PrepareInteractionForVerification` and `VerifyInteraction` to do the actual verification.

uglyog
2023-05-15 03:16
> should the plugin setup the connection before verifying the interactions? This is up to the plugin author to decide how best to handle this. It will depend on the protocol being used. For websockets, this does make sense as it is an upgrade over standard HTTP.

uglyog
2023-05-15 03:17
The current workflow doesn't have any way to directly support that, it would have to be done in a lazy manner, i.e. create the connection the first time it is needed and then cache it.

uglyog
2023-05-15 03:18
Also, depending how the test framework runs things, the plugin may not always be running for the duration of all the tests.

adam.cox
2023-05-15 07:58
Thanks @uglyog. This is very helpful. How can we get data into the metadata of the sync message contracts? I can't see how to add request metadata using `contents_from` or the sync message builder api.

uglyog
2023-05-15 08:00
hmm, let me check that



adam.cox
2023-05-15 08:07
Thank you. I'll take another look. I couldn't see any reference of `requestMetadata` in the rust pact_consumer for handling sync messages. Let me see if it works

adam.cox
2023-05-15 08:20
I have just tried the following and the metadata is not present in the contract. ```let ms = pb .synchronous_message_interaction("sync message example", |mut i| async move { i.contents_from(json!({ "pact:content-type": "application/json-rpc", "request": { "query": "matching(string, 'getMacAddress')" }, "requestMetadata": { "headers": { "Sec-WebSocket-Protocol": "jsonrpc" } }, "response": { "data": "matching(string, '00-B0-D0-63-C2-26')" } })) .await; i.test_name("sync message example"); i }) .await .start_mock_server_async(Some("websockets/transport/websockets")) .await;```

adam.cox
2023-05-15 08:20
```{ "consumer": { "name": "message-consumer" }, "interactions": [ { "comments": { "testname": "sync message example" }, "description": "sync message example", "key": "8e58be3b3ff9c72b", "pending": false, "request": { "contents": { "content": { "query": "matching(string, 'getMacAddress')" }, "contentType": "application/json-rpc", "encoded": false } }, "response": [ { "contents": { "content": { "data": "matching(string, '00-B0-D0-63-C2-26')" }, "contentType": "application/json-rpc", "encoded": false } } ], "type": "Synchronous/Messages" } ], "metadata": { "pactRust": { "consumer": "0.10.5", "models": "1.0.13" }, "pactSpecification": { "version": "4.0" }, "plugins": [ { "configuration": {}, "name": "websockets", "version": "test" } ] }, "provider": { "name": "message-provider" } }```

adam.cox
2023-05-15 08:34
Its doesn't look like the pact_consumer in rust looks for these other fields in the sync_message_builder and so they are ignored.

adam.cox
2023-05-15 08:46
So I suppose in the short term, would it work if we provide the `application/json` content type from the plugin and then use the generate_content functionality to support metadata? It seems like more work than the plugin should need to do but I can't see another way of doing it right now

adam.cox
2023-05-15 10:23
~generate_content~ configure_interaction

uglyog
2023-05-15 23:18
pact_consumer won't set those values, it all gets passed to the plugin to configure.

uglyog
2023-05-15 23:19
You can specify what ever format you want, and the plugin then needs to read that format and configure the interaction appropriately during the `configure_interaction` call

adam.cox
2023-05-16 08:07
I was trying to avoid having to implement the configure_interaction call as I am essentially re-implementing the core application/json content-matcher but adding support for a "metadata" field. The application/json matcher works very well for us already but using it offers no ability to add anything extra to the `metadata` field of the contract.

adam.cox
2023-06-02 09:51
Hello Team! I have a new question about the Configure Interaction request and numeric data types. When a user creates a contract with a definition such as: ```"request": { "id": 1 },``` The configure interaction request receives a payload like this: ```"request": Value { kind: Some(StructValue(Struct { fields: {"id": Value { kind: Some(NumberValue(1.0)) } } })) }``` Now in the contract the the value to match against is `1.0` and not `1` . In the consumer test a message is sent to the mock server with the payload: ```{ "id": 1 }``` When the mock server receives this request we try to match against all interactions in the pact but we get a mismatch for this field as: ```1.1) [$.id] Expected '0.0' to be equal to '0'``` I have been trying to debug and fix this issue and it looks to me like the following is happening: 1. The pact framework is taking the consumer contract and converting it to a protobuf payload to send to the plugin 2. This process converted the id field to a Value::Kind::Number(&f64) 3. In the plugin we decode the protobuf payload using `proto_value_to_json` (I think I took this directly from your protobuf plugin) and for a number Kind it runs: `serde_json::json!(n)` 4. serde is seeing the f64 and creating a Value::Number(Number::Float)) 5. So now we have lost the information that the original number was an int and not a float and our comparison fails when we receive an int It seems to me that serde has a good way of handling the different number types but the prost_types definition of `Kind::NumberValue(f64),` is reducing the amount of information that can be conveyed to the plugin about a numeric field during the configure interaction request. I had a search online around protobuf number types and it looked like different types of numbers are supported so I'm not understanding why prost_types treats all numbers as floats. I am not very familiar with protobuf at all though so I probably am just missing something. In the mean time we are encouraging the users to define the contract as `{ "id": "matching(integer, 1)" }` but I think it should be possible for them to just specify the contract as `{ "id": 1 }` and have it work. This did work when we were using the core application/json matcher but I am assuming that is because the type information is not lost when passing the values around in rust.

uglyog
2023-06-04 23:24
Ah, right! That's because this is the proto definition for Struct: ```// `Value` represents a dynamically typed value which can be either // null, a number, a string, a boolean, a recursive struct value, or a // list of values. A producer of value is expected to set one of these // variants. Absence of any variant indicates an error. // // The JSON representation for `Value` is JSON value. message Value { // The kind of value. oneof kind { // Represents a null value. NullValue null_value = 1; // Represents a double value. double number_value = 2; // Represents a string value. string string_value = 3; // Represents a boolean value. bool bool_value = 4; // Represents a structured value. Struct struct_value = 5; // Represents a repeated `Value`. ListValue list_value = 6; } }```

uglyog
2023-06-04 23:24
Numbers are represented with doubles.

uglyog
2023-06-04 23:27
I'll need to think about how to deal with this.

matt.fellows
2023-06-05 00:32
Looks like we?re running into problem #5 :stuck_out_tongue:

matt.fellows
2023-06-05 00:33
(kind of, I suppose technically in this case protobuf does support other number types)

adam.cox
2023-06-14 13:51
I'm trying to get some metadata_rules added to the contract via the confiure_interaction request and I can't seem to work out why it doesn't work. I have added them into the metadata_rules field of the request part of the interaction and they are going back to the driver. However when I get the start_mock_server request and parse the pact I cannot see any metadata rules in the contract. In my debugging journey I noticed this: https://github.com/pact-foundation/pact-plugins/blob/main/drivers/rust/driver/src/content.rs#L313 The matching rule category is always set to BODY. Could that be related to my issue? Looking at the Category enum it seems that Contents and Metadata are also available and I wonder if those would be more appropriate for message contents and metadata rules.

adam.cox
2023-06-14 14:44
While I am asking questions actually, I may as well explain my true aim. In the metadata field of the request I want a nested object which will match when there are more keys than are specified in the contract. Currently I get this error from the matching ```1) c9d8b50f42b5d1e7 - the following mismatches occurred: 1.1) [] Expected metadata key 'headers' to have value '{"sec-websocket-protocol":"json-rpc"}' but was '{"connection":"upgrade","host":"[::1]:64257","sec-websocket-key":"qtwa71ue1dhx8b0ffbiqyw==","sec-websocket-protocol":"json-rpc","sec-websocket-version":"13","upgrade":"websocket"}' - Expected '{"sec-websocket-protocol":"json-rpc"}' to be equal to '{"connection":"upgrade","host":"[::1]:64257","sec-websocket-key":"qtwa71ue1dhx8b0ffbiqyw==","sec-websocket-protocol":"json-rpc","sec-websocket-version":"13","upgrade":"websocket"}'``` The contract specifies the `"sec-websocket-protocol":"json-rpc"` header, but the request comes in with a lot of others. We only need the one header validated in the contract. The connection request we are establishing has the header and it has the correct value so this should pass. However as the contract doesn't contain all the other headers it fails. I'd like to make the matching work like the header matching in HTTP contracts, however I want the headers in an object called headers and not on the root of the metadata object. This is because we are now trying to add query params as well and I'd like to keep the two separate.

uglyog
2023-06-15 00:02
Ok, let me confirm, this may be a bug

uglyog
2023-06-15 00:04
This would need changes in the Pact libs. I think it treats the metadata as a flat collection.

uglyog
2023-06-15 00:05
What you are asking makes sense, it will just take a bit of effort to implement.

uglyog
2023-06-15 00:05
@matt.fellows :point_up:

uglyog
2023-06-15 01:27
Looks like both the JVM and Rust implementations have this behaviour. I think we need to add a field to indicate which category the matching rules should be assigned too.

uglyog
2023-06-15 01:28
I'm a bit hesitant to change this (your comment is correct, it should be using the "content" category for messages), but I don't know the side-effects this change could have.

adam.cox
2023-06-15 08:41
Yes I thought that might be the case with changing BODY -> CONTENT. But adding new ones for METADATA should be ok?

adam.cox
2023-06-15 09:22
At the moment it looks to me like the metadata is treated how I want my nested property to be. i.e. it ignores unexpected keys. This seems to be coming from the `DiffConfig::AllowUnexpectedKeys` on the matching context. However nested values are compared with Equality. So it would be great if we could apply the DiffConfig setting at least one level down. Also it seems impossible to actually change the matching context for metadata at the moment so if we wanted a different behaviour on metadata we wouldn't actually be able to do it. Although isn't a feature we actually need so not too bothered about that

uglyog
2023-06-16 00:03
Yeah, METADATA should work ok

mich.krzyzanowski
2023-06-17 15:25
has joined #pact-plugins

uglyog
2023-06-19 00:16
@adam.cox @tien.xuan.vo @ali.ustek we are planning to make some improvements to the plugin interface. This will probably just be a minor update to the current interface, if possible. The place to start would be to let us know what the biggest issues you have had using or building the plugins. One area we are definitely looking to improve is the verification sequence, but this will be the opportunity to make other improvements as well.

tien.xuan.vo
2023-06-19 03:51
For me this feature is in my wishlist: auto download binary and meta files for plugins https://pact-foundation.slack.com/archives/G9VHV9VJ9/p1683866419534919?thread_ts=1683820689.902969&cid=G9VHV9VJ9

uglyog
2023-06-19 04:03
The latest FFI should already have that capability.

tien.xuan.vo
2023-06-19 12:21
For me the biggest issue when start using plugin is I can't see its logs, so I really don't know what is going on. For now my understanding about plugins is a bit better so I don't have to read its logs, but I am always afraid of it. Here is the related thread https://pact-foundation.slack.com/archives/C047TCR7B6W/p1679760157876359

adam.cox
2023-06-20 08:29
In order of importance for us: ? Configure interaction to support metadata matching rules. This not working is a pain for us at the moment and is holding us up on making progress without workarounds for one of our providers. ? Nested metadata matching. Being able to configure metadata matching at one or more levels deep and ignoring additional keys would also help us configure the metadata in contracts how we want to. ? Configure Interaction to support different number types other than double. ? Not having to create our own content type to add metadata to contracts. We have had to make the "application/json" content matcher again so that we can add metadata fields into the contract. This means that we have had to find the core implementation of application/json and copy bits of code to keep the same behaviour and then try to add the metadata on top. ? Easy to use / documented core library and utility functions for matching. For example a function we can call with a JSON message payload and a pact and find which contract is the best match. Currently we have pieced together bits of pact_matching with our own transformations from a JSON message and some metadata to match websocket messages as they come in. We also reimplemented the loop that goes over the contract and calls the comparison for each one. This process feels like it could be a bit easier for plugin developers if they want a consistent and out of the box feel for the plugin behaviour. ? The logging point is a good one. It used to be possible to use RUST_LOG when using the plugin for consumer tests and we would see all of the child_process logs but this seems to have stopped. Being about to log to a file would be nice, capturing any stdout from the plugin process. This would also make the logs easier to read/parse as using the tracing crate in both the plugin and the driver means the child_process lines are quite noisy. Very low priority ? Support for downloading plugins from non-open source GitHub repositories ? ARM based docker files for building releases. Currently I am spinning up an x86 EC2 in order to compile the Linux plugin builds as the docker images and cross don't play well on my M2 mac. I think most of these are points we have already covered in other threads but if you want more detail or need any clarification from me then I am happy to provide. I am still working on getting our plugin open sourced.

uglyog
2023-06-22 23:40
Thanks for the feedback, I'm going to raise some cards in our backlog for these items.

praveen.em
2023-07-14 14:15
Hello there. I tried using avro plugin few weeks ago. Looks like it requires java 17. Just wanted to check if there is any plan to make the plugin java 11 compatible?

praveen.em
2023-07-14 14:15
Also wanted to get your thoughts in terms of any preferred programming languages for these pact plugins in general. In the documentation, there was a suggestion to choose a language (like golang or rust) which can be compiled to create a single executable to multiple languages. Are those type of languages strongly recommended for plugins or they don?t matter too much?

praveen.em
2023-07-14 14:19
Btw, I am keen to contribute especially to avro stuff as we have use cases within our org. I tried the plugin creation workshop to get a feel of what is involved in building a plugin. I found https://github.com/pact-foundation/pact-plugin-template-golang quite useful. As a follow on to the workshop, I played with it little bit making use of ANTLR to auto generate parsers for https://github.com/pact-foundation/pact-plugins/blob/main/docs/matching-rule-definition.g4. Then added bit of logic on top of that to create interaction with matching rules for message payload using avro. This is all to get a feel of what is involved and didn?t want to go any further than that. This all looks interesting and I am keen to contribute either to the existing avro plugin or continue creating a version of it using golang if that is the preferred language.

yousafn
2023-07-14 14:22
Hey Pravs, @ali.ustek is the author and there is an #avro channel. I believe its meant to come with into own mini JVM so the user doesn?t need java. https://github.com/pact-foundation/pact-go/pull/291#issuecomment-1631685596

ali.ustek
2023-07-14 14:25
There is discussion thread going on: https://github.com/austek/pact-avro-plugin/issues/26

yousafn
2023-07-14 14:26
we recommend languages that cross compile easily into a single binary, and don?t require end user intervention just for each of use. The pactflow supported plugins are most likely to be written in Rust like https://github.com/pactflow/pact-protobuf-plugin just due to @uglyog being in Rust land most of the time. There are some JVM examples. GoLang is also good but there is less shared experience, @matt.fellows is probably our most versed in golang across the maintainer group. I wouldn?t let it stop you at the moment, as the avro plugin that has been built it still at an early stage, so even if playing via golang is useful to help get your head around the plugin concepts in a language most familiar and then can port across to the avro jvm version, or otherwise maintain your own version.

yousafn
2023-07-14 14:27
:wave: Hey Pravs, Been meaning to catch up with you about all things Pact anyway, so nice timing. Sounds like your have a nice adventure!

yousafn
2023-07-14 14:28
ty @ali.ustek! Hope you are well

praveen.em
2023-07-14 14:50
Thanks @yousafn and @ali.ustek. I will keep an eye on that issue.

praveen.em
2023-07-14 14:56
Hey Yousaf :wave:. Yeah, having bit of fun with plugins last few weeks. Hope all is well with you. Btw, looking forward to the community meetings you were planning to setup :slightly_smiling_face:

praveen.em
2023-07-14 15:00
Great! will continue with Golang in that case at least for time being. Right now, it?s in my own repo. It is most likely to move to our org?s external public repo with some support. will let you know if/when that happens.

praveen.em
2023-07-14 15:18
Just so you know, golang is new to me as well. I just happened to use it as the workshop used golang template. After using it for couple of weeks, i started liking it. There is also bit of resemblance with C which I used to love very much (my first programming language). And in our org we have growing population using Golang for helm charts and kubernetes operators.

yousafn
2023-07-14 15:24
We were just discussing that yesterday, we should be making an announcement on Monday, maybe looking to align times on Thursday with the Cucumber community as they have a session as 3pm and if we are around the same time maybe we can cross pollinate. We?ve been considering having a couple of time slots too, due to having a fair few on different sides of the pond

yousafn
2023-07-14 15:27
golang is pretty cool to be honest, I?ve been writing some github extensions of late

yousafn
2023-07-14 15:28
I particularly like its cross compiling and tiny binaries, and its really fast when doing parallel tasks, over a bash script that is getting overly complicated. I never did C much bar at uni and some programming books off my Dad?s

rohitkrishnan
2023-07-25 20:38
has joined #pact-plugins

rohitkrishnan
2023-07-25 20:39
Is there an estimate of when Pact JS would support plugins? (even a sketchy branch would suffice)


wongkoonwai
2023-07-27 04:02
has joined #pact-plugins

rohitkrishnan
2023-07-27 12:31
Oh wonderful thanks!

yousafn
2023-08-03 11:07
:blobwave: Hey Pact Plugin friends! I?ve been promising a community meet for a while and it?s slow trying to get everything organised. In the interim would people be up for a Plugin show and tell session? It can be pretty informal just in a Slack huddle, or we can do something recorded. cc: @praveen.em / @ali.ustek / @adam.cox

ali.ustek
2023-08-04 08:05
Could do, I don't know if there is much to show on a plugin

praveen.em
2023-08-06 14:31
I can show my journey so far of trying to build using golang plugin template but I feel it might be bit too early though to show something meaningful in my case as I am somewhat in early stages.

yousafn
2023-08-07 11:04
Thanks for the replies gents, was more hoping to give you all a place just to discuss and collab, or just the chance to meet each other and say hello, rather than it being a big demo fanfare. For me its a chance to listen to some feedback on how you've got on, and if there is anything we can do to help. Happy doing it async otherwise.

elenadoty
2023-08-15 18:48
has joined #pact-plugins

elenadoty
2023-08-16 20:42
Hi all! Is there a way to modify the consumer's request in the provider test when using the gRPC plugin with Golang? I'm assuming RequestFilter/BeforeEach/AfterEach are out of the picture, and it doesn't seem like there's an equivalent to the way of doing it with JVM https://github.com/pact-foundation/pact-plugins/blob/818119cc39e0f8921b0f471ebf0ca784663cc58b/examples/gRPC/metadata/provider-jvm/server/src/test/java/io/pact/example/grpc/provider/PactVerificationTest.java#L59. For context, I'm hoping to be able to add an auth header during the provider test so that we don't have to worry about it expiring after being generated/set during the consumer test. I've been able to set it using the requestMetadata field in the consumer test, so I may plan to just write a method that will modify the contract to overwrite the token during the test, but I wanted to make sure there wasn't a better way to do it first. Thanks!

tjones
2023-08-20 21:16
Can you not do this with provider state variables?

joshua.ellis
2023-09-20 06:41
has joined #pact-plugins

srijan.c
2023-10-16 10:16
has joined #pact-plugins

christopher.tonog
2024-01-29 18:01
has joined #pact-plugins

christopher.tonog
2024-01-29 18:06
:wave: Hi all, apologies in advance if the location is obvious, I'm trying to find an example of using the gRPC plugin with a JS consumer. So far I've only found jvm, go, and rust examples here https://docs.pact.io/implementation_guides/pact_plugins/examples/grpc. The provider is a go app with protobuf, so I have been able to find examples with that. Thanks so much!

yousafn
2024-01-29 18:19
Hey, It isn't obvious no, we don't have one under the pact-foundation at the moment, here is one I created a while back https://github.com/YOU54F/pluginopedia/tree/main/example-project-js-grpc-plugin/test

christopher.tonog
2024-01-29 19:08
Ah thanks, that is helpful :bow: I couldn't find the documentation on the `usingPlugin`, `addSynchronousInteraction`, etc APIs. I checked here https://docs.pact.io/implementation_guides/javascript/docs/consumer#api , is there somewhere else that information is located? Thanks again!

matt.fellows
2024-01-29 21:59
It is currently a little hidden, mostly because it?s hidden behind the feature flag. There is an example v4 project in the repo

matt.fellows
2024-01-29 21:59
I think we should release it and add the docs, despite it not being feature complete yet (e.g. no async messages in the V4 interface yet)

jo.laing
2024-02-06 14:04
has joined #pact-plugins

maciej.harapinski
2024-02-19 09:46
has joined #pact-plugins

becca.liss
2024-02-28 15:33
has joined #pact-plugins

becca.liss
2024-02-28 15:41
Hi friends! I'm experiencing a weird issue that I was hoping someone could help provide some insight into. I'm able to run my pact provider test just fine with `consumerVersionSelectors: [{ branch: 'main' }]`, but when I use `consumerVersionSelectors: [{ branch: 'feature-branch' }]` I get an error about not being able to find the protobuf plugin :thinking2:

becca.liss
2024-02-28 15:42
with branch *main* (everything works fine): ```console.log using Verifier options { logLevel: 'trace', provider: 'email-templating', pactBrokerUrl: '<url>', consumerVersionSelectors: [ { branch: 'main' } ] }``` and the relevant plugin output: ```... does stuff... 2024-02-28T15:15:53.950960Z INFO ThreadId(02) verify_provider_async: pact_verifier: Pact file requires plugins, will load those now 2024-02-28T15:15:53.950991Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Loading plugin PluginDependency { name: "protobuf", version: Some("0.3.8"), dependency_type: Plugin } 2024-02-28T15:15:53.951037Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Rust plugin driver version 0.5.1 2024-02-28T15:15:53.951046Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: load_plugin ThreadId(2): Waiting on PLUGIN_REGISTER lock 2024-02-28T15:15:53.951090Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: load_plugin ThreadId(2): Got PLUGIN_REGISTER lock 2024-02-28T15:15:53.951214Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Did not find plugin, will attempt to start it 2024-02-28T15:15:53.951232Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Loading plugin manifest for plugin PluginDependency { name: "protobuf", version: Some("0.3.8"), dependency_type: Plugin } 2024-02-28T15:15:53.951333Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Looking for plugin in "/Users/becca.liss/.pact/plugins" ... fetches a bunch of pacts from the broker ... 2024-02-28T15:15:53.952307Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found: "/Users/becca.liss/.pact/plugins/repository.index.sha256" 2024-02-28T15:15:53.952340Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found: "/Users/becca.liss/.pact/plugins/repository.index" 2024-02-28T15:15:53.952363Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found: "/Users/becca.liss/.pact/plugins/protobuf-0.3.8" 2024-02-28T15:15:53.952389Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found plugin manifest: "/Users/becca.liss/.pact/plugins/protobuf-0.3.8/pact-plugin.json" 2024-02-28T15:15:53.952612Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Parsed plugin manifest: PactPluginManifest { plugin_dir: "", plugin_interface_version: 1, name: "protobuf", version: "0.3.8", executable_type: "exec", minimum_required_version: None, entry_point: "pact-protobuf-plugin", entry_points: {}, args: None, dependencies: None, plugin_config: {"hostToBindTo": String("127.0.0.1"), "downloadUrl": String("https://github.com/protocolbuffers/protobuf/releases/download"), "protocVersion": String("3.19.1")} } 2024-02-28T15:15:53.952683Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::metrics: 'PACT_DO_NOT_TRACK' environment variable is set, will not send metrics 2024-02-28T15:15:53.952690Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Starting plugin with manifest PactPluginManifest { plugin_dir: "/Users/becca.liss/.pact/plugins/protobuf-0.3.8", plugin_interface_version: 1, name: "protobuf", version: "0.3.8", executable_type: "exec", minimum_required_version: None, entry_point: "pact-protobuf-plugin", entry_points: {}, args: None, dependencies: None, plugin_config: {"hostToBindTo": String("127.0.0.1"), "downloadUrl": String("https://github.com/protocolbuffers/protobuf/releases/download"), "protocVersion": String("3.19.1")} } 2024-02-28T15:15:53.982551Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Detected OS: Mac OS 14.2.1 [64-bit] 2024-02-28T15:15:53.982577Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Starting plugin using "/Users/becca.liss/.pact/plugins/protobuf-0.3.8/pact-protobuf-plugin" 2024-02-28T15:15:53.983659Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Plugin protobuf started with PID 57329```

becca.liss
2024-02-28 15:44
with branch *feature-branch* (plugin errors): ```console.log using Verifier options { logLevel: 'trace', provider: 'email-templating', pactBrokerUrl: '<url>', consumerVersionSelectors: [ { branch: 'feature-branch' } ] }``` and then relevant plugin output: ```... does stuff... 2024-02-28T15:16:57.774008Z INFO ThreadId(02) verify_provider_async: pact_verifier: Pact file requires plugins, will load those now 2024-02-28T15:16:57.774039Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Loading plugin PluginDependency { name: "protobuf", version: Some("0.3.13"), dependency_type: Plugin } 2024-02-28T15:16:57.774085Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Rust plugin driver version 0.5.1 2024-02-28T15:16:57.774096Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: load_plugin ThreadId(2): Waiting on PLUGIN_REGISTER lock 2024-02-28T15:16:57.774143Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: load_plugin ThreadId(2): Got PLUGIN_REGISTER lock 2024-02-28T15:16:57.774294Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Did not find plugin, will attempt to start it 2024-02-28T15:16:57.774308Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Loading plugin manifest for plugin PluginDependency { name: "protobuf", version: Some("0.3.13"), dependency_type: Plugin } 2024-02-28T15:16:57.774394Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Looking for plugin in "/Users/becca.liss/.pact/plugins" 2024-02-28T15:16:57.774851Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found: "/Users/becca.liss/.pact/plugins/repository.index.sha256" 2024-02-28T15:16:57.774924Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found: "/Users/becca.liss/.pact/plugins/repository.index" 2024-02-28T15:16:57.774977Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found: "/Users/becca.liss/.pact/plugins/protobuf-0.3.8" 2024-02-28T15:16:57.775168Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Found plugin manifest: "/Users/becca.liss/.pact/plugins/protobuf-0.3.8/pact-plugin.json" 2024-02-28T15:16:57.775593Z TRACE ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Parsed plugin manifest: PactPluginManifest { plugin_dir: "", plugin_interface_version: 1, name: "protobuf", version: "0.3.8", executable_type: "exec", minimum_required_version: None, entry_point: "pact-protobuf-plugin", entry_points: {}, args: None, dependencies: None, plugin_config: {"hostToBindTo": String("127.0.0.1"), "downloadUrl": String("https://github.com/protocolbuffers/protobuf/releases/download"), "protocVersion": String("3.19.1")} } 2024-02-28T15:16:57.775722Z WARN ThreadId(02) verify_provider_async: pact_plugin_driver::plugin_manager: Could not load plugin manifest from disk, will try auto install it: Plugin protobuf:0.3.13 was not found (in $HOME/.pact/plugins or $PACT_PLUGIN_DIR) 2024-02-28T15:16:57.775907Z INFO ThreadId(02) verify_provider_async: pact_plugin_driver::repository: Fetching index from github 2024-02-28T15:16:57.775972Z TRACE ThreadId(02) verify_provider_async: hyper::client::pool: checkout waiting for idle connection: ("https", http://raw.githubusercontent.com) 2024-02-28T15:16:57.776004Z TRACE ThreadId(02) verify_provider_async: hyper::client::connect::http: Http::connect; scheme=Some("https"), host=Some("http://raw.githubusercontent.com"), port=None 2024-02-28T15:16:57.776045Z DEBUG tokio-runtime-worker hyper::client::connect::dns: resolving host="http://raw.githubusercontent.com" 2024-02-28T15:16:57.810817Z DEBUG ThreadId(02) verify_provider_async: hyper::client::connect::http: connecting to 185.199.108.133:443 2024-02-28T15:16:57.829625Z DEBUG ThreadId(02) verify_provider_async: hyper::client::connect::http: connected to 185.199.108.133:443 2024-02-28T15:16:57.849777Z TRACE ThreadId(02) verify_provider_async: hyper::client::pool: checkout dropped for ("https", http://raw.githubusercontent.com) 2024-02-28T15:16:57.849852Z WARN ThreadId(02) verify_provider_async: pact_plugin_driver::repository: Was not able to load index from GitHub - error sending request for url (https://raw.githubusercontent.com/pact-foundation/pact-plugins/main/repository/repository.index): error trying to connect: invalid peer certificate: UnknownIssuer 2024-02-28T15:16:57.851138Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::repository: Loading index file path="/Users/becca.liss/.pact/plugins/repository.index" 2024-02-28T15:16:57.852992Z DEBUG ThreadId(02) verify_provider_async: pact_plugin_driver::repository: Installing plugin protobuf/0.3.13 from index 2024-02-28T15:16:57.853132Z ERROR ThreadId(02) pact_ffi::verifier::handle: Verification execution failed: Plugin protobuf:0.3.13 was not found (in $HOME/.pact/plugins or $PACT_PLUGIN_DIR) 2024-02-28T15:16:57.853150Z TRACE ThreadId(02) pact_ffi::verifier: pactffi_verifier_execute FFI function completed output=2```

becca.liss
2024-02-28 15:46
i was looking through the `plugin_manager` https://github.com/pact-foundation/pact-plugins/blob/9901e209eabfd70fe2fafb3276597c41d08cba0a/drivers/rust/driver/src/plugin_manager.rs to see if anything jumped out at me, but i'm still pretty stumped as to how changing the branch selector could affect loading the plugin

yousafn
2024-02-28 16:20
was the pact created on the feature branch created ny a diff version of the plugin? its held in the plugin section of the pact file

yousafn
2024-02-28 16:20
looks like there is an error re the peer cert when downloading

becca.liss
2024-02-28 16:26
hmm i think you're onto something - i didn't notice that the plugin versions were different. the feature-branch pact was published in CI, which has a different install flow than local development

becca.liss
2024-02-28 16:26
and that would explain why it was trying to download a different version of the plugin

becca.liss
2024-02-28 16:27
good catch! lemme try and get the plugin versions consistent and see if that fixes things

becca.liss
2024-02-28 16:28
and thanks for such a quick response :grinning:

yousafn
2024-02-28 16:29
pleasure. you can also try and download that version of the plugin manually on your machine with the plugin cli

yousafn
2024-02-28 16:29
also love the hand drawn avatar :chefkiss:

becca.liss
2024-02-28 16:32
it's a wonderful thing to have artistic friends :joy:

becca.liss
2024-02-28 16:35
woo yup, downloading `0.3.13` causes the pact verification to run successfully. thanks yousaf!! you're a lifesaver :star-struck:

yousafn
2024-02-28 16:42
:woohoo: glad you are sorted! and totally agree about the arty friends. i owe gratitude to my designer friend Jim for my little pixel art guy

becca.liss
2024-02-28 16:49
i mean, fashion keeps claiming the 90s are back, so why not pixel art??

matt.fellows
2024-02-29 02:12
Pixel art :white_check_mark: Baggy pants :x:

jameshdemaine
2024-03-04 11:36
has joined #pact-plugins

jameshdemaine
2024-03-04 11:39
Hi everyone! I'm currently trying to setup the pact-protobuf plugin, I've setup a skeleton test and am trying to run it with the plugin installed but getting `pact_ffi::plugins: Failed to call out to plugin - Request to configure interaction failed: Failed to process protobuf: Failed to invoke protoc binary: exit code exit status: 1` back when running it. I've checked in the plugins dir that it has actually downloaded `protoc` and the executable is accessible - any help would be appreciated!

yousafn
2024-03-04 11:58
Hey, can you provide some details on your machine, is this in ci, or locally?

jameshdemaine
2024-03-04 12:05
Hi Yousaf, I'm running the test locally, on a ubuntu machine. I installed the pact-plugin-cli binary and then installed the plugin through that

jameshdemaine
2024-03-04 12:08
Also I'm trying to write consumer side tests in JS if that's relevant

yousafn
2024-03-04 12:11
have you got `protoc` executable on the command line? `protoc --version` https://grpc.io/docs/protoc-installation/ if that works, can you invoke the protobuf plugin directly, to run the plugin? There is a grpc example here in the pact-plugin repo, you could try that for starters to check it isn?t something in your test. https://github.com/pact-foundation/pact-plugins/pull/55

jameshdemaine
2024-03-04 12:12
I don't, but I did notice one was bundled with the plugin

jameshdemaine
2024-03-04 12:13
When I do run the executable in the plugin it does look like its starting a mock server `{"port":41785, "serverKey":"3ddf4cc4-fbcd-4a1c-9db3-b513fc0e57af"}`

yousafn
2024-03-04 12:15
There is, it?s a bit old (the bundled one) and doesn?t work for macos arm64 OOB, which is why I asked about platform. I think protoc does need to be available on the path, so could you try installing the protobuf-compiler and see how you get on? It may be that it is actually calling it, but can?t find your protobuf file, so protoc is failing. What does your grpc interaction look like, specifically the path to the protobuf file

yousafn
2024-03-04 12:16
also is there any logs in the pact protobuf plugin directory, post execution of your skeleton test

jameshdemaine
2024-03-04 12:19
Ah! I think I've found it, looks to have been the file path to the `.proto` file. Many thanks!

jameshdemaine
2024-03-04 15:07
Further to this - is there any documentation on matchers and their use that I could take a look at? I've had a look at some examples but I've only seen ones that follow this pattern `"numbers": "atLeast(1), eachValue(matching(regex, '\\d+', '100))"` for repeated fields. If say for example I had a repeated list of objects (potentially containing different types of primitive) instead of a repeated primitive as above, how would I handle that?

yousafn
2024-03-04 15:14
docs for matchers are here https://docs.pact.io/implementation_guides/pact_plugins/docs/matching-rule-definition-expressions although that doesn?t look to have synced in a while source is here https://github.com/pact-foundation/pact-plugins/blob/main/docs/matching-rule-definition-expressions.md you can compose expressions. If you can create an example with your scenario, it?s easier for me to visualise :+1:

jameshdemaine
2024-03-04 15:49
Thanks for sending that Yousaf. This is what I'm trying to do

matt.fellows
2024-03-05 00:53
hmmm. The doc seems to imply it would take the shape from `Asset` but not require that field. @rholshausen any ideas?

rholshausen
2024-03-05 00:53
has joined #pact-plugins

rholshausen
2024-03-05 01:01
Looks like a bug. Are you using the latest version of the protobuf plugin?

jameshdemaine
2024-03-05 09:09
@rholshausen I believe this is the latest

rholshausen
2024-03-05 22:20
Yeah, that is

jameshdemaine
2024-03-06 09:16
Is it possible this worked on a previous version that I could downgrade to?

rholshausen
2024-03-06 22:16
I'm unsure, I won't be able to tell. I looked at some recent commits, but could not see anything that would result in a regression. But there has been a lot of work in this space recently.

rholshausen
2024-03-06 22:17
Better just to fix the issue

rholshausen
2024-03-06 22:55
That form definitely works, there is a test for it in the plugin project: https://github.com/pactflow/pact-protobuf-plugin/blob/main/tests/each_value_tests.rs#L29

rholshausen
2024-03-06 22:57
Can you provide the proto file? Or try change the example name to something like ExampleAsset?

rholshausen
2024-03-06 23:01
Ah, think I see the problem. I think it should be ```"pact:match": "eachValue(matching($'Asset'))``` and not `"pact-match":`

jameshdemaine
2024-03-07 09:58
d'oh

matt.fellows
2024-03-07 11:02
Perhaps we can detect invalid pact prefixes and error/warn

michael_swiss
2024-04-12 17:06
has joined #pact-plugins

gobi
2024-04-17 00:23
has joined #pact-plugins

oak155online
2024-05-05 21:01
has joined #pact-plugins

mbieganski.infomatt
2024-05-06 16:18
has joined #pact-plugins

mbieganski.infomatt
2024-05-06 16:22
Hey :wink: I?m getting below error but tests are working and I?m wondering if it?s some issue with configuration. Any idea? ``````

rholshausen
2024-05-06 23:07
You can ignore that, it doesn't seem to affect the tests

mbieganski.infomatt
2024-05-07 06:30
Looks that way but wondering if I can get rid of it :slightly_smiling_face:

laurentipaolo
2024-06-13 13:13
has joined #pact-plugins

becca.liss
2024-07-09 15:09
Hi friends! Usual caveat about not being sure whether this is the right place to post, so please redirect me if so! I have a proto file with several imports ```syntax = "proto3"; package vts.central_entities.v1.service; import "buf/validate/validate.proto"; // global package (from https://github.com/bufbuild/protoc-gen-validate I believe) import "vts/central_entities/v1/service/entity.proto"; // local proto file``` when I run the pact test, I get this error ```2024-07-09T15:33:55.572407Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.572237Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_write: send frame=Settings { flags: (0x1: ACK) } 2024-07-09T15:33:55.572411Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.572258Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=WindowUpdate { stream_id: StreamId(0), size_increment: 5177345 } 2024-07-09T15:33:55.572488Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_read: received frame=Settings { flags: (0x0), initial_window_size: 1048576, max_frame_size: 16384, max_header_list_size: 16777216 } 2024-07-09T15:33:55.572511Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_write: send frame=Settings { flags: (0x1: ACK) } 2024-07-09T15:33:55.572519Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_read: received frame=Settings { flags: (0x1: ACK) } 2024-07-09T15:33:55.572523Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::proto::settings: received settings ACK; applying Settings { flags: (0x0), enable_push: 0, initial_window_size: 2097152, max_frame_size: 16384 } 2024-07-09T15:33:55.572532Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_read: received frame=WindowUpdate { stream_id: StreamId(0), size_increment: 983041 } 2024-07-09T15:33:55.572558Z DEBUG ffi-setup_contents tower::buffer::worker: service.ready=true processing request 2024-07-09T15:33:55.572500Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.572292Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_write: send frame=WindowUpdate { stream_id: StreamId(0), size_increment: 983041 } 2024-07-09T15:33:55.572670Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.572610Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=Settings { flags: (0x1: ACK) } 2024-07-09T15:33:55.572680Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.572630Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::proto::settings: received settings ACK; applying Settings { flags: (0x0), initial_window_size: 1048576, max_frame_size: 16384, max_header_list_size: 16777216 } 2024-07-09T15:33:55.572879Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_write: send frame=Headers { stream_id: StreamId(1), flags: (0x4: END_HEADERS) } 2024-07-09T15:33:55.572911Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_write: send frame=Data { stream_id: StreamId(1) } 2024-07-09T15:33:55.572941Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_write: send frame=Data { stream_id: StreamId(1), flags: (0x1: END_STREAM) } 2024-07-09T15:33:55.573393Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.573033Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=Headers { stream_id: StreamId(1), flags: (0x4: END_HEADERS) } 2024-07-09T15:33:55.573405Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.573073Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=Data { stream_id: StreamId(1) } 2024-07-09T15:33:55.573410Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.573092Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=Data { stream_id: StreamId(1), flags: (0x1: END_STREAM) } 2024-07-09T15:33:55.573415Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.573150Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: tower_http::trace::on_request: started processing request 2024-07-09T15:33:55.573421Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.573250Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::server: Configure interaction request for content type 'application/grpc': ConfigureInteractionRequest { content_type: "application/grpc", contents_config: Some(Struct { fields: {"additionalIncludes": Value { kind: Some(ListValue(ListValue { values: [Value { kind: Some(StringValue("/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service")) }] })) }, "pact:content-type": Value { kind: Some(StringValue("application/protobuf")) }, "pact:proto": Value { kind: Some(StringValue("/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service/service_commands.proto")) }, "pact:proto-service": Value { kind: Some(StringValue("CommandService/UpsertEntity")) } ...STUFF } 2024-07-09T15:33:55.669983Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.669623Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Detected OS: Mac OS 14.5.0 [64-bit] 2024-07-09T15:33:55.670174Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.670124Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Found unpacked protoc binary 2024-07-09T15:33:55.670190Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.670153Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Invoking protoc: './protoc/bin/protoc --version' 2024-07-09T15:33:55.727713Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.727643Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Protoc binary invoked OK: libprotoc 3.21.12 2024-07-09T15:33:55.727762Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.727776Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.727715Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protobuf: Parsing proto file '/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service/service_commands.proto' 2024-07-09T15:33:55.728166Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.728111Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Invoking protoc: Command { std: "./protoc/bin/protoc" "-o/Users/becca.liss/.pact/plugins/protobuf-0.4.0/tmp/.tmp1ER5tw" "-I/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service" "--include_imports" "/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service/service_commands.proto" "-Iprotoc/include", kill_on_drop: false } 2024-07-09T15:33:55.739710Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.739648Z ERROR tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Protoc output: 2024-07-09T15:33:55.739739Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || 2024-07-09T15:33:55.739688Z ERROR tokio-runtime-worker request{method=POST uri=http://127.0.0.1:63892/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Protoc stderr: buf/validate/validate.proto: File not found. 2024-07-09T15:33:55.739772Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 64004, STDOUT) || vts/central_entities/v1/service/entity.proto: File not found.``` I verified that the `additionalIncludes` paths seem correct (added in the Pact struct as suggested https://github.com/pact-foundation/pact-plugins/blob/da73d16b2f8a24439a03da8e22dbebf571db1b07/examples/gRPC/test_enums/consumer_go/consumer_test.go#L31). tldr: it seems like `protoc` / `pact_protobuf_plugin` is not able to handle protobuf imports. Any help would be hugely appreciated, thank you!

rholshausen
2024-07-09 23:29
What version of the protobuf plugin are you using?

becca.liss
2024-07-09 23:32
`0.4.0`

becca.liss
2024-07-09 23:33
```? ? pact-plugin-cli list installed ?????????????????????????????????????????????????????? ? Name ? Version ? Interface Version? Status ?????????????????????????????????????????????????????? ? protobuf ? 0.4.0 ? 1 ? enabled ??????????????????????????????????????????????????????```

rholshausen
2024-07-09 23:36
Where does the file `buf/validate/validate.proto` live?


becca.liss
2024-07-09 23:40
i think buf does something fancy with it, but i'm not totally sure

rholshausen
2024-07-09 23:40
That will need to be installed locally somewhere

rholshausen
2024-07-09 23:44
Also, from the logs I can see the import path passed to protoc `-I/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service` `entity.proto` is in the same directory, so either change the import directory to `/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf` or change the import line in the proto file to `import "entity.proto";`

becca.liss
2024-07-10 13:33
hmm lemme try that

becca.liss
2024-07-10 13:43
same error

becca.liss
2024-07-10 13:43
```2024-07-10T13:37:53.000919Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.000851Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::proto::settings: received settings ACK; applying Settings { flags: (0x0), initial_window_size: 1048576, max_frame_size: 16384, max_header_list_size: 16777216 } 2024-07-10T13:37:53.000921Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.000875Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=WindowUpdate { stream_id: StreamId(0), size_increment: 5177345 } 2024-07-10T13:37:53.001459Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_read: received frame=Settings { flags: (0x1: ACK) } 2024-07-10T13:37:53.001472Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::proto::settings: received settings ACK; applying Settings { flags: (0x0), enable_push: 0, initial_window_size: 2097152, max_frame_size: 16384 } 2024-07-10T13:37:53.001481Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_write: send frame=Headers { stream_id: StreamId(1), flags: (0x4: END_HEADERS) } 2024-07-10T13:37:53.001505Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_write: send frame=Data { stream_id: StreamId(1) } 2024-07-10T13:37:53.001549Z DEBUG ffi-setup_contents Connection{peer=Client}: h2::codec::framed_write: send frame=Data { stream_id: StreamId(1), flags: (0x1: END_STREAM) } 2024-07-10T13:37:53.003313Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.003261Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=Headers { stream_id: StreamId(1), flags: (0x4: END_HEADERS) } 2024-07-10T13:37:53.003456Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.003347Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=Data { stream_id: StreamId(1) } 2024-07-10T13:37:53.003462Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.003370Z DEBUG tokio-runtime-worker Connection{peer=Server}: h2::codec::framed_read: received frame=Data { stream_id: StreamId(1), flags: (0x1: END_STREAM) } 2024-07-10T13:37:53.003466Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.003430Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: tower_http::trace::on_request: started processing request 2024-07-10T13:37:53.004180Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.003594Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::server: Configure interaction request for content type 'application/grpc': ConfigureInteractionRequest { content_type: "application/grpc", contents_config: Some(Struct { fields: {"additionalIncludes": Value { kind: Some(ListValue(ListValue { values: [Value { kind: Some(StringValue("/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf")) }] })) }, "pact:content-type": Value { kind: Some(StringValue("application/protobuf")) }, "pact:proto": {} } 2024-07-10T13:37:53.060055Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.059890Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Detected OS: Mac OS 14.5.0 [64-bit] 2024-07-10T13:37:53.060075Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.060016Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Found unpacked protoc binary 2024-07-10T13:37:53.060086Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.060031Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Invoking protoc: './protoc/bin/protoc --version' 2024-07-10T13:37:53.105747Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.105469Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Protoc binary invoked OK: libprotoc 3.21.12 2024-07-10T13:37:53.105793Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.105797Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.105558Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protobuf: Parsing proto file '/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service/service_commands.proto' 2024-07-10T13:37:53.106441Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.106389Z DEBUG tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Invoking protoc: Command { std: "./protoc/bin/protoc" "-o/Users/becca.liss/.pact/plugins/protobuf-0.4.0/tmp/.tmp5HV2uq" "-I/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service" "--include_imports" "/Users/becca.liss/Code/monorepo/apps/central-entities/service/idl/protobuf/vts/central_entities/v1/service/service_commands.proto" "-Iprotoc/include", kill_on_drop: false } 2024-07-10T13:37:53.126619Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.126536Z ERROR tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Protoc output: 2024-07-10T13:37:53.126632Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || 2024-07-10T13:37:53.126576Z ERROR tokio-runtime-worker request{method=POST uri=http://127.0.0.1:56223/io.pact.plugin.PactPlugin/ConfigureInteraction version=HTTP/2.0 headers={"te": "trailers", "content-type": "application/grpc", "authorization": Sensitive, "user-agent": "tonic/0.9.2"}}: pact_protobuf_plugin::protoc: Protoc stderr: buf/validate/validate.proto: File not found. 2024-07-10T13:37:53.126633Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || vts/central_entities/v1/service/entity.proto: File not found. 2024-07-10T13:37:53.126635Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || vts/central_entities/v1/service/relationship.proto: File not found. 2024-07-10T13:37:53.126637Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || service_commands.proto:5:1: Import "buf/validate/validate.proto" was not found or had errors. 2024-07-10T13:37:53.126638Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || service_commands.proto:6:1: Import "vts/central_entities/v1/service/entity.proto" was not found or had errors. 2024-07-10T13:37:53.126639Z DEBUG tokio-runtime-worker pact_plugin_driver::child_process: Plugin(protobuf, 10368, STDOUT) || service_commands.proto:7:1: Import "vts/central_entities/v1/service/relationship.proto" was not found or had errors.```

becca.liss
2024-07-24 14:26
for anyone else who comes across this error - i was able to get it working by using `buf export`, putting those files in the same location as the other top-level proto files so that the import paths didn't need to change, and then providing those paths as `ProtobufConfig.AdditionalIncludes = append(pactConfig.ProtobufConfig.AdditionalIncludes, path)` . I'd also recommend running a cleanup task after to delete those files after generating the pacts, since normal buf builds will complain about the duplicate definitions

becca.liss
2024-07-24 14:31
Another question for y'all! I'm using the pact protobuf plugin in my consumer test, and I would like to use a matcher for the response (the provider service returns a random uuid). As best I can tell, `.UsingPlugin` returns a `SynchronousMessageWithPlugin` type, which only allows `.WithContents` to be called on it; since `.WithContents` takes a stringified blob of JSON, I assume it doesn't support using matchers (https://github.com/pact-foundation/pact-go/blob/master/matchers/matcher.go#L164). If someone can verify that understanding and/or help me come up with an alternative solution, that would be great!

yousafn
2024-07-24 14:34
Hey hey, that is correct as they can?t be serialised and sent over the wire to the grpc server (plugin) so an alternative mechanism was introduced https://github.com/pact-foundation/pact-plugins/blob/main/docs/matching-rule-definition-expressions.md these are the plugin supported matchers

becca.liss
2024-07-24 14:35
oh cool! sorry for missing that ? I hadn't seen that doc before

becca.liss
2024-07-24 14:35
i'll give it a try and report back!


becca.liss
2024-07-24 14:40
yeah i think i was looking at the matchers examples on GH (which is for http) and the grpc examples on GH (which don't have matchers)

becca.liss
2024-08-05 15:33
Hi! I have a question about struct matching, and I'm feeling kind of stumped. I have a proto with a `struct` field, e.g. ```message Request { string name = 1; google.protobuf.Struct params = 2; }``` In my test, I am creating a new struct ```params, err := structpb.NewStruct(map[string]any{"kind": "general", "message": "test" })``` and then marshaling it to JSON. The string I am passing to `withContents` looks like this ```{"pact:proto":"whatever.proto","pact:proto-service":"Service/Endpoint","pact:content-type":"application/protobuf","request":{"name":"name","params":{"kind":"general","message":"test"}},"response":{"responses":[{"success":true,"id":"test123"}]}}``` I run the test once and get this error ```Received generate templates error rpc error: code = FailedPrecondition desc = Failed to match the request message - BodyMismatches({"$.params": [BodyMismatch { path: "$.params.fields.key", expected: Some(b"\"message\""), actual: Some(b"\"kind\""), mismatch: "Expected 'kind' (String) to be equal to 'message' (String)" }, BodyMismatch { path: "$.params.fields.value.string_value", expected: Some(b"\"test\""), actual: Some(b"\"general\""), mismatch: "Expected 'general' (String) to be equal to 'test' (String)" }]})``` and then I run the test again (changing nothing, with exact same contents string) and it passes

becca.liss
2024-08-05 15:34
My best guess is that it's doing something weird with struct keys and ordering but I'm not sure what or how to fix it

rholshausen
2024-08-05 23:17
Yeah, it looks like it is getting confused, as I think a google.protobuf.Struct is implemented as a union type or an enum. It may need special handling.

becca.liss
2024-08-07 13:08
Does anyone have any suggestions for how to handle this? I did a preliminary dive into the `matching` https://github.com/pactflow/pact-protobuf-plugin/blob/main/src/matching.rs but didn't get very far. I also looked into the https://github.com/pact-foundation/pact-plugins/blob/main/docs/matching-rule-definition-expressions.md to see if there was something I could use there, but it seems like that's geared more towards primitives. We have a bunch of teams using `google.protobuf.Struct` in their proto files, so this is a pretty big blocker for us :confused:

rholshausen
2024-08-07 23:13
Sorry, I have been dealing with the provider state issue with the gRPC plugin. I'll investigate this for you, but I probably won't get to it before early next week.

matt.fellows
2024-08-07 23:20
Mind raising an issue on https://github.com/pactflow/pact-protobuf-plugin/ Becca for us to investigate please?

becca.liss
2024-08-08 13:27
Oh ya, sometime in the next few weeks is totally fine! Right now I'm able to get away with using a struct with only a single field ? no ordering problems there :joy: And happy to raise an issue ? thanks both for being so responsive! I'll link it here once I create it


slacksync
2024-09-12 12:38
has joined #pact-plugins

rmartine
2024-10-03 18:00
has joined #pact-plugins

paul.beigang
2024-10-15 13:24
has joined #pact-plugins

jithin.joyson
2024-11-01 02:14
has joined #pact-plugins

feisal.ahmad
2024-11-29 21:13
has joined #pact-plugins

feisal.ahmad
2024-11-29 21:20
now that I?ve managed to https://pact-foundation.slack.com/archives/C5F4KFKR8/p1732891353713879, the next hurdle seems to be the pact-cplusplus interface doesn?t actually seem to trigger anything in the plugin interface. I have figured out a workaround by calling `pactffi_using_plugin` and passing in the handle, and it actually loads the plugin and calls `InitPlugin` , but now I?m at a loss? My assumption is the pact-cplusplus is so far out of date it doesn?t actually call any of the methods in the ffi interface to result in the plugin being called with `ConfigureInteraction` , `StartMockServer`, etc. Is that a correct assumption? Where can I find some example code to follow for setting up a transport plugin, so I can figure out what the C++ wrapper should look like to work with plugins?


yousafn
2024-11-29 22:50
pact-go / pact-js / pact-php have interfaces for using plugins via the ffi, if you want to see real world implementations.

yousafn
2024-11-29 22:50
we have planned to build out a maintainer guide for the ffi but time gets swallowed up by other things

feisal.ahmad
2024-11-29 22:51
Thanks, I tried poking around in pact-js and the rust consumer but didn?t get very far :smile: That C# code looks like just what I need for now!

yousafn
2024-11-29 22:52
awesome. and yeah it?s definitely a maze for sure! sometimes you just need to see the few calls you need to make and you can build out your mental model from there.

feisal.ahmad
2024-11-29 23:27
Is this page still valid btw? https://github.com/pact-foundation/pact-plugins/blob/main/docs/protocol-plugin-design.md I?m following the approach in the `GrpcGreeterClientTest.cs` that sets the interaction_content, and that seems to start the mock server with the specified content in the request payload for the `StartMockServer` rpc. I was expecting `ConfigureInteraction` to be called at some point so I can set up the expected requests/responses? I stripped the ?pact:proto? and ?pact:proto-service? btw, not sure how relevant that is, since it?s not a grpc service being tested.

yousafn
2024-11-30 11:26
this is the consumer facing dsl for the pact framework. the configureinteraction is a plugin method and that is being dealt with by the pact-protobuf-plugin for a course of plugin design you can follow https://docs.pact.io/plugins/workshops/create-a-plugin/intro where you will see those methods implemented, and you will end up with a plugin you can call from your pact tests

feisal.ahmad
2024-12-01 14:45
Somehow I completely missed that course? thanks for pointing that out! I was only aware of the pages here https://docs.pact.io/implementation_guides/pact_plugins

rholshausen
2024-12-01 23:01
We didn't think anyone was using the C++ version of Pact, it has been very quite for years.

feisal.ahmad
2024-12-11 14:54
I?ve been making good progress writing our own C++ wrapper for the pactffi interface, but I?m stumped on how transport configs are supposed to be passed to the plugin when starting the mock server. Digging through the rust code, I have the feeling this isn?t fully implemented yet? https://github.com/pact-foundation/pact-reference/blob/74df5d1d3c55856c0b1a37a132e954c0dd65d1fd/rust/pact_consumer/src/mock_server/plugin_mock_server.rs#L59 ``` /// Start a new plugin mock server (async version). This will send the start mock server request /// to the plugin that provides the mock server. pub async fn start_async( pact: Box<dyn Pact + Send + Sync>, output_path: Option<PathBuf>, catalogue_entry: &CatalogueEntry ) -> anyhow::Result<Box<dyn ValidatingMockServer>> { let test_context = hashmap!{}; let result = start_mock_server_v2(catalogue_entry, pact.boxed(), MockServerConfig { output_path: output_path.clone(), host_interface: None, port: 0, tls: false }, test_context).await?; Ok(Box::new(PluginMockServer { mock_server_details: result, pact: pact.boxed(), output_path: output_path.clone(), catalogue_entry: catalogue_entry.clone() })) }``` It looks like the test_context isn?t hooked up yet to receive the value from the call to `pactffi_create_mock_server_for_transport` ?

rholshausen
2024-12-11 22:13
Yes, sorry about that. There are some gaps.

rholshausen
2024-12-11 22:14
Let me look into that, it shouldn't be a lot of work to fix.

rholshausen
2024-12-11 23:51
So there is two types of data required here: transport config (like for TLS you need the cert and cert password), and then test context data (which is needed for some cases, like injecting values from provider state callbacks).

rholshausen
2024-12-11 23:52
Which are you needing to set? I'm assuming the latter. The reason it is not currently implemented is there is no way to pass this data via the FFI calls.

rholshausen
2024-12-11 23:52
This will need a change to the FFI functions.

rholshausen
2024-12-12 00:13
Hmm, actually, the only data used there is the mock server host and port, which the mock server adds itself. What data do you need to pass to the plugin?

rholshausen
2024-12-12 00:15
Do you need something injected in the mock server response? That's the only thing I can think of.

feisal.ahmad
2024-12-12 00:49
So I?m looking for the transport config I guess, my plugin implements a custom transport for our proprietary messaging system. Because the plugin is running out of process, I?m using a bidirectional gRPC stream to relay messages to/from the messaging system. When starting the mock server in the plugin I?d like to be able to tell the plugin what address and port the relay server is on.

feisal.ahmad
2024-12-12 00:50
For now I?m just hard-coding it and it isn?t a big deal, but especially the port I?d like to let the server assign any available port and pass it via the transport config to the plugin

rholshausen
2024-12-12 00:59
Ah! That's a bigger problem to address, there is no field on the `StartMockServerRequest` message to pass that data. That requires a change to that interface. I have written a proposal to fix some of the plugin interface problems, if you want to raise any issues you are having there? See https://github.com/pact-foundation/pact-plugins/blob/main/docs/proposals/001_V2_Plugin_Interface.md

rholshausen
2024-12-12 01:00
So, in the short term, we could pass it through in the `test_context` field, maybe under a `transport_config` key?

feisal.ahmad
2024-12-12 01:07
That would work for us yeah, I?ll take a look at the draft and see if I can give input (probably in the new year after I get back from leave). Thanks :+1:

rholshausen
2024-12-12 01:14
Actually, adding a new field to that message may not be a breaking change. I'll have a look, but it mat affect code across Pact language implementations.


rholshausen
2024-12-12 22:56
I think this will do what you need

feisal.ahmad
2024-12-13 17:42
Nice! Thanks a lot! I?ll figure out how to try out these changes once I?m back from leave

pietro.dibello
2024-12-17 11:23
has joined #pact-plugins

feisal.ahmad
2025-01-22 14:53
FYI I?ve updated our pactffi binaries and I can confirm it works for what I needed :applause: :thankyou:

feisal.ahmad
2025-01-31 11:47
I?m having some trouble figuring out how to use the `pact_verifier_cli` to verify the pact I have now managed to produce using pactffi with the plugin I wrote to add a custom transport as I described before. I don?t know if I?m just expecting the wrong thing here, but what I _hope_ is possible is to do the following: 1. Run `pact_verifier_cli` pointing it to the pact file (I?m just using a local file for now) 2. `pact_verifier_cli` loads the plugin and registers a custom transport 3. `pact_verifier_cli` verifies the interactions by sending requests over the custom transport, I imagine this would be implemented by the various interaction related rpcs in the plugin service So far I am seeing in the trace logs of the cli that it tries to send requests directly, ignoring the plugin. I?ve tried several arguments but haven?t gotten anywhere really. It?s loading the plugin fine, which is getting picked up from the pact file, and I see it in the printed catalogue entries: ```2025-01-31T11:35:33.117935Z DEBUG main verify_provider{provider_name="provider"}: pact_plugin_driver::catalogue_manager: Updated catalogue entries: core/content-generator/binary ... core/matcher/v4-semver plugin/pact-messagebroker/transport/application/adsk_MessageBroker``` Is what I?m trying to do supported? Or do I need to use pactffi to implement the provider tests?

yousafn
2025-01-31 11:49
what does your command look like? are you passing in a transport with the type of your plugin? and port it is running on?

feisal.ahmad
2025-01-31 11:50
I?ve tried several things, but this is what it looks like more or less: ```pact_verifier_cli --transport adsk_MessageBroker --file pacts/PactMessageBrokerConsumerDSL.tst-LibrariesCore.json -l debug -h 127.0.0.1 -p 50575```

feisal.ahmad
2025-01-31 11:52
The thing that doesn?t make complete sense to me yet are the address / port arguments, my plugin will need to connect to a grpc relay service, but from the logs it looks like pact_verifier_cli is trying to connect directly somehow to that host/port

feisal.ahmad
2025-01-31 11:54
This is what the pact file interaction looks like (stripped the contents because IP) ``` "interactions": [ { "contents": { "contentType": "application/json", "encoded": false }, "description": "libraries/getLibraries/request", "pending": false, "providerStates": [ { "name": "I have a list of libraries" } ], "transport": "adsk_MessageBroker", "type": "Asynchronous/Messages" } ],```

yousafn
2025-01-31 11:54
-p, --port <port> Provider port (defaults to protocol default 80/443) [env: PACT_PROVIDER_PORT=] --transport <transport> Provider protocol transport to use (http, https, grpc, etc.) [env: PACT_PROVIDER_TRANSPORT=] [default: http] --transports <transports> Allows multiple protocol transports to be configured (http, https, grpc, etc.) with their associated port numbers separated by a colon. For example, use --transports http:8080 grpc:5555 to configure both is the transport type in your plugin called asdk_xyz? running on localhost:50575? what does the pact entry look like for the plugin? can you try transports and pass the port with seperate by a colon https://github.com/YOU54F/pact-ruby-ffi/blob/8a41f7fcbb525e97baf27a5aaaf173be754381a7/Makefile#L79 example with grpc plugin. I note I?ve specified the provider name aswell. in your screenshot it is using the default name provider

feisal.ahmad
2025-01-31 11:57
well so the thing that?s running on localhost:50575 is a grpc relay service I wrote myself, the plugin?s start mock server rpc starts a client to connect to that relay and listen for requests to respond with mock responses

feisal.ahmad
2025-01-31 11:58
the actual transport is a C++ messagebroker that doesn?t use sockets or anything, it?s just an interface with subscribe and publish methods

feisal.ahmad
2025-01-31 11:59
so the messages described in the pact file are really one level deeper than the grpc relay

feisal.ahmad
2025-01-31 12:00
they?re payloads for the messages sent over grpc

feisal.ahmad
2025-01-31 12:11
I?m digging through the code looking for the debug statements and see something interesting?

yousafn
2025-01-31 12:12
ohh okay, i think this is similar to message pact mode where pact expects a http proxy to act as a broker for the messages. pact clients languages spin up this http proxy and usually map the contents from the payload to a consuming or providing function. pact verifier cli doesn?t provide a http proxy for messages. you would normally start this by setting a transport of type message:<port> https://github.com/pact-foundation/pact-reference/pull/211 maybe that is why you are getting calls to your localhost ( as its expecting that host to serve messages) happy if you want to share any logs in private.

feisal.ahmad
2025-01-31 12:12
```2025-01-31T12:05:27.891555Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier: Executing provider states 2025-01-31T12:05:27.891568Z INFO main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier: Running setup provider state change handler 'I have a list of libraries' for 'libraries/getLibraries/request' 2025-01-31T12:05:27.891574Z WARN main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier::callback_executors: State Change ignored as there is no state change URL provided for interaction 2025-01-31T12:05:27.891579Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier: State Change: "ProviderState { name: "I have a list of libraries", params: {} }" -> Ok({}) 2025-01-31T12:05:27.891588Z INFO main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier: Running provider verification for 'libraries/getLibraries/request' 2025-01-31T12:05:27.891599Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier: Verifying an asynchronous message (single shot) 2025-01-31T12:05:27.891627Z INFO main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier::provider_client: Sending request to provider at http://localhost:50575 2025-01-31T12:05:27.891630Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier::provider_client: Provider details = ProviderInfo { name: "LibrariesCore", protocol: "adsk_MessageBroker", host: "localhost", port: Some(50575), path: "", transports: [ProviderTransport { transport: "adsk_MessageBroker", port: Some(50575), path: None, scheme: None }] } 2025-01-31T12:05:27.891635Z INFO main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier::provider_client: Sending request HTTP Request ( method: POST, path: /, query: None, headers: Some({"Content-Type": ["application/json"]}), body: Present(105 bytes, application/json) ) 2025-01-31T12:05:27.891641Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: pact_verifier::provider_client: body: {"description":"libraries/getLibraries/request","providerStates":[{"name":"I have a list of libraries"}]} 2025-01-31T12:05:27.891693Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: log: starting new connection: http://localhost:50575/ 2025-01-31T12:05:27.891743Z DEBUG tokio-runtime-worker hyper_util::client::legacy::connect::dns: resolving host="localhost" 2025-01-31T12:05:27.892523Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: hyper_util::client::legacy::connect::http: connecting to 127.0.0.1:50575 2025-01-31T12:05:27.892866Z DEBUG main verify_provider{provider_name="LibrariesCore"}:verify_interaction{interaction="libraries/getLibraries/request"}: hyper_util::client::legacy::connect::http: connected to 127.0.0.1:50575``` it?s printing ?Verifying an asynchronous message (single shot)?

yousafn
2025-01-31 12:16
that is correct, your interaction is async message so there is no response ( aka single shot / one way )

yousafn
2025-01-31 12:18
so that log is showing that its sending a request to a state handler, on your sut, so you can do any setup / teardown

yousafn
2025-01-31 12:18
also contains the description of the message to map and return response


feisal.ahmad
2025-01-31 12:22
Thanks, yeah I think there?s something wrong then with my consumer test which I?ll have to figure out, because it?s supposed to be a sync interaction?

feisal.ahmad
2025-01-31 12:22
I?m focusing on the provider side now though so I?ll just manually edit the pact file for the moment and figure that issue out later :confused:

feisal.ahmad
2025-01-31 12:27
So suppose I change the pact file so it?s a proper sync interaction, does that change the HTTP proxy part you explained?

feisal.ahmad
2025-01-31 12:27
I assume it doesn?t

yousafn
2025-01-31 12:36
I would be cautious in modifying the pact file, as sync message has a diff layout (req/res, and resp is an array) fyi I tried testing out the sync message func in v4 pact, and it will only deal with the first resp in an array of messages (not currently coded to support more on the verifier side) my working branch is here. https://github.com/pact-foundation/pact-workshop-message/compare/main...feat/sync_message here is an sync/message plugin pact https://github.com/YOU54F/pact-reference/blob/master/php/pacts/grpc-consumer-php-area-calculator-provider.json which uses the pact-protobuf-plugin - https://github.com/pactflow/pact-protobuf-plugin There is an example of it using https://github.com/pact-foundation/pact-plugins/tree/main/examples/gRPC/area_calculator/provider-go I believe you will still require a http proxy for your provider states. You can turn the providerStates entry to an empty array and it won?t make those calls. And I assume the client libraries would still utilise their proxy handlers to deal with provider states. Whether they are also expected to map the mes I haven?t looked too much into detail as to how provider states work in the plugin ecosystem but i?ll do some digging today.

feisal.ahmad
2025-01-31 12:37
I just rewrote the pact file, restructuring the request response indeed

feisal.ahmad
2025-01-31 12:38
and it looks like that too expects a HTTP proxy, yes

feisal.ahmad
2025-01-31 12:38
I?ll share the pact file and log via DM

yousafn
2025-01-31 12:40
ahh okay, so your provider will need to create the message based on the desc and return it in an encoded header. I believe the pact framework will then send that message to your plugin (which is configured for the transport type).

rholshausen
2025-02-02 22:36
Bit late to this party, but this looks wrong ```pact_verifier_cli --transport adsk_MessageBroker``` and ```plugin/pact-messagebroker/transport/application/adsk_MessageBroker``` It looks like the plugin is registering the transport as `application/adsk_MessageBroker` and not `adsk_MessageBroker`

feisal.ahmad
2025-02-03 11:44
I remember trying `application/adsk_MessageBroker` initially but for some reason I ended up removing the `application/` part and saw it somehow seemed better? I?ll revisit this now I have a better understanding of things

feisal.ahmad
2025-02-03 13:01
Getting there I think! I?ve edited the transport name to be `adsk_MessageBroker` everywhere since the cli doesn?t parse a transport name containing a `/` in it, and added a simple HTTP server to accept the POST requests for state changes and now it continues to hit the plugin?s `PrepareInteractionForVerification` rpc :cool-dog:

feisal.ahmad
2025-02-03 13:03
I?m trying to figure out what would be the ?best practice? at this point, I?m getting the pact JSON with an interaction key. For writing the mock server I relied on the pactffi functions to parse the pact from json, but I don?t quite see how to find the interaction by key looking at the C interface?

feisal.ahmad
2025-02-03 13:04
The pact json in the rpc?s request object looks like this: ```{ consumer: { name: 'PactMessageBrokerConsumerDSL.tst' }, interactions: [ { description: 'libraries/getLibraries/request', key: '75dee697cdd774dd', pending: false, request: [Object], response: [Array], transport: 'adsk_MessageBroker', type: 'Synchronous/Messages' } ], metadata: { pactRust: { ffi: '0.4.26', mockserver: '1.2.11', models: '1.2.5' }, pactSpecification: { version: '4.0' }, plugins: [ [Object] ] }, provider: { name: 'LibrariesCore' } }```

feisal.ahmad
2025-02-03 13:07
I see there?s a function to _set_ the interaction key in pactffi: ```bool pactffi_set_key(InteractionHandle interaction, const char *value);``` but I can?t find any getter for it

rholshausen
2025-02-03 22:03
Can you raise a GitHub issue for that?

feisal.ahmad
2025-02-05 14:58
Sure

juanchazo
2025-02-12 15:20
has joined #pact-plugins

joshmccure
2025-02-21 03:16
has joined #pact-plugins


zlysobey
2025-06-20 12:56
has joined #pact-plugins