Wednesday, May 1, 2013

How to write WSO2 ESB and JMS Integration Test

In the previous blogs post JMS Proxy Service using WSO2 ESB  we discussed about WSO2 ESB JMS transport and JMS proxy service. And the post How to  write a ESB Product Integration test we discussed about writing product integration test using WSO2 test Automation Framework.

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        


 

Thursday, April 25, 2013

Surefire maven plugging configuration for testng

The Surefire Plugin is used during the test phase of the build lifecycle to execute the unit tests of an application. once you write the test classes under test directory you can use following surefire configurations in pom.xml to run you test classes while building the source.


If you want to run all test classes which name end with TestCase


<build>  
     <plugins>  
       <plugin>  
         <artifactId>maven-surefire-plugin</artifactId>  
         <version>2.12.3</version>  
         <inherited>false</inherited>  
         <configuration>  
           <argLine>-Xms512m -Xmx1024m -XX:MaxPermSize=128m</argLine>  
           <testFailureIgnore>true</testFailureIgnore>  
           <disableXmlReport>false</disableXmlReport>  
           <parallel>false</parallel>  
           <includes>  
             <include>**/*TestCase.java</include>  
           </includes>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  

Other option is that you can create a test suite by defining test classes or test packages in a xml file called testng.xml


<build>  
     <plugins>  
       <plugin>  
         <artifactId>maven-surefire-plugin</artifactId>  
         <version>2.12.3</version>  
         <inherited>false</inherited>  
         <configuration>  
           <argLine>-Xms512m -Xmx1024m -XX:MaxPermSize=128m</argLine>  
           <testFailureIgnore>true</testFailureIgnore>  
           <disableXmlReport>false</disableXmlReport>  
           <parallel>false</parallel>  
           <suiteXmlFiles>  
             <suiteXmlFile>src/test/resources/testng1.xml</suiteXmlFile>  
           </suiteXmlFiles>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  

your testng.xml file should be defined as bellow. you can defined your test classes or or package to be run

<suite name="MyTestSuite" parallel="false">   
   <test name="Test1" preserve-order="true" verbose="2">   
    <classes>   
     <class name="com.test.MyTestClass1"/>  
     <class name="com.test.MyTestClass2"/>   
    </classes>   
   </test>   
  <test name="Test2" preserve-order="true" verbose="2">   
    <packages>   
     <package name="com.test.*"/>   
    </packages>   
   </test>   
  </suite>

JMS Proxy service using WSO2 ESB



WSO2 ESB is capable to communicate with JMS transport as well. In this blog post you can see how to configure a proxy service with JMS transport.

Please refer  How to enable ESB for JMS transport for ESB server configuration to work with ActiveMQ JMS Broker.

Bellow proxy service is expose via jms transport by defining the transports="jms". so deploy the proxy service in WSO2  ESB

 <proxy name="JmsProxy" transports="jms" startOnLoad="true" trace="disable">
        <target>
            <endpoint>
                <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
            </endpoint>
            <inSequence>
                <property name="OUT_ONLY" value="true"/>
                <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>
                <header name="Action" value="urn:placeOrder"/>
            </inSequence>
        </target>
        <parameter name="transport.jms.ContentType">
            <rules>
                <jmsProperty>contentType</jmsProperty>
                <default>text/xml</default>
            </rules>
        </parameter>
 </proxy>  

Once you deploy the above proxy service, you can see a queue named jmsProxy is created in JMS broker. then the proxy service is listening to the  jmsProxy queue. whatever a message is put into that queue, the proxy service pick the message from the queue and send it to the endpoint definded in the proxy service. as this proxy service message is route to the SimpleStockQuoteService.

if you want to test this proxy service, you can put a soap message in to the jmsProxy queue using a JMS client or you can create another http proxy service to put a message to the jmsProxy queue.

Bellow proxy service configuration is a http proxy service which route a incomming message to jms queue.

<proxy name="StockQuoteProxyToJMSQueue" transports="http" startOnLoad="true" trace="disable">  
     <description/>  
     <target>  
       <inSequence>  
         <property name="OUT_ONLY" value="true"/>  
         <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>  
         <send>  
           <endpoint>  
             <address  
                 uri="jms:/jmsProxy?transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory&amp;java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&amp;java.naming.provider.url=tcp://127.0.0.1:61616&amp;transport.jms.DestinationType=queue"/>  
           </endpoint>  
         </send>  
       </inSequence>  
     </target>  
   </proxy>  

 then you can send to soap message to StockQuoteProxyToJMSQueue proxy service. then it will put your message to jmsProxy queue. so jmsProxy service pick the message form the queue and send it the actual back end service running on a axis2 server.

 you can use soapui to send the message to http proxy

http://localhost:8282/services/StockQuoteProxyToJMSQueue

<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>20</xsd:price>    
       <xsd:quantity>1000</xsd:quantity>  
       <xsd:symbol>WSO2</xsd:symbol>  
      </ser:order>  
    </ser:placeOrder>  
   </soapenv:Body>  
 </soapenv:Envelope>  







How to send http messages to jms topic using WSO2 ESB Proxy Service


As the previous blog post How to send http messages to jms Queue using WSO2 ESB. WSO2  ESB has the capability to send messages to Queue in JMS broker. Now I am going to show you how to route the incomming message to  Topic in ActiveMQ JMS broker instead of a Queue using WSO2 ESB proxy service. That can be done easily by changing the endpoint configuration only.

Please refer How to send http messages to jms Queue using WSO2 ESB. for ESB server and ActiveMQ broker configurations for ESB to work with JMS Broker 

Bellow HTTP Proxy service is configured to route incomming message to the topic called TestTopic. Deploy the bellow proxy in WSO2 ESB


<proxy name="StockQuoteProxyToJMSTopic" transports="http" startOnLoad="true" trace="disable">  
     <description/>  
     <target>  
       <inSequence>  
         <property name="OUT_ONLY" value="true"/>  
         <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>  
         <send>  
           <endpoint>  
             <address  
                 uri="jms:/TestTopic?transport.jms.ConnectionFactoryJNDIName=TopicConnectionFactory&amp;java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&amp;java.naming.provider.url=tcp://127.0.0.1:61616&amp;transport.jms.DestinationType=topic"/>  
           </endpoint>  
         </send>  
       </inSequence>  
     </target>  
   </proxy>  

Since this is a one-way message, the property “OUT_ONLY” is set to true and “FORCE_SC_ACCEPTED” property is defined to send a 202 response to the client who invokes this proxy.

Once you send to a message to StockQuoteProxyToJMSTopic service via http transport, It will route your message to topic called TestTopic.




How to write WSO2 ESB Integration using WSO2 Test Automation Framework


Your First WSO2 ESB Integration test experience ....

This blog illustrate how to write a simple ESB Integration test class. Most of ESB Integration test is based on synapse configuration or synapse artifacts. so that try to write a test class to test proxy service deployment and undeployment. below is the synapse configuration we are going to test.


<?xml version="1.0" encoding="UTF-8"?>    
  <definitions xmlns="http://ws.apache.org/ns/synapse">    
   <proxy name="simpleProxy" transports="https http"  startOnLoad="true" trace="disable">  
    <target>    
     <inSequence>    
       <send>    
        <endpoint>  <address uri="http://localhost:9000/services/SimpleStockQuoteService" />  </endpoint>    
       </send>    
     </inSequence>    
     <outSequence>   <send />  </outSequence>    
    </target>    
   </proxy>    
  </definitions>  

above proxy service simple rout the incomming message to SimpleStockQuote service and get back the response to the client

Before writing the test case we have to make sure that there must be a ESB instance up and running. as well as another server which has a actual backend service running. Test Automation Framework look after all the preconditions which needed to run the test class successfully. Before running the test class, ESB server and axis2 server with SimpleStockQuoteService are started by framework using the testng listeners. and populate the users defined in userlist.csv(tenantlist.csv) files which are located in resources directory.


within the test class, we should focus on the test scenario only. you can start writing your tests in the following location according to your esb server version :

platform/branches/x.x.x/products/esb/x.x.x/modules/integration/tests

eg:
all the test classes are placed in one module called tests and found under integration module.

Then create a proper packaging and add a java class extending ESBIntegrationTest. then put the synapse configuration file in artifact/ESB under resources folder.

package org.wso2.carbon.esb.proxyservice.test.passThroughProxy;   
  import org.apache.axiom.om.OMElement;   
  import org.testng.annotations.AfterClass;   
  import org.testng.annotations.BeforeClass;   
  import org.testng.annotations.Test;   
  import org.wso2.carbon.esb.ESBIntegrationTest;   
  import javax.xml.namespace.QName;   
  import static org.testng.Assert.assertEquals;   
    
 public class ProxyServiceDeploymentTestCase extends ESBIntegrationTest {   
   @BeforeClass(alwaysRun = true)   
   public void deployService() throws Exception {   
    /* initializing server configuration with the user id 2*/   
    super.init(2);   
    /* deploying the artifact defined in the proxy_service.xml */   
    loadESBConfigurationFromClasspath( "/artifacts/ESB/proxyconfig/proxy/passThroughProxy/proxy_service.xml");   
   }   
   
   @Test(groups = "wso2.esb", description = "Pass through proxy service invocation test")   
   public void testPassThroughProxy() throws Exception {   
    /* invoking the proxy service and getting the response using a service client */   
    OMElement response = axis2Client.sendSimpleStockQuoteRequest(getProxyServiceURL("StockQuoteProxy"), null, "WSO2");   
    /* response assertions */   
    String symbol = response.getFirstElement().getFirstChildWithName(new QName("http://services.samples/xsd", "symbol"))  .getText();   
    assertEquals(symbol, "WSO2", "Fault: value 'symbol' mismatched");   
   }   
   
   @AfterClass(alwaysRun = true)   
   public void unDeployService() throws Exception {   
    /* undeploying deployed artifact */   
    super.cleanup();   
   }   
  }  


