Oracle SOA Suite 11g, wrong settings after re-installation of SOA domain

During my installation of the 11g SOA Suite, things go bad once in a while and domains need to be created and removed, etc.

After last remove and new installation of my domain i got the next error message during startup of the Admin Server :

javax.transaction.SystemException: 
weblogic.transaction.loggingresource.LoggingResourceException: 
java.sql.SQLException: JDBC LLR, table verify failed for table 'WL_LLR_ADMINSERVER', row 
'JDBC LLR Domain//Server' record had unexpected value 'soa11g_new_domain//AdminServer' expected 
'soa_domain//AdminServer'*** ONLY the original domain and server that creates an LLR table
may access it ***

Easy fix would be :

Start sqlplus and connect to ‘DEV_SOAINFRA’ schema.

update WL_LLR_ADMINSERVER
set    RECORDSTR = 'soa_domain//AdminServer'
where  XIDSTR    = 'JDBC LLR Domain//Server';

commit;

Oracle Service Bus 11g, installation

Besides the new patchset for Oracle SOA Suite 11g, Oracle also released the new Oracle Service Bus 11g.
See Edwin his list for the new features.

Download the installer and unpack the files and move the files from Disk2 to Disk1, otherwise the installation won’t complete.





Select the middleware home and we will create the new Oracle Service Bus Home in there.

Configuration Wizard

See this (2.10 Oracle Service Bus Domain Configuration Scenarios) overview to decide what the best infrastructure scenario is for your case. Since it’s my development machine i choose to reuse the SOA Suite domain to extend it with the Oracle Service Bus components. For this i won’t need an extra Weblogic domain.

I selected the Single Domain, since it will be installed on my dev machine. For production Oracle advises to use the All Domain Topologies. In that case Oracle Service Bus will be running in a seperate managed server (just like soa_server1 and bam_server1).

By default the credentials for the SOA Suite Components are already configurated correctly, we only need to change the ‘OSB JMS Reporting Provider’ component.

And we’re done.

Oracle Service Bus Console
http://localhost:7001/sbconsole (new Weblogic login screen)

See also Edwin his blog on the new WSM functionality (policies).

Oracle SOA Suite 11g Patch Set 2, installation

Once in a while i just clean my how Oracle environment and start from scratch which a clean one.

For this new installation i used the next set of installations

Loopback adapter

Optional installation of the Microsoft Loopback adapter (in case of dhcp)

Oracle Database 11g Release 2, Enterprise Edition

Follow the installation guide

*Note
Install the new db and update a few system parameters, otherwise the installation of the SOA Suite will fail

  • alter system set processes=500 scope=spfile;
  • alter system set open_cursors=500 scope=spfile;

Repository Creation Utility

Run: rcuHome/bin/rcu.bat
Select the components you need and finish installation








WebLogic Server

Run: wls1033_oepe111150_win32.exe
Create a new Middleware Home




SOA Suite

Oracle SOA Suite patchset1 was a fullblown new release. For the installation of the new patchset 2, we first need to install the patchset1 release.
Without it you will face the next message 😉

Run: Disk1/setup.exe (soa_11.1.1.2.0)
Select the Middleware Home we just created with the installation of Patchset 1





Run: Disk1/setup.exe (soa_11.1.1.3.0)



Configure Oracle SOA Suite

Run: middleware/wlserver_10.3/common/bin/config.exe
We’ll create a new weblogic domain for the soasuite components. Select the components you want to get installed in the domain, configurate database-settings and go.









Install Oracle Composite Editor for Jdeveloper

I use the manual install of the extension, but you can also update it fron within JDeveloper itself.
Help > Check for Updates > Source > Install From Local File, and Browse to the downloaded zip file, and your done.

*Note
If your Application Server Connection test fails in Jdeveloper, check if the proxy settings in Jdeveloper are correct. By default it’s turned on.

And that’s pretty much it of what’s needed for the installation of a new Oracle SOA Suite stack.

