Eclipse/PDE-Container

This page is work in progress! The EclipseContainer was planed for Exam 4.12.0 but is now developed as a separate extension, it can be accessed via the snapshot repositories, feedback is welcome!


The Eclipse-Container brings the power of the PDE Tools into the world of PaxExam.

With this container you are able to use and provision

  • Bundles
  • Features
  • Installable Units
  • Target-Platforms
  • Product-Definitions

in tests directly without the need of export/reconfigure these to use in PaxExam Tests from one of the following sources

  • P2-Repositories
  • URLs
  • Filesystem
  • Eclipse-Workspaces
  • exported product zips

It is possible to run Eclipse-Platform Applications as well as plain-OSGi ones.

Maven-Setup

to use the container simply add the following to your pom additionally to the ones described in Maven Dependencies.

<dependency>
    <groupId>org.ops4j.pax.exam</groupId>
    <artifactId>pax-exam-container-eclipse</artifactId>
    <version>${pax.exam.version}</version>
    <scope>test</scope>
</dependency>

Basic Concepts

You should already have basic knowledge about Pax Exam so you might want to read especially the Configuration Options part already. Even though the Eclipse-Container provides a lot of own Options you still can use any of the default Pax Exam OSGi ones, infact this implementation produces, as a final result, mostly those standard options for you.

As a very first step you have to decide where your bundles should come from, the so called ArtifactSource, where you always can combine different sources, typically you would choose one or more of the following:

  • a workspace
  • a target.platform
  • an installation folder or exported Eclipse product
  • one or more P2 repositories

ArtifactSources can, depending on there implementation, provide different artifacts to later stages. Then you have to choose which artifacts you want to provision:

  • single bundles
  • features
  • installable units
  • products

typically you want to choose one but you can also combine these as needed. We will describe the different ways to read bundles and provision artifacts.

Creating ArtifactSources

Creating an ArtifactSource from a workspace

The EclipseWorkspace source comes in two flavours, either a 'real' Eclipse workspace you use in your IDE, or a simple directory tree that contains Eclipse projects, in both cases you can create one the following way

EclipseWorkspace workspace = EclipseOptions.fromWorkspace(new File("/home/user/workspace"));

this will read all projects from the given location and provide you with bundles and features (if found). This source is a little bit special in the way since it provides you with access to an artifact that is not directly used by tests but comes handy when provisioning things: a project.

You can access projects by name and the access resources from it, e.g product or target definitions, or any resource that seems useful

EclipseProject project = workspace.project("target-project");
InputStream targetStream = project.getResourceAsStream("default.target");

Creating an ArtifactSource from a target platform

You probably already has some sort of target platform for your development, so you can use this to provision items from

InputStream targetDefinition = ...;
File cacheFolder = new File("target/eclipsecache");
EclipseOptions.fromTarget(targetDefinition, cacheFolder);

You need to provide an inputstream to the target file an optionally a cache folder. Since resolving a target can be quite time consuming a cache folder is recommended especially when using software-sites/p2 repros. You might find it handy to fetch the InputStream from a workspace like described before but of course can provide if from any source you like.

Creating an ArtifactSource from an installationfolder or exported Eclipse product

The simplest case is where you have a bunch of bundles or features exported as jar files (e.g. an exported product or an eclipse installation or something you have created yourself) you can read in these items like this:

EclipseInstallation installation = EclipseOptions.fromInstallation(new File("/home/user/exported_product"));

the method detects several layouts of the folder, e.g. having all in one folder or having seperate plugins/features folders.

Creating an ArtifactSource from one or more P2 repositories

You maybe already have deployed everything into a p2 repository? Then you can read of course from one of those

EclipseRepository repository = EclipseOptions.createRepository(new URL("http://download.eclipse.org/eclipse/updates/4.7"), "eclipse");

just keep in mind that using p2-repositories can be very time consuming (even if there is some caching under the hood). To speed up things you can define a (test) target platform and add the relevant parts there and the use the caching feature of the target platform, since this downloads all necessary parts and keep them on disk this is a lot faster! Just keep in mind to increment the target version number if you repro changes.

Combine different Sources

different Sources can be combined into one like this

EclipseWorkspace workspace = EclipseOptions.fromWorkspace(new File("/home/user/workspace"));
EclipseProject project = workspace.project("target-project");
InputStream targetStream = project.getResourceAsStream("default.target");
File cacheFolder = new File("target/eclipsecache");
EclipseTargetPlatform target = EclipseOptions.fromTarget(targetStream, cacheFolder);
        
CombinedEclipseArtifactSource combine = EclipseOptions.combine(workspace, target);

Provisioning from Products and Installations

Even though most powerful, provisioning directly from the source (see below) can be very time consuming and error prone, since you have to configure all things accordingly. In most cases you already have a product defined (or can define one for testing purpose) that is easily configured through the Eclipse UI. These can also be used to provision your test. This is the preferable way to setup your test as you can completely configure your test case with the tools you know and only need to specif the Product under Test.

Build from a product