ESBIntegrationTest class abstract most of useful method for esb testing and once it is inherited it will ease your work by providing important features.

init(userid) will build the esb server configuration such as backend url, service url, etc.. and authenticate user which is defined in userlist.csv with the server and it is called under @BeforeClass(). then it will runs before all the test methods.

loadESBConfigurationFromClasspath("/artifacts/ESB/$path/synapse_config.xml") will deployed the artifact defined in the file(proxy, endpoints, sequence, message store, etc..) using admin services. it go through the configuration and deployed artifact one by one. if the same artifact name is already in the system, it is deleted and new one is deployed.

getProxyServiceURL("StockQuoteProxy") will returns the proxy service url http

cleanup() will undeploye the deployed artifact and it is called under @AfterClass(). then it will runs after all the test methods.

Above flow will executes your test scenario clearly and if any exception thrown an assertion failure happens, it will indicate as a test failure.

as above we can write lot of test cases and there are more other utility methods provided by automation framework.

to run the test class you have to add your test classes in testng.xml( can be found under resources directory)

 <test name="first-test" preserve-order="true" verbose="2">   
   <classes>   
    <class name="org.wso2.carbon.esb.proxyservice.test.passThroughProxy.ProxyServiceDeploymentTestCase"/>   
   </classes>   
  </test> 