Oracle SOA Suite 11g and the new Partitions feature

In the old school Oracle SOA Suite we had the functionality to create different domains in the BPEL Console to group our applications.
This functionality was gone in the 11g SOA Suite, and because it still was a wanted feature, Oracle reintroduced it as feature in the new Oracle SOA 11g Patchset2.

Now it’s called ‘Partitions’.

So let’s see how to manage them.
Go to the Enterprise Manager (http://localhost:7001/em), Farm_ > SOA > soa-infra (soa_server1).
Right mouseclick on soa-infra > Manage Partitions. Create the new partition.

The new partition should be added to the list (beneath the default partition).

JDeveloper
In JDeveloper we will create a simple SOA Composit application.
Deploy the new application and now in the wizard of the deployment when we select a server it gives us a new selectbox to select the newly created partition. By default it will use the ‘default’ partition.

Deploy the application and let’s go back to the console.
Now we will see the new deployed application in the list of the ‘test_partition’ partition.

Using ant

ant-sca-mgmt.xml createPartition – Creates a partition in the SOA Infrastructure.
Location of the file :

<ORACL_MIDDLEWARE_HOME>/bin

ant -f ant-sca-mgmt.xml createPartition -Dhost=localhost -Dport=8001 -Duser=weblogic -Dpassword=weblogic -Dpartition=my_ant_partition

Buildfile: ant-sca-mgmt.xml
     [echo] oracle.home = E:\oraclehome\11g\middleware\Oracle_SOA1\bin/..

createPartition:
    [input] skipping input as property host has already been set.
    [input] skipping input as property port has already been set.
    [input] skipping input as property user has already been set.
[secure-input] skipping secure-input as property password has already been set.
    [input] skipping input as property partition has already been set.
     [echo] oracle.home = E:\oraclehome\11g\middleware\Oracle_SOA1\bin/..

folderMgrTask:
     [java] calling FolderManager.initConnection(), m_host=localhost, m_port=8001, m_user=weblogic
     [java] Connecting to: service:jmx:t3://localhost:8001/jndi/weblogic.management.mbeanservers.runtime
     [java] connection initiated
     [java] folderMBean=oracle.soa.config:name=soa-infra,j2eeType=FolderLifecycleConfig,Application=soa-infra
     [java] Partition (my_ant_partition) is successfully created.

BUILD SUCCESSFUL

And the partitions list in the console

Using wlst

http://download.oracle.com/docs/cd/E14571_01/web.1111/e13813/custom_soa.htm#CDEHBBID
SOA Composite Application Partition Management Commands

Oracle SOA Suite 11gR1 Patch Set 2 released and other nice goodies!

A lot of new releases/patches coming from Oracle the last few days.

SOA Suite 11g

Other links

Oracle Service Bus 11g (11.1.1.3.0)

Time to fill the download queues and play with the new goodies!

EAI/Oracle Service Bus testing with Citrus Framework, part2

Before reading on, read my first article on the Citrus Framework.
In this second part of testing by use of the Citrus Framework i want to test a new scenario which was part of the middleware of my last customer.

Scenario

Some third party application stores messages on the Weblogic JMS queue in the middleware. My Oracle Service Bus project picks up the messages, does some transformation/enrichment/etc, and stores the data on the file share.
Storing the file on the filesystem is the trigger for starting a new process, but this will be out of scope for this article.

What we want to test is the blackbox which runs in the middleware. I want to be able to store the xml data file (fact 1), in the jms queue, and eventually read the file from filesystem (fact 2) and see if the response
matches my expected response defined in the Citrus Framework.

Requirements

See the requirements of the first article, what we need again are the inbound queues and the used connection factory. In the middleware we need a Oracle Service Bus flow.

Oracle Service Bus

The Oracle Service Bus project i want to test is a real basic one with only 2 resources.

  1. jms_ps – proxy service with service type ‘Any XML Service’ and jms protocol
    The flow consists of only a simple route action whichs routes the incoming message of the jms queue 1 on 1 to business service which stores the content on filesystem.
  2. file_bs – business service which stores the file on my local file system

Citrus configuration

First we need to config src/citrus/resources/citrus-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:citrus="http://www.citrusframework.org/schema/config"
       xmlns:citrus-ws="http://www.citrusframework.org/schema/ws/config"
       xmlns:citrus-http="http://www.citrusframework.org/schema/http/config"
       xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:si="http://www.springframework.org/schema/integration"
	   xmlns:file="http://www.springframework.org/schema/integration/file"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	   http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
	   http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file-2.0.xsd
       http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config-1.1.xsd">

	<!-- Common settings -->
	<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:com/consol/citrus/samples/greeting/schema/greeting.xsd"/>
				</bean>
			</list>
		</property>
	</bean>	   

	<bean class="com.consol.citrus.variable.GlobalVariables">
		<property name="variables">
			<map>
				<entry key="project.name" value="Citrus Greeting sample"/>
			</map>
		</property>
	</bean>	

	<bean class="com.consol.citrus.aop.StoreMessageInterceptorAspect"/>	   

	<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
		<property name="environment">
			<props>
				<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
				<prop key="java.naming.provider.url">t3://localhost:7001</prop>
			</props>
		</property>
	</bean>	

	<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate">
			<ref bean="jndiTemplate" />
		</property>
		<property name="jndiName">
			<value>TestCF</value>
		</property>
	</bean>	

	<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
		<property name="jndiTemplate">
			<ref bean="jndiTemplate" />
		</property>
		<property name="cache">
			<value>true</value>
		</property>
	</bean>

	<bean id="sendGreeting" class="com.consol.citrus.jms.JmsMessageSender">
		<property name="destinationName" value="citrus_queue_in"/>
		<property name="connectionFactory">
			<ref bean="connectionFactory" />
		</property>
		<property name="destinationResolver">
			<ref bean="jmsDestinationResolver" />
		</property>
	</bean>

	<file:inbound-channel-adapter id="fileAdapter" directory="file://e:/temp/files_out" channel="fileInputChannel">
		<si:poller max-messages-per-poll="100">
			<si:interval-trigger time-unit="MILLISECONDS" interval="1" />
		</si:poller>
	</file:inbound-channel-adapter>
	
	<si:channel id="fileInputChannel">
		<si:queue capacity="25"/>
		<si:interceptors>
			<bean class="org.springframework.integration.transformer.MessageTransformingChannelInterceptor">
				<constructor-arg>
					<bean class="org.springframework.integration.file.transformer.FileToStringTransformer"/>
				</constructor-arg>
			</bean>
		</si:interceptors>
	</si:channel>

	<citrus:message-channel-receiver id="fileInputChannelReceiver"
                                    channel="fileInputChannel"
                                    receive-timeout="5000"/>	

	<!-- TestSuite definition -->
	<bean name="citrus-samples-greeting" class="com.consol.citrus.TestSuite"/>
</beans>

Again we use the ‘sendGreeting’ bean to send the message to the jms queue. For Citrus to be able to do his actions on the messages he needs to get the message from a MessageChannel.
When the file gets stored on filesystem the ‘inbound-channel-adapter’ will poll for the file and puts it on the ‘fileInputChannel’ messagechannel, eventually citrus will pick up the message from this channel.

Documentation of Citrus doesn’t give you any hints on how to integrate the file-protocol. Since Citrus makes use of Spring Integration we can easily adopt the file support from this framework and add it to the Citrus context file.
The following changes are needed on the citrus-context.xml file

  • Addition of the integration namespaces/schemalocations
  • Addition of the (file) inbound-channel-adapter
  • Addition of the channel for the file
  • Citrus Message channel polling on the file input channel
  • Copy the Spring Integration File jar to the libs folder. I used ‘org.springframework.integration.file-1.0.3.RELEASE.jar’ from the Spring Integration framework

A few notes on the fileInputChannel.
If we would just add

<si:channel id="fileInputChannel">

, Citrus will give us the next error :

[citrus] Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fileInputChannelReceiver': Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [org.springframework.integration.channel.DirectChannel] to required type 
[org.springframework.integration.channel.PollableChannel] for property 'channel'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [org.springframework.integration.channel.DirectChannel] 
to required type [org.springframework.integration.channel.PollableChannel] for property 'channel': no matching editors or conversion strategy found

So Citrus expects some other type of channel. Adding

<si:queue capacity="25"/>

, will fix this problem.

Running the sample again will give us the next error :

   [citrus] Caused by: org.w3c.dom.ls.LSException: Content is not allowed in prolog.
   [citrus]     at org.apache.xerces.parsers.DOMParserImpl.parse(Unknown Source)
   [citrus]     at com.consol.citrus.util.XMLUtils.parseMessagePayload(XMLUtils.java:333)
   [citrus]     at com.consol.citrus.validation.DefaultXMLMessageValidator.validateXMLSchema(DefaultXMLMessageValidator.java:300)
   [citrus]     at com.consol.citrus.validation.DefaultXMLMessageValidator.validateMessage(DefaultXMLMessageValidator.java:98)
   [citrus]     ... 54 more
   [citrus] Caused by: ::::1:1:0:Content is not allowed in prolog.
   [citrus]     at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
   [citrus]     at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
   [citrus]     at org.apache.xerces.impl.XMLScanner.reportFatalError(Unknown Source)
   [citrus]     at org.apache.xerces.impl.XMLDocumentScannerImpl$PrologDispatcher.dispatch(Unknown Source)
   [citrus]     at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
   [citrus]     at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   [citrus]     at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
   [citrus]     at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
   [citrus]     ... 58 more   

The inbound-adapter passes on the file 1 on 1 to the file channel. Since the channel expects a string instead of a file object we need to transform this file-object to a string-object. Spring Framework gives us a default Transformer for this.
To intercept the File-object before it gets stored on the MessageChannel we can add an ‘interceptor’, as argument to the call of the interceptor we define the ‘FileToStringTransformer’.

Secondly we need to config src/citrus/tests/com/consol/citrus/samples/greeting/jms/GreetingJmsTest.xml

<?xml version="1.0" encoding="UTF-8"?>
<spring:beans xmlns="http://www.citrusframework.org/schema/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/testcase http://www.citrusframework.org/schema/testcase/citrus-testcase.xsd">
	<testcase name="GreetingJmsTest">
		<meta-info>
			<author>Eric Elzinga</author>
			<creationdate>2010-03-25</creationdate>
			<status>FINAL</status>
			<last-updated-by>Eric Elzinga</last-updated-by>
			<last-updated-on>2010-03-28T00:00:00</last-updated-on>
		</meta-info>

		<variables>
			<variable name="correlationId" value="citrus:randomNumber(10)"></variable>
			<variable name="user" value="Christoph"></variable>
		</variables>

		<actions>
			<send with="receiveGreeting">
			<message>
				<resource file="classpath:xmlData/greeting_request.xml" />
			</message>
			<header>
				<element name="Operation" value="sayHello"/>
				<element name="CorrelationId" value="${correlationId}"/>
			</header>
		</send>

		<receive with="fileAdapter">
		<selector>
			<value>CorrelationId = '${correlationId}'</value>
		</selector>
		<message>
		  <resource file="classpath:xmlData/greeting_response.xml" />
		  <ignore path="//tns:GreetingRequestMessage/tns:Text" />
		</message>
		<header>
			<element name="Operation" value="sayHello"/>
			<element name="CorrelationId" value="${correlationId}"/>
		</header>
	</receive>
</actions>
</testcase>
</spring:beans>

Only change in here compaired to part1 is the

<receive with="fileInputChannelReceiver">

Now run the test again and see if the framework matches the generated file on filesystem with the payload we configurated.
Since i don’t do any transformations in the middleware the request payload should match the response payload.

ant citrus.run.tests

..and see the results

   [citrus] 19047  INFO  port.LoggingReporter| TEST FINISHED: GreetingJmsTest
   [citrus] 19047  INFO  port.LoggingReporter| ------------------------------------------------------------------------
   [citrus] 19063  INFO  port.LoggingReporter| FINISH TESTSUITE citrus-samples-greeting
   [citrus] 19063  INFO  port.LoggingReporter| ------------------------------------------------------------------------
   [citrus] 19063  INFO  port.LoggingReporter| ________________________________________________________________________
   [citrus] 19063  INFO  port.LoggingReporter|
   [citrus] 19079  INFO  port.LoggingReporter| CITRUS TEST RESULTS
   [citrus] 19079  INFO  port.LoggingReporter|
   [citrus] 19079  INFO  port.LoggingReporter|  GreetingJmsTest ............................................... SUCCESS
   [citrus] 19079  INFO  port.LoggingReporter|
   [citrus] 19079  INFO  port.LoggingReporter| Total number of tests: 1
   [citrus] 19079  INFO  port.LoggingReporter| Skipped: 0 (0.0%)
   [citrus] 19079  INFO  port.LoggingReporter| Failed:  0 (0.0%)
   [citrus] 19079  INFO  port.LoggingReporter| Success: 1 (100.0%)

Conclusion

I hope this gave you good overview on how to implement integration tests with the Citrus Framework. For me it’s an ideal way to test my Oracle Service Bus flows.
How do you guys think about it ? Or do you use other frameworks for testing?

Enterprise Application Integration testing with Citrus Framework

Last week i read a thread on the Oracle forums on how to test the Oracle Service Bus processes.
A comment from one of the users lead to me this framework, Citrus Framework.

Citrus is an integration testing framework written in Java that tests your software application to fit into your customer’s environment. The tool simulates
surrounding systems across various transports (e.g. Http, JMS, TCP/IP, SOAP, …) in order to perform automatic end-to-end use case testing.

For one of my customers we had a lot of unit tests for testing all the flows in the middleware. Different scenarios, different protocols, eventually all needed to be tested.
Constructing all theses possible scenarios, we build everything from scratch to be able to send messages on different protocols and do all the correlation of the messages which go in and which eventually arrive at target destination.

To simulate a one of these scenarios i wanted to try the Citrus Framework to see what it could do for me.

For my test i used the greetings sample which ships with the citrus-1.1-SNAPSHOT distribution.

Directory structure
Create the directory structure as desribed over here.
When all done you should have a structure like this

  • src/citrus/java – location of the generated Testng testcases
  • src/citrus/resoruces – location of all the configuration needed for the framework
  • src/citrus/tests – location of all the defined testcases
  • optional – lib – location of all the dependency libraries
  • optional – log – location in which citrus framework will store logging (payload fragments)
  • build.xml – ant build script

Example of the used build.xml

<project name="greetings" basedir="." default="citrus.run.tests">
		
	<property file="src/citrus/resources/citrus.properties"/>
	
    <path id="citrus-classpath">
        <pathelement path="src/citrus/java"/>
    	<fileset dir="lib">
            <include name="*.jar"/>
        </fileset>
    </path>
    
	<typedef resource="citrustasks" classpath="lib/citrus-ant-tasks-1.1-SNAPSHOT.jar"/>
	
	<target name="compile.tests">
	    <javac srcdir="src/citrus/java" classpathref="citrus-classpath"/>
		<javac srcdir="src/citrus/tests" classpathref="citrus-classpath"/>
	</target>
	
	<target name="citrus.run.tests" depends="compile.tests" description="Runs all Citrus tests">
		<citrus suitename="${testsuite.name}" package="com.consol.citrus.samples.*"/>
	</target>
	
	<target name="citrus.run.single.test" depends="compile.tests" description="Runs a single test by name">
   	 	<touch file="test.history"/>
    	
    	<loadproperties srcfile="test.history"/>
    	
    	<echo message="Last test executed: ${last.test.executed}"/>

    	<input message="Enter test name:" addproperty="testclass" defaultvalue="${last.test.executed}"/>
    	
    	<propertyfile file="test.history">
			<entry key="last.test.executed" type="string" value="${testclass}"/>
		</propertyfile>

		<citrus suitename="citrus-samples" test="${testclass}"/>
    </target>
	
	<target name="create.test" description="Creates a new empty test case">
		<input message="Enter test name:" addproperty="test.name"/>
        <input message="Enter test description:" addproperty="test.description" defaultvalue="TODO: Description"/>
        <input message="Enter author's name:" addproperty="test.author" defaultvalue="${default.test.author}"/>
        <input message="Enter package:" addproperty="test.package" defaultvalue="${default.test.package}"/>
		<input message="Enter framework:" addproperty="test.framework" defaultvalue="testng"/>
	    
		<java classname="com.consol.citrus.util.TestCaseCreator">
            <classpath refid="citrus-classpath"/>
			<arg line="-name ${test.name} -author ${test.author} -description ${test.description} -package ${test.package} -framework ${test.framework}"/>
        </java>
    </target>
	
	<target name="create.html.doc" description="Creates test documentation in html">
        <mkdir dir="target"/>
        
        <java classname="com.consol.citrus.doc.HtmlTestDocGenerator">
            <classpath refid="citrus-classpath" />    
            
            <arg value="src/citrus/tests"/>
            <arg value="target/CitrusTests.html"/>
            <arg value="Citrus Test Documentation"/>
            <arg value="logo.png"/>
            <arg value="Overview"/>
        </java>
        
        <copy todir="target" file="src/citrus/resources/logo.png"/>
        
        <zip destfile="target/CitrusTests.zip">
            <fileset dir="target">
                <include name="CitrusTests.html"/>
                <include name="logo.png"/>
            </fileset>
        </zip>
    </target>
    
    <target name="create.xls.doc" description="Creates test documentation in excel">
        <mkdir dir="target"/>
        
        <java classname="com.consol.citrus.doc.ExcelTestDocGenerator">
            <classpath refid="citrus-classpath" />
            
            <arg value="src/citrus/tests"/>
            <arg value="CitrusTests"/>
            <arg value="Citrus Test Documentation"/>
            <arg value="Citrus Testframework"/>
            <arg value="ConSol* Software GmbH"/>
        </java>
    </target>
</project>

Scenario
Middleware gets delivered a new message on a queue. Some process picks up the message, does some transformation/validation on it, and passes it on. Eventually a new message will get sended to some other queue.

– Pre-Requirements

  • weblogic jms queue (citrus_queue_in, citrus_queue_out)
  • weblogic connection factory (TestCF)
  • wlfullclient.jar (cd WL_HOME/server/lib, java -jar wljarbuilder.jar)
  • available process flow for testing (i used a simple Oracle Service Bus (OSB)) flow which received a message on citrus_queue_in and routes the mesage to citrus_queue_out)

