Thursday, 31 March 2011

Testing ServiceMix 4.3 services with PaxExam

In the project that I'm currently working on we are developing a set of extensions for ServiceMix - more or less some monitoring stuff. It's pretty simple using SMX ExchangeListeners - you implement the interface, register it via Spring DM and voila - you have everything you need. But how are you going to test it? Of course, we write unit tests, and functional tests, but all of them are leaving NMR/OSGi stuff behind - you just don't include osgi-beans.xml's.
This leaves us with untested code - my baaaaad ;)

Fortunately, here comes a rescue - it's PaxExam. It's a framework for testing OSGi services in various containers - most notably felix & equinox. But making it play nicely with latest & greates ServiceMix 4.3 was not so easy - so I what to share it. I made a sample project, it's on my github

It consists of 2 modules: first contains service & listener under test, and the second one contains The Test.

I won't go into details about the service bundle - it's just cxf-bc endpoint passing invocations to camel router, which sets output message. The listener is also very simple. The point is that we have 2 of most widely used smx components, with OSGi packaging and OSGi-config configuration.

This leaves us with itests module. It's core is BaseIntegrationTest, which contains Pax Exam configuration and some utility methods. Pax Exam configuration was the most difficult part for me. The reason is that servicemix consists of many, many dependant projects, each of them having own release cycle, and Pax Exam has it's own.
Anyway, here is what works for me (note - it'll work with sun jdk 1.6 only I think).

JUnit test (which is of course no unit test btw) using Pax Exam has to have static configuration method, which tells testing framework how to prepare container - which one, which parameters, which bundles to install. It looks like this:

So, what should go into configuration method?
First, we have to set up system packages. We have to exclude StAX API and some SOAP APIs from system packages:



The system property "org.ops4j.pax.runner.platform.ee" tells PaxRunner where to look for system packages. I copied them from SMX distro - except that I had to add two Sun packages containing Schema and JAXP implementations - otherwise XPath & schema failed to work. Still, to make SchemaFactory work I had to manually add system property specifying implementation class.

Next thing is rather standard PaxExam configuration: OSGi container, logging profile, spring and spring DM setup (note - you have to use 1.2 version, not the latest one):


Two notes here. A profile is a set of bundles predefined to be used in PaxExam. Also note that we don't use System.setProperty, but PaxExam DSL expression. The reason is that the OSGi container is run separately, so we have to distinguish system properties used to start it, and properties that will be accessible to bundles inside it.

Then comes felix install configuration. I wanted to mimic SMX configuration conventions (files in etc dir, ended with .cfg), so I copied felixInstall configuration and add appropriate system properties. Note, that we set start level to 2. In Karaf deafatul start level is 60, in PaxRunner - it's 5. But I decided to stay with Pax way - don't have that many bundles to need so fine grained configuration.


Now, karaf configuration. It's also pretty standard, just remember that we need Aries bluepring in version 0.2-incubation, and not 0.1 (as PaxExam has it) or latest 0.3


Now, time for Servicemix components configuration. We'll use nice PaxExam feature - feature scan. This means that we can specify Karaf features package, and PaxExam will install appropriate bundles. So, we choose servicemix features, specify servicemix-camel, camel-nmr and servicemix-cxf-bc, and ...?
And it turns out that servicemix-cxf-bc has unresolved dependencies :/ The reason is that it was (at least it seems so ;)) tested with full distro, which contains also activemq-blueprint feature. Since we don't want activemq for our test setup, we'll install required bundles manually:


Now, everything is ready for the final step - installation of services bundle:
mavenBundle("pl.touk.smx4", "paxExamSample-service")

To make testing easier I also created few util methods. Two interesting ones are: getBean and sendMessage.


getBean uses ServiceTracker to get Spring/Blueprint bean registered as a OSGi service. Note, that it is done asynchronously - that's why we need Thread.sleep for ServiceTracker.


sendMessage wraps interaction with NMR - it creates inOut exchange, populates it and send synchronously via channel.

Well... this setup is not particularly easy, but once we get through it, the tests look quite nice:


This sends test message down the NMR, check that output is ok, and that it was caught by Listener.

What's left to do?
You can see some nasty explicit dependencies in configuration - should be taken from maven. Next goal would also be to run SOAPUI tests for testing end to end interaction. But let's leave it for next entry.

To sum up: I think PaxExam is a great tool, although the setup is not so easy. Tests setup is quite long - actually it's faster to build the service bundle and run update on Servicemix to see changes. That's why I would rather recommend using PaxExam for regression tests, run on Hudson (whooops, Jenkins ;))

No comments:

Post a Comment