or you can add the all classes to run by adding package name
<test name="first-test" preserve-order="true" verbose="2">   
   <packages>   
    <package name="org.wso2.carbon.esb.proxyservice.test.passThroughProxy"/>   
   </packages>   
  </test>  

Then issuing mvn clean install execute your test classes and generated the reports in target/surefire-reports

Running Test on Different Environments....
Once you write a test case you can run that test case in different environments. Just need to change the property file called automation.properties (can be found under resources directory) and executing.  

Executing test on integration Environment as a user
By default test runs on the integration environment(while building the product from source) as a user . Setting builder.enable=true will handle the ESB and axis2 servers startups.
 stratos.test=false   
 #execution.environment = integration|platform|stratos   
 execution.environment=integration   
 #execution.mode = user|tenant|all   
 execution.mode=user   
 port.enable=true   
 carbon.web.context.enable=false   
 builder.enable=true 


Executing as a tenant
if you want to run the test as a tenant. setting below will execute the test as tenant.

 execution.mode=tenant   

Executing test on Platform Environment
if you want to run the test against the ESB instance already up and running, you can do it by changing the below properties as mentioned.

 execution.environment=platform  
 builder.enable=false  

once you change the execution environment to platform, you need to change the server configurations too.

 esb.host.name=192.168.1.10   
 esb.http.port=9763   
 esb.https.port=9443   
 esb.nhttp.port=8280   
 esb.nhttps.port=8243   
 #esb.webContext.root  