First we need to config src/citrus/resources/citrus-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:citrus="http://www.citrusframework.org/schema/config"
       xmlns:citrus-ws="http://www.citrusframework.org/schema/ws/config"
       xmlns:citrus-http="http://www.citrusframework.org/schema/http/config"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
       http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config-1.1.xsd">

	<!-- Common settings -->
	<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:com/consol/citrus/samples/greeting/schema/greeting.xsd"/>
				</bean>
			</list>
		</property>
	</bean>	   

	<bean class="com.consol.citrus.variable.GlobalVariables">
		<property name="variables">
			<map>
				<entry key="project.name" value="Citrus Greeting sample"/>
			</map>
		</property>
	</bean>	

	<bean class="com.consol.citrus.aop.StoreMessageInterceptorAspect"/>	   

	<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
		<property name="environment">
			<props>
				<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
				<prop key="java.naming.provider.url">t3://localhost:7001</prop>
			</props>
		</property>
	</bean>	

	<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiTemplate">
			<ref bean="jndiTemplate" />
		</property>
		<property name="jndiName">
			<value>TestCF</value>
		</property>
	</bean>	

	<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
		<property name="jndiTemplate">
			<ref bean="jndiTemplate" />
		</property>
		<property name="cache">
			<value>true</value>
		</property>
	</bean>

	<bean id="sendGreeting" class="com.consol.citrus.jms.JmsMessageSender">
		<property name="destinationName" value="citrus_queue_in"/>
		<property name="connectionFactory">
			<ref bean="connectionFactory" />
		</property>	
		<property name="destinationResolver">
			<ref bean="jmsDestinationResolver" />
		</property>		
	</bean>

	<bean id="receiveGreeting" class="com.consol.citrus.jms.JmsMessageReceiver">
		<property name="destinationName" value="citrus_queue_out"/>
		<property name="connectionFactory">
			<ref bean="connectionFactory" />
		</property>		
		<property name="destinationResolver">
			<ref bean="jmsDestinationResolver" />
		</property>	
	</bean>	
