Vaunt
Table of Contents
Overview
This repository contains toolkit to define and validate contracts in JMS
Idea
There are 3 most typical scenarios and any other scenario is a combination of these 3.
Scenario I: Service 1 -> Queue A -> Service 2
Scenario II: Service 3 -> Topic B -> Service 4
Scenario III: Service 5 -> Topic C -> Queue D -> Service 6
In Scenario I Service 1 sends commands to Queue A. Service 2 handles these commands.
In Scenario II Service 3 publishes events to Topic B. Service 4 listens to the events.
In Scenario III Service 5 publishes events to Topic C. They are sent further to Queue D and Service 6 listens to the events.
A provider is a service providing functionality to other services.
A consumer is a service depending on functionality provided by the provider.
What does it mean from the perspective of 3 specified scenarios?
In scenario I Service 2 is the provider. It accepts commands (to perform a task) via its queue from Service 1, which is a consumer of its functionality.
In scenario II Service 3 is the provider. Events generated by Service 3 are consumed by Service 4, therefore Service 4 is the consumer.
In scenario III situation is similar like in scenario II. Queue D is an internal concern of Service 6. This scenario may be simplified to the following one:
Scenario IIIb: Service 5 -> Topic C -> (Queue D) Service 6
As a result, Service 5 is the provider, service 6 is the consumer.
A contract contains:
- Provider's JMS destination type: topic/queue/temporary queue
- Provider's JMS destination name (omitted in case of temporary queues)
- Message id (by default name of the class representing message, can be customized)
- JSON schema of a message exchanged between consumer and provider
Capabilities of a provider should contain the contract.
Expectations of a consumer should contain the contract and name of the provider.
Annotations @Consumer and @Provider should be used on messages exchanged between consumer and provider. One message can be annotated with multiple annotations For now classes representing messages should have the same name. Objects belonging to other via composition might have different names (ids).
It is possible to provide properties with JMS destination names.
Fields contained in message on provider side must be a superset of fields contained in message on consumer side. Same applies to enums. Enum on provider side can be represented by String as well. It requires setting DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL in ObjectMapper (or equivalent) in producer and @JsonIgnoreProperties(ignoreUnknown = true) (or equivalent) in case of Strings.
Vaunt-Generator does not use "ref" (i. e. uses inlining) with the exception of JsonSchema (threat of StackOverflow).
Currently Vaunt Validator supports BooleanSchema, IntegerSchema, NumberSchema, ObjectSchema, StringSchema, ArraySchema.
Vaunt validator validates in order how contract is specified i.e. when expectations are verified and no capabilities match them, then in results the most similar expectations and corresponding errors are displayed
Example of code snippet with test creating Vaunt contract
@SpringBootTest
class GenerateVauntIT extends Specification {
@Autowired
Environment env
@Autowired
private ApplicationContext applicationContext
@Subject
VauntGenerator vauntGenerator = new VauntGenerator()
def 'should generate vaunt file'() {
expect:
YAMLConfiguration config = new YAMLConfiguration()
config.read(new FileInputStream("src/main/resources/application.yml"))
def props = new Properties()
for(String key : config.getKeys()) {
props.put(key, env.getProperty(key))
}
vauntGenerator.writeVauntFile('com.hltech.sample.component', 'sample-component', 'target/classes/static/vaunt', props)
}
}
Built with
- Gradle - dependency management & build tool
Authors
- Filip Łazarski - Development - Felipe444
License
vaunt is MIT licensed.