Last updated 15 days ago

Pact was originally written by a development team (including Ron Holshausen from DiUS) at realestate.com.au in 2013. They were trying to solve the problem of how to do integration testing for their new Ruby microservices architecture, and they threw together a codebase that was to become the first Pact implementation. As the team was writing Ruby microservices, the serialisation of the "matching logic" (e.g. regular expressions) was done using Ruby specific code. The team was under the pump to finish their actual customer deliverable, so they got their Pact MVP working, and left it at that.

A few months later Beth Skurrie from DiUS joined the one of the teams that was working with the Pact authors' team. She had recently seen a talk by J.B.Rainsberger entitled "Integration tests are a scam", which promoted the concept of "collabration" and "contract" tests, so she was immediately interested when she was introduced to Pact. After trying (as most people do) to convince the authors that the provider should be the contract writer, she was soon convinced by Brent Snook, one of the original authors, of the value of consumer driven contracts. At this stage, she realised that what was missing in the current implementation was the ability to run the same request under different conditions, and "provider states" were born.

Soon after, Beth decided that Pact idea was the best thing since sliced bread, and she hasn't stopped yacking on about it since.

Pact spread around the codebases in the wider program of work at realestate.com.au, until it hit its first Java microservice. realestate.com.au had many JVM projects, so a group of DiUS consultants (including Ron Holshausen again) started the pact-jvm project on a hack day. It was at this stage that the authors realised that the Rubyisms in the format were going to have to be replaced by a non-language specific format, and the idea of the v2 pact-specification arose (though it would take a while before it became reality).

Soon it became obvious that Javascript UIs would benefit greatly from using Pact with their backend APIs. After tossing around the idea of implementing Pact yet again in another language, a decision was made to wrap the Ruby implementation (which was packaged as a standalone executable) to avoid the maintenance burden and potential of implementation mismatches. This became the pattern that was used for all the following Pact implementations. Each language implemented a Pact DSL and mock service/verifier client, and called out to the Ruby mock service process/verifier in the background. The original Ruby JSON syntax was often used between the native clients and the mock service, as it was simpler to implement, however, the mock service took care of writing the actual pact in the v2 format.

Since the implementation of the v2 format, newer features have been added, and the v3 and v4 formats add support for handing multiple provider states, messaging, and 'generators'.

Wrapping the Ruby implementation allowed new languages to implement Pact quickly, however, it had its downsides. The standalone package worked by bundling the entire Ruby runtime with the codebase using Travelling Ruby, so it was large (~9MB). The native libraries also had to deal with the mock service process management, which could be fiddly on different platforms. It also made it difficult to run consumer tests in parallel, as each mock service process could only handle one thread at a time. The Ruby implementation was also lagging behind in feature development compared to the JVM, as Beth was spending more time on the Pact Broker.

To provide a single Pact implementation that could be used by all the required languages, the decision was made to create a reference implementation in Rust, that could be wrapped by each client language using FFI. The distributable package will be orders of magnitude smaller, and make it easier to run tests in parallel and avoid the process management issues. It is currently a work in progress (Nov 2017), and is the reason that development on the newer versions of the pact specification in the JVM and Ruby implementations has been slowed.