You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 10 Next »

After developing a component of our OSGI application, we aim to test the new functionality before integrating it. Unitary tests are a good solution to check the classes of our bundle in an isolated way, but what if we want to test how our bundle fits with the other components of our application? Well, we need a testing toolkit providing us the availibity of emulating our deployment environment, like Pax-Exam.

Pax-Exam

Pax-Exam is an automated testing framework for OSGI applications. Its main particularity is how it works. Pax-Exam starts an OSGI container, installs bundles into it, and runs our test classes. This methodology allows us to make assertions over many components, like the services we publish or the result of an operation. 

Integration tests in OpenNaaS are developed using Pax-Exam 2.3.0. Using configuration options provided by this technology, we deploy our own platform inside the OSGI container, automating the installation of bundles and additional features. 

We will use OSPF integration test as an example to illustrate this tutorial. 

Configuring the OSGI container

Test driver and reactor strategy

An integration test is just no more than a java class with some particular annotations and methods. First of all, we have to define the driver the test will run with (in our case, JUnit driver), using the @RunWith annotation

@RunWith(JUnit4TestRunner.class)
public abstract class OSPFIntegrationTest
{
	...
}

As an optional parameter you can also define the reactor strategy. It determinates the behaviour of the container between tests of the same class, but also of the rest of the classes. Available options are "AllConfinedStagedReactorFactory" (a new test container will be started and stoped for each test) and "EagerSingleStagedReactorFactory" (all configured test containers are stated before starting the first test). Default strategy is "AllConfinedStagedReactorFactory". This attribute can be configured by the @ExamReactorStrategy annotation.

@RunWith(JUnit4TestRunner.class)
@ExamReactorStrategy(AllConfinedStagedReactorFactory.class)
public abstract class OSPFIntegrationTest
{
	...
}
Configuration options

In order to configure the main attributes of the OSGI container, Pax-Exam provides multiple configuration mechanisms, like the classpath, JVM configuration options, framework selection, etc. Just to simplify the development of new tests, OpenNaaSs contain a helper class you can use from any integration test. The most important methods are:

  • karafDistrubutionBaseConfigurationOption : Defines OpenNaaS platform as the framework where the tests will be runned.
  • includeTestHelper : include the test helpers bundles in the OSGI container.
  • includeFeatures : include the installation of additional features in the OSGI container.
  • noConsole : starts Karaf without console

All this options must be defined in a @Configuration annotated method  and returning the Option[] type.

@Configuration
public static Option[] configuration() {
	return options(opennaasDistributionConfiguration(),
			includeFeatures("opennaas-router", "opennaas-junos"),
			noConsole(),
			keepRuntimeFolder());
}

As an example, we can see how opennaas-router and opennaas-junos features are included to run the tests of this class.

Writing our test class

Dependency Injection

Pax-Exam allows the injection of dependencies inside the test class directly from the OSGI service registrry. It provides two ways to do it: either using the javax.inject.Inject annotation or optional @Filter one using the BundleContext API.

@Inject
protected IResourceManager		resourceManager;
 
@Inject
protected IProtocolManager		protocolManager;


@Inject
protected BundleContext			bundleContext;


@Inject
@Filter("(osgi.blueprint.container.symbolicname=org.opennaas.extensions.protocols.netconf)")
private BlueprintContainer		netconfService;


@Inject
@Filter("(osgi.blueprint.container.symbolicname=org.opennaas.extensions.router.repository)")
private BlueprintContainer		routerRepoService;

The example above illustrates both possibilities. First of all we inject the ResourceManager, the ProtocolManager and the BundleContext using the java.inject.Inject annotation. On the other hand, using the @Filter Pax-Exam looks in the OSGI service registry the service identified by the given type and also the given attribute value. Router Repository service and Netconf service are retrieved using the name of the its blueprint container.

From this moment, we can call all exported methods by the OSGI services we have injected as an usual insantiated class

@Test
public void resourceManagerIsEmpty() {
	Assert.assertTrue(resourceManager.listResources().isEmpty());
}

 

Creating tests

A simple class can contain multiple test. Tests are no more than methods annotated with the @Test annotation. After configurint and starting the OSGI container, Pax-Exam will scan the class looking for all the annotated functions and will run them according to the reactor strategy we have set. 

/**
 * Test to check if capability is available from OSGi.
 */
@Test
public void isCapabilityAccessibleFromResource()
			throws ResourceException, ProtocolException
{
	startResource();
	Assert.assertTrue(routerResource.getCapabilities().size() > 0);

	stopResource();
	Assert.assertTrue(resourceManager.listResources().isEmpty());
}

The test checks if after starting a resource, it contains at least one capability (startResource() adds the OSPF and Queue capabilities) and that after stopping the resource it has been successfully removed from the ResourceManager service.

As in unitary tests, you can take advantage of the @Before and @After annotation. Functions with these annotations will be called before/after executing the integration test in order to prepare the test environment or to check the state of the container after them. 

Debugging your test

Pax-Exam provides configuration options to pass arguments to the JVM that will be started. We can take advantage of it to debug our test. In OpenNaaS we have created a helper method that will take care of it. 

