BROOKLYN-546: add unit test Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/2a539c0d Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/2a539c0d Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/2a539c0d
Branch: refs/heads/master Commit: 2a539c0dc181c7b82e0e8e8c1b2345b464325d10 Parents: bfabe7c Author: Aled Sage <[email protected]> Authored: Mon Oct 23 17:37:05 2017 +0100 Committer: Aled Sage <[email protected]> Committed: Fri Oct 27 12:31:20 2017 +0100 ---------------------------------------------------------------------- .../brooklyn/core/mgmt/ha/OsgiManager.java | 11 ++ .../AbstractBrooklynLauncherRebindTest.java | 10 +- .../BrooklynLauncherRebindCatalogOsgiTest.java | 100 ++++++++++++++++++- 3 files changed, 119 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2a539c0d/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java index 995f7ed..9f47a44 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java @@ -76,6 +76,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.annotations.Beta; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -326,6 +327,16 @@ public class OsgiManager { brooklynBundlesCacheDir = null; } + @VisibleForTesting + public static Maybe<Framework> tryPeekFrameworkForReuse() { + synchronized (OSGI_FRAMEWORK_CONTAINERS_FOR_REUSE) { + if (!OSGI_FRAMEWORK_CONTAINERS_FOR_REUSE.isEmpty()) { + return Maybe.of(OSGI_FRAMEWORK_CONTAINERS_FOR_REUSE.get(0)); + } + } + return Maybe.absent(); + } + /** Map of bundles by UID */ public Map<String, ManagedBundle> getManagedBundles() { return managedBundlesRecord.getManagedBundles(); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2a539c0d/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java ---------------------------------------------------------------------- diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java index 0369862..89bcae0 100644 --- a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java +++ b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java @@ -25,6 +25,7 @@ import static org.testng.Assert.assertNull; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; @@ -138,7 +139,14 @@ public abstract class AbstractBrooklynLauncherRebindTest { Files.write(contents, file, Charsets.UTF_8); return file; } - + + protected File newTmpCopy(File orig) throws Exception { + File file = java.nio.file.Files.createTempFile("brooklynLauncherRebindTest-"+Identifiers.makeRandomId(4), "txt").toFile(); + tmpFiles.add(file); + Streams.copyClose(new FileInputStream(orig), new FileOutputStream(file)); + return file; + } + protected File newTmpBundle(Map<String, byte[]> files, VersionedName bundleName) { return newTmpBundle(files, bundleName, ImmutableMap.of()); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/2a539c0d/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java ---------------------------------------------------------------------- diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java index 2e9c78e..d4e8c75 100644 --- a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java +++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java @@ -18,15 +18,30 @@ */ package org.apache.brooklyn.launcher; +import static org.testng.Assert.assertEquals; + import java.io.File; import java.nio.charset.StandardCharsets; +import java.io.FileInputStream; +import java.net.URI; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; +import org.apache.brooklyn.api.typereg.ManagedBundle; +import org.apache.brooklyn.api.typereg.RegisteredType; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; +import org.apache.brooklyn.core.mgmt.ha.OsgiManager; +import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; +import org.apache.brooklyn.entity.stock.BasicEntity; import org.apache.brooklyn.test.support.TestResourceUnavailableException; +import org.apache.brooklyn.util.core.osgi.Osgis; +import org.apache.brooklyn.util.os.Os; import org.apache.brooklyn.util.osgi.OsgiTestResources; import org.apache.brooklyn.util.osgi.VersionedName; +import org.osgi.framework.Bundle; +import org.osgi.framework.launch.Framework; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -38,6 +53,8 @@ import com.google.common.collect.Iterables; public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLauncherRebindTest { + private static final String CATALOG_EMPTY_INITIAL = "classpath://rebind-test-empty-catalog.bom"; + private static final VersionedName COM_EXAMPLE_BUNDLE_ID = new VersionedName( OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_SYMBOLIC_NAME_FULL, OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_VERSION); @@ -45,6 +62,8 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc private static final Set<VersionedName> COM_EXAMPLE_BUNDLE_CATALOG_IDS = ImmutableSet.of( new VersionedName("com.example.simpleTest", "0.0.0-SNAPSHOT")); + private boolean reuseOsgi = false; + @BeforeMethod(alwaysRun=true) @Override public void setUp() throws Exception { @@ -58,7 +77,7 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc @Override protected boolean reuseOsgi() { - return false; + return reuseOsgi; } private BrooklynLauncher newLauncherForTests(String catalogInitial) { @@ -88,6 +107,79 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc assertManagedBundle(newLauncher, bundleName, bundleItems); } + /** + * See https://issues.apache.org/jira/browse/BROOKLYN-546. + * + * We built up to launcher3, which will have three things: + * 1. a pre-installed "system bundle" + * 2. an initial catalog that references this same system bundle (hence the bundle will be "managed") + * 3. persisted state that references this same system bundle. + * + * At the end of this, we want only one version of that "system bundle" to be installed, but also for + * it to be a "brooklyn managed bundle". + * + * This scenario isn't quite the same as BROOKLYN-546. To make it fail, we'd need to have bundle URLs like: + * "mvn:org.apache.brooklyn/brooklyn-software-cm-ansible/1.0.0-SNAPSHOT" + * (as is used in brooklyn-library/karaf/catalog/target/classes/catalog.bom). + * + * When that is used, the "osgi unique url" is the same as for the system library, so when it tries + * to replace the library by calling "installBundle" then it fails. + * + * We ensure this isn't happening by asserting that our manually installed "system bundle" is still the same. + */ + @Test + public void testRebindWithSystemBundleInCatalog() throws Exception { + Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0-SNAPSHOT")); + String bundleBom = createCatalogYaml(ImmutableList.of(), bundleItems); + VersionedName bundleName = new VersionedName("org.example.testRebindWithSystemBundleInCatalog", "1.0.0.SNAPSHOT"); + File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); + File bundleFileCopy = newTmpCopy(bundleFile); + + File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); + + Framework reusedFamework = null; + Bundle pseudoSystemBundle = null; + try { + reuseOsgi = true; + + // Launch and terminate brooklyn to ensure there is a reusable OSGi Framework + BrooklynLauncher launcher = newLauncherForTests(CATALOG_EMPTY_INITIAL); + launcher.start(); + launcher.terminate(); + Os.deleteRecursively(persistenceDir); + + // Add our bundle, so it feels for all intents and purposes like a "system bundle" + reusedFamework = OsgiManager.tryPeekFrameworkForReuse().get(); + pseudoSystemBundle = installBundle(reusedFamework, bundleFileCopy); + + // Launch brooklyn, where initial catalog includes a duplicate of the system bundle + BrooklynLauncher launcher2 = newLauncherForTests(initialBomFile.getAbsolutePath()); + launcher2.start(); + assertCatalogConsistsOfIds(launcher2, bundleItems); + assertManagedBundle(launcher2, bundleName, bundleItems); + launcher2.terminate(); + + // Launch brooklyn, where persisted state now includes the initial catalog's bundle + BrooklynLauncher launcher3 = newLauncherForTests(initialBomFile.getAbsolutePath()); + launcher3.start(); + assertCatalogConsistsOfIds(launcher3, bundleItems); + assertManagedBundle(launcher3, bundleName, bundleItems); + + // Should not have replaced the original "system bundle" + reusedFamework.getBundleContext().getBundles(); + List<Bundle> matchingBundles = Osgis.bundleFinder(reusedFamework).symbolicName(bundleName.getSymbolicName()).version(bundleName.getOsgiVersionString()).findAll(); + assertEquals(matchingBundles, ImmutableList.of(pseudoSystemBundle)); + + launcher3.terminate(); + + } finally { + reuseOsgi = false; + if (pseudoSystemBundle != null && pseudoSystemBundle.getState() != Bundle.UNINSTALLED) { + pseudoSystemBundle.uninstall(); + } + } + } + @Test public void testRebindUpgradesBundleWithSameItems() throws Exception { Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); @@ -169,4 +261,10 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc assertCatalogConsistsOfIds(newLauncher, COM_EXAMPLE_BUNDLE_CATALOG_IDS); assertManagedBundle(newLauncher, COM_EXAMPLE_BUNDLE_ID, COM_EXAMPLE_BUNDLE_CATALOG_IDS); } + + private Bundle installBundle(Framework framework, File bundle) throws Exception { + try (FileInputStream stream = new FileInputStream(bundle)) { + return framework.getBundleContext().installBundle(bundle.toURI().toString(), stream); + } + } }
