This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit https://wso2.com/documentation/.

Writing WSO2 ESB and JMS Integration Tests

This page demonstrates how to write a WSO2 ESB integration test using JMS Broker. The following example uses a test class to test the functionality of the JMS proxy service behaviour.

First, test the functionality by following the steps below:

  1. Start a JMS broker (ActiveMQ) session.
  2. Change the axis2.xml to enable JMS transport in ESB.
  3. Copy activemq-core-5.7.0.jar and geronimo-j2ee-management_1.1_spec-1.0.1.jar to $WSO2_ESB_HOME/repository/components/lib.
  4. Start the ESB server.
  5. Deploy the proxy service.
  6. Send messages to the destination queue for the proxy service to consume. 

Next, you need to decide where to place your test class. Depending on your ESB product version, go to platform/branches/x.x.x/products/esb/x.x.x/modules/integration/tests. The tests module is where the integration tests are written.

Find the org.wso2.carbon.esb.jms.transport.test package. This is the best place to put your JMS related test classes as the JMSBrokerStartupTestCase class takes care of steps 1-4 above. Therefore, you don't need to write any code for those steps within the test class itself, and can focus only on your test scenario.

The JMSBrokerStartupTestCase class has two methods running under @BeforeTest(). Those methods execute before and after all other test executions of the test classes in the jms.transport package and therefore, the JMS broker startup and ESB configuration do not need to be repeated within your test classes when running, thereby reducing the time taken to execute all test classes.
 
package org.wso2.carbon.esb.jms.transport.test;  
  
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import org.wso2.carbon.automation.engine.annotations.ExecutionEnvironment;
import org.wso2.carbon.automation.engine.annotations.SetEnvironment;
import org.wso2.carbon.automation.engine.context.AutomationContext;
import org.wso2.carbon.automation.engine.context.TestUserMode;
import org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSQueueMessageConsumer;
import org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSQueueMessageProducer;
import org.wso2.carbon.automation.extensions.servers.jmsserver.controller.JMSBrokerController;
import org.wso2.carbon.automation.extensions.servers.jmsserver.controller.config.JMSBrokerConfiguration;
import org.wso2.carbon.automation.extensions.servers.jmsserver.controller.config.JMSBrokerConfigurationProvider;
import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager;
import org.wso2.esb.integration.common.utils.ESBIntegrationTest;
import org.wso2.esb.integration.common.utils.common.TestConfigurationProvider;
import java.io.File;
public class JMSBrokerStartupTestCase extends ESBIntegrationTest {
    
    private JMSBrokerController activeMqBroker;
    private ServerConfigurationManager serverManager = null;
    private final String ACTIVEMQ_CORE = "activemq-core-5.2.0.jar";
    private final String GERONIMO_J2EE_MANAGEMENT = "geronimo-j2ee-management_1.1_spec-1.0.1.jar";
    private final String GERONIMO_JMS = "geronimo-jms_1.1_spec-1.1.1.jar";
    @SetEnvironment(executionEnvironments = {ExecutionEnvironment.STANDALONE})
    @BeforeTest(alwaysRun = true)
    public void startJMSBrokerAndConfigureESB() throws Exception {
        context = new AutomationContext("ESB", TestUserMode.SUPER_TENANT_ADMIN);
        serverManager = new ServerConfigurationManager(context);
        activeMqBroker = new JMSBrokerController("localhost", getJMSBrokerConfiguration());
        if (!JMSBrokerController.isBrokerStarted()) {
            Assert.assertTrue(activeMqBroker.start(), "JMS Broker(ActiveMQ) stating failed");
        }
        //copping dependency jms jar files to component/lib
        serverManager.copyToComponentLib(new File(TestConfigurationProvider.getResourceLocation() + File.separator + "artifacts" + File.separator 
                                                   + "ESB" + File.separator + "jar" + File.separator + ACTIVEMQ_CORE));
        serverManager.copyToComponentLib(new File(TestConfigurationProvider.getResourceLocation() + File.separator + "artifacts" + File.separator + "ESB"
                                                   + File.separator + "jar" + File.separator + GERONIMO_J2EE_MANAGEMENT));
        serverManager.copyToComponentLib(new File(TestConfigurationProvider.getResourceLocation() + File.separator + "artifacts" + File.separator + "ESB"
                                                  + File.separator + "jar" + File.separator + GERONIMO_JMS));
        //enabling jms transport with ActiveMQ
        serverManager.applyConfiguration(new File(TestConfigurationProvider.getResourceLocation() + File.separator + "artifacts" + File.separator + "ESB"
                                                  + File.separator + "jms" + File.separator + "transport"
                                                    + File.separator + "axis2config" + File.separator
                                                     + "activemq" + File.separator + "axis2.xml"));
    }
    @SetEnvironment(executionEnvironments = {ExecutionEnvironment.STANDALONE})
    @AfterTest(alwaysRun = true)
    public void stopJMSBrokerRevertESBConfiguration() throws Exception {
        try {
            //reverting the changes done to esb sever
            Thread.sleep(10000); //let server to clear the artifact undeployment
            if (serverManager != null) {
                serverManager.removeFromComponentLib(ACTIVEMQ_CORE);
                serverManager.removeFromComponentLib(GERONIMO_J2EE_MANAGEMENT);
                serverManager.removeFromComponentLib(GERONIMO_JMS);
                serverManager.restoreToLastConfiguration();
            }
        } finally {
            if (activeMqBroker != null) {
                Assert.assertTrue(activeMqBroker.stop(), "JMS Broker(ActiveMQ) Stopping failed");
            }
        }

    }
    private JMSBrokerConfiguration getJMSBrokerConfiguration() {
        return JMSBrokerConfigurationProvider.getInstance().getBrokerConfiguration();
    }
}

