Testing custom Apache Karaf distributions

Apache Karaf provides KarafTestSupport to easily implement test on Karaf runtime.

Karaf itself uses it to test most of Karaf services in the build (including Jenkins CI).

This approach doesn’t only work for Karaf “vanilla” distribution, but also for any custom distributions based on Karaf.

Custom distribution is available via Maven URL

To illustrate, I’m implementing a test for Apache Unommi. Apache Unomi is a actually a custom Karaf distribution.
It’s available on Maven Central. For this blog, I gonna test Unomi 1.5.1 release: https://repo1.maven.org/maven2/org/apache/unomi/unomi/1.5.1/.

Let’s start with the pom.xml. It basically contains:

  • Karaf itest common and pax exam dependencies
  • Unomi distribution we want to test

Here’s the pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>net.nanthrax.blog</groupId>
    <artifactId>unomi-test</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!-- Provide the KarafTestSupport -->
        <dependency>
            <groupId>org.apache.karaf.itests</groupId>
            <artifactId>common</artifactId>
            <version>4.2.10-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <!-- Unomi distribution to test -->
        <dependency>
            <groupId>org.apache.unomi</groupId>
            <artifactId>unomi</artifactId>
            <version>1.5.1</version>
            <type>tar.gz</type>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Required to use shell commands in the tests -->
        <dependency>
            <groupId>org.apache.karaf.shell</groupId>
            <artifactId>org.apache.karaf.shell.core</artifactId>
            <version>4.2.10-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <!-- Provide the PaxExam Karaf support -->
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-container-karaf</artifactId>
            <version>4.13.3</version>
            <scope>test</scope>
        </dependency>
        <!-- Provide the PaxExam JUnit extension -->
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-junit4</artifactId>
            <version>4.13.4-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-atinject_1.0_spec</artifactId>
            <version>1.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.awaitility</groupId>
            <artifactId>awaitility</artifactId>
            <version>3.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.servicemix.bundles</groupId>
            <artifactId>org.apache.servicemix.bundles.hamcrest</artifactId>
            <version>1.3_1</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.servicemix.tooling</groupId>
                <artifactId>depends-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>generate-depends-file</id>
                        <goals>
                            <goal>generate-depends-file</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <forkCount>1</forkCount>
                    <reuseForks>false</reuseForks>
                    <systemPropertyVariables>
                        <my.system.property>foo</my.system.property>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

We are now ready to create our test class, extending KarafTestSupport and overriding getKarafDistribution() method to define the custom distribution we want to test:

package net.nanthrax.blog.test.unomi;

import org.apache.karaf.itests.KarafTestSupport;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.CoreOptions;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;

@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class ExampleCustomDistributionITest extends KarafTestSupport {

    @Override
    public String getKarafDistribution() {
        return CoreOptions.maven().groupId("org.apache.unomi").artifactId("unomi").versionAsInProject().type("tar.gz").getURL();
    }

    @Test
    public void simpleTest() throws Exception {
        String output = executeCommand("bundle:list -t 0");
        System.out.println(output);
    }

}

This test is very basic: it downloads Unomi, uncompress it, starts it and execute <code>bundle:list -t 0</code> command in the running instance.

We have the complete structure to implement smarter and complete tests now.

Custom distribution locally

The previous test shows how to use a distribution available on a Maven repository. The test is able to download, extract and run the “remote” custom distribution.

There’s another approach available thanks for KarafTestSupport: test an existing distribution located locally.
Instead of download and extracting the distribution, it’s possible to directly use a folder containing the distribution locally.

The approach is similar to the previous one, the only difference is that we don’t need the dependency in the pom.xml and instead provide the local location of the distribution in the test configuration and define is not an archive (not tar.gz or zip):

package net.nanthrax.blog.test.local;

import org.apache.karaf.itests.KarafTestSupport;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;

@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class ExampleLocalDistributionITest extends KarafTestSupport {

    @Override
    public String getKarafDistribution() {
        return "file:/path/to/mydistribution";
    }

    @Override
    public boolean isArchive() {
        // as the distribution is already extracted locally, I'm using directly
        return false;
    }

    @Test
    public void simpleTest() throws Exception {
        System.out.println(executeCommand("shell:info"));
    }

}

What’s next

This blog uses SNAPSHOT version of Karaf and Pax Exam. The reason is that I did change to support such behaviors.
It will be included (backward compatible) in Pax Exam 4.13.4 and Karaf 4.2.10.

In a next blog post, I will show how to test KarService smoothly.

You May Also Like

About the Author: jbonofre

ASF Member, PMC for Apache Karaf, PMC for Apache ServiceMix, PMC for Apache Archiva, PMC for Apache Felix, PMC for Apache Camel, PMC for Apache Syncope, PMC for Apache Beam, PMC for Apache CarbonData, PMC for Apache Bahir, PMC for Apache Brooklyn, PMC for Apache Falcon, PMC for Apache Guacamole, PMC for Apache Lens, Committer for Apache ActiveMQ and much more ! Twitter: jbonofre IRC: jbonofre on #servicemix,#karaf,#camel,#cxf on Freenode