Reading run requirements from POM (test) dependencies

We can use statements like this in a .bndrun files:

-runrequires: \
	bnd.identity;id='${project.groupId}.${project.artifactId}',\
	bnd.identity;id='${project.groupId}.${project.artifactId}-tests',\

Now, typically I need a bunch of additional bundles / artifacts which do not have hard code-references in the main artifact - e.g. they may only contain optional resources. In my Maven POM, I have those as test dependencies. Is there some way to query the test dependencies from the Maven POM and inject them here under runrequires as well?

Currently, I have to manually update both, the pom.xml file and the .bndrun file when I need a new resource bundle test dependency.

Do you have a lot of things that you need to add manually? Usually it is the resolvers job to collect this stuff. In most of our cases the we only have the bnd.identity;id='${project.groupId}.${project.artifactId}-tests' as runrequires and we let the resolver do the rest.

Well, yes :slight_smile: I have various artifacts that contain only data (OSGI fragments without any Java code) and those are test dependencies in Maven and in the bndrun file I use for testing, I have to add them again.

Imagine a tool that supports different languages through language packs. The tool is sold to different markets, each only with one language pack. However, when testing, I want to test against all languages. So the dependency on the language packs is a test dependency in Maven. The language pack is an OSGI artifact which contains only some language files and no code.

So there is no hard code-wise dependency from the test code to the data fragments. Iā€™m not sure how the resolver should be able to detect that I want them to be available - other by actually looking at the test-scoped dependencies in the POM - which I think it does not do.

While this is not exactly the situation Iā€™m facing, itā€™s close enough.

This is exactly what youā€™d use Requirements and Capabilities for as an end user of OSGi.

Define, in each Data bundle, that it provides a capability. There could be several tiers of capabilities defined such that you can pin down what you want on multiple levels; individuals, subset, entire set:

e.g. Letā€™s say you have bundle that has this header:

Provide-Capability: data-file;data-file=lua;family=intepreted;language=lua

and another:
Provide-Capability: data-file;data-file=c;family=compiled;language=c

In a bundle that requires to have at least one data bundle of any particular type:

`Require-Capability: data-file;filter:=ā€˜(data-file=*)ā€™

Or in a test suite where you want a specific one (bnd -runrequires for instance):
`Require-Capability: data-file;filter:=ā€˜(data-file=c)ā€™

Or maybe just any interpreted ones:
`Require-Capability: data-file;filter:=ā€˜(family=intepreted)ā€™

See https://blog.osgi.org/2015/12/using-requirements-and-capabilities.html for a more thorough example.

I do have to learn more about capabilities, but I do not think it helps me in this case.

The Maven POM defines which test artifacts I want to use. It does so via test dependencies.

Even with capabilities, I would need to duplicate the configuration from the POM in the bndrun file. I might be able to use some wildcards or such, but still I would have to duplicate the configuration.

Want I would prefer is to be able to say hey bnd, use all those test-scoped dependencies from the POM and add them to your "runrequires" please so I would have exactly those test dependencies - not more and not less.

So maybe something like:

-runrequires: \
	bnd.identity;id='${project.dependencies;scope=compile},\
	bnd.identity;id='${project.dependencies;scope=test},\

hey bnd, use all those test-scoped dependencies from the POM and add them to your "runrequires" please

The bnd-resolver-maven-plugin in combination with the bnd-testing-maven-plugin can do exactly that.

I call it ā€œcontinuous resolutionā€. When running tests, your first real test should be ā€œdoes this all resolve?ā€.

If you canā€™t even resolve, then your other ā€œtestsā€ arenā€™t likely going to make your usersā€™ lives any easier and youā€™re probably already in deeper trouble than you think (assembling an application from your bundles will feel like just throwing spaghetti at the wall to see what sticks).

As an example of this in the real world, when we exposed tooling/infrastructure projects like JUnit(5), AssertJ, Mockito and so on to this mindset, they realized that ā€œcontinuous resolutionā€ prevented a slew of hard to detect OSGi problems and acts as a great safety net that you can point users to to say with confidence ā€œthis set of OSGi bundles is good, because not only do we run a battery of tests, but we resolve the entire runnable assembly every time we run tests.ā€

So, I recommend using ā€œresolutionā€ as your first line of checking, resolve your tests, which is what the bnd tester allows you to do, even in maven via the bnd-testing-maven-plugin.

Lastly, if you resolve, if you resolve your tests, you can use any requirements & capabilities to constrain what getā€™s into those test runtimes too.

There are several real world example projects that show how this is done (several Apache Aries subprojects operate this way using maven.)

Requirements and capabilities would be my reaction too.
I think it could look like this:

TestBundleA and TestBundleB, both declare and provide the capability ā€œi-am-languageā€ in their respective bnd.bnd files. Then you specify a requirement for this capability in a .bndrun file.

TestBundleAā€™s bnd.bnd:

In the bnd.bnd file for TestBundleA, you need to specify that this bundle provides a capability. Hereā€™s how this could look like:

Bundle-SymbolicName: TestBundleA
Bundle-Version: 1.0.0
Provide-Capability: i-am-language; i-am-language="german"

TestBundleBā€™s bnd.bnd:

Similarly, for TestBundleB:

Bundle-SymbolicName: TestBundleB
Bundle-Version: 1.0.0
Provide-Capability: i-am-language; i-am-language="greek"

.bndrun file:

For the .bndrun file, you can specify a requirement to use any bundle providing the ā€œi-am-languageā€ capability. Hereā€™s how you could write this:

-runrequires: \
    osgi.identity;filter:='(i-am-language=*)'

This setup should instruct OSGi to include any available bundle that provides a matching capability.
Not sure this is syntactically correct, but this is how I understand req & cap.

On second though, I think my example was not close enough :frowning:

I wrote I want to test against all languages, but I should have written I want to test against some languages - namely exactly those for which I also include the respective dependencies in the pom.xml file.

Otherwise, the capabilities might indeed offer a nice way to go. But the some here makes the whole difference I believe.

ok :slight_smile:

Sounds a bit like your approach is somehow pom.xml first. I have no experience with this.

Just a last tip for learning and visualising Requirements & Capabilities, in case you donā€™t know already:

The Resolution view makes Capabilities (and Requirements) of bundles visible. It allows you to see and the capabilities of specific bundles (and maybe it helps to find one that you maybe not be aware of).

  • (multi-)select your bundles you want to observe in the Repository Browser
  • then check the right side of the Resolution view for the capabilities of the selected bundles

The screenshot is from a 7.1 snapshot.

1 Like

If you have a property in bnd, you can use the template macro to build a new header.