For integration tests, the Test Automation Framework starts an embedded ActiveMQ broker and does the necessary ESB server configuration.

Now you have the JMS transport enabled ESB server and ActiveMQ JMS broker up and running in the machine. To automate our test scenario, you only need to follow steps 5 and 6.

Following step 5, deploy the proxy service as below:

<?xml version="1.0" encoding="UTF-8"?>  
<definitions xmlns="http://ws.apache.org/ns/synapse">  
  <proxy name="JmsProxy" transports="jms" startOnLoad="true" trace="disable">  
    <target>  
      <inSequence>  
        <property action="set" name="OUT_ONLY" value="true"/>  
        <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>  
      </inSequence>  
      <endpoint>  
        <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>  
      </endpoint>  
      <outSequence>  
  
        <send/>  
      </outSequence>  
      <parameter name="transport.jms.ContentType">  
        <rules>  
          <jmsProperty>contentType</jmsProperty>  
          <default>application/xml</default>  
        </rules>  
      </parameter>  
    </target>  
  </proxy>  
  
  
</definitions>

Save the file above as jms_transport_proxy_service.xml under /artifacts/ESB/jms/transport under the test resource directory.

Add a test class as mentioned below:
 
package org.wso2.carbon.esb.jms.transport.test;
import org.apache.axiom.om.OMElement;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSQueueMessageConsumer;
import org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSQueueMessageProducer;
import org.wso2.carbon.automation.extensions.servers.jmsserver.controller.config.JMSBrokerConfigurationProvider;
import org.wso2.esb.integration.common.utils.ESBIntegrationTest;
import org.wso2.esb.integration.common.utils.JMSEndpointManager;


public class JMSTransportProxyTestCase extends ESBIntegrationTest {
    
@BeforeClass(alwaysRun = true)
    protected void init() throws Exception {
        super.init();
        OMElement synapse = esbUtils.loadResource("/artifacts/ESB/jms/transport/jms_transport_proxy_service.xml");
        updateESBConfiguration(JMSEndpointManager.setConfigurations(synapse));
    }
    @Test(groups = {"wso2.esb"}, description = "Test proxy service with jms transport")
    public void testJMSProxy() throws Exception {
        JMSQueueMessageProducer sender = new JMSQueueMessageProducer(JMSBrokerConfigurationProvider.getInstance().getBrokerConfiguration());
        String queueName = "JmsProxy";
        try {
            sender.connect(queueName);
            for (int i = 0; i < 3; i++) {
                sender.pushMessage("<?xml version='1.0' encoding='UTF-8'?>" +
                                   "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"" +
                                   " xmlns:ser=\"http://services.samples\" xmlns:xsd=\"http://services.samples/xsd\">" +
                                   "   <soapenv:Header/>" +
                                   "   <soapenv:Body>" +
                                   "      <ser:placeOrder>" +
                                   "         <ser:order>" +
                                   "            <xsd:price>100</xsd:price>" +
                                   "            <xsd:quantity>2000</xsd:quantity>" +
                                   "            <xsd:symbol>JMSTransport</xsd:symbol>" +
                                   "         </ser:order>" +
                                   "      </ser:placeOrder>" +
                                   "   </soapenv:Body>" +
                                   "</soapenv:Envelope>");
            }
        } finally {
            sender.disconnect();
        }
        Thread.sleep(10000);
        JMSQueueMessageConsumer consumer = new JMSQueueMessageConsumer(JMSBrokerConfigurationProvider.getInstance().getBrokerConfiguration());
        try {
            consumer.connect(queueName);
            for (int i = 0; i < 3; i++) {
                if (consumer.popMessage() != null) {
                    Assert.fail("JMS Proxy service failed to pick the messages from Queue");
                }
            }
        } finally {
            consumer.disconnect();
        }
    }