<!--
	<citrus:jms-message-sender id="getOrdersRequestSender"
						       destination-name="testJMSServer/citrus_queue_in"/>

	<citrus:jms-message-receiver id="getOrdersResponseReceiver"
								 destination-name="testJMSServer/citrus_queue_out"/>
-->
	<!-- TestSuite definition -->
	<bean name="citrus-samples-greeting" class="com.consol.citrus.TestSuite"/>							 
</beans>

Let’s discuss a few parts

  • bean id=”schemaRepository” class=”com.consol.citrus.xml.XsdSchemaRepository”
  • Registrate the xsd for the message payload, which eventually will be used to validate the messages
  • bean class=”com.consol.citrus.variable.GlobalVariables”
  • Setup some global settings
  • bean class=”com.consol.citrus.aop.StoreMessageInterceptorAspect”
  • Activate extra debugging
  • bean id=”jndiTemplate, connectionFactory and jmsDestinationResolver”
  • Configuration for the lookup of the weblogic resources
  • bean id=”sendGreeting” class=”com.consol.citrus.jms.JmsMessageSender”
  • used for sending the messages to the jms queue
  • bean id=”receiveGreeting” class=”com.consol.citrus.jms.JmsMessageReceiver”
  • used for receiving the messages of the jms queue

** Note. Default configuration describes to make use of :

