https://pact.io logo
Join Slack
Powered by
# pact-plugins
  • a

    Adam Cox

    03/21/2023, 12:05 PM
    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,
    y
    u
    • 3
    • 10
  • t

    Tien Vo

    03/25/2023, 4:07 AM
    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.
    t
    m
    • 3
    • 15
  • t

    Tien Vo

    03/25/2023, 4:02 PM
    I got this error when working with protobuf plugin:
    Copy code
    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:
    Copy code
    LOG_LEVEL=debug PACT_LOGLEVEL=trace phpunit example/async-message/consumer/tests/Contract/
    u
    • 2
    • 12
  • t

    Tien Vo

    03/27/2023, 1:46 AM
    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
    u
    • 2
    • 5
  • t

    Tien Vo

    04/03/2023, 5:06 AM
    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:
    Copy code
    $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:
    Copy code
    gender,id,name
    $gender,$id,$name
    Is this expected behavior?
    u
    • 2
    • 5
  • t

    Tien Vo

    04/03/2023, 5:51 AM
    Currently when provider verifier can't find the required plugin, it simply shutdown without any error message:
    Copy code
    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:
    Copy code
    Can't find plugin csv in /home/myname/.pact/plugins
    Do you think so?
    u
    y
    • 3
    • 8
  • j

    Jordan Brooks

    04/18/2023, 1:23 PM
    Hey 👋 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.
    👋 1
    y
    • 2
    • 4
  • a

    Adam Cox

    04/28/2023, 2:18 PM
    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 🙂 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
    m
    u
    • 3
    • 11
  • a

    Adam Cox

    05/09/2023, 1:28 PM
    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.
    <ws://localhost:9998/jsonrpc>
    - 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
    ralph wave 1
    y
    u
    • 3
    • 39
  • a

    Adam Cox

    06/02/2023, 9:51 AM
    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:
    Copy code
    "request": { "id": 1 },
    The configure interaction request receives a payload like this:
    Copy code
    "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:
    Copy code
    {
      "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:
    Copy code
    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.
    u
    m
    • 3
    • 5
  • a

    Adam Cox

    06/14/2023, 1:51 PM
    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.
    u
    • 2
    • 5
  • a

    Adam Cox

    06/14/2023, 2:44 PM
    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
    Copy code
    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.
    u
    • 2
    • 4
  • u

    uglyog

    06/19/2023, 12:16 AM
    @Adam Cox @Tien 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.
    t
    a
    • 3
    • 5
  • p

    Praveen Erode Mohanasundaram

    07/14/2023, 2:15 PM
    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?
    y
    a
    • 3
    • 4
  • p

    Praveen Erode Mohanasundaram

    07/14/2023, 2:15 PM
    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?
    y
    • 2
    • 5
  • p

    Praveen Erode Mohanasundaram

    07/14/2023, 2:19 PM
    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 this template quite useful. As a follow on to the workshop, I played with it little bit making use of ANTLR to auto generate parsers for this grammar. 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.
    y
    • 2
    • 3
  • r

    Rohit Krishnan

    07/25/2023, 8:39 PM
    Is there an estimate of when Pact JS would support plugins? (even a sketchy branch would suffice)
    m
    • 2
    • 2
  • y

    Yousaf Nabi (pactflow.io)

    08/03/2023, 11:07 AM
    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 Erode Mohanasundaram / @Ali Ustek / @Adam Cox
    a
    p
    • 3
    • 3
  • e

    Elena Doty

    08/16/2023, 8:42 PM
    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 here. 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!
    t
    • 2
    • 1
  • c

    Christopher Tonog

    01/29/2024, 6:06 PM
    👋 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!
    blobwave 1
    y
    m
    • 3
    • 4
  • b

    Becca Liss

    02/28/2024, 3:41 PM
    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
    blobwave 1
    y
    m
    • 3
    • 16
  • j

    James Demaine

    03/04/2024, 11:39 AM
    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!
    y
    m
    r
    • 4
    • 24
  • s

    s1apped

    05/06/2024, 4:22 PM
    Hey 😉 I’m getting below error but tests are working and I’m wondering if it’s some issue with configuration. Any idea? ``````
  • s

    s1apped

    05/06/2024, 4:23 PM
    r
    • 2
    • 2
  • b

    Becca Liss

    07/09/2024, 3:09 PM
    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
    Copy code
    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
    Copy code
    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 here). tldr: it seems like
    protoc
    /
    pact_protobuf_plugin
    is not able to handle protobuf imports. Any help would be hugely appreciated, thank you!
    r
    • 2
    • 12
  • b

    Becca Liss

    07/24/2024, 2:31 PM
    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 (e.g.). If someone can verify that understanding and/or help me come up with an alternative solution, that would be great!
    y
    • 2
    • 5
  • b

    Becca Liss

    08/05/2024, 3:33 PM
    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.
    Copy code
    message Request {
      string name = 1;
      google.protobuf.Struct params = 2;
    }
    In my test, I am creating a new struct
    Copy code
    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
    Copy code
    {
      "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
    Copy code
    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
    r
    m
    • 3
    • 7
  • f

    Feisal Ahmad

    11/29/2024, 9:20 PM
    now that I’ve managed to get things to compile in C++ with a recent pact_ffi version, 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?
    y
    r
    • 3
    • 9
  • f

    Feisal Ahmad

    12/11/2024, 2:54 PM
    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/74df5d1d3c55856c0b1a37a132e[…]65d1fd/rust/pact_consumer/src/mock_server/plugin_mock_server.rs
    Copy code
    /// 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
    ?
    r
    • 2
    • 17
  • f

    Feisal Ahmad

    01/31/2025, 11:47 AM
    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:
    Copy code
    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?
    y
    r
    • 3
    • 34