    @AfterClass(alwaysRun = true)
    public void destroy() throws Exception {
        super.cleanup();
    }
}

 In this test class, you can see 3 methods.

  1. deployeService() under @BeforeClass Annotation - This will set the JMS endpoint (if needed) and deploy your proxy service.
  2. testJMSProxy() under @Test Annotation - This will send a message to the destination queue and wait for the proxy service to consume the message. Check if the message is available in the destination queue. If it is not available, the proxy service is working fine and it dequeues the message from the queue.
  3. UndeployeService() under @AfterClass Annotation - This will undeploy the deployed proxy service.

An important method is the deployeService() method   

JMSEndpointManager.setConfigurations(synapse);

As mentioned in step 1 above, the ActiveMQ broker is used as the JMS Broker. The ActiveMQ Broker is used only when running tests under an integration environment (product building time by maven). When you move to a platform test that means that the servers are supposed to be up and running with the proper configuration (you can set the test to run in a platform environment by setting the properties in the automation.properties file under the Resource directory).

Then, your test classes run with WSO2 MB as the JMS Broker instead of the ActiveMQ embedded broker started by the framework (you have to start an MB server as well). JMSEndpointManager will replace the endpoint details in your synapse configuration as for the WSO2 MB broker. It will replace as below in the synapse configuration only if the execution.environment is defined as platform.

org.apache.activemq.jndi.ActiveMQInitialContextFactory >>> org.wso2.andes.jndi.PropertiesFileInitialContextFactory

tcp://127.0.0.1:61616 >>> repository/conf/jndi.properties

In the above synapse configuration, the replacement did not happen because there is no JMS endpoint defined in the synapse configuration.

If your test class runs with WSO2 MB, the proxy service destination queue URI is also changed. If WSO2 ESB is to work with WSO2 MB, you need to define any queue or topic you defined in your synapse configuration or queue of JMS, in the proxy jndi.properties file in the $WSO2_ESB_HOME/repository/conf directory.

For more details on ESB and MB integration, see Integrating WSO2 ESB.

You have already added a resource file in artifacts/ESB/jms/transport/jndi.properties under the test resource directory. You must add the queue or topic you used into jndi.properties. When you run a test in the platform environment, you can easily copy that file into ESB and run the test without any issue. Keep that in mind when writing JMS related tests as well.
 
# register some connection factories  
# connectionfactory.[jndiname] = [ConnectionURL]  
connectionfactory.QueueConnectionFactory = amqp://admin:admin@clientID/carbon?brokerlist='tcp://localhost:5676'  
connectionfactory.TopicConnectionFactory = amqp://admin:admin@clientID/carbon?brokerlist='tcp://localhost:5676'  
  
# register some queues in JNDI using the form  
# queue.[jndiName] = [physicalName]     
queue.JmsProxy = JmsProxy  
 
# register some topics in JNDI using the form  
# topic.[jndiName] = [physicalName]  
topic.TestTopic = TestTopic

Now you have finished writing the scenario. You need to verify that the test class can be executed and that the test scenario is working fine without any failure.

To enable test classes to run, you need to add an entry in the testng.xml (in the Resource directory) as well.

To run all the classes in the org.wso2.carbon.esb.jms.transport.test package:

<test name="jms-transport" preserve-order="true" verbose="2">  
    <packages> <package name="org.wso2.carbon.esb.jms.transport.test.*"/>  
    </packages>  
  </test>

To run a single class, you need to define the JMSBrokerStartupTestCase as well because it is the class which start the JMS broker and configures the ESB Server in the integration environment.

<test name="jms-transport" preserve-order="true" verbose="2">  
    <classes> <class name="org.wso2.carbon.esb.jms.transport.test.JMSBrokerStartupTestCase"/>  
      <class name="org.wso2.carbon.esb.jms.transport.test.JMSQueueAsProxyEndpointTestCase"/>  
    </classes>  
  </test>
 
 Issuing an MVN clean install will run the test classes as the testng.xml. If the test configuration is as below, the test class is executed with the ActiveMQ broker.

<executionEnvironment>standalone</executionEnvironment>

The test class is executed with WSO2 MB Broker if you set it as below:

<executionEnvironment>platform</executionEnvironment>

Similar to above, you can add many test classes to test the JMS related test scenario.

Useful JMS client classes are provided by Test Automation Framework:

  1. org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSQueueMessageConsumer - To consume messages from a queue.
  2. org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSQueueMessageProducer - To send messages to a queue.
  3. org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSTopicMessageConsumer - To consume messages from a topic.
  4. org.wso2.carbon.automation.extensions.servers.jmsserver.client.JMSTopicMessagePublisher - To publish messages to a topic.