when execution environment is changed to platform, we host the actual backend services(which were available in axis2 server for integration environment) in WSO2 Application server. so AS configurations is also need to configure and server must be up and running.

 as.host.name=localhost   
 as.http.port=9763   
 as.https.port=9443   
 #as.webContext.root  

Executing test on stratos or cloud
if you want to run your test class against stratos, change setting as below. 

 stratos.test=true   
 execution.environment=stratos   
 execution.mode=tenant   
 cluster.enable=true  
 #Stratos server details   
 app.service.host.name=manager.appserver.stratoslive.wso2.com, appserver.stratoslive.wso2.com   
 esb.service.host.name=manager.esb.stratoslive.wso2.com,esb.stratoslive.wso2.com    
 manager.service.host.name=stratoslive.wso2.com


Friday, March 8, 2013

How to Run Jmeter test script(.jmx) using WSO2 Test Automation Framework

Most of time Jmeter tests are executed from Jmeter tool GUI. Once you want to execute a test script without Jmeter GUI, There is a option called Jmeter command-line arguments or you can find some maven plugging to do it.

 Test Automation Framework also provide the ability to execute the Jmeter test without GUI. This post help you to run Jmeter script programatically. Test Automation framework look after underline Jmeter test execution. It use the Jmeter command-line options to execute the test and initialize a jmeter in the target directory. No Jmeter installation is required to execute the test.

I have a jmeter script which tests the service list page of the WSO2 ESB. Script contains following requests

1) Go to login page
2) Authenticate using username and password
3) Go to List Services page
4) SingOut
 
Create a maven project with bellow dependency
<dependencies>  
     <dependency>  
       <groupId>org.testng</groupId>  
       <artifactId>testng</artifactId>  
       <version>6.1.1</version>  
     </dependency>  
     <dependency>  
       <groupId>org.wso2.carbon.automation</groupId>  
       <artifactId>org.wso2.carbon.automation.tools.jmeter</artifactId>  
       <version>4.0.8</version>  
     </dependency>  
   </dependencies>  

Create a testng test class to execute the test. You need to point out your .jmx file path
package com.test;  
 import org.testng.annotations.Test;  
 import org.wso2.automation.tools.jmeter.JMeterTest;  
 import org.wso2.automation.tools.jmeter.JMeterTestManager;  
 import java.io.File;  
 public class JMeterTestToListServicesTestCase {  
   @Test()  
   public void listServices() throws Exception {  
     JMeterTest script = new JMeterTest(  
         new File("/home/nuwanw/projects/JmeterIntegrationWithFramework" +  
              "/src/test/resource/jmeter/ESB-list-service.jmx"));  
     JMeterTestManager manager = new JMeterTestManager();  
     manager.runTest(script);  
   }  
 }  

Then you have added a test to execute the jmeter test.
Add following surefire configuration in the pom file to run test while building the project

