Citrus testcase example: CSV File Inbound -> Xml Http Outbound

30 Apr

As promised I’m going to show a test case for which I have used Citrus to implement it. The case is like this:
In a predefined folder on a machine a character-separated file is placed. This file is picked up by our Mule ESB application. The content is transformed to XML and this XML document is posted to another application over HTTP. This application responds with XML document telling the document was processed correctly.
To test this interface with Citrus we have to perform the following steps:

  1. Copy the input test-file to the predefined folder so it is picked up by the test instance of our Mule ESB
  2. Our Mule ESB will poll a directory each second to check if there is placed a new file to process. Our test case starts by having Citrus putting a test file in the directory .

  3. Have Citrus listen on a predefined HTTP port to receive the XML message over HTTP
  4. Inside our Mule ESB the file is transformed to XML message and posted on a HTTP port to be processed by the ‘ORDER’ system. We have configured Citrus to listen on this specific HTTP port to pick up the XML message.

  5. Reply to the received message with a predefined XML message
  6. This steps mimics the ‘ORDER’ system as it would normally process the incoming XML message and respond with another XML message. In this case Citrus will send back a predefined XML message as response.


The citrus-config.xml for this test case can be found here. I will explain the content of the config file next:

<bean id="citrusJMSConnectionFactory"
         class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="vm://localhost:61616" />
        <property name="userName" value="user"/>
        <property name="password" value="password"/>
</bean>

This part defines a ‘in-memory’ JMS provider to be used by Citrus. We will see later how we use it to check the incoming HTTP request (as described here in the Citrus reference guide).

<bean id="namespaceContextBuilder" class="com.consol.citrus.xml.namespace.NamespaceContextBuilder">
        <property name="namespaceMappings">
            <props>
                <prop key="ns1">http://www.pascalalma.net/invoice</prop>
            </props>
        </property>
</bean>

Here we define the namespaces that are used in the xml messages in our test. We will use this namespace in the test to check values of certain XML elements.

<bean name="pascalalmaIntegrationTests"
         class="com.consol.citrus.TestSuite">
        <property name="tasksBefore">
            <list>
                <bean class="com.consol.citrus.actions.ExecuteSQLAction">
                    <property name="dataSource" ref="rsDataSource"/>
                    <property name="statements">
                        <list>
                            <value>DELETE FROM RS_LOGS</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
</bean>

With this part I have Citrus clean up my log table in the database of my Mule ESB. We log all incoming and outgoing messages in our ESB to the database.

 
<!-- manadatory if XML files are used in a test -->
<bean id="xmlMessageValidator" class="com.consol.citrus.validation.xml.DomXmlMessageValidator"/>
    <bean id="schemaRepository"
           class="com.consol.citrus.xml.XsdSchemaRepository">
        <property name="schemas">
            <list>
                <bean class="org.springframework.xml.xsd.SimpleXsdSchema">
                    <property name="xsd"
                               value="classpath:schemas/rs_invoice_0.3.xsd"/>
                </bean>
            </list>
        </property>
</bean>

When you want to work with XML messages in your test (and that is very likely nowadays) you will need to define an ‘xmlMessageValidator’. And to be able to validate the message against an XML schema you will need to define the schemas in the ‘schemaRepository’ as I have done here.

<bean id="rsDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="url" value="jdbc:oracle:thin:@test-vm:1521:XE"/>
        <property name="username" value="user"/>
        <property name="password" value="password"/>
        <property name="driverClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>
        <property name="removeAbandoned" value="true"/>
</bean> 

This is the datasource that Citrus can use to access the database that is used by our Mule ESB application. We use this datasource to clean up the logtable and can use it to perform validations after messages have been processed.

 <citrus:message-channel-sender id="invoiceFileSender" channel="fileOutboundChannel"/>
<file:outbound-channel-adapter id="invoice-files-out" channel="fileOutboundChannel"
        directory="file://Volumes/staging/invoice" filename-generator="test-filename-generator" />
<bean id="test-filename-generator" class="net.pascalalma.citrus.TestFileNameGenerator" />
<si:channel id="fileOutboundChannel" />