<citrus:jms-message-sender id="getOrdersRequestSender" destination-name="testJMSServer/citrus_queue_in"/>

This gave me errors about Spring/Citrus not able to find the destination queue.
In case of weblogic resources use the “bean id-….” definition. (thanks to Christoph of the Consol team for helping me out on this one)

Secondly we need to config src/citrus/tests/com/consol/citrus/samples/greeting/jms/GreetingJmsTest.xml

<?xml version="1.0" encoding="UTF-8"?>
<spring:beans xmlns="http://www.citrusframework.org/schema/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/testcase http://www.citrusframework.org/schema/testcase/citrus-testcase.xsd">
	<testcase name="GreetingJmsTest">
		<meta-info>
			<author>Eric Elzinga</author>
			<creationdate>2010-03-25</creationdate>
			<status>FINAL</status>
			<last-updated-by>Eric Elzinga</last-updated-by>
			<last-updated-on>2010-03-28T00:00:00</last-updated-on>
		</meta-info>

		<variables>
			<variable name="correlationId" value="citrus:randomNumber(10)"></variable>      
			<variable name="user" value="Eric"></variable>
		</variables>

		<actions>
			<send with="sendGreeting">
			<message>
				<resource file="classpath:xmlData/greeting_request.xml" />
			</message>
			<header>
				<element name="Operation" value="sayHello"/>
				<element name="CorrelationId" value="${correlationId}"/>
			</header>
		</send>

		<receive with="receiveGreeting">
		<selector>
			<value>CorrelationId = '${correlationId}'</value>
		</selector>
		<message>
		  <resource file="classpath:xmlData/greeting_response.xml" />
		  <ignore path="//tns:GreetingRequestMessage/tns:Text" />
		</message>
		<header>
			<element name="Operation" value="sayHello"/>
			<element name="CorrelationId" value="${correlationId}"/>
		</header>
	</receive>
