Mark Derricutt's Disturbing Thoughts

My Top Tags

                                       

My Jaiku

Dealing With Bad Apples

Sunday, 20 July 2008 7:26 A GMT+12

Open source saves another marriage

Saturday, 19 July 2008 4:49 P GMT+12

Dark Fortress – Catacrusis

Saturday, 19 July 2008 3:14 P GMT+12

(Untitled)

Saturday, 19 July 2008 10:09 A GMT+12

Code Coverage as a "Static Debugger"

Saturday, 19 July 2008 6:46 A GMT+12

Dimmu Borgir – Absolute Sole Right

Friday, 18 July 2008 2:17 P GMT+12

Wooji Juice: Stage Hand Support

Thursday, 17 July 2008 3:12 P GMT+12

Lion's Share – Cult Of Denial

Thursday, 17 July 2008 1:36 P GMT+12

The Ultimate Software Gold Plating

Thursday, 17 July 2008 5:06 A GMT+12

Search Box

 

OSGi based Integration testing with TestNG and Apache Felix

posted Tuesday, 13 May 2008

Over the last month or so I've been getting my feet wet with a new job, new team mates, and new technology - with the majority of my time getting my head around OSGi and our custom OSGi orientated build tool. Now that I've settled in and starting to see my code take shape it's starting to irk me that I have ZERO tests in any of the code I've written - everything has been a developed under a cycle of code, build, update, test, repeat whilst single stepping through the code in the debugger.

Initially I was 'ok' with the lack of tests as I was still experimenting inside the debugger, interactively hacking my way through foreign code. However now I need to move on from the hacking and get something a little more respectable along with some reproducible tests.

However, now I have a series of OSGi bundles which are exporting services, listening and interacting with other bundles, and doing all manner of things which crossed the boundary of a single bundle - this means I'm needing integration tests more than unit tests.

After thinking up various interesting, but overkill ways of OSGi-enabling TestNG to provide some nice integration testing I settled on the simplest approach (which also looks to be the best, and most flexible so far): embed felix - we already had a custom Felix launcher so this was very much similar (and so simple that it's almost not worth blogging about).

The basic test class simply starts and stops an embedded felix instance:

public class FelixTest {
  private Felix m_felix;

  @BeforeTest
  public void setupFelix() throws IOException, BundleException {
    Map configMap = new StringMap(false);
    configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
      "org.osgi.framework; version=1.3.0," +
      "org.osgi.service.packageadmin; version=1.2.0," +
      "org.osgi.service.startlevel; version=1.0.0," +
      "org.osgi.service.url; version=1.0.0");

    configMap.put(BundleCache.CACHE_PROFILE_PROP, "test");
    File file = File.createTempFile("osgi", "testng");
    file.delete();
    file.mkdir();
    file.deleteOnExit();

    configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, file.getPath());
    // Create an instance of the framework.
    m_felix = new Felix(configMap, new ArrayList());
    m_felix.start();
  }

  @AfterTest
  public void turnOffFelix() throws BundleException {
    m_felix.stop();
  }
}

This simply starts the Felix OSGi container, with a fresh/temp profile directory. Now comes the actual test:

  @Test
  public void testSomethingWithFelix() throws BundleException, InterruptedException {
    BundleContext bundleContext = m_felix.getBundleContext();

    bundleContext
      .installBundle("file:///Users/amrk/temp/osgi-test/test-rest/target/test-rest-1.0-SNAPSHOT.jar")
      .start();
    bundleContext
      .installBundle("file:///Users/amrk/temp/osgi-test/test-client/target/test-client-1.0-SNAPSHOT.jar")
      .start();

    Bundle[] bundles = bundleContext.getBundles();
    for (Bundle bundle : bundles) {
      assert bungle.getState() == Bundle.ACTIVE
        : "Bundle " + bundle.getSymbolicName() + " is not started.";
    }

    ServiceReference sr = bundleContext.getServiceReference(MyService.class.getName());
    if (sr != null) {
      Object myService = bundleContext.getService(sr);
      if (myService != null) {
        method("run").in(myService).invoke();
      }
    } else {
      assert false: "No Service Reference for MyService";
    }
  }

The test starts off by installing and starting two bundles from the file system then checks they all have the ACTIVE state (meaning they installed, resolved, and started running without problem). The test then looks up a service which should be exported from the test-rest bundle, then via reflection (using FEST-Reflect) executes the service. (reflection is used here as 'myService' service is an instance of MyService from the OSGi bundles class loader and not from the tests class loader.)

Now I have a good base for writing OSGi based integration tests that easily be extended with database creations/migrations and anything else that may come to mind.

tags:          

links: digg this    del.icio.us    technorati    reddit