package org.apache.aries.subsystem.ctt.itests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.osgi.framework.namespace.BundleNamespace.BUNDLE_NAMESPACE; import static org.osgi.framework.namespace.PackageNamespace.PACKAGE_NAMESPACE; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.aries.subsystem.itests.Header; import org.apache.aries.subsystem.itests.SubsystemTest; import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; import org.ops4j.pax.exam.spi.reactors.PerMethod; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.wiring.BundleWire; import org.osgi.framework.wiring.BundleWiring; import org.osgi.service.subsystem.Subsystem; /* * A set of tests to cover OSGi Subsystems CTT section 4, "Subsystem Dependency Tests" * This is going to look a bit like ProvisionPolicyTest with a bit of * DependencyLifecycle thrown in. * * - The following bundles are used for the tests - Bundle A that export package x - Bundle B that provides capability y - Bundle C that imports package x - Bundle D that requires bundle A - Bundle E that requires capability y - Bundle F that export package x - Bundle G that provides capability y - The following repositories are defined - Repository R1 - Bundle A - Bundle B - Bundle C - Bundle D - Bundle E - Bundle F - Bundle G - Repository R2 - Bundle A - Bundle B - Bundle C - Bundle D - Bundle E */ @ExamReactorStrategy(PerMethod.class) public abstract class SubsystemDependencyTestBase extends SubsystemTest { protected static String BUNDLE_A = "sdt_bundle.a.jar"; protected static String BUNDLE_B = "sdt_bundle.b.jar"; protected static String BUNDLE_C = "sdt_bundle.c.jar"; protected static String BUNDLE_D = "sdt_bundle.d.jar"; protected static String BUNDLE_E = "sdt_bundle.e.jar"; protected static String BUNDLE_F = "sdt_bundle.f.jar"; protected static String BUNDLE_G = "sdt_bundle.g.jar"; @Override protected void createApplications() throws Exception { // We'd like to do this in an @BeforeClass method, but files written in @BeforeClass // go into the project's target/ directory whereas those written in @Before go into // paxexam's temp directory, which is where they're needed. createBundleA(); createBundleB(); createBundleC(); createBundleD(); createBundleE(); createBundleF(); createBundleG(); } private void createBundleA() throws Exception { createBundle(name(BUNDLE_A), version("1.0.0"), exportPackage("x")); } private void createBundleB() throws Exception { // TODO: see comment below about bug=true createBundle(name(BUNDLE_B), version("1.0.0"), new Header(Constants.PROVIDE_CAPABILITY, "y;y=randomNamespace")); } private void createBundleC() throws Exception { createBundle(name(BUNDLE_C), version("1.0.0"), importPackage("x")); } private void createBundleD() throws Exception { createBundle(name(BUNDLE_D), version("1.0.0"), requireBundle(BUNDLE_A)); } // TODO: /* * According to the OSGi Core Release 5 spec section 3.3.6 page 35, * "A filter is optional, if no filter directive is specified the requirement always matches." * * If omitted, we first get an NPE in DependencyCalculator.MissingCapability.initializeAttributes(). * If that's fixed, we get exceptions of the form, * * Caused by: java.lang.IllegalArgumentException: The filter must not be null. * at org.eclipse.equinox.internal.region.StandardRegionFilterBuilder.allow(StandardRegionFilterBuilder.java:49) * at org.apache.aries.subsystem.core.internal.SubsystemResource.setImportIsolationPolicy(SubsystemResource.java:655) * * This looks to be an Equinox defect - at least in the level of 3.8.0 currently being used by these tests. */ private void createBundleE() throws Exception { createBundle(name(BUNDLE_E), version("1.0.0"), new Header(Constants.REQUIRE_CAPABILITY, "y")); } private void createBundleF() throws Exception { createBundle(name(BUNDLE_F), version("1.0.0"), exportPackage("x")); } // TODO: see comment above about bug=true private void createBundleG() throws Exception { createBundle(name(BUNDLE_G), version("1.0.0"), new Header(Constants.PROVIDE_CAPABILITY, "y;y=randomNamespace")); } protected void registerRepositoryR1() throws Exception { registerRepositoryService(BUNDLE_A, BUNDLE_B, BUNDLE_C, BUNDLE_D, BUNDLE_E, BUNDLE_F, BUNDLE_G); } protected void registerRepositoryR2() throws Exception { registerRepositoryService(BUNDLE_A, BUNDLE_B, BUNDLE_C, BUNDLE_D, BUNDLE_E); } /** * - Verify that bundles C, D and E in subsystem s wire to A->x, A, B->y respectively */ protected void checkBundlesCDandEWiredToAandB (Subsystem s) { verifySinglePackageWiring (s, BUNDLE_C, "x", BUNDLE_A); verifyRequireBundleWiring (s, BUNDLE_D, BUNDLE_A); verifyCapabilityWiring (s, BUNDLE_E, "y", BUNDLE_B); } /** * Check that wiredBundleName in subsystem s is wired to a single package, * expectedPackage, from expectedProvidingBundle * @param s * @param wiredBundleName * @param expectedPackage * @param expectedProvidingBundle */ protected void verifySinglePackageWiring (Subsystem s, String wiredBundleName, String expectedPackage, String expectedProvidingBundle) { Bundle wiredBundle = context(s).getBundleByName(wiredBundleName); assertNotNull ("Bundle not found", wiredBundleName); BundleWiring wiring = (BundleWiring) wiredBundle.adapt(BundleWiring.class); List<BundleWire> wiredPackages = wiring.getRequiredWires(PACKAGE_NAMESPACE); assertEquals ("Only one package expected", 1, wiredPackages.size()); String packageName = (String) wiredPackages.get(0).getCapability().getAttributes().get(PACKAGE_NAMESPACE); assertEquals ("Wrong package found", expectedPackage, packageName); String providingBundle = wiredPackages.get(0).getProvider().getSymbolicName(); assertEquals ("Package provided by wrong bundle", expectedProvidingBundle, providingBundle); } /** * Verify that the Require-Bundle of wiredBundleName in subsystem s is met by a wire * to expectedProvidingBundleName * @param s * @param wiredBundleName * @param expectedProvidingBundleName */ protected void verifyRequireBundleWiring (Subsystem s, String wiredBundleName, String expectedProvidingBundleName) { Bundle wiredBundle = context(s).getBundleByName(BUNDLE_D); assertNotNull ("Target bundle " + wiredBundleName + " not found", wiredBundle); BundleWiring wiring = (BundleWiring) wiredBundle.adapt(BundleWiring.class); List<BundleWire> wiredBundles = wiring.getRequiredWires(BUNDLE_NAMESPACE); assertEquals ("Only one bundle expected", 1, wiredBundles.size()); String requiredBundleName = (String) wiredBundles.get(0).getCapability().getAttributes().get(BUNDLE_NAMESPACE); assertEquals ("Wrong bundle requirement", BUNDLE_A, requiredBundleName); String providingBundle = wiredBundles.get(0).getProvider().getSymbolicName(); assertEquals ("Wrong bundle provider", expectedProvidingBundleName, providingBundle); } /** * Verify that a bundle with wiredBundleName imports a single capability in namespace * from expectedProvidingBundleName * @param s * @param wiredBundleName * @param namespace * @param expectedProvidingBundleName */ protected void verifyCapabilityWiring (Subsystem s, String wiredBundleName, String namespace, String expectedProvidingBundleName) { Bundle wiredBundle = context(s).getBundleByName(wiredBundleName); assertNotNull ("Targt bundle " + wiredBundleName + " not found", wiredBundleName); BundleWiring wiring = (BundleWiring) wiredBundle.adapt(BundleWiring.class); List<BundleWire> wiredProviders = wiring.getRequiredWires(namespace); assertEquals("Only one wire for capability namespace " + namespace +" expected", 1, wiredProviders.size()); String capabilityNamespace = (String) wiredProviders.get(0).getCapability().getNamespace(); assertEquals ("Wrong namespace", namespace, capabilityNamespace); String providingBundle = wiredProviders.get(0).getProvider().getSymbolicName(); assertEquals ("Wrong bundle provider", expectedProvidingBundleName, providingBundle); } /** * Verify that bundles with names bundleNames are installed into the subsystem with subsystemName * and bundle context bc * @param bc * @param subsystemName * @param bundleNames */ protected void verifyBundlesInstalled (BundleContext bc, String subsystemName, String ... bundleNames) { for (String bundleName: bundleNames) { boolean bundleFound = false; inner: for (Bundle b: bc.getBundles()) { if (b.getSymbolicName().equals(bundleName)) { bundleFound = true; break inner; } } assertTrue ("Bundle " + bundleName + " not found in subsystem " + subsystemName, bundleFound); } } /** * Check that no new bundles have been provisioned by [x] * @param failText where the failure occurred * @param rootBundlesBefore Bundles before [x] * @param rootBundlesAfter Bundles after [x] */ protected void checkNoNewBundles(String failText, Bundle[] rootBundlesBefore, Bundle[] rootBundlesAfter) { Set<String> bundlesBefore = new HashSet<String>(); for (Bundle b : rootBundlesBefore) { bundlesBefore.add(b.getSymbolicName() + "_" + b.getVersion().toString()); } Set<String> bundlesAfter = new HashSet<String>(); for (Bundle b : rootBundlesAfter) { bundlesAfter.add(b.getSymbolicName() + "_" + b.getVersion().toString()); } boolean unchanged = bundlesBefore.containsAll(bundlesAfter) && bundlesAfter.containsAll(bundlesBefore); if (!unchanged) { bundlesAfter.removeAll(bundlesBefore); fail ("Extra bundles provisioned in " + failText + " : " + bundlesAfter); } } }