- Basic problem of OSGi bundle testing
- Running a unit test inside an OSGi Framework
- Interaction between a test runner and the OSGi Framework
One of the main characteristics of an OSGi environment is its high dynamicity. Services come and go at any time or get updated by newer versions. To verify that functionality provided by an OSGi Bundle does indeed behave as expected, you need good test coverage of that functionality. This of course is a general truth that is not limited to OSGi alone.
The benefit of unit testing is to isolate functionality and show that it behaves as expected. A unit test provides a strict, written contract that the piece of code must satisfy.
The basic problem in OSGi is that you cannot access the artefacts that you deploy in a bundle directly from the test case that runs external to the OSGi Framework. The test case is loaded from different classloader than the artefacts contained in the bundle.
Embedded OSGi Framework
This is probably the most common usage. A test or a wrapper around a collection of tests bootstraps the OSGi Framework installs a number of bundles and verifies their correct behaviour. Husky test cases leverage the OSGi Framework Launch API. Framework launching should not require prior knowledge of the actual framework implementation. OSGi Framework and test runner share the same VM. From the perspective of the test runner, the test can be executed like an ordinary unit test, which gives the developer the freedom of choice with respect to the runner (i.e. Eclipse, IntelliJ, Maven, Ant). The test reports results back to the runner like an ordinary unit test, which preserves the runner's test report functionality.
Remote OSGi Framework
In an enterprise scenario the OSGi Framework is more often than not a standalone container. The same test as above should be deployable in a remote framework that is already running. It is a configuration option of the test environment of whether the test gets installed into an embedded OSGi Framework or deployed to a remote framework instance. OSGi Framework and test runner do not share the same VM. From the perspective of the test runner, the test can still be executed like an ordinary unit test and it is completely transparent that the test gets actually executed in a remote environment. Conceptually, this is similar to what Apache Cactus is about.
- The solution MUST support plain JUnit4 POJO test cases
- There SHOULD be no requirement to extend a specific test base class
- There MUST be no requirement on a specific test runner
- There SHOULD be a minimum test framework leakage into the test case
- The test framework MUST support embedded and remote OSGi Runtimes with no change required to the test
- The same test case MUST be executable from outside as well as from within the OSGi Framework
- There SHOULD be a pluggable communication layer from the test runner to the OSGi Framework
- The test framework MUST NOT depend on OSGi Framework specific features
- There MUST be no automated creation of test bundles required by the test framework
JBoss OSGi Husky has client side interceptor that fields the test request to an embedded/remote OSGi Framework where the test case is then actually executed.
How does it work
- A Bridge intercepts a test and determines the FQN of the test case and the test method from the call stack. It then delegates the execution to the same (or another) test in and isolated test environment. An isolated test environment is one that does not have the same class loading space as the test itself.
- A Bridge is associated with an Invoker. Invokers may be arbitarily complex. Local 'in proccess' invokers are possible just as well as remote invokers.
- The Invoker sends the Request to a Connector in the isolated test environment.
- A Connector has associated PackageListeners that are responsible for processing test cases for their respective test packages.
- A PackageListeners delegates the Request to a test Runner, typicaly this would be a JUnitRunner.
- The Runner injects the Context into the test case and returns a Response, which the Connector returns to the Invoker.
- The Bridge finally translates potential Failures that may be contained in the Result, to test failures on the client side.
In the target OSGi Framework, which is the one that has the jboss-osgi-husky.jar bundle installed, you set these properties.
# Husky socket connector propertiesBoth properties must be set for the SocketConnector to be available.
On the client side, you configure the Invoker that you want to use.
# Husky invoker properties
This particular invoker will also look for the host and port properties and if availbale will use socket invocation.
Writing Husky Tests
In a typical Husky test you have
- A discriminator to distinguish between client and 'in container' execution
- An interceptor that delegates the call to an Invoker
public class SimpleHuskyTestCase
public BundleContext context;
public void testSimpleBundle() throws Exception
// Tell Husky to run this test method within the OSGi Runtime
if (context == null)
// Stop here if the context is not injected
// Get the SimpleService reference
ServiceReference sref = context.getServiceReference("SimpleService");
assertNotNull("SimpleService Not Null", sref);
// Access the SimpleService
SimpleService service = (SimpleService)context.getService(sref);
The bundle that contains the test case must have the Test-Package manifest header configured.
Bundle-SymbolicName: example-simple-huskyThat's it for now. JBoss OSGi 1.0.0.Beta4 is ready and waiting for the files to show up on Sourceforge. In a follow up post you can read about our new native OSGi Framework implementation that is based on the JBoss Microcontainer and how JBoss OSGi uses Pax Web to provide support for OSGi WebApps.
# Export the package that contains the test case
# Tell Husky that there are test cases in this package
May this be useful