AMQP-791: Support JUnit5
JIRA: https://jira.spring.io/browse/AMQP-791 - refactor `BrokerRunning` JUnit4 `@Rule` so it can be invoked from an `ExecutionCondition`. - Add `@RabbitAvailable` annotation with queue list and auto-delete queues at the end of the class; purge them between tests. * Implement `ParameterResolver` to access the rule's connection factory. * Support CTOR Injection and `BrokerRunning` Injection - user might want to invoke methods such as `deleteQueues()`. * Patches omitted from previous commit * WIP - Spring * Polishing - PR Comments * Convert `RabbitTemplateMPPIntegrationTests` - JUnit5 * Remove bogus test * Docs + `@LongRunning` * Polishing - PR Comments
This commit is contained in:
committed by
Artem Bilan
parent
48412b93f6
commit
d73f4ffc0a
27
build.gradle
27
build.gradle
@@ -8,6 +8,7 @@ buildscript {
|
||||
classpath 'me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1'
|
||||
classpath 'io.spring.gradle:dependency-management-plugin:1.0.2.RELEASE'
|
||||
classpath 'io.spring.gradle:spring-io-plugin:0.0.8.RELEASE'
|
||||
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.2'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +88,10 @@ subprojects { subproject ->
|
||||
ext {
|
||||
hamcrestVersion = '1.3'
|
||||
jackson2Version = '2.9.1'
|
||||
junitVersion = '4.12'
|
||||
junit4Version = '4.12'
|
||||
junitJupiterVersion = '5.0.2'
|
||||
junitPlatformVersion = '1.0.2'
|
||||
junitVintageVersion = '4.12.2'
|
||||
log4jVersion = '2.8.2'
|
||||
logbackVersion = '1.2.3'
|
||||
mockitoVersion = '2.11.0'
|
||||
@@ -112,7 +116,7 @@ subprojects { subproject ->
|
||||
|
||||
// dependencies that are common across all java projects
|
||||
dependencies {
|
||||
testCompile ("junit:junit:$junitVersion") {
|
||||
testCompile ("junit:junit:$junit4Version") {
|
||||
exclude group: 'org.hamcrest', module: 'hamcrest-core'
|
||||
}
|
||||
testCompile "org.apache.logging.log4j:log4j-core:$log4jVersion"
|
||||
@@ -123,6 +127,18 @@ subprojects { subproject ->
|
||||
testCompile "org.springframework:spring-test:$springVersion"
|
||||
testCompile "org.slf4j:slf4j-log4j12:$slf4jVersion" // amqp-client now uses SLF4J
|
||||
testRuntime "org.apache.logging.log4j:log4j-jcl:$log4jVersion"
|
||||
|
||||
testCompile "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"
|
||||
testRuntime "org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}"
|
||||
testRuntime "org.junit.platform:junit-platform-commons:${junitPlatformVersion}"
|
||||
testRuntime "org.junit.platform:junit-platform-launcher:${junitPlatformVersion}"
|
||||
|
||||
// To support JUnit 4 tests
|
||||
testRuntime "org.junit.vintage:junit-vintage-engine:${junitVintageVersion}"
|
||||
|
||||
// To avoid compiler warnings about @API annotations in JUnit code
|
||||
testCompileOnly 'org.apiguardian:apiguardian-api:1.0.0'
|
||||
|
||||
}
|
||||
|
||||
// enable all compiler warnings; individual projects may customize further
|
||||
@@ -265,12 +281,15 @@ project('spring-rabbit-junit') {
|
||||
dependencies { // no spring-amqp dependencies allowed
|
||||
|
||||
compile "org.springframework:spring-core:$springVersion"
|
||||
compile "junit:junit:$junitVersion"
|
||||
compile "junit:junit:$junit4Version"
|
||||
compile "com.rabbitmq:amqp-client:$rabbitmqVersion"
|
||||
compile ("com.rabbitmq:http-client:$rabbitmqHttpClientVersion") {
|
||||
exclude group: 'org.springframework', module: 'spring-web'
|
||||
}
|
||||
compile "org.springframework:spring-web:$springVersion"
|
||||
compile "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"
|
||||
compile "org.junit.platform:junit-platform-commons:${junitPlatformVersion}"
|
||||
compileOnly 'org.apiguardian:apiguardian-api:1.0.0'
|
||||
|
||||
}
|
||||
|
||||
@@ -282,7 +301,7 @@ project('spring-rabbit-test') {
|
||||
dependencies {
|
||||
|
||||
compile project(":spring-rabbit")
|
||||
compile ("junit:junit:$junitVersion") {
|
||||
compile ("junit:junit:$junit4Version") {
|
||||
exclude group: 'org.hamcrest', module: 'hamcrest-core'
|
||||
}
|
||||
compile "org.hamcrest:hamcrest-all:$hamcrestVersion"
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.amqp.rabbit.junit;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -367,38 +369,8 @@ public final class BrokerRunning extends TestWatcher {
|
||||
Channel channel = null;
|
||||
|
||||
try {
|
||||
connection = connectionFactory.newConnection();
|
||||
connection.setId(generateId());
|
||||
channel = connection.createChannel();
|
||||
|
||||
for (String queueName : this.queues) {
|
||||
|
||||
if (this.purge) {
|
||||
logger.debug("Deleting queue: " + queueName);
|
||||
// Delete completely - gets rid of consumers and bindings as well
|
||||
channel.queueDelete(queueName);
|
||||
}
|
||||
|
||||
if (isDefaultQueue(queueName)) {
|
||||
// Just for test probe.
|
||||
channel.queueDelete(queueName);
|
||||
}
|
||||
else {
|
||||
channel.queueDeclare(queueName, true, false, false, null);
|
||||
}
|
||||
}
|
||||
brokerOffline.put(this.port, false);
|
||||
if (!this.assumeOnline) {
|
||||
Assume.assumeTrue(brokerOffline.get(this.port));
|
||||
}
|
||||
|
||||
if (this.management) {
|
||||
Client client = new Client(getAdminUri(), this.adminUser, this.adminPassword);
|
||||
if (!client.alivenessTest("/")) {
|
||||
throw new RuntimeException("Aliveness test failed for localhost:15672 guest/quest; "
|
||||
+ "management not available");
|
||||
}
|
||||
}
|
||||
connection = getConnection(connectionFactory);
|
||||
channel = createQueues(connection);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.warn("Not executing tests because basic connectivity test failed: " + e.getMessage());
|
||||
@@ -419,7 +391,59 @@ public final class BrokerRunning extends TestWatcher {
|
||||
return super.apply(base, description);
|
||||
}
|
||||
|
||||
private boolean fatal() {
|
||||
public void isUp() throws Exception {
|
||||
Connection connection = getConnectionFactory().newConnection();
|
||||
Channel channel = null;
|
||||
try {
|
||||
channel = createQueues(connection);
|
||||
}
|
||||
finally {
|
||||
closeResources(connection, channel);
|
||||
}
|
||||
}
|
||||
|
||||
private Connection getConnection(ConnectionFactory connectionFactory) throws IOException, TimeoutException {
|
||||
Connection connection = connectionFactory.newConnection();
|
||||
connection.setId(generateId());
|
||||
return connection;
|
||||
}
|
||||
|
||||
private Channel createQueues(Connection connection) throws IOException, MalformedURLException, URISyntaxException {
|
||||
Channel channel;
|
||||
channel = connection.createChannel();
|
||||
|
||||
for (String queueName : this.queues) {
|
||||
|
||||
if (this.purge) {
|
||||
logger.debug("Deleting queue: " + queueName);
|
||||
// Delete completely - gets rid of consumers and bindings as well
|
||||
channel.queueDelete(queueName);
|
||||
}
|
||||
|
||||
if (isDefaultQueue(queueName)) {
|
||||
// Just for test probe.
|
||||
channel.queueDelete(queueName);
|
||||
}
|
||||
else {
|
||||
channel.queueDeclare(queueName, true, false, false, null);
|
||||
}
|
||||
}
|
||||
brokerOffline.put(this.port, false);
|
||||
if (!this.assumeOnline) {
|
||||
Assume.assumeTrue(brokerOffline.get(this.port));
|
||||
}
|
||||
|
||||
if (this.management) {
|
||||
Client client = new Client(getAdminUri(), this.adminUser, this.adminPassword);
|
||||
if (!client.alivenessTest("/")) {
|
||||
throw new RuntimeException("Aliveness test failed for localhost:15672 guest/quest; "
|
||||
+ "management not available");
|
||||
}
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
public static boolean fatal() {
|
||||
String serversRequired = System.getenv(BROKER_REQUIRED);
|
||||
if (Boolean.parseBoolean(serversRequired)) {
|
||||
logger.error("RABBITMQ IS REQUIRED BUT NOT AVAILABLE");
|
||||
@@ -465,7 +489,7 @@ public final class BrokerRunning extends TestWatcher {
|
||||
Channel channel = null;
|
||||
|
||||
try {
|
||||
connection = connectionFactory.newConnection();
|
||||
connection = getConnection(connectionFactory);
|
||||
connection.setId(generateId() + ".queueDelete");
|
||||
channel = connection.createChannel();
|
||||
|
||||
@@ -491,7 +515,7 @@ public final class BrokerRunning extends TestWatcher {
|
||||
Channel channel = null;
|
||||
|
||||
try {
|
||||
connection = connectionFactory.newConnection();
|
||||
connection = getConnection(connectionFactory);
|
||||
connection.setId(generateId() + ".queueDelete");
|
||||
channel = connection.createChannel();
|
||||
|
||||
@@ -517,7 +541,7 @@ public final class BrokerRunning extends TestWatcher {
|
||||
Channel channel = null;
|
||||
|
||||
try {
|
||||
connection = connectionFactory.newConnection();
|
||||
connection = getConnection(connectionFactory);
|
||||
connection.setId(generateId() + ".exchangeDelete");
|
||||
channel = connection.createChannel();
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2017 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.amqp.rabbit.junit;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* Test classes annotated with this will not run if an environment variable or system
|
||||
* property (default {@code RUN_LONG_INTEGRATION_TESTS}) is not present or does not have
|
||||
* the value that {@link Boolean#parseBoolean(String)} evaluates to {@code true}.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.0.2
|
||||
*
|
||||
*/
|
||||
@ExtendWith(LongRunningIntegrationTestCondition.class)
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface LongRunning {
|
||||
|
||||
/**
|
||||
* The name of the variable/property used to determine whether long runnning tests
|
||||
* should run.
|
||||
* @return the name of the variable/property.
|
||||
*/
|
||||
String value() default LongRunningIntegrationTest.RUN_LONG_INTEGRATION_TESTS;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2017 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.
|
||||
@@ -36,12 +36,21 @@ public class LongRunningIntegrationTest extends TestWatcher {
|
||||
|
||||
private final static Log logger = LogFactory.getLog(LongRunningIntegrationTest.class);
|
||||
|
||||
private static final String RUN_LONG_PROP = "RUN_LONG_INTEGRATION_TESTS";
|
||||
public static final String RUN_LONG_INTEGRATION_TESTS = "RUN_LONG_INTEGRATION_TESTS";
|
||||
|
||||
private boolean shouldRun = false;
|
||||
|
||||
public LongRunningIntegrationTest() {
|
||||
for (String value: new String[] { System.getenv(RUN_LONG_PROP), System.getProperty(RUN_LONG_PROP) }) {
|
||||
this(RUN_LONG_INTEGRATION_TESTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check using a custom variable/property name.
|
||||
* @param property the variable/property name.
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public LongRunningIntegrationTest(String property) {
|
||||
for (String value: new String[] { System.getenv(property), System.getProperty(property) }) {
|
||||
if (Boolean.parseBoolean(value)) {
|
||||
this.shouldRun = true;
|
||||
break;
|
||||
@@ -58,4 +67,12 @@ public class LongRunningIntegrationTest extends TestWatcher {
|
||||
return super.apply(base, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the test should run.
|
||||
* @return true to run.
|
||||
*/
|
||||
public boolean isShouldRun() {
|
||||
return this.shouldRun;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2017 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.amqp.rabbit.junit;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.platform.commons.util.AnnotationUtils;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ExecutionCondition} to skip long running tests unless an environment
|
||||
* variable or property is set.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.0.2
|
||||
* @see LongRunning
|
||||
*/
|
||||
public class LongRunningIntegrationTestCondition implements ExecutionCondition {
|
||||
|
||||
private static final ConditionEvaluationResult ENABLED = ConditionEvaluationResult.enabled(
|
||||
"@LongRunning is not present");
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
Optional<AnnotatedElement> element = context.getElement();
|
||||
Optional<LongRunning> longRunning = AnnotationUtils.findAnnotation(element, LongRunning.class);
|
||||
if (longRunning.isPresent()) {
|
||||
String property = longRunning.get().value();
|
||||
if (!StringUtils.hasText(property)) {
|
||||
property = LongRunningIntegrationTest.RUN_LONG_INTEGRATION_TESTS;
|
||||
}
|
||||
LongRunningIntegrationTest lrit = new LongRunningIntegrationTest(property);
|
||||
return lrit.isShouldRun() ? ConditionEvaluationResult.enabled("Long running tests must run")
|
||||
: ConditionEvaluationResult.disabled("Long running tests are skipped");
|
||||
}
|
||||
return ENABLED;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2017 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.amqp.rabbit.junit;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* Test classes annotated with this will not run if there is no broker on localhost.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.0.2
|
||||
*
|
||||
*/
|
||||
@ExtendWith(RabbitAvailableCondition.class)
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RabbitAvailable {
|
||||
|
||||
/**
|
||||
* The queues to create and ensure empty; they will be deleted after the test class
|
||||
* completes.
|
||||
* @return the queues.
|
||||
*/
|
||||
String[] queues() default {};
|
||||
|
||||
/**
|
||||
* Requires the management plugin to be available.
|
||||
* @return true to require a management plugin.
|
||||
*/
|
||||
boolean management() default false;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2017 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.amqp.rabbit.junit;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback;
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext.Store;
|
||||
import org.junit.jupiter.api.extension.ParameterContext;
|
||||
import org.junit.jupiter.api.extension.ParameterResolutionException;
|
||||
import org.junit.jupiter.api.extension.ParameterResolver;
|
||||
import org.junit.platform.commons.util.AnnotationUtils;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* JUnit5 {@link ExecutionCondition}.
|
||||
* Looks for {@code @RabbitAvailable} annotated classes and disables
|
||||
* if found the broker is not available.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 2.0.2
|
||||
*
|
||||
*/
|
||||
public class RabbitAvailableCondition implements ExecutionCondition, AfterAllCallback, ParameterResolver {
|
||||
|
||||
private static final ConditionEvaluationResult ENABLED = ConditionEvaluationResult.enabled(
|
||||
"@RabbitAvailable is not present");
|
||||
|
||||
private static final ThreadLocal<BrokerRunning> brokerRunningHolder = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
Optional<AnnotatedElement> element = context.getElement();
|
||||
Optional<RabbitAvailable> rabbit = AnnotationUtils.findAnnotation(element, RabbitAvailable.class);
|
||||
if (rabbit.isPresent()) {
|
||||
try {
|
||||
String[] queues = rabbit.get().queues();
|
||||
BrokerRunning brokerRunning = getStore(context).get("brokerRunning", BrokerRunning.class);
|
||||
if (brokerRunning == null) {
|
||||
if (rabbit.get().management()) {
|
||||
brokerRunning = BrokerRunning.isBrokerAndManagementRunningWithEmptyQueues(queues);
|
||||
}
|
||||
else {
|
||||
brokerRunning = BrokerRunning.isRunningWithEmptyQueues(queues);
|
||||
}
|
||||
}
|
||||
brokerRunning.isUp();
|
||||
brokerRunningHolder.set(brokerRunning);
|
||||
Store store = getStore(context);
|
||||
store.put("brokerRunning", brokerRunning);
|
||||
store.put("queuesToDelete", queues);
|
||||
return ConditionEvaluationResult.enabled("RabbitMQ is available");
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (BrokerRunning.fatal()) {
|
||||
throw new IllegalStateException("Required RabbitMQ is not available");
|
||||
}
|
||||
return ConditionEvaluationResult.disabled("RabbitMQ is not available");
|
||||
}
|
||||
}
|
||||
return ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll(ExtensionContext context) throws Exception {
|
||||
brokerRunningHolder.remove();
|
||||
Store store = getStore(context);
|
||||
BrokerRunning brokerRunning = store.remove("brokerRunning", BrokerRunning.class);
|
||||
if (brokerRunning != null) {
|
||||
brokerRunning.removeTestQueues();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
|
||||
throws ParameterResolutionException {
|
||||
Class<?> type = parameterContext.getParameter().getType();
|
||||
return type.equals(ConnectionFactory.class) || type.equals(BrokerRunning.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext context)
|
||||
throws ParameterResolutionException {
|
||||
// in parent for method injection, Composite key causes a store miss
|
||||
BrokerRunning brokerRunning =
|
||||
getParentStore(context).get("brokerRunning", BrokerRunning.class) == null
|
||||
? getStore(context).get("brokerRunning", BrokerRunning.class)
|
||||
: getParentStore(context).get("brokerRunning", BrokerRunning.class);
|
||||
Assert.state(brokerRunning != null, "Could not find brokerRunning instance");
|
||||
Class<?> type = parameterContext.getParameter().getType();
|
||||
return type.equals(ConnectionFactory.class) ? brokerRunning.getConnectionFactory()
|
||||
: brokerRunning;
|
||||
}
|
||||
|
||||
private Store getStore(ExtensionContext context) {
|
||||
return context.getStore(Namespace.create(getClass(), context));
|
||||
}
|
||||
|
||||
private Store getParentStore(ExtensionContext context) {
|
||||
ExtensionContext parent = context.getParent().get();
|
||||
return parent.getStore(Namespace.create(getClass(), parent));
|
||||
}
|
||||
|
||||
public static BrokerRunning getBrokerRunning() {
|
||||
return brokerRunningHolder.get();
|
||||
}
|
||||
|
||||
}
|
||||
15
spring-rabbit-junit/src/main/resources/log4j2-test.xml
Normal file
15
spring-rabbit-junit/src/main/resources/log4j2-test.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration>
|
||||
<Appenders>
|
||||
<Console name="STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d %5p %c [%t] : %m%n" />
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="org.springframework.amqp.rabbit" level="info"/>
|
||||
<Logger name="org.springframework.beans.factory" level="info"/>
|
||||
<Root level="info">
|
||||
<AppenderRef ref="STDOUT" />
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2017 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.amqp.rabbit.junit;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0.2
|
||||
*
|
||||
*/
|
||||
@LongRunning("LongRunningIntegrationTestsConditionTests")
|
||||
public class LongRunningIntegrationTestsConditionTests {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2017 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.amqp.rabbit.junit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.rabbitmq.client.AMQP.Queue.DeclareOk;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0.2
|
||||
*
|
||||
*/
|
||||
@RabbitAvailable(queues = "rabbitAvailableTests.queue")
|
||||
public class RabbitAvailableCTORInjectionTests {
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
|
||||
public RabbitAvailableCTORInjectionTests(BrokerRunning brokerRunning) {
|
||||
this.connectionFactory = brokerRunning.getConnectionFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test(ConnectionFactory cf) throws Exception {
|
||||
assertSame(cf, this.connectionFactory);
|
||||
Connection conn = this.connectionFactory.newConnection();
|
||||
Channel channel = conn.createChannel();
|
||||
DeclareOk declareOk = channel.queueDeclarePassive("rabbitAvailableTests.queue");
|
||||
assertEquals(0, declareOk.getConsumerCount());
|
||||
channel.close();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2017 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.amqp.rabbit.junit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.rabbitmq.client.AMQP.Queue.DeclareOk;
|
||||
import com.rabbitmq.client.Channel;
|
||||
import com.rabbitmq.client.Connection;
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.0.2
|
||||
*
|
||||
*/
|
||||
@RabbitAvailable(queues = "rabbitAvailableTests.queue")
|
||||
public class RabbitAvailableTests {
|
||||
|
||||
@Test
|
||||
public void test(ConnectionFactory connectionFactory) throws Exception {
|
||||
Connection conn = connectionFactory.newConnection();
|
||||
Channel channel = conn.createChannel();
|
||||
DeclareOk declareOk = channel.queueDeclarePassive("rabbitAvailableTests.queue");
|
||||
assertEquals(0, declareOk.getConsumerCount());
|
||||
channel.close();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,10 +18,7 @@ package org.springframework.amqp.rabbit.core;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.amqp.core.Message;
|
||||
import org.springframework.amqp.core.MessagePostProcessor;
|
||||
@@ -30,30 +27,31 @@ import org.springframework.amqp.rabbit.annotation.EnableRabbit;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.junit.BrokerRunning;
|
||||
import org.springframework.amqp.rabbit.junit.RabbitAvailable;
|
||||
import org.springframework.amqp.rabbit.junit.RabbitAvailableCondition;
|
||||
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 1.7.6
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@RabbitAvailable(queues = {
|
||||
RabbitTemplateMPPIntegrationTests.QUEUE,
|
||||
RabbitTemplateMPPIntegrationTests.REPLIES })
|
||||
@SpringJUnitConfig
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
public class RabbitTemplateMPPIntegrationTests {
|
||||
|
||||
private static final String QUEUE = "mpp.tests";
|
||||
public static final String QUEUE = "mpp.tests";
|
||||
|
||||
private static final String REPLIES = "mpp.tests.replies";
|
||||
|
||||
@ClassRule
|
||||
public static BrokerRunning brokerIsRunning = BrokerRunning.isRunningWithEmptyQueues(QUEUE, REPLIES);
|
||||
public static final String REPLIES = "mpp.tests.replies";
|
||||
|
||||
@Autowired
|
||||
private RabbitTemplate template;
|
||||
@@ -61,11 +59,6 @@ public class RabbitTemplateMPPIntegrationTests {
|
||||
@Autowired
|
||||
private Config config;
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
brokerIsRunning.removeTestQueues();
|
||||
}
|
||||
|
||||
@Test // 2.0.x only
|
||||
public void testMPPsAppliedDirectReplyToContainerTests() {
|
||||
this.template.sendAndReceive(new Message("foo".getBytes(), new MessageProperties()));
|
||||
@@ -119,7 +112,8 @@ public class RabbitTemplateMPPIntegrationTests {
|
||||
|
||||
@Bean
|
||||
public CachingConnectionFactory cf() {
|
||||
return new CachingConnectionFactory(brokerIsRunning.getConnectionFactory());
|
||||
return new CachingConnectionFactory(RabbitAvailableCondition.getBrokerRunning()
|
||||
.getConnectionFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -23,40 +23,40 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.amqp.core.MessageListener;
|
||||
import org.springframework.amqp.core.Queue;
|
||||
import org.springframework.amqp.rabbit.connection.SingleConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.core.RabbitAdmin;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.amqp.rabbit.junit.BrokerRunning;
|
||||
import org.springframework.amqp.rabbit.junit.LongRunningIntegrationTest;
|
||||
import org.springframework.amqp.rabbit.junit.LongRunning;
|
||||
import org.springframework.amqp.rabbit.junit.RabbitAvailable;
|
||||
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.amqp.utils.test.TestUtils;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.rabbitmq.client.ConnectionFactory;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 1.2.1
|
||||
*
|
||||
*/
|
||||
@RabbitAvailable(queues = SimpleMessageListenerContainerLongTests.QUEUE)
|
||||
@LongRunning
|
||||
public class SimpleMessageListenerContainerLongTests {
|
||||
|
||||
public static final String QUEUE = "SimpleMessageListenerContainerLongTests.queue";
|
||||
|
||||
private final Log logger = LogFactory.getLog(SimpleMessageListenerContainerLongTests.class);
|
||||
|
||||
@Rule
|
||||
public LongRunningIntegrationTest longTest = new LongRunningIntegrationTest();
|
||||
private final SingleConnectionFactory connectionFactory;
|
||||
|
||||
@Rule
|
||||
public BrokerRunning brokerRunning = BrokerRunning.isRunningWithEmptyQueues("foo");
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
this.brokerRunning.removeTestQueues();
|
||||
public SimpleMessageListenerContainerLongTests(ConnectionFactory connectionFactory) {
|
||||
this.connectionFactory = new SingleConnectionFactory(connectionFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -70,11 +70,11 @@ public class SimpleMessageListenerContainerLongTests {
|
||||
}
|
||||
|
||||
private void testChangeConsumerCountGuts(boolean transacted) throws Exception {
|
||||
final SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory("localhost");
|
||||
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(singleConnectionFactory);
|
||||
SimpleMessageListenerContainer container =
|
||||
new SimpleMessageListenerContainer(this.connectionFactory);
|
||||
try {
|
||||
container.setMessageListener(new MessageListenerAdapter(this));
|
||||
container.setQueueNames("foo");
|
||||
container.setQueueNames(QUEUE);
|
||||
container.setAutoStartup(false);
|
||||
container.setConcurrentConsumers(2);
|
||||
container.setChannelTransacted(transacted);
|
||||
@@ -85,9 +85,9 @@ public class SimpleMessageListenerContainerLongTests {
|
||||
container.setConcurrentConsumers(1);
|
||||
waitForNConsumers(container, 1);
|
||||
container.setMaxConcurrentConsumers(3);
|
||||
RabbitTemplate template = new RabbitTemplate(singleConnectionFactory);
|
||||
RabbitTemplate template = new RabbitTemplate(this.connectionFactory);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
template.convertAndSend("foo", "foo");
|
||||
template.convertAndSend(QUEUE, "foo");
|
||||
}
|
||||
waitForNConsumers(container, 2); // increased consumers due to work
|
||||
waitForNConsumers(container, 1, 20000); // should stop the extra consumer after 10 seconds idle
|
||||
@@ -95,7 +95,7 @@ public class SimpleMessageListenerContainerLongTests {
|
||||
waitForNConsumers(container, 3);
|
||||
container.stop();
|
||||
waitForNConsumers(container, 0);
|
||||
singleConnectionFactory.destroy();
|
||||
this.connectionFactory.destroy();
|
||||
}
|
||||
finally {
|
||||
container.stop();
|
||||
@@ -104,13 +104,13 @@ public class SimpleMessageListenerContainerLongTests {
|
||||
|
||||
@Test
|
||||
public void testAddQueuesAndStartInCycle() throws Exception {
|
||||
final SingleConnectionFactory connectionFactory = new SingleConnectionFactory("localhost");
|
||||
final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
|
||||
final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(
|
||||
this.connectionFactory);
|
||||
container.setMessageListener((MessageListener) message -> { });
|
||||
container.setConcurrentConsumers(2);
|
||||
container.afterPropertiesSet();
|
||||
|
||||
RabbitAdmin admin = new RabbitAdmin(connectionFactory);
|
||||
RabbitAdmin admin = new RabbitAdmin(this.connectionFactory);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Queue queue = new Queue("testAddQueuesAndStartInCycle" + i);
|
||||
admin.declareQueue(queue);
|
||||
|
||||
@@ -4569,7 +4569,8 @@ The default retry properties (3 retries at 5 second intervals) can be overridden
|
||||
a| image::images/tickmark.png[]
|
||||
a| image::images/tickmark.png[]
|
||||
|
||||
| possibleAuthenticationFailureFatal
|
||||
| possibleAuthentication
|
||||
FailureFatal
|
||||
(possible-authentication-failure-fatal)
|
||||
|
||||
a| When set to `true` (default), if a `PossibleAuthenticationFailureException` is thrown during connection, it is considered fatal.
|
||||
@@ -4587,7 +4588,10 @@ You can also use a properties bean to set the property globally for all containe
|
||||
[source,xml]
|
||||
----
|
||||
<util:properties id="spring.amqp.global.properties">
|
||||
<prop key="mlc.possible.authentication.failure.fatal">false</prop>
|
||||
<prop
|
||||
key="mlc.possible.authentication.failure.fatal">
|
||||
false
|
||||
</prop>
|
||||
</util:properties>
|
||||
----
|
||||
|
||||
@@ -4750,7 +4754,8 @@ a| image::images/tickmark.png[]
|
||||
a| image::images/tickmark.png[]
|
||||
a| image::images/tickmark.png[]
|
||||
|
||||
| afterReceivePostProcessors
|
||||
| afterReceive
|
||||
PostProcessors
|
||||
(N/A)
|
||||
|
||||
| An array of `MessagePostProcessor` s which are invoked, before invoking the listener.
|
||||
@@ -4955,7 +4960,8 @@ The `deliveryMode` (or any other properties) can be changed in the `additionalHe
|
||||
RepublishMessageRecoverer recoverer = new RepublishMessageRecoverer(amqpTemplate, "error") {
|
||||
|
||||
protected Map<? extends String, ? extends Object> additionalHeaders(Message message, Throwable cause) {
|
||||
message.getMessageProperties().setDeliveryMode(message.getMessageProperties().getReceivedDeliveryMode());
|
||||
message.getMessageProperties()
|
||||
.setDeliveryMode(message.getMessageProperties().getReceivedDeliveryMode());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -278,112 +278,113 @@ Here is a simple test case that uses the template:
|
||||
@RunWith(SpringRunner.class)
|
||||
public class TestRabbitTemplateTests {
|
||||
|
||||
@Autowired
|
||||
private TestRabbitTemplate template;
|
||||
@Autowired
|
||||
private TestRabbitTemplate template;
|
||||
|
||||
@Autowired
|
||||
private Config config;
|
||||
@Autowired
|
||||
private Config config;
|
||||
|
||||
@Test
|
||||
public void testSimpleSends() {
|
||||
this.template.convertAndSend("foo", "hello1");
|
||||
assertThat(this.config.fooIn, equalTo("foo:hello1"));
|
||||
this.template.convertAndSend("bar", "hello2");
|
||||
assertThat(this.config.barIn, equalTo("bar:hello2"));
|
||||
assertThat(this.config.smlc1In, equalTo("smlc1:"));
|
||||
this.template.convertAndSend("foo", "hello3");
|
||||
assertThat(this.config.fooIn, equalTo("foo:hello1"));
|
||||
this.template.convertAndSend("bar", "hello4");
|
||||
assertThat(this.config.barIn, equalTo("bar:hello2"));
|
||||
assertThat(this.config.smlc1In, equalTo("smlc1:hello3hello4"));
|
||||
@Test
|
||||
public void testSimpleSends() {
|
||||
this.template.convertAndSend("foo", "hello1");
|
||||
assertThat(this.config.fooIn, equalTo("foo:hello1"));
|
||||
this.template.convertAndSend("bar", "hello2");
|
||||
assertThat(this.config.barIn, equalTo("bar:hello2"));
|
||||
assertThat(this.config.smlc1In, equalTo("smlc1:"));
|
||||
this.template.convertAndSend("foo", "hello3");
|
||||
assertThat(this.config.fooIn, equalTo("foo:hello1"));
|
||||
this.template.convertAndSend("bar", "hello4");
|
||||
assertThat(this.config.barIn, equalTo("bar:hello2"));
|
||||
assertThat(this.config.smlc1In, equalTo("smlc1:hello3hello4"));
|
||||
|
||||
this.template.setBroadcast(true);
|
||||
this.template.convertAndSend("foo", "hello5");
|
||||
assertThat(this.config.fooIn, equalTo("foo:hello1foo:hello5"));
|
||||
this.template.convertAndSend("bar", "hello6");
|
||||
assertThat(this.config.barIn, equalTo("bar:hello2bar:hello6"));
|
||||
assertThat(this.config.smlc1In, equalTo("smlc1:hello3hello4hello5hello6"));
|
||||
}
|
||||
this.template.setBroadcast(true);
|
||||
this.template.convertAndSend("foo", "hello5");
|
||||
assertThat(this.config.fooIn, equalTo("foo:hello1foo:hello5"));
|
||||
this.template.convertAndSend("bar", "hello6");
|
||||
assertThat(this.config.barIn, equalTo("bar:hello2bar:hello6"));
|
||||
assertThat(this.config.smlc1In, equalTo("smlc1:hello3hello4hello5hello6"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendAndReceive() {
|
||||
assertThat(this.template.convertSendAndReceive("baz", "hello"), equalTo("baz:hello"));
|
||||
}
|
||||
@Test
|
||||
public void testSendAndReceive() {
|
||||
assertThat(this.template.convertSendAndReceive("baz", "hello"), equalTo("baz:hello"));
|
||||
}
|
||||
----
|
||||
[source, java]
|
||||
----
|
||||
@Configuration
|
||||
@EnableRabbit
|
||||
public static class Config {
|
||||
@Configuration
|
||||
@EnableRabbit
|
||||
public static class Config {
|
||||
|
||||
public String fooIn = "";
|
||||
public String fooIn = "";
|
||||
|
||||
public String barIn = "";
|
||||
public String barIn = "";
|
||||
|
||||
public String smlc1In = "smlc1:";
|
||||
public String smlc1In = "smlc1:";
|
||||
|
||||
@Bean
|
||||
public TestRabbitTemplate template() throws IOException {
|
||||
return new TestRabbitTemplate(connectionFactory());
|
||||
}
|
||||
@Bean
|
||||
public TestRabbitTemplate template() throws IOException {
|
||||
return new TestRabbitTemplate(connectionFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConnectionFactory connectionFactory() throws IOException {
|
||||
ConnectionFactory factory = mock(ConnectionFactory.class);
|
||||
Connection connection = mock(Connection.class);
|
||||
Channel channel = mock(Channel.class);
|
||||
willReturn(connection).given(factory).createConnection();
|
||||
willReturn(channel).given(connection).createChannel(anyBoolean());
|
||||
given(channel.isOpen()).willReturn(true);
|
||||
return factory;
|
||||
}
|
||||
@Bean
|
||||
public ConnectionFactory connectionFactory() throws IOException {
|
||||
ConnectionFactory factory = mock(ConnectionFactory.class);
|
||||
Connection connection = mock(Connection.class);
|
||||
Channel channel = mock(Channel.class);
|
||||
willReturn(connection).given(factory).createConnection();
|
||||
willReturn(channel).given(connection).createChannel(anyBoolean());
|
||||
given(channel.isOpen()).willReturn(true);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() throws IOException {
|
||||
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
|
||||
factory.setConnectionFactory(connectionFactory());
|
||||
return factory;
|
||||
}
|
||||
@Bean
|
||||
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() throws IOException {
|
||||
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
|
||||
factory.setConnectionFactory(connectionFactory());
|
||||
return factory;
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "foo")
|
||||
public void foo(String in) {
|
||||
this.fooIn += "foo:" + in;
|
||||
}
|
||||
@RabbitListener(queues = "foo")
|
||||
public void foo(String in) {
|
||||
this.fooIn += "foo:" + in;
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "bar")
|
||||
public void bar(String in) {
|
||||
this.barIn += "bar:" + in;
|
||||
}
|
||||
@RabbitListener(queues = "bar")
|
||||
public void bar(String in) {
|
||||
this.barIn += "bar:" + in;
|
||||
}
|
||||
|
||||
@RabbitListener(queues = "baz")
|
||||
public String baz(String in) {
|
||||
return "baz:" + in;
|
||||
}
|
||||
@RabbitListener(queues = "baz")
|
||||
public String baz(String in) {
|
||||
return "baz:" + in;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleMessageListenerContainer smlc1() throws IOException {
|
||||
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
|
||||
container.setQueueNames("foo", "bar");
|
||||
container.setMessageListener(new MessageListenerAdapter(new Object() {
|
||||
@Bean
|
||||
public SimpleMessageListenerContainer smlc1() throws IOException {
|
||||
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
|
||||
container.setQueueNames("foo", "bar");
|
||||
container.setMessageListener(new MessageListenerAdapter(new Object() {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void handleMessage(String in) {
|
||||
smlc1In += in;
|
||||
}
|
||||
@SuppressWarnings("unused")
|
||||
public void handleMessage(String in) {
|
||||
smlc1In += in;
|
||||
}
|
||||
|
||||
}));
|
||||
return container;
|
||||
}
|
||||
}));
|
||||
return container;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
[[junit-rules]]
|
||||
==== JUnit @Rules
|
||||
[[junit4-rules]]
|
||||
==== JUnit4 @Rules
|
||||
|
||||
Spring AMQP _version 1.7_ provides an additional jar `spring-rabbit-junit`; this jar contains a couple of utility `@Rule` s for use when running JUnit tests.
|
||||
Spring AMQP _version 1.7_ and later provide an additional jar `spring-rabbit-junit`; this jar contains a couple of utility `@Rule` s for use when running JUnit4 tests.
|
||||
See <<junit5-conditions>> for JUnit5 testing.
|
||||
|
||||
===== BrokerRunning
|
||||
|
||||
@@ -407,6 +408,7 @@ public static void tearDown() {
|
||||
|
||||
There are several `isRunning...` static methods such as `isBrokerAndManagementRunning()` which verifies the broker has the management plugin enabled.
|
||||
|
||||
[[brokerRunning-configure]]
|
||||
====== Configuring the Rule
|
||||
|
||||
There are times when you want tests to fail if there is no broker, such as a nightly CI build.
|
||||
@@ -485,3 +487,159 @@ public LongRunningIntegrationTest longTests = new LongRunningIntegrationTest();
|
||||
----
|
||||
|
||||
To disable the rule at runtime, set an environment variable `RUN_LONG_INTEGRATION_TESTS` to `true`.
|
||||
|
||||
[[junit5-conditions]]
|
||||
==== JUnit5 Conditions
|
||||
|
||||
Version _2.0.2_ introduced support for JUnit5.
|
||||
|
||||
===== @RabbitAvailable Annotation
|
||||
|
||||
This class-level annotation is similar to the `BrokerRunning` `@Rule` discussed in <<junit4-rules>>; it is processed by the `RabbitAvailableCondition`.
|
||||
|
||||
The annotation has two properties:
|
||||
|
||||
* `queues` - an array of queues that will be declared (and purged) before each test and deleted when all tests are complete.
|
||||
* `management` - set to `true` if your tests also require the management plugin installed on the broker.
|
||||
|
||||
It is used to check if the broker is available and skip the tests if not.
|
||||
As discussed in <<brokerRunning-configure>> the environment variable `RABBITMQ_SERVER_REQUIRED`, if `true` will cause the tests to fail fast if there is no broker.
|
||||
The condition can be configured using environment variables as discussed in <<brokerRunning-configure>>.
|
||||
|
||||
In addition, the `RabbitAvailableCondition` supports argument resolution for parameterized test constructors and methods.
|
||||
Two argument types are supported `BrokerRunning` (the instance) and `ConnectionFactory` - the `BrokerRunning` 's RabbitMQ connection factory.
|
||||
|
||||
Here is an example of each:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@RabbitAvailable(queues = "rabbitAvailableTests.queue")
|
||||
public class RabbitAvailableCTORInjectionTests {
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
|
||||
public RabbitAvailableCTORInjectionTests(BrokerRunning brokerRunning) {
|
||||
this.connectionFactory = brokerRunning.getConnectionFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test(ConnectionFactory cf) throws Exception {
|
||||
assertSame(cf, this.connectionFactory);
|
||||
Connection conn = this.connectionFactory.newConnection();
|
||||
Channel channel = conn.createChannel();
|
||||
DeclareOk declareOk = channel.queueDeclarePassive("rabbitAvailableTests.queue");
|
||||
assertEquals(0, declareOk.getConsumerCount());
|
||||
channel.close();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
This test is in the framework itself and verifies the argument injection and that the condition created the queue properly.
|
||||
|
||||
A practical user test might be:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@RabbitAvailable(queues = "rabbitAvailableTests.queue")
|
||||
public class RabbitAvailableCTORInjectionTests {
|
||||
|
||||
private final CachingConnectionFactory connectionFactory;
|
||||
|
||||
public RabbitAvailableCTORInjectionTests(BrokerRunning brokerRunning) {
|
||||
this.connectionFactory =
|
||||
new CachingConnectionFactory(brokerRunning.getConnectionFactory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
RabbitTemplate template = new RabbitTemplate(this.connectionFactory);
|
||||
...
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
When using a Spring annotation application context within a test class, it is also possible to get a reference to the condition's connection factory via a static method `RabbitAvailableCondition.getBrokerRunning()`.
|
||||
Here is another test from the framework that demonstrates the usage:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@RabbitAvailable(queues = {
|
||||
RabbitTemplateMPPIntegrationTests.QUEUE,
|
||||
RabbitTemplateMPPIntegrationTests.REPLIES })
|
||||
@SpringJUnitConfig
|
||||
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||
public class RabbitTemplateMPPIntegrationTests {
|
||||
|
||||
public static final String QUEUE = "mpp.tests";
|
||||
|
||||
public static final String REPLIES = "mpp.tests.replies";
|
||||
|
||||
@Autowired
|
||||
private RabbitTemplate template;
|
||||
|
||||
@Autowired
|
||||
private Config config;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
...
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableRabbit
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public CachingConnectionFactory cf() {
|
||||
return new CachingConnectionFactory(RabbitAvailableCondition
|
||||
.getBrokerRunning()
|
||||
.getConnectionFactory());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RabbitTemplate template() {
|
||||
|
||||
...
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleRabbitListenerContainerFactory
|
||||
rabbitListenerContainerFactory() {
|
||||
|
||||
...
|
||||
|
||||
}
|
||||
|
||||
@RabbitListener(queues = QUEUE)
|
||||
public byte[] foo(byte[] in) {
|
||||
return in;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
===== @LongRunning Annotation
|
||||
|
||||
Similar to the `LongRunningIntegrationTest` JUnit4 `@Rule`, this annotation causes tests to be skipped unless an environment variable (or system property) is set to `true`.
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@RabbitAvailable(queues = SimpleMessageListenerContainerLongTests.QUEUE)
|
||||
@LongRunning
|
||||
public class SimpleMessageListenerContainerLongTests {
|
||||
|
||||
public static final String QUEUE = "SimpleMessageListenerContainerLongTests.queue";
|
||||
|
||||
...
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
By default, the variable is `RUN_LONG_INTEGRATION_TESTS` but the variable name can be specified in the annotation's `value` attribute.
|
||||
|
||||
Reference in New Issue
Block a user