This is a mix of Citrus with spring-integration configuration. With this configuration I am able to send files to my test VM with Citrus. It also shows how easy it is to mix Citrus with spring-integration.

<!-- receive Invoice HTTP request -->
<citrus-http:server id="orderHttpServer"
               port="8060"
               uri="/services/post-invoice"
               deamon="false"
               message-handler="jmsForwardingMessageHandler"
               auto-start="true"/>

Definition of the HTTP Server in Citrus which listens on port 8060 for a request of our Mule ESB.

 
 <bean id="jmsForwardingMessageHandler"
         class="com.consol.citrus.adapter.handler.JmsConnectingMessageHandler">
        <property name="destinationName" value="Citrus.order-response"/>
        <property name="connectionFactory" ref="citrusJMSConnectionFactory" />
        <property name="replyTimeout" value="6000"/>
    </bean>

    <!-- Process all received requests -->
    <citrus:jms-sync-message-receiver id="orderRequestReceiver"
                            destination-name="Citrus.order-response"
                            connection-factory="citrusJMSConnectionFactory" />
    <citrus:jms-reply-message-sender id="orderResponseSender"
                            reply-destination-holder="orderRequestReceiver"
                            connection-factory="citrusJMSConnectionFactory" />

THis part forwards the incoming HTTP request to a JMS endpoint. In our test we can perform tests on this incoming JMS message and check if it is valid.

Next thing I want to explain is the test-config.xml itself. I think it is quite self-explainatory:

<?xml version="1.0" encoding="UTF-8"?>
<spring:beans xmlns="http://www.citrusframework.org/schema/testcase"
              xmlns:ws="http://www.citrusframework.org/schema/ws/testcase"
              xmlns:spring="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd


http://www.citrusframework.org/schema/ws/testcase


http://www.citrusframework.org/schema/ws/testcase/citrus-ws-testcase.xsd


http://www.citrusframework.org/schema/testcase


http://www.citrusframework.org/schema/testcase/citrus-testcase.xsd">

    <testcase name="Testcase001Test">
        <meta-info>
            <author>Pascal Alma</author>
            <creationdate>2011-04-24</creationdate>
            <status>DRAFT</status>
        </meta-info>

        <description>Tests Testcase001</description>

        <actions>
            <send with="invoiceFileSender">
                <message>
                    <resource file="classpath:data/testcase001.txt"/>
                </message>
            </send>
            <receive with="orderRequestReceiver">

                <message schema-validation="true">
                    <validate path="//ns1:post-invoice/ns1:CompanyCode" value="1"/>
                    <validate path="string:count(//ns1:post-invoice/ns1:InvoiceLine/ns1:DocID)" value="3"/>
                </message>
                <header>
                    <element name="rs_address" value="order-purchase-invoice-queue" />
                </header>
                <extract>
                    <message path="count(//ns1:post-invoice/ns1:InvoiceLine/ns1:DocID)" variable="${nrOfInvoiceLines}"/>
                </extract>
            </receive>

            <echo>
                <message>${nrOfInvoiceLines}</message>
            </echo>
            <send with="orderResponseSender">
                <message>
                    <resource file="classpath:data/response-testcase001.xml"/>
                </message>
            </send>
        </actions>
    </testcase>
</spring:beans>

The first action that is done is sending a file to my Mule ESB. The next step is that I wait for the response from my ESB. When I received that I check the contents of XML message at some points and check if it is valid against the schema.
Then after echoing the number of invoice lines I have Citrus return the HTTP request with a fixed XML response so the Mule ESB ends this action successfully.
That completes this example of how to use Citrus to test your ESB implemention. I hope it is more clear now how you can use Citrus for your (automated) integration tests with this real life example.

One Response to “Citrus testcase example: CSV File Inbound -> Xml Http Outbound”

  1. Christoph Deppisch 04/05/2011 at 06:45 #

    Thank you for this excellent example on Citrus working with file and http adapters! We will definitely work on the documentation lacks you have mentioned and improve the configuration, so people get into the framework more easily.

    Cheers,
    Christoph

Comments are closed.

Follow

Get every new post delivered to your Inbox.

Join 101 other followers

%d bloggers like this: