Salesforce <> BOS Contract Testing

The purpose of this project is to have a testing mechanism that ensure no failures after code changes that affects synchronization between Salesforce and BOS platforms.

Problem Description

We don't have any automated mechanism that ensure synchronization process between Salesforce and BOS goes smoothly. Cause of that we have faced some hotfixes at both ecosystems Ebury and Frontierpay.

Background

Right now code changes related to synchronization between Salesforce and BOS are covered by unit tests, meaning any code change at one of the platforms can break the synchronization due to lack of mechanism to confirm process will continue working as expected at the other end.

Solution

Include a suite of Contract Testing into Salesforce and BOS CI. This suite will ensure that every API request that happens during synchronization process provides expected data to be consumed.

In order to achieve this we will use Consumer-Driven Contract Testing philosophy. This means that we have a set of files called "Contracts" that will include example requests and responses that serve as input for a mock provider (for tests on the Consumer side) and a mock consumer (for tests on the Provider side) against which every system involve in the contract can be tested independently. Also means that any change on those "Contracts" can be done only if the Consumer needs to add/remove some data to be consumed.

alt_text

Terminology:

  • Consumer: A service/component calling another service e.g. via a HTTP/REST API call, independent of the data flow direction (it does not matter if the HTTP request is a GET, PUT, POST, PATCH or DELETE).
  • Provider: A service/component being called from another service e.g. via a HTTP/REST interface.
  • Mock Service Provider: Used by tests in the consumer pipeline to mock the actual provider. Integration-like tests can be run without the actual provider.
  • Interaction: A request and response pair, e.g. a concrete GET request with its parameters and the response data.
  • Contract: A contract consists of a collection of interactions.
  • Broker: Service to share Contracts.

Consumer tests:

  • Specify all the Interactions at Contracts (only need to do it first time or when new Interaction want to be tested. Frameworks usually do it from tests executions).
  • Execute test against Mock Service Provider.
  • If new/modified Contract exists needs to be generated and stored (usually at Consumer or independent repository).
  • After Contract changes Provider tests need to be launched.

alt_text

Provider tests:

  • Setup Provider state
  • Mock Consumer execute tests against Provider, comparing responses with the "minimal expected response".
  • Teardown Provider state

alt_text

Example:

BOS (Consumer) → request api/getUser | expected to consume {name: String} SF (Provider) → response api/getUser | expected to provide {name: String, address: String, id: Integer} Contract → api/getUser (mock) | response {name: “Elmo“}

BOS change code to consume {name: String, address: String} → BOS Tests are runned against Mock Service Provider → Test fail cause the mocked response has no “address” data. BOS update the mock code, run tests again and cause of that generates a new Contract: Contract → api/getUser (mock) | response {name: “Elmo“, address: “mapple street“} Mock Consumer tests runs against SF (whenever a contract changes the Provider must run tests against it) and … green build (cause “address” is already provided by response)

BOS change code to consume {name: String, address: String, phone: Integer} → BOS Tests are runned against Mock Server Provider → Test fail cause the mocked response has no “phone” data. BOS update the mock code, run tests again and cause of that generates a new Contract: Contract → api/getUser (mock) | response {name: “Elmo“, address: “mapple street“, phone: 999999999} Mock Consumer tests runs against SF (whenever a contract changes the Provider must run tests against it) and … red build (cause “phone” is not provided by response) → Synchronization is broken → BOS Task cannot be deployed till SF Task to provide “phone” data is done.

SF change code to provide {name: String, phone: Integer} → Mock Consumer tests runs against SF → Test fail cause real response has no “address” data → SF needs to amend the development to accomplish the Contract, cannot provide a response without “address” data.

Tools:

In order to achieve Consumer-Driven Contract Testing there are tools like: POSTMAN, Pact, Spring Cloud Contract, etc.

Alternatives

Instead of Contract Testing we can go for Integration Tests, meaning we need both systems up and connected to be able to run the tests.

Caveats

N/A

Operation

Contract Testing will be run into the CI cycle related to BOS as Consumer/Provider and if Contract change is detected it will be run also as Provider against Salesforce.

Contract Testing will be run into the CI cycle related to SF as Consumer/Provider and if Contract change is detected it will be run also as Provider against BOS.

Security Impact

N/A

Performance Impact

N/A

Developer Impact

Learn how to use a Consumer-Driven Contract Testing framework.

Data Consumer Impact

N/A

Deployment

N/A

Dependencies

N/A

References

Epic: https://fxsolutions.atlassian.net/browse/ODT-31