The builder also reads VM-Options, start-levels and so on from the product file so you are ready to go testing (smile)

@Configuration
public Option[] configure() throws IOException {
    EclipseArtifactSource source = ... ;
    EclipseApplicationOption option = EclipseOptions.buildFromProduct(SimpleContainerTest.class.getResourceAsStream("/testcase1.product"))
       .source(source).create();
    return options(option, junitBundles());
}

Build from an installation

Here you don't even need a source since the installation itself is used as the source.

@Configuration
public Option[] configure() throws IOException {
    EclipseApplicationOption option = EclipseOptions.buildFromEclipseInstallation(EclipseOptions.fromInstallation(new File("/opt/eclise-installation/"))).create();
    return options(option, junitBundles());
}

Build from a Zip-File

And you can even just use a Zipped version of your product

@Configuration
public Option[] configure() throws IOException {
    EclipseApplicationOption option = EclipseOptions.buildFromEclipseArchive(new File("/tmp/eclipse.zip")).create();
    return options(option, junitBundles());
}

Extend an existing product for testing purpose

From time to time you might want to extend an existing product by some features/bundles/... even that is possible

@Configuration
public Option[] configureFromProduct() throws IOException {
    EclipseUnitSource source = ... ;
    EclipseApplicationOption option = EclipseOptions.buildFromProduct(SimpleContainerTest.class.getResourceAsStream("/testcase1.product"))
       .source(source).create();
    EclipseProvision provision = option.getProduct().getLauncher().getProvision();
    provision.singletonConflictResolution(SingletonConflictResolution.USE_HIGHEST_VERSION);
    
    EclipseRepository repository = EclipseOptions.createRepository(new URL("http://download.eclipse.org/technology/swtbot/releases/latest/"), "swt-bot");
    EclipseInstallableUnit gnerator_unit = repository.unit("org.eclipse.swtbot.generator");
    EclipseInstallableUnit eclipse_unit = repository.unit("org.eclipse.swtbot.eclipse.feature.group");
    EclipseInstallableUnit hamcrestlib_unit = repository.unit("org.hamcrest.library");
    List<EclipseBundleOption> bundles = provision
                    .units(IncludeMode.PLANNER, repository, gnerator_unit, eclipse_unit, hamcrestlib_unit);
    
    
    return options(option, junitBundles());
}


Provision Artifacts from the sources directly

Now we have a source to provision items from we can proceed by adding items from this source to our test setup. Depending on the type the following things can be accessed. Even though this way is very flexible it requires you to setup a bunch of stuff (bundles to include, setting startlevels and so on) it is adviced to use products instead to configure your test setup (see above!).

EclipseBundleSource

The basic artifact to use is the bundle, you can obtain bundles either by name, by name and version or by name and version range. A bundle might be used directly with pax exam.

@Configuration
public Option[] configure() throws IOException {
    EclipseBundleSource bundleSource = ...;
    return options(EclipseOptions.launcher(EclipseOptions.provision(bundleSource)).ignoreApp(), bundleSource.bundle("my.eclipse.bundle"), junitBundles());
}

In fact it is more convenient to not provision bundles directly, so keep on reading to learn about more options...

EclipseFeatureSource

You can obtain features either by name, by name and version or by name and version range. A feature structures a set of bundles and dependent features (either required or optional). Even though a feature can be added as-is to pax exam this is not desirable in most cases, since you can't install a feature that way into the OSGi-Framework. To take full advantage of a feature it must be resolved first.

@Configuration
public Option[] configure() throws IOException {
    EclipseFeatureSource featureSource = EclipseOptions.fromInstallation(new File(""));
    EclipseFeatureOption feature = featureSource.feature("my.eclipse.feature");
        
    EclipseProvision provision = EclipseOptions.provision(featureSource);
    List<EclipseBundleOption> list = provision.feature(feature);
    for (EclipseBundleOption bundle : list) {
       //configure bundle here
    }
    return options(EclipseOptions.launcher(provision).ignoreApp(), junitBundles());
}

EclipseUnitSource

This is the most powerful source since you can provision a whole eclipse feature including dependencies! Like features Installable Units can not be installed directly but must be resolved. Beside this it is the most expensive operation in terms of resolving time since it requires to fetch and compute potential large datasets. So you are able to cache a resolved result of this but take in mind that you are responsible for clearing the cache if needed!

@Configuration
public Option[] configure() throws IOException {
    EclipseUnitSource unitSource = EclipseOptions.createRepository(new URL("http://download.eclipse.org/eclipse/updates/4.7"), "eclipse");
    EclipseInstallableUnit unit = unitSource.unit("org.eclipse.pde");
    
    EclipseProvision provision = EclipseOptions.provision(unitSource);
    provision.singletonConflictResolution(SingletonConflictResolution.USE_HIGHEST_VERSION);
    List<EclipseBundleOption> list = provision.units(IncludeMode.PLANNER, unit);
    for (EclipseBundleOption bundle : list) {
        //configure bundle here
    }
    return options(EclipseOptions.launcher(provision).ignoreApp(), junitBundles());
}