In this blog post I am going to demonstrate How to write a WSO2 ESB integration test with JMS Broker. so I am going to write a test class to test the functionality of the JMS proxy service behavior.
In this scenario we have to do following steps to test the functionality.
1) Starting a JMS broker(ActiveMQ)
2) Changing the axis2.xml to enable JMS transport in ESB
3) Copy activemq-core-5.7.0.jar, geronimo-j2ee-management_1.1_spec-1.0.1.jar to $WSO2_ESB_HOME/repository/components/lib.
4) Starting ESB Server
5) Deploying the proxy service
6) Sending messages to the destination queue for proxy service to consume.
First you have to find the place to put your test class. so go to the "platform/branches/x.x.x/products/esb/x.x.x/modules/integration/tests" as your ESB product version. tests module is the place where we write the integration tests.
then find the package named "org.wso2.carbon.esb.jms.transport.test". This is the best place to put your JMS related test classes. Because there is a class named "JMSBrokerStartupTestCase" which reduced above 1, 2 , 3 and 4 steps from your test class. Otherwise you have to write the codes for above 3 steps also your test class itself.
Since JMSBrokerStartupTestCase will look after the 1, 2 , 3 and 4 steps, you need to focus on your test scenario only and It will save your time.
JMSBrokerStartupTestCase has two methods running under @BeforeTest() annotation. So those methods execute before and after the all other test executions of the test classes in jms.transport package.so It will reduce the time takes to execute all test classes. because no need to repeat the JMS broker startup and ESB configuration within your test classes when writing and running.
package org.wso2.carbon.esb.jms.transport.test;
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.wso2.carbon.automation.core.ProductConstant;
import org.wso2.carbon.automation.core.utils.environmentutils.EnvironmentBuilder;
import org.wso2.carbon.automation.core.utils.environmentutils.EnvironmentVariables;
import org.wso2.carbon.automation.core.utils.jmsbrokerutils.controller.JMSBrokerController;
import org.wso2.carbon.automation.core.utils.jmsbrokerutils.controller.config.JMSBrokerConfiguration;
import org.wso2.carbon.automation.core.utils.jmsbrokerutils.controller.config.JMSBrokerConfigurationProvider;
import org.wso2.carbon.automation.core.utils.serverutils.ServerConfigurationManager;
import java.io.File;
public class JMSBrokerStartupTestCase {
private EnvironmentBuilder builder = null;
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";
@BeforeTest(alwaysRun = true)
public void startJMSBroker() throws Exception {
builder = new EnvironmentBuilder().esb(ProductConstant.ADMIN_USER_ID);
EnvironmentVariables esbServer = builder.build().getEsb();
serverManager = new ServerConfigurationManager(esbServer.getBackEndUrl());
if (builder.getFrameworkSettings().getEnvironmentSettings()
.is_builderEnabled()) {
//starting jms broker
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(ProductConstant.getResourceLocations(ProductConstant.ESB_SERVER_NAME)
+ File.separator + "jar" + File.separator + ACTIVEMQ_CORE));
serverManager.copyToComponentLib(new File(ProductConstant.getResourceLocations(ProductConstant.ESB_SERVER_NAME)
+ File.separator + "jar" + File.separator + GERONIMO_J2EE_MANAGEMENT));
serverManager.copyToComponentLib(new File(ProductConstant.getResourceLocations(ProductConstant.ESB_SERVER_NAME)
+ File.separator + "jar" + File.separator + GERONIMO_JMS));
//enabling jms transport with ActiveMQ by copping axis2.xml in resource directory and restarting ESB server
serverManager.applyConfiguration(new File(ProductConstant.getResourceLocations(ProductConstant.ESB_SERVER_NAME)
+ File.separator + "jms" + File.separator + "transport"
+ File.separator + "axis2config" + File.separator
+ "activemq" + File.separator + "axis2.xml"));
}
}
@AfterTest(alwaysRun = true)
public void stopJMSBroker() throws Exception {
if (builder.getFrameworkSettings().getEnvironmentSettings().is_builderEnabled()) {
try {
//reverting the changes done to esb sever
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 test, Automation framework start a Embedded ActiveMQ Broker and do the necessary ESB server configuration.
Now we have JMS transport enabled ESB server and ActiveMQ JMS broker up and running in our machine.
Then we see how to automate our test scenario. only need to do the steps 5 and 6.
as steps 5 , I am going to deploy the bellow proxy service.
<?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>
So I save above file as jms_transport_proxy_service.xml in the directory /artifacts/ESB/jms/transport under test resource directory.
Then add a test class as mentioned bellow.
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.core.utils.jmsbrokerutils.client.JMSQueueMessageConsumer; import org.wso2.carbon.automation.core.utils.jmsbrokerutils.client.JMSQueueMessageProducer; import org.wso2.carbon.automation.core.utils.jmsbrokerutils.controller.config.JMSBrokerConfigurationProvider; import org.wso2.carbon.esb.ESBIntegrationTest; import org.wso2.carbon.esb.util.JMSEndpointManager; public class JMSTransportProxyTestCase extends ESBIntegrationTest { @BeforeClass(alwaysRun = true) public void deployeService() throws Exception { super.init(); OMElement synapse = esbUtils.loadClasspathResource("/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
UndeployeService() throws Exception { super.cleanup(); } }
In this test class you can see 3 methods
1) deployeService() under @BeforeClass Annotation
This will set JMS endpoint(if needed) and deploy the your proxy service
2) testJMSProxy() under @Test Annotation
This will send a message to the destination queue and wait for proxy service to consume the message. then check the message is available in the destination queue. if it is not available, proxy service is working fine. it dequeue the message from the queue.
3) UndeployeService() under @AfterClass Annotation
This will undeploy the proxy service deployed
An important method you can see in deployeService() method
JMSEndpointManager.setConfigurations(synapse);
What does JMSEndpointManager does ?
As above step 1, I mentioned ActiveMQ broker is used as the JMS Broker. ActiveMQ Broker is used only when running test under integration environment. (Product building time by maven.). when we moved to platform test that means servers are supposed to up and running with proper configuration(you can set test to run in platform environment by setting properties in automation.properties file under resource directory)
Then your test classes run with WSO2 MB as the JMS Broker instead of AcitveMQ Embedded broker started by framework. (You have to start a MB server as well). JMSEndpointManager will replace the endpoint details in your synapse configuration as for the WSO2 MB broker.
It will replace bellow in synapse configuration if only 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 above synapse configuration, above replacement not happened because of no JMS endpoint defined in synapse configuration
Other important this is that, if your test class to run with WSO2 MB, Proxy service destination queue uri also changed. If WSO2 ESB to work with WSO2 MB you need to defined any queue or topic you defined in your synapse configuration or queue of JMS in proxy jndi.properties file in $WSO2_ESB_HOME/repository/conf directory.
Refer http://docs.wso2.org/wiki/display/MB201/Integrating+WSO2+ESB for more details for ESB and MB Integartion
So we have already added a resource file in artifacts/ESB/jms/transport/jndi.properties under test resource directory. you must add the queue or topic you used into jndi.properties. When we run a test in platform environment, we can easily copy that file into ESB and run our test without any issue. That also keep in mind when writing JMS related test.
# 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 we have finished writing the scenario. Then we need to verify the test class can be executed and the test scenario is working fine without any failure.
To enable test classes to run , you need to add entry in testng.xml(can be found in resource directory) as well.
To Run all the classes in 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 single class. You need to defined JMSBrokerStartupTestCase as well. Because it is the class which start the JMS broker and configure ESB Server in 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>
Then issuing mvn clean install will run the test classes as the testng.xml.
If the test configuration as bellow, test class is executed with ActiveMQ broker
execution.environment=integration
builder.enable=true
or test class is executed with WSO2 MB Broker if you set it to bellow
execution.environment=platform
builder.enable=false
Now I think you have got a idea how to write a JMS related ESB integration test.
Like above, You can add lots of test classes to test the JMS related test scenario.
Note: Useful JMS client classes provided by Automation Framework to ease your work.
1)org.wso2.carbon.automation.core.utils.jmsbrokerutils.client.JMSQueueMessageConsumer
To Consume messages from a Queue
2)org.wso2.carbon.automation.core.utils.jmsbrokerutils.client.JMSQueueMessageProducer
To send messages to a Queue
3)org.wso2.carbon.automation.core.utils.jmsbrokerutils.client.JMSTopicMessageConsumer
To Consume messages from a Topic
4)org.wso2.carbon.automation.core.utils.jmsbrokerutils.client.JMSTopicMessagePublisher
To publish messages to a Topic
No comments:
Post a Comment