add spring-amqp/spring-rabbit support for message contracts (#106)
This commit is contained in:
committed by
Marcin Grzejszczak
parent
74ea3fd27d
commit
2b70b450b9
@@ -305,7 +305,7 @@ with __Contract Definition Language__ (DSL). Contract definitions are used to pr
|
||||
|
||||
* JSON stub definitions to be used by WireMock when doing integration testing on the client code (__client tests__).
|
||||
Test code must still be written by hand, test data is produced by Spring Cloud Contract Verifier.
|
||||
* Messaging routes if you're using one. We're integrating with Spring Integration, Spring Cloud Stream and Apache Camel. You can however set your own integrations if you want to
|
||||
* Messaging routes if you're using one. We're integrating with Spring Integration, Spring Cloud Stream, Spring AMQP and Apache Camel. You can however set your own integrations if you want to
|
||||
* Acceptance tests (in JUnit or Spock) used to verify if server-side implementation of the API is compliant with the contract (__server tests__).
|
||||
Full test is generated by Spring Cloud Contract Verifier.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ with __Contract Definition Language__ (DSL). Contract definitions are used to pr
|
||||
|
||||
* JSON stub definitions to be used by WireMock when doing integration testing on the client code (__client tests__).
|
||||
Test code must still be written by hand, test data is produced by Spring Cloud Contract Verifier.
|
||||
* Messaging routes if you're using one. We're integrating with Spring Integration, Spring Cloud Stream and Apache Camel. You can however set your own integrations if you want to
|
||||
* Messaging routes if you're using one. We're integrating with Spring Integration, Spring Cloud Stream, Spring AMQP and Apache Camel. You can however set your own integrations if you want to
|
||||
* Acceptance tests (in JUnit or Spock) used to verify if server-side implementation of the API is compliant with the contract (__server tests__).
|
||||
Full test is generated by Spring Cloud Contract Verifier.
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@ All of our integrations are working with Spring but you can also create one your
|
||||
|
||||
==== Integrations
|
||||
|
||||
You can use one of the three integration configurations:
|
||||
You can use one of the four integration configurations:
|
||||
|
||||
- Apache Camel
|
||||
- Spring Integration
|
||||
- Spring Cloud Stream
|
||||
- Spring AMQP
|
||||
|
||||
Since we're using Spring Boot then if you have added one of the aforementioned libraries
|
||||
to the classpath then automatically all the messaging configuration will be set up.
|
||||
|
||||
@@ -5,6 +5,7 @@ Stub Runner has the functionality to run the published stubs in memory. It can i
|
||||
- Spring Integration
|
||||
- Spring Cloud Stream
|
||||
- Apache Camel
|
||||
- Spring AMQP
|
||||
|
||||
It also provides points of entry to integrate with any other solution on the market.
|
||||
|
||||
@@ -53,4 +54,6 @@ include::{tests_path}/spring-cloud-contract-stub-runner-camel/README.adoc[]
|
||||
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-integration/README.adoc[]
|
||||
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/README.adoc[]
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-stream/README.adoc[]
|
||||
|
||||
include::{tests_path}/spring-cloud-contract-stub-runner-amqp/README.adoc[]
|
||||
10
pom.xml
10
pom.xml
@@ -104,6 +104,16 @@
|
||||
<artifactId>spock-global-unroll</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.amqp</groupId>
|
||||
<artifactId>spring-rabbit</artifactId>
|
||||
<version>1.6.2.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>1.10.19</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-dependencies</artifactId>
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
<artifactId>spring-cloud-stream-test-support</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.amqp</groupId>
|
||||
<artifactId>spring-rabbit</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
@@ -90,7 +95,6 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.messaging.amqp;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.amqp.support.SimpleAmqpHeaderMapper;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.amqp.support.converter.MessagingMessageConverter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
import org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifierIntegrationConfiguration;
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage;
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging;
|
||||
import org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configuration setting up {@link MessageVerifier} for use with plain spring-rabbit/spring-amqp
|
||||
*
|
||||
* @author Mathias Düsterhöft
|
||||
* @since 1.0.2
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({Message.class, RabbitTemplate.class, Mockito.class})
|
||||
@ConditionalOnMissingClass("org.springframework.integration.core.MessageSource")
|
||||
@AutoConfigureBefore(ContractVerifierIntegrationConfiguration.class)
|
||||
@AutoConfigureAfter(ContractVerifierStreamAutoConfiguration.class)
|
||||
public class ContractVerifierAmqpAutoConfiguration {
|
||||
|
||||
@SpyBean
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
@Autowired(required = false)
|
||||
private MessageListenerAdapter messageListenerAdapter;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MessageVerifier<Message> contractVerifierMessageExchange() {
|
||||
return new SpringAmqpStubMessages(this.rabbitTemplate, this.messageListenerAdapter);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ContractVerifierMessaging<Message> contractVerifierMessaging(
|
||||
MessageVerifier<Message> exchange) {
|
||||
return new ContractVerifierHelper(exchange, this.rabbitTemplate.getMessageConverter());
|
||||
}
|
||||
}
|
||||
|
||||
class ContractVerifierHelper extends ContractVerifierMessaging<Message> {
|
||||
|
||||
private final MessageConverter messageConverter;
|
||||
|
||||
public ContractVerifierHelper(MessageVerifier<Message> exchange, MessageConverter messageConverter) {
|
||||
super(exchange);
|
||||
this.messageConverter = messageConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractVerifierMessage convert(Message message) {
|
||||
MessagingMessageConverter messageConverter = new MessagingMessageConverter(this.messageConverter, new SimpleAmqpHeaderMapper());
|
||||
org.springframework.messaging.Message<?> messagingMessage = (org.springframework.messaging.Message<?>) messageConverter.fromMessage(message);
|
||||
return new ContractVerifierMessage(messagingMessage.getPayload(), messagingMessage.getHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.springframework.cloud.contract.verifier.messaging.amqp;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
|
||||
/**
|
||||
* Spring rabbit test utility that provides a mock ConnectionFactory to avoid having to connect against a running broker.
|
||||
*
|
||||
* Set verifier.amqp.mockConnection=true to enable the mocked ConnectionFactory
|
||||
*
|
||||
* @author Mathias Düsterhöft
|
||||
* @since 1.0.2
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({Message.class, RabbitTemplate.class, Mockito.class})
|
||||
@ConditionalOnMissingClass("org.springframework.integration.core.MessageSource")
|
||||
@AutoConfigureAfter(ContractVerifierAmqpAutoConfiguration.class)
|
||||
@ConditionalOnProperty(value = "verifier.amqp.mockConnection", havingValue = "true", matchIfMissing = true)
|
||||
public class RabbitMockConnectionFactoryAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory connectionFactory() {
|
||||
com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class);
|
||||
Connection mockConnection = mock(Connection.class);
|
||||
Channel mockChannel = mock(Channel.class);
|
||||
try {
|
||||
when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection);
|
||||
when(mockConnection.isOpen()).thenReturn(true);
|
||||
when(mockConnection.createChannel()).thenReturn(mockChannel);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new CachingConnectionFactory(mockConnectionFactory);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.contract.verifier.messaging.amqp;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mockingDetails;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.springframework.amqp.support.converter.DefaultClassMapper.DEFAULT_CLASSID_FIELD_NAME;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.core.MessagePropertiesBuilder;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.amqp.rabbit.support.CorrelationData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link MessageVerifier} implementation to integrate with plain spring-amqp/spring-rabbit.
|
||||
* It is meant to be used without interacting with a running bus.
|
||||
*
|
||||
* It relies on the RabbitTemplate to be a spy to be able to capture send messages.
|
||||
*
|
||||
* Messages are not sent to the bus - but are handed over to the {@link MessageListenerAdapter} which
|
||||
* allows us to test the full deserialization and listener invocation.
|
||||
*
|
||||
* @author Mathias Düsterhöft
|
||||
* @since 1.0.2
|
||||
*/
|
||||
public class SpringAmqpStubMessages implements
|
||||
MessageVerifier<Message> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringAmqpStubMessages.class);
|
||||
|
||||
private final RabbitTemplate rabbitTemplate;
|
||||
|
||||
private final MessageListenerAdapter messageListenerAdapter;
|
||||
|
||||
@Autowired
|
||||
public SpringAmqpStubMessages(RabbitTemplate rabbitTemplate, MessageListenerAdapter messageListenerAdapter) {
|
||||
Assert.notNull(rabbitTemplate);
|
||||
Assert.isTrue(mockingDetails(rabbitTemplate).isSpy() || mockingDetails(rabbitTemplate).isMock()); //we get send messages by capturing arguments on the spy
|
||||
this.rabbitTemplate = rabbitTemplate;
|
||||
this.messageListenerAdapter = messageListenerAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void send(T payload, Map<String, Object> headers, String destination) {
|
||||
Message message = org.springframework.amqp.core.MessageBuilder
|
||||
.withBody(((String) payload).getBytes())
|
||||
.andProperties(
|
||||
MessagePropertiesBuilder.newInstance()
|
||||
.setContentType((String) headers.get("contentType"))
|
||||
.copyHeaders(headers).build())
|
||||
.build();
|
||||
if (headers.containsKey(DEFAULT_CLASSID_FIELD_NAME)) {
|
||||
message.getMessageProperties().setHeader(DEFAULT_CLASSID_FIELD_NAME, headers.get(DEFAULT_CLASSID_FIELD_NAME));
|
||||
}
|
||||
send(message, destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Message message, String destination) {
|
||||
if (this.messageListenerAdapter == null) {
|
||||
throw new IllegalStateException("no MessageListenerAdapter wired - cannot send message");
|
||||
}
|
||||
this.messageListenerAdapter.onMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message receive(String destination, long timeout, TimeUnit timeUnit) {
|
||||
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(this.rabbitTemplate).send(eq(destination), anyString(), messageCaptor.capture(), any(CorrelationData.class));
|
||||
|
||||
if (messageCaptor.getAllValues().isEmpty()) {
|
||||
log.info("no messages found on destination {}", destination);
|
||||
return null;
|
||||
} else if (messageCaptor.getAllValues().size() > 1) {
|
||||
log.info("multiple messages found on destination {} returning last one - {}", destination);
|
||||
return messageCaptor.getValue();
|
||||
}
|
||||
return messageCaptor.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message receive(String destination) {
|
||||
return receive(destination, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,5 +2,7 @@
|
||||
org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier=\
|
||||
org.springframework.cloud.contract.verifier.messaging.stream.ContractVerifierStreamAutoConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifierIntegrationConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.amqp.ContractVerifierAmqpAutoConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.amqp.RabbitMockConnectionFactoryAutoConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.camel.ContractVerifierCamelConfiguration,\
|
||||
org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.springframework.cloud.contract.verifier.messaging.amqp
|
||||
|
||||
import org.springframework.amqp.core.Message
|
||||
import org.springframework.amqp.core.MessageBuilder
|
||||
import org.springframework.amqp.core.MessagePropertiesBuilder
|
||||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage
|
||||
import spock.lang.Specification
|
||||
|
||||
import static org.springframework.amqp.core.MessageProperties.CONTENT_TYPE_JSON
|
||||
/**
|
||||
* @author Mathias Düsterhöft
|
||||
*/
|
||||
class ContractVerifierHelperSpec extends Specification {
|
||||
|
||||
def "should convert message"() {
|
||||
given:
|
||||
String payload = '''{"name":"some"}'''
|
||||
Message message = MessageBuilder
|
||||
.withBody(payload.bytes)
|
||||
.andProperties(MessagePropertiesBuilder.newInstance()
|
||||
.setHeader("my-header", "some")
|
||||
.setContentType(CONTENT_TYPE_JSON)
|
||||
.build()).build()
|
||||
ContractVerifierHelper contractVerifierHelper = new ContractVerifierHelper(null, new Jackson2JsonMessageConverter())
|
||||
when:
|
||||
ContractVerifierMessage contractVerifierMessage = contractVerifierHelper.convert(message)
|
||||
then:
|
||||
((Map) contractVerifierMessage.payload).containsKey("name")
|
||||
contractVerifierMessage.headers.containsKey("contentType")
|
||||
contractVerifierMessage.headers.containsKey("my-header")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springframework.cloud.contract.verifier.messaging.amqp
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.springframework.amqp.core.Message
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate
|
||||
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter
|
||||
import spock.lang.Specification
|
||||
|
||||
import static org.mockito.Mockito.mock
|
||||
import static org.springframework.amqp.core.MessageProperties.CONTENT_TYPE_JSON
|
||||
import static org.springframework.amqp.support.converter.DefaultClassMapper.DEFAULT_CLASSID_FIELD_NAME
|
||||
/**
|
||||
* @author Mathias Düsterhöft
|
||||
*/
|
||||
class SpringAmqpStubMessagesSpec extends Specification {
|
||||
|
||||
RabbitTemplate rabbitTemplate = mock(RabbitTemplate.class)
|
||||
MessageListenerAdapter messageListenerAdapter = Mock(MessageListenerAdapter.class)
|
||||
|
||||
def "should send amqp message with type id"() {
|
||||
given:
|
||||
String payload = '''{"name":"some"}'''
|
||||
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class)
|
||||
SpringAmqpStubMessages messageVerifier = new SpringAmqpStubMessages(rabbitTemplate, messageListenerAdapter)
|
||||
when:
|
||||
messageVerifier.send(payload,
|
||||
ImmutableMap.builder()
|
||||
.put(DEFAULT_CLASSID_FIELD_NAME, "org.example.Some")
|
||||
.put("contentType", CONTENT_TYPE_JSON)
|
||||
.build(),
|
||||
"test-exchange")
|
||||
then:
|
||||
1 * messageListenerAdapter.onMessage({
|
||||
it.getMessageProperties().getContentType() == CONTENT_TYPE_JSON &&
|
||||
it.getMessageProperties().getHeaders().get(DEFAULT_CLASSID_FIELD_NAME) == "org.example.Some"
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,14 @@
|
||||
<module>samples-messaging-spring</module>
|
||||
<module>samples-messaging-stream</module>
|
||||
<module>samples-messaging-integration</module>
|
||||
<module>samples-messaging-amqp</module>
|
||||
<module>spring-cloud-contract-stub-runner-boot-eureka</module>
|
||||
<module>spring-cloud-contract-stub-runner-boot-zookeeper</module>
|
||||
<module>spring-cloud-contract-stub-runner-camel</module>
|
||||
<module>spring-cloud-contract-stub-runner-context-path</module>
|
||||
<module>spring-cloud-contract-stub-runner-integration</module>
|
||||
<module>spring-cloud-contract-stub-runner-stream</module>
|
||||
<module>spring-cloud-contract-stub-runner-amqp</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
|
||||
48
tests/samples-messaging-amqp/pom.xml
Normal file
48
tests/samples-messaging-amqp/pom.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-tests</artifactId>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-sample-amqp</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Sample Spring Amqp</name>
|
||||
<description>Spring Cloud Contract Sample Spring Amqp Rabbit</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-verifier</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.example;
|
||||
|
||||
import static org.springframework.amqp.core.MessageProperties.CONTENT_TYPE_JSON;
|
||||
|
||||
import org.springframework.amqp.core.Exchange;
|
||||
import org.springframework.amqp.core.TopicExchange;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter;
|
||||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AmqpMessagingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AmqpMessagingApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageConverter messageConverter(ObjectMapper objectMapper) {
|
||||
final Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
|
||||
jsonMessageConverter.setJsonObjectMapper(objectMapper);
|
||||
jsonMessageConverter.setCreateMessageIds(true);
|
||||
final ContentTypeDelegatingMessageConverter messageConverter = new ContentTypeDelegatingMessageConverter(jsonMessageConverter);
|
||||
messageConverter.addDelegate(CONTENT_TYPE_JSON, jsonMessageConverter);
|
||||
return messageConverter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
|
||||
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
|
||||
rabbitTemplate.setMessageConverter(messageConverter);
|
||||
return rabbitTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Exchange testExchange() {
|
||||
return new TopicExchange("test-exchange");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.example;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
public class Book {
|
||||
|
||||
private String name;
|
||||
|
||||
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
|
||||
public Book(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.example;
|
||||
|
||||
import org.springframework.amqp.core.Exchange;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class MessagePublisher {
|
||||
|
||||
private final RabbitTemplate rabbitTemplate;
|
||||
|
||||
private final Exchange exchange;
|
||||
@Autowired
|
||||
public MessagePublisher(RabbitTemplate rabbitTemplate, Exchange exchange) {
|
||||
this.rabbitTemplate = rabbitTemplate;
|
||||
this.exchange = exchange;
|
||||
}
|
||||
|
||||
public void sendMessage(Book book) {
|
||||
this.rabbitTemplate.convertAndSend(this.exchange.getName(), "routingkey", book);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example
|
||||
|
||||
import com.jayway.jsonpath.DocumentContext
|
||||
import com.jayway.jsonpath.JsonPath
|
||||
import com.toomuchcoding.jsonassert.JsonAssertion
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging
|
||||
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import spock.lang.Specification
|
||||
|
||||
import javax.inject.Inject
|
||||
// Context configuration would end up in base class
|
||||
@ContextConfiguration(classes = [AmqpMessagingApplication], loader = SpringBootContextLoader)
|
||||
@DirtiesContext
|
||||
@AutoConfigureMessageVerifier
|
||||
public class AmqpMessagingApplicationSpec extends Specification {
|
||||
|
||||
// ALL CASES
|
||||
@Inject ContractVerifierMessaging contractVerifierMessaging
|
||||
@Inject ContractVerifierObjectMapper contractVerifierObjectMapper
|
||||
|
||||
def "should work for triggered based messaging"() {
|
||||
given:
|
||||
def dsl = Contract.make {
|
||||
// Human readable description
|
||||
description 'Some description'
|
||||
// Label by means of which the output message can be triggered
|
||||
label 'some_label'
|
||||
// input to the contract
|
||||
input {
|
||||
// the contract will be triggered by a method
|
||||
triggeredBy('publishBook()')
|
||||
}
|
||||
// output message of the contract
|
||||
outputMessage {
|
||||
// destination to which the output message will be sent
|
||||
sentTo('test-exchange')
|
||||
// the body of the output message
|
||||
body('''{ "name" : "some" }''')
|
||||
// the headers of the output message
|
||||
headers {
|
||||
header('contentType', 'application/json')
|
||||
header('__TypeId__', 'com.example.Book')
|
||||
}
|
||||
}
|
||||
}
|
||||
// generated test should look like this:
|
||||
when:
|
||||
publishBook()
|
||||
then:
|
||||
def response = contractVerifierMessaging.receive('test-exchange')
|
||||
response.headers.get('contentType') == 'application/json'
|
||||
and:
|
||||
DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload))
|
||||
JsonAssertion.assertThat(parsedJson).field('name').isEqualTo('some')
|
||||
}
|
||||
|
||||
// BASE CLASS WOULD HAVE THIS:
|
||||
|
||||
@Autowired MessagePublisher messagePublisher
|
||||
|
||||
void publishBook() {
|
||||
this.messagePublisher.sendMessage(new Book("some"))
|
||||
}
|
||||
}
|
||||
84
tests/spring-cloud-contract-stub-runner-amqp/README.adoc
Normal file
84
tests/spring-cloud-contract-stub-runner-amqp/README.adoc
Normal file
@@ -0,0 +1,84 @@
|
||||
=== Stub Runner Spring AMQP
|
||||
|
||||
Spring Cloud Contract Verifier Stub Runner's messaging module provides an easy way to integrate with Spring AMQP's Rabbit Template.
|
||||
For the provided artifacts it will automatically download the stubs and register the required
|
||||
routes.
|
||||
|
||||
The integration tries to work standalone, that is without interaction with a running RabbitMQ message broker. It expects a `RabbitTemplate` on the application context and uses it as a spring boot test `@SpyBean`.
|
||||
Thus it can use the mockito spy functionality to verify and introspect messages sent by the application.
|
||||
|
||||
IMPORTANT: In the current status of the implementation tries to find a `MessageListenerAdapter` on the application context to send messages into the application, because we want to avoid interacting with a running bus.
|
||||
Using annotation driven listener endpoints (e.g. `@RabbitListener` annotated listener methods) is currently not supported.
|
||||
|
||||
==== Adding it to the project
|
||||
|
||||
It's enough to have both Spring AMQP and Spring Cloud Contract Stub Runner on classpath.
|
||||
Remember to annotate your test class with `@AutoConfigureMessageVerifier`.
|
||||
|
||||
==== Examples
|
||||
|
||||
===== Stubs structure
|
||||
|
||||
Let us assume that we have the following Maven repository with a deployed stubs for the
|
||||
`spring-cloud-contract-amqp-test` application.
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
└── .m2
|
||||
└── repository
|
||||
└── com
|
||||
└── example
|
||||
└── spring-cloud-contract-amqp-test
|
||||
├── 0.4.0-SNAPSHOT
|
||||
│ ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT.pom
|
||||
│ ├── spring-cloud-contract-amqp-test-0.4.0-SNAPSHOT-stubs.jar
|
||||
│ └── maven-metadata-local.xml
|
||||
└── maven-metadata-local.xml
|
||||
----
|
||||
|
||||
And the stubs contain the following structure:
|
||||
|
||||
[source,bash,indent=0]
|
||||
----
|
||||
├── META-INF
|
||||
│ └── MANIFEST.MF
|
||||
└── contracts
|
||||
└── shouldProduceValidPersonData.groovy
|
||||
----
|
||||
|
||||
Let's consider the following contract:
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerSpec.groovy[tags=amqp_contract,indent=0]
|
||||
----
|
||||
|
||||
|
||||
and the following Spring configuration:
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
include::src/test/resources/application.yml[]
|
||||
----
|
||||
|
||||
===== Triggering the message
|
||||
|
||||
So to trigger a message using the contract above we'll use the `StubTrigger` interface as follows.
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
include::src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/amqp/AmqpStubRunnerSpec.groovy[tags=client_trigger,indent=0]
|
||||
----
|
||||
|
||||
===== Spring AMQP Test Configuration
|
||||
|
||||
In order to avoid that Spring AMQP is trying to connect to a running broker during our tests we configure a mock `ConnectionFactory`.
|
||||
|
||||
To disable the mocked ConnectionFactory set the property `verifier.amqp.mockConnection=false`
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
verifier:
|
||||
amqp:
|
||||
mockConnection: false
|
||||
----
|
||||
81
tests/spring-cloud-contract-stub-runner-amqp/pom.xml
Normal file
81
tests/spring-cloud-contract-stub-runner-amqp/pom.xml
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-tests</artifactId>
|
||||
<version>1.0.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-contract-stub-runner-amqp</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Contract Stub Runner AMQP</name>
|
||||
<description>Spring Cloud Contract Stub Runner AMQP</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-stub-runner</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-contract-stub-runner-jetty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-verifier</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.amqp</groupId>
|
||||
<artifactId>spring-rabbit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
<artifactId>spock-spring</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.solidsoft.spock</groupId>
|
||||
<artifactId>spock-global-unroll</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.amqp;
|
||||
|
||||
import static org.springframework.amqp.core.MessageProperties.CONTENT_TYPE_JSON;
|
||||
|
||||
import org.springframework.amqp.core.Exchange;
|
||||
import org.springframework.amqp.core.TopicExchange;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter;
|
||||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
|
||||
import org.springframework.amqp.support.converter.MessageConverter;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@SpringBootApplication
|
||||
public class AmqpMessagingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AmqpMessagingApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageConverter messageConverter(ObjectMapper objectMapper) {
|
||||
final Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
|
||||
jsonMessageConverter.setJsonObjectMapper(objectMapper);
|
||||
jsonMessageConverter.setCreateMessageIds(true);
|
||||
final ContentTypeDelegatingMessageConverter messageConverter = new ContentTypeDelegatingMessageConverter(jsonMessageConverter);
|
||||
messageConverter.addDelegate(CONTENT_TYPE_JSON, jsonMessageConverter);
|
||||
return messageConverter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
|
||||
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
|
||||
rabbitTemplate.setMessageConverter(messageConverter);
|
||||
return rabbitTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Exchange testExchange() {
|
||||
return new TopicExchange("test-exchange");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageListenerAdapter messageListenerAdapter(MessageSubscriber messageSubscriber, MessageConverter messageConverter) {
|
||||
return new MessageListenerAdapter(messageSubscriber, messageConverter);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.amqp;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class MessageSubscriber {
|
||||
|
||||
public void handleMessage(Person person) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.amqp;
|
||||
|
||||
public class Person {
|
||||
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.springframework.cloud.contract.stubrunner.messaging.amqp
|
||||
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootContextLoader
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.stubrunner.StubTrigger
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import spock.lang.Specification
|
||||
|
||||
import static org.mockito.BDDMockito.then
|
||||
|
||||
@ContextConfiguration(classes = [AmqpMessagingApplication], loader = SpringBootContextLoader)
|
||||
@AutoConfigureStubRunner
|
||||
class AmqpStubRunnerSpec extends Specification {
|
||||
|
||||
@Autowired
|
||||
StubTrigger stubTrigger
|
||||
|
||||
@SpyBean
|
||||
MessageSubscriber messageSubscriber
|
||||
|
||||
@Captor
|
||||
ArgumentCaptor<Person> personArgumentCaptor
|
||||
|
||||
def "should trigger stub amqp message"() {
|
||||
given:
|
||||
// tag::amqp_contract[]
|
||||
|
||||
Contract.make {
|
||||
// Human readable description
|
||||
description 'Should produce valid person data'
|
||||
// Label by means of which the output message can be triggered
|
||||
label 'contract-test.person.created.event'
|
||||
// input to the contract
|
||||
input {
|
||||
// the contract will be triggered by a method
|
||||
triggeredBy('createPerson()')
|
||||
}
|
||||
// output message of the contract
|
||||
outputMessage {
|
||||
// destination to which the output message will be sent
|
||||
sentTo 'contract-test.exchange'
|
||||
headers {
|
||||
header('contentType': 'application/json')
|
||||
header('__TypeId__': 'org.springframework.cloud.contract.stubrunner.messaging.amqp.Person')
|
||||
}
|
||||
// the body of the output message
|
||||
body ([
|
||||
id: $(consumer(9), producer(regex("[0-9]+"))),
|
||||
name: "me"
|
||||
])
|
||||
}
|
||||
}
|
||||
// end::amqp_contract[]
|
||||
when:
|
||||
// tag::client_trigger[]
|
||||
stubTrigger.trigger("contract-test.person.created.event")
|
||||
// end::client_trigger[]
|
||||
then:
|
||||
then(messageSubscriber).should().handleMessage(personArgumentCaptor.capture())
|
||||
personArgumentCaptor.value.name != null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
stubrunner.repositoryRoot: classpath:m2repo/repository/
|
||||
stubrunner.ids: org.springframework.cloud.contract.verifier.stubs.amqp:spring-cloud-contract-amqp-test:0.4.0-SNAPSHOT:stubs
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs.amqp</groupId>
|
||||
<artifactId>spring-cloud-contract-amqp-test</artifactId>
|
||||
<version>0.4.0-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<snapshot>
|
||||
<localCopy>true</localCopy>
|
||||
</snapshot>
|
||||
<lastUpdated>20161007155639</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs.amqp</groupId>
|
||||
<artifactId>spring-cloud-contract-amqp-test</artifactId>
|
||||
<version>0.4.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs.amqp</groupId>
|
||||
<artifactId>spring-cloud-contract-amqp-test</artifactId>
|
||||
<version>0.4.0-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.4.0-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2016 the original author or authors.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<metadata>
|
||||
<groupId>org.springframework.cloud.contract.verifier.stubs.amqp</groupId>
|
||||
<artifactId>spring-cloud-contract-amqp-test</artifactId>
|
||||
<version>0.4.0-SNAPSHOT</version>
|
||||
<versioning>
|
||||
<versions>
|
||||
<version>0.4.0-SNAPSHOT</version>
|
||||
</versions>
|
||||
<lastUpdated>20160409062112</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
Reference in New Issue
Block a user