are there any examples of how to use the Rust FFI ...
# pact-rust
s
are there any examples of how to use the Rust FFI implementation in ruby? Since ruby only has v2 support, I need to support v4 specifications from other languages. However having never used Rust or FFI before it would be great to have an example to see how it could replace the ruby gem for a provider. At this point I have installed rust, pulled down the Rust project from Github, ran
cargo build
. I have also installed the rubygem
ffi
in the provider project.
m
s
Thanks Matt, so do I use that gem instead of the old Ruby one. It can be used to act as a provider?
m
I'm not sure, I'm just digging up examples. There's another somewhere also
s
Ok thanks. I was under the impression I needed to use the rust library, compile it and reference it in Ruby using the ffi gem. But that's all guesswork at this point 👍 hopefully you find something
m
You probably don't need to compile it. As we already have compiled targets. You will probably need to use an ffi gem (or another lib inbuilt or otherwise) to interface to the FFI (C interface)
Here's the other example repo: https://github.com/YOU54F/hello_ffi
💯 1
s
Would be great if there were some examples of how the
pact_helper.rb
should look when using the FFI implementation, and and example of
provider_states
also
y
Hey @sr I’ve created a Ruby Gem which has a dep of the FFI gem and the pact ffi library. https://github.com/YOU54F/pact-ruby-ffi It has most of the methods exposed from the Rust FFI. I partially started to integrate it into the existing Pact Provider Verifier (Ruby based) but didn’t get very far as got distracted by other stuff but there should are some examples in this repo that may help
Ok thanks. I was under the impression I needed to use the rust library, compile it and reference it in Ruby using the ffi gem. But that’s all guesswork at this point 👍 hopefully you find something
The Pact-Reference provides shared libraries in the releases section under pact_ffi. These are shared libraries which you can load with the
ffi
gem. You need to map the methods exposed by the FFI in C (pre compiled from Rust) in Ruby, and then you can use them as though they are somewhat native to Ruby. Feel free to let us know how you get on, and happy to help answer any questions. PS. Happy for anyone to fork and hack on that repo, or start afresh 🙂 not precious about it
nice little example post to maybe get you started with ruby + ffi https://www.rubyguides.com/2019/05/ruby-ffi/
s
Thanks for that. I did get it working to a certain extent but I'm just not sure what attached methods need to be called or used, for example how would you write this using the ffi implementation:
Copy code
# In spec/service_consumers/pact_helper.rb

require 'pact/provider/rspec'

Pact.service_provider "Animal Service" do

  honours_pact_with 'Zoo App' do

    # This example points to a local file, however, on a real project with a continuous
    # integration box, you would use a [Pact Broker](<https://github.com/pact-foundation/pact_broker|https://github.com/pact-foundation/pact_broker>) or publish your pacts as artifacts,
    # and point the pact_uri to the pact published by the last successful build.

    pact_uri '../zoo-app/spec/pacts/zoo_app-animal_service.json'
  end
end
y
s
I have been reviewing the example above and I am struggling to understand what is happening here. So you are having to manually start the mock server in code, none of it is abstracted away like the ruby gem is? If you simply want to pull down pact file from a broker, run them and publish the results can that not be achieved simply as before?
Copy code
Pact.service_provider "Provider-app" do
  publish_verification_results true

  honours_pacts_from_pact_broker do
    pact_broker_base_url "<http://localhost:9292/>"
    app_version "1.0.0"
    app_version_branch "main"
    app_version_tags ["foo", "bar"]
  end
end
y
none of it is abstracted away like the ruby gem is?
correct., pact-ruby provides a nice dsl to the user as shown in your example. pact-ruby-ffi gem has the glue code which allows the individual methods to be called in the rust backend core. They haven’t been integrated together yet You can either 1. utilise pact-ruby-ffi in its raw form, and call the individual methods to setup your verifier, a. https://github.com/YOU54F/pact-ruby-ffi/blob/c29c7bce58e8c87c40a894f379dfac12868e2375/spec/pactffi_verifier_spec.rb#L43-L47 2. integrate pact-ruby with pact-ruby-ffi, such that behind the scenes to the user, the input parameters are mapped to the relevant ffi functions. This is the ultimate aim, I would imagine, and the path of least resistance for end users of the pact-ruby library.
I have been reviewing the example above and I am struggling to understand what is happening here. So you are having to manually start the mock server in code
In the code above, 1. I am using fake provider application, which I am starting before the test, so that my Pact verifier, has a real endpoint to call. a. https://github.com/YOU54F/pact-ruby-ffi/blob/c29c7bce58e8c87c40a894f379dfac12868e2375/spec/pactffi_verifier_spec.rb#L9-L35 2. I instantiate the pact verifier a. https://github.com/YOU54F/pact-ruby-ffi/blob/c29c7bce58e8c87c40a894f379dfac12868e2375/spec/pactffi_verifier_spec.rb#L36 3. I pass various options to the verifier. In this case, the provider info (name, base path, port) and the Pact source ( a file in this case) a. https://github.com/YOU54F/pact-ruby-ffi/blob/c29c7bce58e8c87c40a894f379dfac12868e2375/spec/pactffi_verifier_spec.rb#L43-L45 4. I then call the verifier, which will issue requests to my provider, and return the results a. https://github.com/YOU54F/pact-ruby-ffi/blob/c29c7bce58e8c87c40a894f379dfac12868e2375/spec/pactffi_verifier_spec.rb#L46
s
Thanks kindly for the explanation and clarification
no problem 1
y
You would need to use these functions, in order to retrieve from pacts from a broker, and publish results, the latter two aren’t shown in the above example. They are exposed in the https://github.com/YOU54F/pact-ruby-ffi/blob/main/lib/pact/ffi/verifier.rb to Ruby clients • https://docs.rs/pact_ffi/latest/pact_ffi/verifier/fn.pactffi_verifier_set_provider_info.html ◦ allows you to set the ▪︎ name: *const c_char, ▪︎ scheme: *const c_char, ▪︎ host: *const c_char, ▪︎ port: c_ushort, ▪︎ path: *const c_char • https://docs.rs/pact_ffi/latest/pact_ffi/verifier/fn.pactffi_verifier_broker_source_with_selectors.html ◦ allows you to set a broker source, with consumer version selectors • https://docs.rs/pact_ffi/latest/pact_ffi/verifier/fn.pactffi_verifier_set_publish_options.html ◦ publication options
m
I have been reviewing the example above and I am struggling to understand what is happening here. So you are having to manually start the mock server in code, none of it is abstracted away like the ruby gem is?
If you simply want to pull down pact file from a broker, run them and publish the results can that not be achieved simply as before?
exactly. To elaborate, the rust core is a low level C interface that provides all of the capabilities for any language to integrate and use. e.g. Pact JS has a high level DSL for users, but under the hood it maps to all of these functions.