OSGi Service Test Helper: ServiceCollector
OSGi services come in handy for the development of systems based on loosely coupled components. But loose coupling can make it difficult to recognize problems related to dangling service references. Thus we usually run integrations tests to ensure the availability of service components at runtime.
With the intention to reduce boilerplate needed for these kind of tests, I have written a simple utility class to obtain particular service implementations. As this might also be useful for other people, I decided to provide a short usage description in this post.
OSGi Service Relations
OSGi services may depend or use other components to fulfill their purpose. And the web of relations in a running system might get quite complex. This can make it sometimes hard to find out why a certain functionality of an application does not work as expected.
Consider a component that notifies other components using the whiteboard-pattern for example. In case one of the observers fails to register itself, the notification will not happen and dependent capabilities could be broken.
While the reason for this problem might be trivial – e.g. a missing component declaration in the MANIFEST.MF
– it could take some time before it is spotted. Hence it seems to be a good idea to prevent these problems by means of integration tests.
Such tests run after the system’s build process, start the bundle-under-test within an appropriate OSGi environment and verify the its proper component contribution at runtime.
For general OSGi testing purposes there is an OSGi Testing Utils project at GitHub. However I was not able to code a simple one-liner using this library to retrieve a particular service implementation from the registry. That is why I have written the utility class described in this post. But as always there is a good chance that I simply was too stupid to find the proper solution…
ServiceCollector
Let us assume we have a component type Service
…
// Service API declaration interface Service { [...] }
…and a bundle providing an appropriate implementation class…
// Service implementation provided by another bundle public class ServiceImpl implements Service { [...] }
… which is registered via declarative services:
<?xml version="1.0" encoding="UTF-8"?> <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="Implementation of Service API"> <implementation class="com.codeaffine.example.core.ServiceImpl"/> <service< <provide interface="com.codeaffine.example.api.Service"/> </service> </scr:component>
To ensure that the bundle actually succeeds in registering the ServiceImpl
instance, a test could retrieve the components of type Service
from the registry at runtime and somehow filter our particular component contribution. Which is in principle what the ServiceCollector
does.
However I use a down-to-earth approach searching for a particular implementation only. While this might not be conclusive under rare conditions (multiple services of the same implementation type provided by different bundles or the like), it is straight forward for the use cases we encounter in our daily work.
@Test public void serviceAvailable() { List services = collectServices( Service.class, ServiceImpl.class ); assertThat( services ).hasSize( 1 ); }
As you can see ServiceCollector#collectServices
takes the service declaration and its implementation type as parameter to lookup available service instances contributed by a bundle at runtime. It returns a list of components since multiple service instances matching the implementation type might be registered.
Conclusion
So far the ServiceCollector
proves itself quite useful in our current project. Before writing any funtionality related tests when creating a new service, the first thing we usually do is to verify the service availability – which is a piece of cake with the little helper.
But note again that the intended usage is a service-contributions-per-bundle integration test scenario. So be careful with e.g. multiple instances of a a particular implementation provided by different
bundles. Such situations induce unwanted coupling of the bundle related tests.
The ServiceCollector
is part of the com.codeaffine.osgi.test.util feature of the Xiliary P2 repository: http://fappel.github.io/xiliary
In case you want to have a look at the code or file an issue you might also have a look at the Xiliary GitHub project: https://github.com/fappel/xiliary
For everything else feel free to use the commenting section below. So stay tuned – next time I introduce another helper of this package, a JUnit rule useful for test service registrations…
Reference: | OSGi Service Test Helper: ServiceCollector from our JCG partner Frank Appel at the Code Affine blog. |