</actions>
</testcase>
</spring:beans>

**Notes

  • resource vs data tag. To include the payload of the test we can either use
    <message>
    	<resource file="classpath:xmlData/greeting_request.xml" />
    </message>
    

    or

    <message>
    	<data>
    		<![CDATA[
    		   <tns:GreetingRequestMessage xmlns:tns="http://www.citrusframework.org/samples/greeting">
    			   <tns:CorrelationId>${correlationId}</tns:CorrelationId>
    			   <tns:Operation>sayHello</tns:Operation>
    			   <tns:User>${user}</tns:User>
    			   <tns:Text>Hello Citrus!</tns:Text>
    		   </tns:GreetingRequestMessage>								
    		]]>
    	</data>
    </message>
    
  • header tag adds/validates header information (soap headers/jms properties/etc)
  • selector tag gives us the option to let the framework only select the message we would expect there to be.
    If we were testing against a ‘running’ environment, it could be possible that other processes are also sending messages to queue. With the selector tag we only select the message from the queue which succeed the criteria.

    <selector>
    	<value>CorrelationId = '${correlationId}'</value>
    </selector>
    

    If we skip this selector, put some messages in the out-queue and do the test again we will see the next error message :

    [citrus] Caused by: java.lang.IllegalArgumentException: Values not equal for header element 'CorrelationId', expected '2243051261' but was '2791756984'
    

    So it will try to match the first message it will find in the queue.

  • the ignore tag will give us the option to select elements the framework should not validate
    elements which consist of current datetime values are an example of these
  • full validation vs partial validation
  • in the example included i validate the whole xml message. in case we only want to validate/check a few elements from the message we can use the next :

    <message>
    	<validate path="//tns:GreetingRequestMessage/tns:Operation" value="sayHello"/>
    </message>
    

    The result
    Run the ant buildfile, ant citrus.run.tests

       [citrus] 4547   INFO  port.LoggingReporter| TEST FINISHED: GreetingJmsTest
       [citrus] 4547   INFO  port.LoggingReporter| ------------------------------------------------------------------------
       [citrus] 4563   INFO  port.LoggingReporter| FINISH TESTSUITE citrus-samples-greeting
       [citrus] 4563   INFO  port.LoggingReporter| ------------------------------------------------------------------------
       [citrus] 4563   INFO  port.LoggingReporter| ________________________________________________________________________
       [citrus] 4563   INFO  port.LoggingReporter|
       [citrus] 4563   INFO  port.LoggingReporter| CITRUS TEST RESULTS
       [citrus] 4563   INFO  port.LoggingReporter|
       [citrus] 4563   INFO  port.LoggingReporter|  GreetingJmsTest ............................................... SUCCESS
       [citrus] 4563   INFO  port.LoggingReporter|
       [citrus] 4563   INFO  port.LoggingReporter| Total number of tests: 1
       [citrus] 4563   INFO  port.LoggingReporter| Skipped: 0 (0.0%)
    

    Successful result!

    What we have tested in here :
    – Are we able to put a message on the in-queue, and get a response back on the out-queue.
    – Does the response xml validates against the supplied schema definition (xsd)
    – Do the response queue message also have the correct header properties

    Other features
    Ant/Maven support
    Database access/validation
    Adapters (tibco/ws/http)
    … and more

    In a following blog item i will try to simulate some other scenario to see if the framework covers it all.