This library is an Elixir wrapper for the pact-reference implementation
And it is in PRE alpha shape without any semantic versioning or documentation.
It is not yet usable as many needed parts like publishing a pact file to a broker or pact verification on the provider side are still missing. Also there is no documentation available, yet.
Discussion about the development of this library takes places in the #pact-elixir Channel at https://pact-foundation.slack.com/.
You need Rust in order to build and install the package.
If available in Hex, the package can be installed
by adding pact_elixir
to your list of dependencies in mix.exs
:
def deps do
[
{:pact_elixir, "~> 0.5.2"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/pact_elixir.
This is an example test case:
defmodule PactElixir.PactMockServerTest do
use ExUnit.Case
alias PactElixir.{PactMockServer, ServiceProvider}
import PactElixir.Dsl
setup do
options = %{provider: "SomeProvider", consumer: "SomeConsumer"}
provider = new_service_provider(options)
{:ok, mock_server_pid} = start_supervised({PactMockServer, provider})
{:ok, mock_server_pid: mock_server_pid, provider: provider}
end
describe "SomeProvider talks to SomeConsumer" do
test "some basic test", %{mock_server_pid: mock_server_pid} do
expected = "{groups: ['Editors'], id: 123, username: 'UserA'}"
user(mock_server_pid)
assert expected == user(mock_server_pid).body
assert {:ok} == PactMockServer.write_pact_file(mock_server_pid)
end
end
defp get_request(path, mock_server_pid) when is_pid(mock_server_pid) do
get_request(path, PactMockServer.port(mock_server_pid))
end
defp get_request(path, port) when is_number(port) do
%HTTPoison.Response{} = HTTPoison.get!("http://localhost:#{port}#{path}")
end
def user(mock_server_pid) do
get_request("/users/UserA", mock_server_pid)
end
defp new_service_provider(options \\ %{}) do
options
|> PactElixir.Dsl.service_provider()
|> add_interaction(
"give me foo",
given("UserA exists and is not an administrator"),
with_request(method: :get, path: "/users/UserA"),
will_respond_with(status: 200, body: "{groups: ['Editors'], id: 123, username: 'UserA'}")
)
end
end
You should be able to run it with mix test <path_to_test_case>
.
Publishing
If the test passes, a json file will be created and saved in a new directory - ./pacts
.
Currently, pact publishing is not yet implemented in this library. You can run the following bash script for your basic publishing needs:
#!/bin/bash
# This script:
# 1) extracts the name of provider and consumer from the name of a JSON pact file
# e.g.: Consumer1-Provider.json gives you consumer Consumer1 and provider Provider
# 2) reads the JSON pact file from /pacts directory (pacts are stored there by specification)
# 3) publishes pact to Pact Broker
for pact in ./pacts/*.json; do
pact_name=$(basename $pact)
consumer=${pact_name%-*}
provider=${pact_name#*-}
provider=${provider%.*}
curl -v -XPUT \-H "Content-Type: application/json" \
-d@${pact} \
https://<your-pact-broker-url>/pacts/provider/$provider/consumer/$consumer/version/<some-version-number>
done
Compiling NIF crate :pactmockserver (native/pactmockserver)...
could not compile dependency :pact_elixir, "mix compile"
failed. You can recompile this dependency with "mix deps.compile pact_elixir", update it with "mix deps.update pact_elixir" or clean it with "mix deps.clean pact_elixir"
This can be solved by ensuring proper structure of mix.exs
.
1) Ensure you have rustler
listed in compilers
2) Ensure pactmockserver
is listed in rustler_crates
def project do
[
#...
compilers: [:phoenix, :rustler] ++ Mix.compilers(),
rustler_crates: rustler_crates(Mix.env()),
#...
]
end
(This is an example setting, where you don't want to ship any rustler crates to production. Bottom line is, there has to be a function that returns the crates list, including pactmockserver).
defp rustler_crates(mix_env) when mix_env in [:test, :dev] do
[
pactmockserver: [
path: "deps/pact_elixir/native/pactmockserver",
mode: (:debug),
]
]
end
defp rustler_crates(_prod) do
[]
end
Properly installing Rust should solve a majority of the problems. Just add the following code (this is for a Debian distro, it assumes you have curl installed):
# Rust is required by pact-elixir
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
ENV PATH=$HOME/.cargo/bin:$PATH