<build>  
     <plugins>  
       <plugin>  
         <artifactId>maven-surefire-plugin</artifactId>  
         <version>2.12.3</version>  
         <inherited>false</inherited>  
         <configuration>  
           <argLine>-Xms512m -Xmx1024m -XX:MaxPermSize=128m</argLine>  
           <testFailureIgnore>true</testFailureIgnore>  
           <disableXmlReport>false</disableXmlReport>  
           <parallel>false</parallel>  
           <includes>  
             <include>**/*TestCase.java</include>  
           </includes>  
         </configuration>  
       </plugin>  
     </plugins>  
   </build>  

You can see the test result after building the project if thee is no failures
Results :  
 Tests run: 1, Failures: 0, Errors: 0, Skipped: 0  

Jmeter test executor generate a separate log file and report(.jtl) file for each and every test script executed. If you need any Further Result, go to target directory. Then there is a directory called jmeter. under jmeter directory you can find logs and reports directories. inside those directories you can see a .log files and .jtl files. log and report files are generated from you test script name + timeStamp 

Now you can execute the Jmeter test which ensure a functionality of a product with proper assertions with the product integration test while building the product.



Sunday, February 17, 2013

How to send http messages to jms endpoint using WSO2 ESB

WSO2 ESB can route incomming messages to various endpoint type. This blog shows how to configure esb http proxy service to send incomming messages to jms queue.

Download WSO2 ESB and  ActiveMQ.  ActiveMQ is used as the jms broker.

Uncomment following configuration from axis2.xml to enable jms transport in WSO2 ESB. axis2.xml can be found in $WSO2_ESB_HOME/repository/axis2.aml or repository/axis2/axis2.xml

Copy below jars

activemq-core-5.7.0.jar
geronimo-j2ee-management_1.1_spec-1.0.1.jar
geronimo-jms_1.1_spec-1.1.1.jar

to $WSO2_ESB_HOME/repository/components/lib. Those jar file can be found from $ActiveMQ_HOME/lib directory

<transportReceiver name="jms" class="org.apache.axis2.transport.jms.JMSListener">  
     <parameter name="myTopicConnectionFactory" locked="false">  
          <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>  
          <parameter name="java.naming.provider.url" locked="false">tcp://localhost:61616</parameter>  
          <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">TopicConnectionFactory</parameter>  
           <parameter name="transport.jms.ConnectionFactoryType" locked="false">topic</parameter>  
     </parameter>  
     <parameter name="myQueueConnectionFactory" locked="false">  
          <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>  
          <parameter name="java.naming.provider.url" locked="false">tcp://localhost:61616</parameter>  
          <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">QueueConnectionFactory</parameter>  
           <parameter name="transport.jms.ConnectionFactoryType" locked="false">queue</parameter>  
     </parameter>  
     <parameter name="default" locked="false">  
          <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter>  
          <parameter name="java.naming.provider.url" locked="false">tcp://localhost:61616</parameter>  
          <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">QueueConnectionFactory</parameter>  
           <parameter name="transport.jms.ConnectionFactoryType" locked="false">queue</parameter>  
     </parameter>  
   </transportReceiver>  

 <transportSender name="jms" class="org.apache.axis2.transport.jms.JMSSender"/>

Start jms broker(./activemq console) and create  a queue named TestQueue(go to http://0.0.0.0:8161/admin/).

Then Start WSO2 ESB Server(./wso2server.sh) and create a proxy service and a endpoint from bellow configuration

<proxy name="proxyWithJmsEndpoint" transports="https http" startOnLoad="true" trace="disable">  
     <target endpoint="jmsEndpoint">  
       <inSequence>  
         <property name="OUT_ONLY" value="true"/>  
         <property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>  
       </inSequence>  
       <outSequence>  
         <drop/>  
       </outSequence>  
     </target>  
   </proxy>  


<endpoint name="jmsEndpoint">  
     <address uri="jms:/TestQueue?transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory&amp;java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&amp;java.naming.provider.url=tcp://127.0.0.1:61616&amp;transport.jms.DestinationType=queue" format="pox"/>  
   </endpoint>  

In endpoint, uri format is pox. so it remove the soap envelop and send actual payload. It is useful for REST Services. If you want to send SOAP messages to queue remove format.

Now We have finished the configuration. Since this is a one-way message, the property “OUT_ONLY” is set to true and “FORCE_SC_ACCEPTED” property is defined to send a 202 response to the client who invokes this proxy.

 once you send a SOAP messages via http transport to above proxy service, It will send the messages to TestQueue. 



Sunday, February 10, 2013

How to remove or set empty value to HTTP header SOAPAction on outgoing message in WSO2 ESB

When you invoke a web service, there is a HTTP header called SOAPAction which keeps the value of service operation name. if you want to remove or set empty value for SOAPAction within your proxy service, following configuration in your proxy configuration can do it. Both header and property mediators are required.

To set empty string to SOAPAction


<header name="Action" value="" />  
<property name="SOAPAction" scope="transport" value="" /> 

Then out put will be:
 POST /services/SimpleStockQuoteService HTTP/1.1  
 Content-Type: text/xml; charset=UTF-8  
 Accept-Encoding: gzip,deflate  
 SOAPAction:   
 TransformationSequence: s1  
 Transfer-Encoding: chunked  
 Host: 127.0.0.1:9000 

To remove SOAPAction

<header name="Action" action="remove" />  
<property name="SOAPAction" scope="transport" action="remove" />  

Then out put will be:

 POST /services/SimpleStockQuoteService HTTP/1.1  
 Content-Type: text/xml; charset=UTF-8  
 Accept-Encoding: gzip,deflate  
 TransformationSequence: s1  
 Transfer-Encoding: chunked  
 Host: 127.0.0.1:9000 

if you want to change the SOAPAction value, header mediator can do this.

<header name="Action" value="newAction" /> 

Then out put will be:

 POST /services/SimpleStockQuoteService HTTP/1.1  
 Content-Type: text/xml; charset=UTF-8  
 Accept-Encoding: gzip,deflate  
 TransformationSequence: s1  
 SOAPAction: "newAction"  
 Transfer-Encoding: chunked  
 Host: 127.0.0.1:9000  





Saturday, February 2, 2013

Invoking WSO2 Carbon Admin Services using Service Stub

This blog will help you to understand you how to invoke a WSO2 Carbon product functionality from your own client.

In WSO2 products we use client server architecture within our servers.
Any functionality available to you via WSO2 Carbon management console can also be invoked via a web service call.Those calls are called Admin Services calls.

There are three component we can see in our products to provides a particular service.

1) Service component - which provide actual service
2) UI Component  - which provide the web user interface to provide the service
3) Service Stub  -  Interface to invoke the service generated from the service WSDL.

You can find those component in $CARBON_HOME/repository/components/plugins folder

 In this example,  see how to list the deployed services in wso2esb-4.6.0.















To invoke an admin service you have to authenticate user first. then get the session cookie and invoke the services you want.

for this example we have to use two service stub classes for authentication and service listing. the relevant service stubs components as bellow.

You can resolve all the dependency by adding following maven dependency or by adding class path to plugins directory

  <dependencies>  
     <dependency>  
       <groupId>org.wso2.carbon</groupId>  
       <artifactId>org.wso2.carbon.authenticator.stub</artifactId>  
       <version>4.0.0</version>    
     </dependency>  
     <dependency>  
       <groupId>org.wso2.carbon</groupId>  
       <artifactId>org.wso2.carbon.service.mgt.stub</artifactId>  
       <version>4.0.0</version>  
     </dependency>  
     <dependency>  
       <groupId>org.apache.axis2.wso2</groupId>  
       <artifactId>axis2-client</artifactId>  
       <version>1.6.1.wso2v5</version>  
     </dependency>  
   </dependencies> 
 
<repositories>
        <repository>
            <id>wso2.releases</id>
            <name>WSO2 internal Repository</name>
            <url>http://maven.wso2.org/nexus/content/repositories/releases/</url>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </repository>
        <repository>
            <id>wso2-nexus</id>
            <name>WSO2 internal Repository</name>
            <url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </repository>
    </repositories> 


Client code for Authenticate user and get the session cookie

import org.apache.axis2.AxisFault;  
 import org.apache.axis2.transport.http.HTTPConstants;  
 import org.wso2.carbon.authenticator.stub.AuthenticationAdminStub;  
 import org.wso2.carbon.authenticator.stub.LoginAuthenticationExceptionException;  
 import org.wso2.carbon.authenticator.stub.LogoutAuthenticationExceptionException;  
 import org.apache.axis2.context.ServiceContext;  
 import java.rmi.RemoteException;  
   
 public class LoginAdminServiceClient {  
   private final String serviceName = "AuthenticationAdmin";  
     private AuthenticationAdminStub authenticationAdminStub;  
     private String endPoint;  
   
     public LoginAdminServiceClient(String backEndUrl) throws AxisFault {  
       this.endPoint = backEndUrl + "/services/" + serviceName;  
       authenticationAdminStub = new AuthenticationAdminStub(endPoint);  
     }  
   
     public String authenticate(String userName, String password) throws RemoteException,  
                                       LoginAuthenticationExceptionException {  
   
       String sessionCookie = null;  
   
       if (authenticationAdminStub.login(userName, password, "localhost")) {  
         System.out.println("Login Successful");  
   
         ServiceContext serviceContext = authenticationAdminStub.  
             _getServiceClient().getLastOperationContext().getServiceContext();  
         sessionCookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING);  
         System.out.println(sessionCookie);  
       }  
   
       return sessionCookie;  
     }  
   
     public void logOut() throws RemoteException, LogoutAuthenticationExceptionException {  
       authenticationAdminStub.logout();  
     }  
 }  


One of the important this is that you need to figure out the service end point url that you wish to invoke. Service management service name is "ServiceAdmin". to get the service name, find the service component in plugins directory and there is a file named service.xml in META-INF directory in the bundle. It contains the service information

service end point url is like , https://localhost:9443/services/ServiceAdmin

import org.apache.axis2.AxisFault;  
 import org.apache.axis2.client.Options;  
 import org.apache.axis2.client.ServiceClient;  
 import org.wso2.carbon.service.mgt.stub.ServiceAdminStub;  
 import org.wso2.carbon.service.mgt.stub.types.carbon.ServiceMetaDataWrapper;  
 import java.rmi.RemoteException;  
   
 public class ServiceAdminClient {  
   private final String serviceName = "ServiceAdmin";  
   private ServiceAdminStub serviceAdminStub;  
   private String endPoint;  
   
   public ServiceAdminClient(String backEndUrl, String sessionCookie) throws AxisFault {  
     this.endPoint = backEndUrl + "/services/" + serviceName;  
     serviceAdminStub = new ServiceAdminStub(endPoint);  
     //Authenticate Your stub from sessionCooke  
     ServiceClient serviceClient;  
     Options option;  
   
     serviceClient = serviceAdminStub._getServiceClient();  
     option = serviceClient.getOptions();  
     option.setManageSession(true);  
     option.setProperty(org.apache.axis2.transport.http.HTTPConstants.COOKIE_STRING, sessionCookie);  
   }  
   
   public void deleteService(String[] serviceGroup) throws RemoteException {  
     serviceAdminStub.deleteServiceGroups(serviceGroup);  
   
   }  
   
   public ServiceMetaDataWrapper listServices() throws RemoteException {  
     return serviceAdminStub.listServices("ALL", "*", 0);  
   }  
 }  


to list services


import org.wso2.carbon.authenticator.stub.LoginAuthenticationExceptionException;  
 import org.wso2.carbon.authenticator.stub.LogoutAuthenticationExceptionException;  
 import org.wso2.carbon.service.mgt.stub.types.carbon.ServiceMetaData;  
 import org.wso2.carbon.service.mgt.stub.types.carbon.ServiceMetaDataWrapper;  
   
 import java.rmi.RemoteException;  
   
 public class ListServices {  
   public static void main(String[] args)  
       throws RemoteException, LoginAuthenticationExceptionException,  
           LogoutAuthenticationExceptionException {  
     System.setProperty("javax.net.ssl.trustStore", "$ESB_HOME/repository/resources/security/wso2carbon.jks");  
     System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");  
     System.setProperty("javax.net.ssl.trustStoreType", "JKS");  
     String backEndUrl = "https://localhost:9443";  
   
     LoginAdminServiceClient login = new LoginAdminServiceClient(backEndUrl);  
     String session = login.authenticate("admin", "admin");  
     ServiceAdminClient serviceAdminClient = new ServiceAdminClient(backEndUrl, session);  
     ServiceMetaDataWrapper serviceList = serviceAdminClient.listServices();  
     System.out.println("Service Names:");  
     for (ServiceMetaData serviceData : serviceList.getServices()) {  
       System.out.println(serviceData.getName());  
     }  
   
     login.logOut();  
   }  
 }  

out put will be
Login Successful  
 JSESSIONID=64F29C9EE6ACEA2A0DA596FB97DCC278; Path=/; Secure=null; HttpOnly=null  
 Service Names:  
 echo  
 Version  
 wso2carbon-sts  

like this example , any admin service can be invoked using service stub



Monday, January 7, 2013

Axis2 Client Side Maven Dependency for Axis2 Service Invocation


Once you add following dependency in your maven project, it will add all the jar files required for Axis2 service invocation in to class path

 <dependency>  
       <groupId>org.apache.axis2.wso2</groupId>  
       <artifactId>axis2-client</artifactId>  
       <version>1.6.1.wso2v5</version>  
     </dependency>  

Configuring TCP transport in WSO2 ESB for soap12 messages

This will demonstrate how to configure WSO2 ESB TCP transport with soap12 messages.To enable the TCP transport for samples, simply open up the repository/conf/axis2/axis2.xml file in a text editor and add the following transport receiver configuration and sender configuration. TCP transport module is shipped with ESB by default.
 
 <!-- Enable TCP message -->  
   <transportReceiver name="tcp" class="org.apache.axis2.transport.tcp.TCPTransportListener">  
     <parameter name="transport.tcp.port">8290</parameter>  
     <parameter name="transport.tcp.contentType">application/soap+xml</parameter>  
   </transportReceiver>  
   <transportSender name="tcp" class="org.apache.axis2.transport.tcp.TCPTransportSender"/>  

application/soap+xml is the content type of the soap12 messages and application/soap+xml is the message content type of the server for tcp transport.

once configuration is done. start server. then you can see following log for TCP transport

[2013-01-07 19:27:19,241]  INFO - TCPTransportListener TCP listener started
[2013-01-07 19:27:19,250]  INFO   [2013-01-07 19:27:19,245]  INFO - TCPServer TCP server started on port : 8290

Add following configuration for a proxy service
 
<proxy xmlns="http://ws.apache.org/ns/synapse" name="tcpProxy" transports="tcp" startOnLoad="true" trace="disable">   
    <target>   
     <inSequence>   
      <log level="full"/>   
      <callout serviceURL="http://localhost:9000/services/SimpleStockQuoteService"   
        action="urn:getQuote">   
       <source xmlns:s12="http://www.w3.org/2003/05/soap-envelope"   
         xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/"   
         xpath="s11:Body/child::*[fn:position()=1] | s12:Body/child::*[fn:position()=1]"/>   
       <target xmlns:s12="http://www.w3.org/2003/05/soap-envelope"   
         xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/"   
         xpath="s11:Body/child::*[fn:position()=1] | s12:Body/child::*[fn:position()=1]"/>   
      </callout>   
      <property name="RESPONSE" value="true"/>   
      <property name="messageType" value="application/soap+xml" scope="axis2"/>   
      <property name="ClientApiNonBlocking" scope="axis2" action="remove"/>   
      <header name="To" action="remove"/>   
      <log level="full"/>   
      <send/>   
      <log level="full"/>   
     </inSequence>   
    </target>   
   </proxy>    

Refer proxy service by
tcp://10.100.3.55:8290/services/tcpProxy?contentType=application/soap+xml