- User declares contract between consumer and provider. Pact builder object is created.
builder {
serviceConsumer 'MessageConsumer'
hasPactWith 'MessageProvider'
}
- Using builder object, user sets up expectation of message using Pact DSL (message class is a Pact library object)
given:
builder {
given 'the provider has data for a message'
expectsToReceive 'a confirmation message for a group order'
withMetaData(contentType: 'application/json')
withContent {
name 'Bob'
date = '2000-01-01'
status 'bad'
age 100
}
- User executes tests showing that the consumer can handle the message correctly
builder.run { Message message ->
def content = new JsonSlurper().parse(message.contentsAsBytes())
// do something here that handles message
}
then:
true
- Builder merges message into pact file using provider state and description as the key (potentially call to pact ruby CLI to convert the simple ruby pact JSON into the proper message format?)
Q. What triggers the writing of the message?
-
Iterate through each message a) set up state b) invoke provider code that is expected to produce the message (argument is the message description) c) perform matching of expected/actual d) tear down state
-
Pass/fail based on overall state
Reuse pact-provider-verifier. Instead of user providing HTTP endpoints for the verifications and the state set up, they provide scripts.
eg.
pact-provider-verifier consumer-provider.json --provider-script provider.js --setup-script setup.js
Argument to the provider-script would be the message description. Argument to the setup-script would be either piped JSON (Q is this possible across platforms?) or key value pairs.
@bethesque here are some notes on implementation as I've seen it from JS/Go-land:
Consumer test:
pact-message reify
to get the contents, and then have the wrapper framework invoke the message consumer functionProvider tests:
/setup
API endpoints and use this instead? (probably not if people are still using the verifier as a standalone thing)Terminology:
I've standardised on the following naming conventions:
{name: "some state", ...}
in order to configure a provider state, and returns an error (throws / rejected Promise...) if it can'tMessageProvider
s andMessageConsumer
s - e.g. MQ, Kinesis. For the purposes of Pact tests, it includes the transport (e.g. tcp) and wire protocol (e.g. JSON/binary)Intermediary
, and invoking theMessageConsumer
/MessageProvider
It would be great to do something similar for framework implementation authors. For instance, your
message invoker
is what I've been calling the"Native Adapter"
, as it's job is to convert from an HTTP interface to a native one. I'm not too fussed either way, we just need a common language.