ibm-messaging / mq-jms-spring

Components to assist MQ JMS integration with Spring frameworks
Apache License 2.0
190 stars 102 forks source link

Embedded / Integration Testing Support #23

Closed jameschensmith closed 5 years ago

jameschensmith commented 5 years ago

This is more of a question, which may lead to a request. It is quite difficult to do JMS testing with IBM MQ. I find this spring boot dependency extremely useful, but during testing the application chooses to connect to IBM MQ instead of a broker with embedded support like AMQ.

Looking for a way to test JMS classes, either embedded or integration testing against, say, a docker container spun up when the test is triggered.

ibmmqmet commented 5 years ago

The default configuration inside the Spring Boot module is designed to match that within the MQ Docker container for developers - client connection to localhost(1414), qmgr is QM1 - specifically to make it easy to do testing.

mballoni commented 5 years ago

For testing I was using an embedded activemq, since my application was using "just" the JMS contract, this way I could execute it without the need for a docker environment (client limitations). Take a look at this example:

https://github.com/mballoni/springboot-mqseries

Pay attention for the exclude configuration at the test properties file.

ibmmqmet commented 5 years ago

Answered.

vmhaskar1 commented 4 years ago

If I try using "MQ Docker container for developers", however I am getting exactly same issue as that mentioned by james-r-smith on April 9th 2019 in my spring boot code. Any idea how this issues was solved/closed ? I am stuck totally..

I am running MQ on docker within Ububtu in VMbox. Here is the docker command I used -

sudo docker run --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --publish 1414:1414 --publish 9443:9443 --detach ibmcom/mq

I get below error, when I try to put message ->

vinay@vinay-VirtualBox:~$ sudo docker run -p 8084:8084 mqspring

. _ _ /\ / '_ () \ \ \ \ ( ( )\ | ' | '| | ' \/ ` | \ \ \ \ \/ _)| |)| | | | | || (| | ) ) ) ) ' |__| .|| ||| |\, | / / / / =========|_|==============|__/=//// :: Spring Boot :: (v2.2.6.RELEASE)

2020-03-27 15:29:22.429 INFO 1 --- [ main] c.example.mqspring.MqspringApplication : Starting MqspringApplication v0.0.1-SNAPSHOT on 59c59e3c5ce5 with PID 1 (/mqspring-0.0.1-SNAPSHOT.jar started by root in /) 2020-03-27 15:29:22.434 INFO 1 --- [ main] c.example.mqspring.MqspringApplication : No active profile set, falling back to default profiles: default 2020-03-27 15:29:26.366 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8084 (http) 2020-03-27 15:29:26.437 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-03-27 15:29:26.438 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33] 2020-03-27 15:29:26.703 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-03-27 15:29:26.704 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4024 ms 2020-03-27 15:29:28.834 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-03-27 15:29:29.523 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8084 (http) with context path '' 2020-03-27 15:29:29.532 INFO 1 --- [ main] c.example.mqspring.MqspringApplication : Started MqspringApplication in 8.263 seconds (JVM running for 9.95) 2020-03-27 15:30:16.388 INFO 1 --- [nio-8084-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2020-03-27 15:30:16.388 INFO 1 --- [nio-8084-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2020-03-27 15:30:16.415 INFO 1 --- [nio-8084-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 27 ms org.springframework.jms.IllegalStateException: JMSWMQ0018: Failed to connect to queue manager 'QM1' with connection mode 'Client' and host name 'localhost(1414)'.; nested exception is com.ibm.msg.client.jms.DetailedIllegalStateException: JMSWMQ0018: Failed to connect to queue manager 'QM1' with connection mode 'Client' and host name 'localhost(1414)'. Check the queue manager is started and if running in client mode, check there is a listener running. Please see the linked exception for more information.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2538' ('MQRC_HOST_NOT_AVAILABLE'). at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:274) at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:185) at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:507)

Having simple Spring Boot application - with below POM -> <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.6.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mqspring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mqspring</name>
<description>Demo project for Spring Boot</description>

<properties>
    <java.version>1.8</java.version>
    <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>com.ibm.mq</groupId>
        <artifactId>mq-jms-spring-boot-starter</artifactId>
        <version>2.0.0</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

samirm commented 4 years ago

@vmhaskar1 I'm getting the same error on my machine. Were you able to figure it out? Thanks.

Manfred73 commented 2 years ago

Issue is closed, but how was this solved or is there a workaround?

I'm having a component which deals with messaging, and now added mq-jms-spring-boot-starter to connect to IBM MQ using ssl truststore and keystore. This is working fine after adding my own MQConfigurationProperties bean as @Primary (as shown in this example: https://myshittycode.com/2019/04/23/spring-boot-connecting-to-ibm-mq-over-jms-using-non-ibm-jre/).

My existing integration tests which use ActiveMQ now fail and I'm unable to use docker for this (not allowed at client). Is there a way to still use ActiveMQ (or some other embedded mq) without having to use docker?

Manfred73 commented 2 years ago

Update:

Looking at the source code I found there is an MQAutoConfiguration class which tries to configure MQ on startup of the application.

Stackoverflow mentions you can add spring.autoconfigure.exclude=com.ibm.mq.spring.boot.MQAutoConfiguration to your application.properties or yaml, but this only worked for me if I added it to application.yaml and not if I added it to application-test.yaml. That's not desireable, since I do want to use mq when the application is run normally, only not for integration tests with SpringBootTest.

A better solution I found at baeldung was to add the following annotation to the SpringBootTest class, excluding the MQAutoConfiguration.class: @EnableAutoConfiguration(exclude=MQAutoConfiguration.class)

This way Spring doesn't configure MQ at startup and you can just include spring active mq depencency with scope test. Your SpringBootTest will than work again using active mq instead of mq.

mballoni commented 2 years ago

In order to make spring use the application-test.yaml you need to set "test" as an active profile. I may have a working example for your use case I did a few years ago when I was using this library:

https://github.com/mballoni/springboot-mqseries

Manfred73 commented 2 years ago

Tried out a few things and I think I did set "test" as active profile, but note entirely sure anymore. Could be that it was commented out when trying some things. But I found the solution I have now using the @EnableAutoConfiguration to be working fine and I don't need to have a separate test profile for that.