@Configuration
public static Option[] configuration() {
	return options(opennaasDistributionConfiguration(),
			...
			openDebugSocket(),
			...
}

 

Bassicaly, this function opens a debug socket in port 5005. You can connect your Eclipse (or another IDE) configuring the address and the port of the remove java application.

Maven depenencies

Integration tests in OpenNaaS are located under /itests/ folder. Therefore they inherit from it all the necessary dependencies for starting and configuring the OSGI container.

<dependencies>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
	</dependency>
	<dependency>
		<groupId>org.ops4j.pax.swissbox</groupId>
		<artifactId>pax-swissbox-framework</artifactId>
	</dependency>
	<dependency>
		<groupId>org.osgi</groupId>
		<artifactId>org.osgi.compendium</artifactId>
	</dependency>
	<dependency>
		<groupId>org.opennaas</groupId>
		<artifactId>platform</artifactId>
		<version>${project.version}</version>
		<type>zip</type>
		<scope>test</scope>
		<exclusions>
			<!-- This exclusion is recommended by the Karaf test
			     container manual to ensure compatibility with
			     Eclipse. -->
			<exclusion>
				<groupId>org.apache.karaf.shell</groupId>
				<artifactId>org.apache.karaf.shell.dev</artifactId>
			</exclusion>
		</exclusions>
	</dependency>
</dependencies>

So, the only dependencies we have to define in our pom are the ones containing the componentes we want to check. OSGF integration tests require OpenNaaS core , due it contains ResourceManager and ResourceRepository; the Router Repository to add and remove routers, the Router Model to make assertions over it, and also the capabilities and actionset to test the OSPF developed funcionality.

<dependencies>
	<dependency>
		<groupId>org.opennaas</groupId>
		<artifactId>org.opennaas.core.resources</artifactId>
	</dependency>
	<dependency>
		<groupId>org.opennaas</groupId>
		<artifactId>org.opennaas.extensions.router.repository</artifactId>
	</dependency>
	<dependency>
		<groupId>org.opennaas</groupId>
		<artifactId>org.opennaas.extensions.router.model</artifactId>
	</dependency>
	<dependency>
		<groupId>org.opennaas</groupId>
		<artifactId>org.opennaas.extensions.queuemanager</artifactId>
	</dependency>
	<dependency>
		<groupId>org.opennaas</groupId>
		<artifactId>org.opennaas.extensions.router.capability</artifactId>
	</dependency>
	<dependency>
		<groupId>org.opennaas</groupId>
		<artifactId>org.opennaas.extensions.router.actionsets.junos</artifactId>
	</dependency>
	<dependency>
		<groupId>org.opennaas.itests</groupId>
		<artifactId>org.opennaas.itests.helpers</artifactId>
	</dependency>		
	<dependency>
		<groupId>net.i2cat.netconf</groupId>
		<artifactId>netconf4j</artifactId>
	</dependency>
</dependencies>

 

Pax-Exam Containers

Even thought in OpenNaaS we deploy our platform to run the tests, Pax-Exam 2.x provides three different OSGI containers in which you can launch an OSGI framework and install bundles. Native Container is launched in the same JVM as the driver, and Forked Container launch the framework in an isolated JVM. The third option is the Pax Runner Container. As the forked container, the framework is launched in a separrate VM, but it uses Pax Runner as the main tool to configure and run the tests. The list of maven dependencies you must include in your pom file is defined in the Pax-Exam wiki.

Container Configuration

As seen in OpenNaaS example, we can configure the containter Pax-Exam will provide to test our application. In this section we will explain the main additional options.

Framework

In Pax Runner Container we can choose between Felix, Equinox and Knopflerfish framework and restriction the version we want to use. It will require the correct dependencies in our pom in order to add the selected framework to the container. For example, if we want to run our tests in Felix 1.0.4 version, we have to indicate the following information:

@Configure
public Option[] configuration {
	return new Option[]{
		...
		felix().version("1.0.4"),
		...
	}
}
 
Bundles

The three containers allow you to provision additional bundles to the system by indicating the maven URL.

@Configure
public Option[] configuration {
	return new Option[]{
		...
		bundle("mvn:org.opennaas/org.opennaas.extensions.router.repository/0.0.17-SNAPSHOT"),
		...
	}
}
 
Also you can install a group of bundles if they're defined in a feature by the scanFeatures tool. You need to indicate the feature url and the name of the features you wan to install.

 

@Configure
public Option[] configuration {
	return new Option[]{
		...
		provision(scanFeatures("mvn:org.opennaas/org.opennaas.core.features/0.0.17-		
			SNAPSHOT/xml/features", "router", "bod")),
		...
	}
}
Junit Bundles

If for some reason you  need to include Junit bundles in your container, Pax-Exam provides a helper class that take care of it. 

@Configure
public Option[] configuration {
	return new Option[]{
		...
		junitBundles(),
		...
	}
}

Include system packages

Sometimes, one of our bundles needs to import a package no exported by default by the JVM. Pax-Exam lets you configure a list of additional packages you want the system bundle to export.

@Configure
public Option[] configuration {
	return new Option[]{
		...
		systemPackages("javax.activation.xa", "com.sun.*),
		...
	}
}

 
 Additional configuration options.

You can find complete list of configuration options in Pax-Exam wiki.

 
 
  • No labels