/*
* Copyright 2012-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.boot.autoconfigure.jms.artemis;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;
import org.apache.activemq.artemis.jms.server.config.TopicConfiguration;
import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;
import org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;
import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.SessionCallback;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.DynamicDestinationResolver;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ArtemisAutoConfiguration}.
*
* @author EddĂș MelĂ©ndez
* @author Stephane Nicoll
*/
public class ArtemisAutoConfigurationTests {
@Rule
public final TemporaryFolder folder = new TemporaryFolder();
private AnnotationConfigApplicationContext context;
@After
public void tearDown() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void nativeConnectionFactory() {
load(EmptyConfiguration.class, "spring.artemis.mode:native");
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertThat(connectionFactory).isEqualTo(jmsTemplate.getConnectionFactory());
assertNettyConnectionFactory(connectionFactory, "localhost", 61616);
assertThat(connectionFactory.getUser()).isNull();
assertThat(connectionFactory.getPassword()).isNull();
}
@Test
public void nativeConnectionFactoryCustomHost() {
load(EmptyConfiguration.class, "spring.artemis.mode:native",
"spring.artemis.host:192.168.1.144", "spring.artemis.port:9876");
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertNettyConnectionFactory(connectionFactory, "192.168.1.144", 9876);
}
@Test
public void nativeConnectionFactoryCredentials() {
load(EmptyConfiguration.class, "spring.artemis.mode:native",
"spring.artemis.user:user", "spring.artemis.password:secret");
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertThat(connectionFactory).isEqualTo(jmsTemplate.getConnectionFactory());
assertNettyConnectionFactory(connectionFactory, "localhost", 61616);
assertThat(connectionFactory.getUser()).isEqualTo("user");
assertThat(connectionFactory.getPassword()).isEqualTo("secret");
}
@Test
public void embeddedConnectionFactory() {
load(EmptyConfiguration.class, "spring.artemis.mode:embedded");
ArtemisProperties properties = this.context.getBean(ArtemisProperties.class);
assertThat(properties.getMode()).isEqualTo(ArtemisMode.EMBEDDED);
assertThat(this.context.getBeansOfType(EmbeddedJMS.class)).hasSize(1);
org.apache.activemq.artemis.core.config.Configuration configuration = this.context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse();
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
}
@Test
public void embeddedConnectionFactoryByDefault() {
// No mode is specified
load(EmptyConfiguration.class);
assertThat(this.context.getBeansOfType(EmbeddedJMS.class)).hasSize(1);
org.apache.activemq.artemis.core.config.Configuration configuration = this.context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.isPersistenceEnabled()).isFalse();
assertThat(configuration.isSecurityEnabled()).isFalse();
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
}
@Test
public void nativeConnectionFactoryIfEmbeddedServiceDisabledExplicitly() {
// No mode is specified
load(EmptyConfiguration.class, "spring.artemis.embedded.enabled:false");
assertThat(this.context.getBeansOfType(EmbeddedJMS.class)).isEmpty();
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertNettyConnectionFactory(connectionFactory, "localhost", 61616);
}
@Test
public void embeddedConnectionFactoryEvenIfEmbeddedServiceDisabled() {
// No mode is specified
load(EmptyConfiguration.class, "spring.artemis.mode:embedded",
"spring.artemis.embedded.enabled:false");
assertThat(this.context.getBeansOfType(EmbeddedJMS.class)).isEmpty();
ActiveMQConnectionFactory connectionFactory = this.context
.getBean(ActiveMQConnectionFactory.class);
assertInVmConnectionFactory(connectionFactory);
}
@Test
public void embeddedServerWithDestinations() {
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue1,Queue2",
"spring.artemis.embedded.topics=Topic1");
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("Queue1", true);
checker.checkQueue("Queue2", true);
checker.checkQueue("QueueWillNotBeAutoCreated", true);
checker.checkTopic("Topic1", true);
checker.checkTopic("TopicWillBeAutoCreated", true);
}
@Test
public void embeddedServerWithDestinationConfig() {
load(DestinationConfiguration.class);
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("sampleQueue", true);
checker.checkTopic("sampleTopic", true);
}
@Test
public void embeddedServiceWithCustomJmsConfiguration() {
// Ignored with custom config
load(CustomJmsConfiguration.class,
"spring.artemis.embedded.queues=Queue1,Queue2");
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("custom", true); // See CustomJmsConfiguration
checker.checkQueue("Queue1", true);
checker.checkQueue("Queue2", true);
}
@Test
public void embeddedServiceWithCustomArtemisConfiguration() {
load(CustomArtemisConfiguration.class);
org.apache.activemq.artemis.core.config.Configuration configuration = this.context
.getBean(org.apache.activemq.artemis.core.config.Configuration.class);
assertThat(configuration.getName()).isEqualTo("customFooBar");
}
@Test
public void embeddedWithPersistentMode() throws IOException, JMSException {
File dataFolder = this.folder.newFolder();
// Start the server and post a message to some queue
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=TestQueue",
"spring.artemis.embedded.persistent:true",
"spring.artemis.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
final String msgId = UUID.randomUUID().toString();
JmsTemplate jmsTemplate = this.context.getBean(JmsTemplate.class);
jmsTemplate.send("TestQueue", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(msgId);
}
});
this.context.close(); // Shutdown the broker
// Start the server again and check if our message is still here
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=TestQueue",
"spring.artemis.embedded.persistent:true",
"spring.artemis.embedded.dataDirectory:" + dataFolder.getAbsolutePath());
JmsTemplate jmsTemplate2 = this.context.getBean(JmsTemplate.class);
jmsTemplate2.setReceiveTimeout(1000L);
Message message = jmsTemplate2.receive("TestQueue");
assertThat(message).isNotNull();
assertThat(((TextMessage) message).getText()).isEqualTo(msgId);
}
@Test
public void severalEmbeddedBrokers() {
load(EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue1");
AnnotationConfigApplicationContext anotherContext = doLoad(
EmptyConfiguration.class, "spring.artemis.embedded.queues=Queue2");
try {
ArtemisProperties properties = this.context.getBean(ArtemisProperties.class);
ArtemisProperties anotherProperties = anotherContext
.getBean(ArtemisProperties.class);
assertThat(properties.getEmbedded().getServerId() < anotherProperties
.getEmbedded().getServerId()).isTrue();
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("Queue1", true);
checker.checkQueue("Queue2", true);
DestinationChecker anotherChecker = new DestinationChecker(anotherContext);
anotherChecker.checkQueue("Queue2", true);
anotherChecker.checkQueue("Queue1", true);
}
finally {
anotherContext.close();
}
}
@Test
public void connectToASpecificEmbeddedBroker() {
load(EmptyConfiguration.class, "spring.artemis.embedded.serverId=93",
"spring.artemis.embedded.queues=Queue1");
AnnotationConfigApplicationContext anotherContext = doLoad(
EmptyConfiguration.class, "spring.artemis.mode=embedded",
"spring.artemis.embedded.serverId=93", // Connect to the "main" broker
"spring.artemis.embedded.enabled=false"); // do not start a specific one
try {
DestinationChecker checker = new DestinationChecker(this.context);
checker.checkQueue("Queue1", true);
DestinationChecker anotherChecker = new DestinationChecker(anotherContext);
anotherChecker.checkQueue("Queue1", true);
}
finally {
anotherContext.close();
}
}
private TransportConfiguration assertInVmConnectionFactory(
ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration transportConfig = getSingleTransportConfiguration(
connectionFactory);
assertThat(transportConfig.getFactoryClassName())
.isEqualTo(InVMConnectorFactory.class.getName());
return transportConfig;
}
private TransportConfiguration assertNettyConnectionFactory(
ActiveMQConnectionFactory connectionFactory, String host, int port) {
TransportConfiguration transportConfig = getSingleTransportConfiguration(
connectionFactory);
assertThat(transportConfig.getFactoryClassName())
.isEqualTo(NettyConnectorFactory.class.getName());
assertThat(transportConfig.getParams().get("host")).isEqualTo(host);
assertThat(transportConfig.getParams().get("port")).isEqualTo(port);
return transportConfig;
}
private TransportConfiguration getSingleTransportConfiguration(
ActiveMQConnectionFactory connectionFactory) {
TransportConfiguration[] transportConfigurations = connectionFactory
.getServerLocator().getStaticTransportConfigurations();
assertThat(transportConfigurations.length).isEqualTo(1);
return transportConfigurations[0];
}
private void load(Class<?> config, String... environment) {
this.context = doLoad(config, environment);
}
private AnnotationConfigApplicationContext doLoad(Class<?> config,
String... environment) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(config);
applicationContext.register(ArtemisAutoConfiguration.class,
JmsAutoConfiguration.class);
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
applicationContext.refresh();
return applicationContext;
}
private final static class DestinationChecker {
private final JmsTemplate jmsTemplate;
private final DestinationResolver destinationResolver;
private DestinationChecker(ApplicationContext applicationContext) {
this.jmsTemplate = applicationContext.getBean(JmsTemplate.class);
this.destinationResolver = new DynamicDestinationResolver();
}
public void checkQueue(String name, boolean shouldExist) {
checkDestination(name, false, shouldExist);
}
public void checkTopic(String name, boolean shouldExist) {
checkDestination(name, true, shouldExist);
}
public void checkDestination(final String name, final boolean pubSub,
final boolean shouldExist) {
this.jmsTemplate.execute(new SessionCallback<Void>() {
@Override
public Void doInJms(Session session) throws JMSException {
try {
Destination destination = DestinationChecker.this.destinationResolver
.resolveDestinationName(session, name, pubSub);
if (!shouldExist) {
throw new IllegalStateException("Destination '" + name
+ "' was not expected but got " + destination);
}
}
catch (JMSException e) {
if (shouldExist) {
throw new IllegalStateException("Destination '" + name
+ "' was expected but got " + e.getMessage());
}
}
return null;
}
});
}
}
@Configuration
protected static class EmptyConfiguration {
}
@Configuration
protected static class DestinationConfiguration {
@Bean
JMSQueueConfiguration sampleQueueConfiguration() {
JMSQueueConfigurationImpl jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName("sampleQueue");
jmsQueueConfiguration.setSelector("foo=bar");
jmsQueueConfiguration.setDurable(false);
jmsQueueConfiguration.setBindings("/queue/1");
return jmsQueueConfiguration;
}
@Bean
TopicConfiguration sampleTopicConfiguration() {
TopicConfigurationImpl topicConfiguration = new TopicConfigurationImpl();
topicConfiguration.setName("sampleTopic");
topicConfiguration.setBindings("/topic/1");
return topicConfiguration;
}
}
@Configuration
protected static class CustomJmsConfiguration {
@Bean
public JMSConfiguration myJmsConfiguration() {
JMSConfiguration config = new JMSConfigurationImpl();
JMSQueueConfiguration jmsQueueConfiguration = new JMSQueueConfigurationImpl();
jmsQueueConfiguration.setName("custom");
jmsQueueConfiguration.setDurable(false);
config.getQueueConfigurations().add(jmsQueueConfiguration);
return config;
}
}
@Configuration
protected static class CustomArtemisConfiguration {
@Bean
public ArtemisConfigurationCustomizer myArtemisCustomize() {
return new ArtemisConfigurationCustomizer() {
@Override
public void customize(
org.apache.activemq.artemis.core.config.Configuration configuration) {
configuration.setClusterPassword("Foobar");
configuration.setName("customFooBar");
}
};
}
}
}