Repository: brooklyn-server Updated Branches: refs/heads/master 43a861c49 -> 48f090071
remove code duplication in tests, run more standby refactor using fixtures to run more tests in both terminate-then-rebind and standby-promote modes, without duplicating assertions Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/7b929320 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/7b929320 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/7b929320 Branch: refs/heads/master Commit: 7b92932009453c22f62e97310a411893e116dd6f Parents: 43a861c Author: Alex Heneveld <[email protected]> Authored: Mon Oct 30 10:21:39 2017 +0000 Committer: Alex Heneveld <[email protected]> Committed: Mon Oct 30 10:21:39 2017 +0000 ---------------------------------------------------------------------- .../catalog/internal/CatalogInitialization.java | 5 +- .../BrooklynLauncherRebindCatalogOsgiTest.java | 681 ++++++++++--------- 2 files changed, 364 insertions(+), 322 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7b929320/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java index faa3b92..1012d63 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java @@ -382,7 +382,10 @@ public class CatalogInitialization implements ManagementContextInjectable { populateViaInitialBomImpl(catalog); } catch (Throwable e) { - log.warn("Error populating catalog (rethrowing): "+e, e); + if (!Thread.currentThread().isInterrupted()) { + // normal on interruption, esp during tests; only worth remarking here otherwise (we rethrow in any case) + log.warn("Error populating catalog (rethrowing): "+e, e); + } throw Exceptions.propagate(e); } finally { isPopulatingInitial = false; http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7b929320/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 e9c7a07..bcc46ad 100644 --- a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java +++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java @@ -34,7 +34,6 @@ import org.apache.brooklyn.api.mgmt.ManagementContext; import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode; import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; import org.apache.brooklyn.api.objs.BrooklynObjectType; -import org.apache.brooklyn.api.typereg.ManagedBundle; import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog; import org.apache.brooklyn.core.catalog.internal.CatalogInitialization; import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult; @@ -52,6 +51,7 @@ import org.apache.brooklyn.util.osgi.VersionedName; import org.apache.brooklyn.util.text.Identifiers; import org.osgi.framework.Bundle; import org.osgi.framework.launch.Framework; +import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; @@ -61,7 +61,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLauncherRebindTest { +public abstract class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLauncherRebindTest { private static final String CATALOG_EMPTY_INITIAL = "classpath://rebind-test-empty-catalog.bom"; @@ -77,14 +77,21 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc * (so no cached bundles), or a local restart. We can also use {@code reuseOsgi = true} to emulate * system bundles (by pre-installing them into the reused framework at the start of the test). */ - private boolean reuseOsgi = false; + protected boolean reuseOsgi = false; - private List<Bundle> reusedBundles = new ArrayList<>(); + protected List<Bundle> reusedBundles = new ArrayList<>(); + + BrooklynLauncher launcherT1, launcherT2, launcherLast; + Runnable startupAssertions; + + protected abstract boolean isT1KeptRunningWhenT2Starts(); @AfterMethod(alwaysRun=true) @Override public void tearDown() throws Exception { try { + launcherT1 = null; launcherT2 = null; launcherLast = null; + startupAssertions = null; reuseOsgi = false; for (Bundle bundle : reusedBundles) { if (bundle != null && bundle.getState() != Bundle.UNINSTALLED) { @@ -107,253 +114,292 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc return reuseOsgi; } - private BrooklynLauncher newLauncherForTests(String catalogInitial) { + protected BrooklynLauncher newLauncherForTests(String catalogInitial) { CatalogInitialization catalogInitialization = new CatalogInitialization(catalogInitial); return super.newLauncherForTests() .catalogInitialization(catalogInitialization); - } - - @Test - public void testRebindGetsInitialOsgiCatalog() throws Exception { - Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); - String bundleBom = createCatalogYaml(ImmutableList.of(), bundleItems); - VersionedName bundleName = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "1.0.0"); - File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); - File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); + } + + protected void startT1(BrooklynLauncher l) { + if (launcherT1!=null) throw new IllegalStateException("Already started T1 launcher"); - BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher.start(); - assertCatalogConsistsOfIds(launcher, bundleItems); - assertManagedBundle(launcher, bundleName, bundleItems); - - launcher.terminate(); - - BrooklynLauncher newLauncher = newLauncherForTests(initialBomFile.getAbsolutePath()); - newLauncher.start(); - assertCatalogConsistsOfIds(newLauncher, bundleItems); - assertManagedBundle(newLauncher, bundleName, bundleItems); - } - - /** - * See https://issues.apache.org/jira/browse/BROOKLYN-546. - * - * We built up to launcher2, 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")); - VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest."+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); - File bundleFile = newTmpBundle(bundleItems, bundleName); - File bundleFileCopy = newTmpCopy(bundleFile); - - File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); - - reuseOsgi = true; + if (isT1KeptRunningWhenT2Starts()) { + l.highAvailabilityMode(HighAvailabilityMode.MASTER); + } + l.start(); + launcherLast = launcherT1 = l; - // Add our bundle, so it feels for all intents and purposes like a "system bundle" - Framework reusedFramework = initReusableOsgiFramework(); - Bundle pseudoSystemBundle = installBundle(reusedFramework, bundleFileCopy); - reusedBundles.add(pseudoSystemBundle); + if (startupAssertions!=null) startupAssertions.run(); + } + + protected void startT2(BrooklynLauncher l) { + if (launcherT2!=null) throw new IllegalStateException("Already started T2 launcher"); - // Launch brooklyn, where initial catalog includes a duplicate of the system bundle - BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher.start(); - assertCatalogConsistsOfIds(launcher, bundleItems); - assertManagedBundle(launcher, bundleName, bundleItems); - launcher.terminate(); - - // Launch brooklyn, where persisted state now includes the initial catalog's bundle - BrooklynLauncher launcher2 = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher2.start(); - assertCatalogConsistsOfIds(launcher2, bundleItems); - assertManagedBundle(launcher2, bundleName, bundleItems); + try { + RebindTestUtils.waitForPersisted(launcherT1.getManagementContext()); + } catch (Exception e) { + throw Exceptions.propagate(e); + } + if (!isT1KeptRunningWhenT2Starts()) { + launcherT1.terminate(); + } else { + l.highAvailabilityMode(HighAvailabilityMode.HOT_STANDBY); + } + l.start(); + launcherLast = launcherT2 = l; + if (isT1KeptRunningWhenT2Starts()) { + assertHotStandbyNow(launcherT2); + } - // Should not have replaced the original "system bundle" - assertOnlyBundle(reusedFramework, bundleName, pseudoSystemBundle); - - launcher2.terminate(); + if (startupAssertions!=null) startupAssertions.run(); } - + protected void promoteT2IfStandby() { + if (isT1KeptRunningWhenT2Starts()) { + launcherT1.terminate(); + assertMasterEventually(launcherT2); + + if (startupAssertions!=null) startupAssertions.run(); + } + } + @Test - public void testInstallPreexistingBundle() throws Exception { - Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0-SNAPSHOT")); - VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest."+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); - File bundleFile = newTmpBundle(bundleItems, bundleName); - File bundleFileCopy = newTmpCopy(bundleFile); - - reuseOsgi = true; + public static class LauncherRebindSubTests extends BrooklynLauncherRebindCatalogOsgiTest { + @Override protected boolean isT1KeptRunningWhenT2Starts() { return false; } - // Add our bundle, so it feels for all intents and purposes like a "system bundle" - Framework reusedFramework = initReusableOsgiFramework(); - Bundle pseudoSystemBundle = installBundle(reusedFramework, bundleFileCopy); - reusedBundles.add(pseudoSystemBundle); + // tests here should run only for straight rebind as they assume a reused framework - // Launch brooklyn, and explicitly install pre-existing bundle. - // Should bring it under brooklyn-management (should not re-install it). - BrooklynLauncher launcher = newLauncherForTests(CATALOG_EMPTY_INITIAL); - launcher.start(); - installBrooklynBundle(launcher, bundleFile, false).getWithError(); + /** + * See https://issues.apache.org/jira/browse/BROOKLYN-546. + * + * We built up to launcher2, 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")); + VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest."+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); + File bundleFile = newTmpBundle(bundleItems, bundleName); + File bundleFileCopy = newTmpCopy(bundleFile); + + File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); + + reuseOsgi = true; + + // Add our bundle, so it feels for all intents and purposes like a "system bundle" + Framework reusedFramework = initReusableOsgiFramework(); + Bundle pseudoSystemBundle = installBundle(reusedFramework, bundleFileCopy); + reusedBundles.add(pseudoSystemBundle); + + startupAssertions = () -> { + assertCatalogConsistsOfIds(launcherLast, bundleItems); + assertManagedBundle(launcherLast, bundleName, bundleItems); + }; + + // Launch brooklyn, where initial catalog includes a duplicate of the system bundle + startT1(newLauncherForTests(initialBomFile.getAbsolutePath())); + + // Launch brooklyn, where persisted state now includes the initial catalog's bundle + startT2(newLauncherForTests(initialBomFile.getAbsolutePath())); + + // Should not have replaced the original "system bundle" + assertOnlyBundle(reusedFramework, bundleName, pseudoSystemBundle); + + launcherT2.terminate(); + } - assertOnlyBundle(launcher, bundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher, bundleItems); - assertManagedBundle(launcher, bundleName, bundleItems); - launcher.terminate(); - - // Launch brooklyn again (because will have persisted the pre-installed bundle) - BrooklynLauncher launcher2 = newLauncherForTests(CATALOG_EMPTY_INITIAL); - launcher2.start(); - assertOnlyBundle(reusedFramework, bundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher2, bundleItems); - assertManagedBundle(launcher2, bundleName, bundleItems); - launcher2.terminate(); - } + @Test + public void testInstallPreexistingBundle() throws Exception { + Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0-SNAPSHOT")); + VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest."+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); + File bundleFile = newTmpBundle(bundleItems, bundleName); + File bundleFileCopy = newTmpCopy(bundleFile); + + reuseOsgi = true; + + // Add our bundle, so it feels for all intents and purposes like a "system bundle" + Framework reusedFramework = initReusableOsgiFramework(); + Bundle pseudoSystemBundle = installBundle(reusedFramework, bundleFileCopy); + reusedBundles.add(pseudoSystemBundle); + + // Launch brooklyn, and explicitly install pre-existing bundle. + // Should bring it under brooklyn-management (should not re-install it). + startT1(newLauncherForTests(CATALOG_EMPTY_INITIAL)); + installBrooklynBundle(launcherT1, bundleFile, false).getWithError(); + + assertOnlyBundle(launcherT1, bundleName, pseudoSystemBundle); + startupAssertions = () -> { + assertCatalogConsistsOfIds(launcherLast, bundleItems); + assertManagedBundle(launcherLast, bundleName, bundleItems); + }; + startupAssertions.run(); + + // Launch brooklyn again (because will have persisted the pre-installed bundle) + startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL)); + assertOnlyBundle(reusedFramework, bundleName, pseudoSystemBundle); + + launcherT2.terminate(); + } - @Test - public void testInstallPreexistingBundleViaIndirectBrooklynLibrariesReference() throws Exception { - Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0-SNAPSHOT")); - VersionedName systemBundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest.system"+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); - File systemBundleFile = newTmpBundle(bundleItems, systemBundleName); + @Test + public void testInstallPreexistingBundleViaIndirectBrooklynLibrariesReference() throws Exception { + Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0-SNAPSHOT")); + VersionedName systemBundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest.system"+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); + File systemBundleFile = newTmpBundle(bundleItems, systemBundleName); + + String bundleBom = createCatalogYaml(ImmutableList.of(), ImmutableList.of(systemBundleName), ImmutableList.of()); + VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest.initial"+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); + File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); + + File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); + + reuseOsgi = true; + + // Add our bundle, so it feels for all intents and purposes like a "system bundle" + Framework reusedFramework = initReusableOsgiFramework(); + Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile); + reusedBundles.add(pseudoSystemBundle); + + startupAssertions = () -> { + assertOnlyBundle(launcherLast, systemBundleName, pseudoSystemBundle); + assertCatalogConsistsOfIds(launcherLast, bundleItems); + assertManagedBundle(launcherLast, systemBundleName, bundleItems); + assertManagedBundle(launcherLast, bundleName, ImmutableSet.of()); + }; + + // Launch brooklyn, with initial catalog pointing at bundle that points at system bundle. + // Should bring it under brooklyn-management (without re-installing it). + startT1(newLauncherForTests(initialBomFile.getAbsolutePath())); + + // Launch brooklyn again (because will have persisted both those bundles) + startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL)); + + launcherT2.terminate(); + } - String bundleBom = createCatalogYaml(ImmutableList.of(), ImmutableList.of(systemBundleName), ImmutableList.of()); - VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest.initial"+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); - File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); - - File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); - - reuseOsgi = true; + @Test + public void testInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference() throws Exception { + runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(false); + } - // Add our bundle, so it feels for all intents and purposes like a "system bundle" - Framework reusedFramework = initReusableOsgiFramework(); - Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile); - reusedBundles.add(pseudoSystemBundle); + // Aled thought we supported version ranges in 'brooklyn.libraries', but doesn't work here. + @Test(groups="Broken") + public void testInstallPreexistingBundleViaInitialBomBrooklynLibrariesReferenceWithVersionRange() throws Exception { + runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(true); + } - // Launch brooklyn, with initial catalog pointing at bundle that points at system bundle. - // Should bring it under brooklyn-management (without re-installing it). - BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher.start(); - assertOnlyBundle(launcher, systemBundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher, bundleItems); - assertManagedBundle(launcher, systemBundleName, bundleItems); - assertManagedBundle(launcher, bundleName, ImmutableSet.of()); - launcher.terminate(); - - // Launch brooklyn again (because will have persisted both those bundles) - BrooklynLauncher launcher2 = newLauncherForTests(CATALOG_EMPTY_INITIAL); - launcher2.start(); - assertOnlyBundle(launcher2, systemBundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher2, bundleItems); - assertManagedBundle(launcher2, systemBundleName, bundleItems); - assertManagedBundle(launcher2, bundleName, ImmutableSet.of()); - launcher2.terminate(); - } - - @Test - public void testInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference() throws Exception { - runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(false); - } - - // Aled thought we supported version ranges in 'brooklyn.libraries', but doesn't work here. - @Test(groups="Broken") - public void testInstallPreexistingBundleViaInitialBomBrooklynLibrariesReferenceWithVersionRange() throws Exception { - runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(true); - } - - protected void runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(boolean useVersionRange) throws Exception { - Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); - VersionedName systemBundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest.system"+Identifiers.makeRandomId(4), "1.0.0"); - File systemBundleFile = newTmpBundle(bundleItems, systemBundleName); + protected void runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(boolean useVersionRange) throws Exception { + Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); + VersionedName systemBundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest.system"+Identifiers.makeRandomId(4), "1.0.0"); + File systemBundleFile = newTmpBundle(bundleItems, systemBundleName); + + VersionedName systemBundleNameRef; + if (useVersionRange) { + systemBundleNameRef = new VersionedName(systemBundleName.getSymbolicName(), "[1,2)"); + } else { + systemBundleNameRef = systemBundleName; + } + File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(), ImmutableList.of(systemBundleNameRef), ImmutableList.of())); + + reuseOsgi = true; + + // Add our bundle, so it feels for all intents and purposes like a "system bundle" + Framework reusedFramework = initReusableOsgiFramework(); + Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile); + reusedBundles.add(pseudoSystemBundle); + + startupAssertions = () -> { + assertOnlyBundle(launcherLast, systemBundleName, pseudoSystemBundle); + assertCatalogConsistsOfIds(launcherLast, bundleItems); + assertManagedBundle(launcherLast, systemBundleName, bundleItems); + }; + + // Launch brooklyn, with initial catalog pointing at system bundle. + // Should bring it under brooklyn-management (without re-installing it). + startT1(newLauncherForTests(initialBomFile.getAbsolutePath())); + + // Launch brooklyn again (because will have persisted both those bundles) + startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL)); + launcherT2.terminate(); + } - VersionedName systemBundleNameRef; - if (useVersionRange) { - systemBundleNameRef = new VersionedName(systemBundleName.getSymbolicName(), "[1,2)"); - } else { - systemBundleNameRef = systemBundleName; + @Test + public void testInstallReplacesPreexistingBundleWithoutForce() throws Exception { + runInstallReplacesPreexistingBundle(false); } - File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(), ImmutableList.of(systemBundleNameRef), ImmutableList.of())); - reuseOsgi = true; - - // Add our bundle, so it feels for all intents and purposes like a "system bundle" - Framework reusedFramework = initReusableOsgiFramework(); - Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile); - reusedBundles.add(pseudoSystemBundle); + @Test + public void testInstallReplacesPreexistingBundleWithForce() throws Exception { + runInstallReplacesPreexistingBundle(true); + } - // Launch brooklyn, with initial catalog pointing at system bundle. - // Should bring it under brooklyn-management (without re-installing it). - BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher.start(); - assertOnlyBundle(launcher, systemBundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher, bundleItems); - assertManagedBundle(launcher, systemBundleName, bundleItems); - launcher.terminate(); - - // Launch brooklyn again (because will have persisted both those bundles) - BrooklynLauncher launcher2 = newLauncherForTests(CATALOG_EMPTY_INITIAL); - launcher2.start(); - assertOnlyBundle(launcher2, systemBundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher2, bundleItems); - assertManagedBundle(launcher2, systemBundleName, bundleItems); - launcher2.terminate(); - } - - @Test - public void testInstallReplacesPreexistingBundleWithoutForce() throws Exception { - runInstallReplacesPreexistingBundle(false); + protected void runInstallReplacesPreexistingBundle(boolean force) throws Exception { + Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0-SNAPSHOT")); + VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest."+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); + File systemBundleFile = newTmpBundle(bundleItems, bundleName); + File replacementBundleFile = newTmpBundle(bundleItems, bundleName, "randomDifference"+Identifiers.makeRandomId(4)); + + reuseOsgi = true; + + // Add our bundle, so it feels for all intents and purposes like a "system bundle" + Framework reusedFramework = initReusableOsgiFramework(); + Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile); + reusedBundles.add(pseudoSystemBundle); + + + // Launch brooklyn, and explicitly install pre-existing bundle. + // Should bring it under brooklyn-management (should not re-install it). + startT1(newLauncherForTests(CATALOG_EMPTY_INITIAL)); + installBrooklynBundle(launcherT1, replacementBundleFile, force).getWithError(); + assertOnlyBundleReplaced(launcherLast, bundleName, pseudoSystemBundle); + startupAssertions = () -> { + assertCatalogConsistsOfIds(launcherLast, bundleItems); + assertManagedBundle(launcherLast, bundleName, bundleItems); + }; + startupAssertions.run(); + + // Launch brooklyn again (because will have persisted the pre-installed bundle) + startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL)); + assertOnlyBundleReplaced(reusedFramework, bundleName, pseudoSystemBundle); + launcherT2.terminate(); + } } - + @Test - public void testInstallReplacesPreexistingBundleWithForce() throws Exception { - runInstallReplacesPreexistingBundle(true); + public static class HotStandbyRebindSubTests extends BrooklynLauncherRebindCatalogOsgiTest { + @Override protected boolean isT1KeptRunningWhenT2Starts() { return true; } } - - protected void runInstallReplacesPreexistingBundle(boolean force) throws Exception { - Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0-SNAPSHOT")); - VersionedName bundleName = new VersionedName("org.example.brooklynLauncherRebindCatalogOsgiTest."+Identifiers.makeRandomId(4), "1.0.0.SNAPSHOT"); - File systemBundleFile = newTmpBundle(bundleItems, bundleName); - File replacementBundleFile = newTmpBundle(bundleItems, bundleName, "randomDifference"+Identifiers.makeRandomId(4)); - reuseOsgi = true; - - // Add our bundle, so it feels for all intents and purposes like a "system bundle" - Framework reusedFramework = initReusableOsgiFramework(); - Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile); - reusedBundles.add(pseudoSystemBundle); - - // Launch brooklyn, and explicitly install pre-existing bundle. - // Should bring it under brooklyn-management (should not re-install it). - BrooklynLauncher launcher = newLauncherForTests(CATALOG_EMPTY_INITIAL); - launcher.start(); - installBrooklynBundle(launcher, replacementBundleFile, force).getWithError(); + @Test + public void testRebindGetsInitialOsgiCatalog() throws Exception { + Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); + String bundleBom = createCatalogYaml(ImmutableList.of(), bundleItems); + VersionedName bundleName = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "1.0.0"); + File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); + File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); - assertOnlyBundleReplaced(launcher, bundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher, bundleItems); - assertManagedBundle(launcher, bundleName, bundleItems); - launcher.terminate(); - - // Launch brooklyn again (because will have persisted the pre-installed bundle) - BrooklynLauncher launcher2 = newLauncherForTests(CATALOG_EMPTY_INITIAL); - launcher2.start(); - assertOnlyBundleReplaced(reusedFramework, bundleName, pseudoSystemBundle); - assertCatalogConsistsOfIds(launcher2, bundleItems); - assertManagedBundle(launcher2, bundleName, bundleItems); - launcher2.terminate(); + startupAssertions = () -> { + assertCatalogConsistsOfIds(launcherLast, bundleItems); + assertManagedBundle(launcherLast, bundleName, bundleItems); + }; + startT1( newLauncherForTests(initialBomFile.getAbsolutePath()) ); + startT2(newLauncherForTests(initialBomFile.getAbsolutePath())); + promoteT2IfStandby(); } - + @Test public void testRebindUpgradesBundleWithSameItems() throws Exception { Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); @@ -367,17 +413,12 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc File bundleFileV2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleNameV2); File initialBomFileV2 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV2.toURI()), ImmutableList.of())); - BrooklynLauncher launcher = newLauncherForTests(initialBomFileV1.getAbsolutePath()); - launcher.start(); - assertCatalogConsistsOfIds(launcher, bundleItems); - assertManagedBundle(launcher, bundleNameV1, bundleItems); - - launcher.terminate(); - - BrooklynLauncher newLauncher = newLauncherForTests(initialBomFileV2.getAbsolutePath()); - newLauncher.start(); - assertCatalogConsistsOfIds(newLauncher, bundleItems); - assertManagedBundle(newLauncher, bundleNameV2, bundleItems); + startupAssertions = () -> { + assertCatalogConsistsOfIds(launcherLast, bundleItems); + assertManagedBundle(launcherLast, bundleNameV1, bundleItems); + }; + startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath())); + startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath())); } @Test @@ -394,18 +435,19 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc File bundleFileV2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBomV2.getBytes(StandardCharsets.UTF_8)), bundleNameV2); File initialBomFileV2 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV2.toURI()), ImmutableList.of())); - BrooklynLauncher launcher = newLauncherForTests(initialBomFileV1.getAbsolutePath()); - launcher.start(); - assertCatalogConsistsOfIds(launcher, bundleItemsV1); - assertManagedBundle(launcher, bundleNameV1, bundleItemsV1); - - launcher.terminate(); - - BrooklynLauncher newLauncher = newLauncherForTests(initialBomFileV2.getAbsolutePath()); - newLauncher.start(); - assertCatalogConsistsOfIds(newLauncher, Iterables.concat(bundleItemsV1, bundleItemsV2)); - assertManagedBundle(newLauncher, bundleNameV1, bundleItemsV1); - assertManagedBundle(newLauncher, bundleNameV2, bundleItemsV2); + startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath())); + + assertCatalogConsistsOfIds(launcherLast, bundleItemsV1); + assertManagedBundle(launcherLast, bundleNameV1, bundleItemsV1); + // above for T1 should become the following for T2 + startupAssertions = () -> { + assertCatalogConsistsOfIds(launcherLast, Iterables.concat(bundleItemsV1, bundleItemsV2)); + assertManagedBundle(launcherLast, bundleNameV1, bundleItemsV1); + assertManagedBundle(launcherLast, bundleNameV2, bundleItemsV2); + }; + + startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath())); + promoteT2IfStandby(); } // TODO bundle fails to start: @@ -423,48 +465,22 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc " - " + OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_URL); File initialBomFile = newTmpFile(initialBom); - BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher.start(); - assertCatalogConsistsOfIds(launcher, COM_EXAMPLE_BUNDLE_CATALOG_IDS); - assertManagedBundle(launcher, COM_EXAMPLE_BUNDLE_ID, COM_EXAMPLE_BUNDLE_CATALOG_IDS); - - launcher.terminate(); - - BrooklynLauncher newLauncher = newLauncherForTests(initialBomFile.getAbsolutePath()); - newLauncher.start(); - assertCatalogConsistsOfIds(newLauncher, COM_EXAMPLE_BUNDLE_CATALOG_IDS); - assertManagedBundle(newLauncher, COM_EXAMPLE_BUNDLE_ID, COM_EXAMPLE_BUNDLE_CATALOG_IDS); + startupAssertions = () -> { + assertCatalogConsistsOfIds(launcherLast, COM_EXAMPLE_BUNDLE_CATALOG_IDS); + assertManagedBundle(launcherLast, COM_EXAMPLE_BUNDLE_ID, COM_EXAMPLE_BUNDLE_CATALOG_IDS); + }; + startT1(newLauncherForTests(initialBomFile.getAbsolutePath())); + startT2(newLauncherForTests(initialBomFile.getAbsolutePath())); + promoteT2IfStandby(); } - @Test - public void testPersistsSingleCopyOfInitialCatalog() throws Exception { - Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); - String bundleBom = createCatalogYaml(ImmutableList.of(), bundleItems); - VersionedName bundleName = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog"+Identifiers.makeRandomId(4), "1.0.0"); - File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); - File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); - - // First launcher should persist the bundle - BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher.start(); - String bundlePersistenceId = findManagedBundle(launcher, bundleName).getId(); - launcher.terminate(); - assertEquals(getPersistenceListing(BrooklynObjectType.MANAGED_BUNDLE), ImmutableSet.of(bundlePersistenceId)); - - // Second launcher should read from initial catalog and persisted state. Both those bundles have different ids. - // Should only end up with one of them in persisted state. - // (Current impl is that it will be the "initial catalog" version, discarding the previously persisted bundle). - BrooklynLauncher launcher2 = newLauncherForTests(initialBomFile.getAbsolutePath()); - launcher2.start(); - String bundlePersistenceId2 = findManagedBundle(launcher2, bundleName).getId(); - launcher2.terminate(); - assertEquals(getPersistenceListing(BrooklynObjectType.MANAGED_BUNDLE), ImmutableSet.of(bundlePersistenceId2)); - } - /** * It is vital that the brooklyn-managed-bundle ids match those in persisted state. If they do not, * then deletion of a brooklyn-managed-bundle will not actually delete it from persisted state. * + * This test (like many here) asserts for simple terminate-rebind and for hot-standby and promotion, + * but here note the paths are vbery different. + * * Under the covers, the scenario of HOT_STANDBY promoted to MASTER is very different from when * it starts as master: * <ol> @@ -513,7 +529,7 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc * </ol> */ @Test - public void testPersistsSingleCopyOfInitialCatalogOnHotStandbyPromotion() throws Exception { + public void testPersistsSingleCopyOfInitialCatalog() throws Exception { Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0")); String bundleBom = createCatalogYaml(ImmutableList.of(), bundleItems); VersionedName bundleName = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog"+Identifiers.makeRandomId(4), "1.0.0"); @@ -521,29 +537,47 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()), ImmutableList.of())); // First launcher should persist the bundle - BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath()) - .highAvailabilityMode(HighAvailabilityMode.MASTER); - launcher.start(); - String bundlePersistenceId = findManagedBundle(launcher, bundleName).getId(); - RebindTestUtils.waitForPersisted(launcher.getManagementContext()); - assertEquals(getPersistenceListing(BrooklynObjectType.MANAGED_BUNDLE), ImmutableSet.of(bundlePersistenceId)); - - // Second launcher goes into hot-standby, and will thus rebind periodically. - // When we terminate the first launcher, it will be promoted to master automatically. - // However, we'll say state="master" before we've fully initialised, so need to use - // assert-eventually. - BrooklynLauncher launcher2 = newLauncherForTests(initialBomFile.getAbsolutePath()) - .highAvailabilityMode(HighAvailabilityMode.HOT_STANDBY); - launcher2.start(); - assertHotStandbyEventually(launcher2); + startT1(newLauncherForTests(initialBomFile.getAbsolutePath())); + String bundlePersistenceId1 = findManagedBundle(launcherT1, bundleName).getId(); - launcher.terminate(); - assertMasterEventually(launcher2); - assertPersistedBundleListingEqualsEventually(launcher2, ImmutableSet.of(bundleName)); - launcher2.terminate(); + if (!isT1KeptRunningWhenT2Starts()) { + launcherT1.terminate(); + } else { + RebindTestUtils.waitForPersisted(launcherT1.getManagementContext()); + } + assertEquals(getPersistenceListing(BrooklynObjectType.MANAGED_BUNDLE), ImmutableSet.of(bundlePersistenceId1)); + + // Second launcher should read from initial catalog and persisted state. Both those bundles have different ids. + // Should only end up with one of them in persisted state. + // (Current impl is that it will be the "initial catalog" version, discarding the previously persisted bundle). + startT2(newLauncherForTests(initialBomFile.getAbsolutePath())); + if (isT1KeptRunningWhenT2Starts()) { + assertEquals(getPersistenceListing(BrooklynObjectType.MANAGED_BUNDLE), ImmutableSet.of(bundlePersistenceId1)); + } + + promoteT2IfStandby(); + + String bundlePersistenceId2 = findManagedBundle(launcherT2, bundleName).getId(); + launcherT2.terminate(); + + // ID2 only persisted after promotion - checks above are for ID1 + assertEquals(getPersistenceListing(BrooklynObjectType.MANAGED_BUNDLE), ImmutableSet.of(bundlePersistenceId2)); + + if (isT1KeptRunningWhenT2Starts()) { + // would like if we could make them the same but currently code should _always_ change + Assert.assertNotEquals(bundlePersistenceId1, bundlePersistenceId2); + } } - private void assertPersistedBundleListingEqualsEventually(BrooklynLauncher launcher, Set<VersionedName> bundles) { + // TODO tests: + // TODO remove on hot standby promotion (above), succeed and failing + // TODO deploy blueprint with old item after upgrade + // TODO rebind upgrade item deployed + // TODO rebind upgrade spec item in deployment + // TODO deploy mention of old item after upgrade + // TODO upgrade on hot standby and promotion + + protected void assertPersistedBundleListingEqualsEventually(BrooklynLauncher launcher, Set<VersionedName> bundles) { Asserts.succeedsEventually(new Runnable() { @Override public void run() { try { @@ -560,17 +594,22 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc }}); } - private void assertHotStandbyEventually(BrooklynLauncher launcher) { - ManagementContext mgmt = launcher.getManagementContext(); + protected void assertHotStandbyEventually(BrooklynLauncher launcher) { Asserts.succeedsEventually(new Runnable() { public void run() { - assertTrue(mgmt.isStartupComplete()); - assertTrue(mgmt.isRunning()); - assertEquals(mgmt.getHighAvailabilityManager().getNodeState(), ManagementNodeState.HOT_STANDBY); - }}); + assertHotStandbyNow(launcher); + } + }); + } + + protected void assertHotStandbyNow(BrooklynLauncher launcher) { + ManagementContext mgmt = launcher.getManagementContext(); + assertTrue(mgmt.isStartupComplete()); + assertTrue(mgmt.isRunning()); + assertEquals(mgmt.getHighAvailabilityManager().getNodeState(), ManagementNodeState.HOT_STANDBY); } - private void assertMasterEventually(BrooklynLauncher launcher) { + protected void assertMasterEventually(BrooklynLauncher launcher) { ManagementContext mgmt = launcher.getManagementContext(); Asserts.succeedsEventually(new Runnable() { public void run() { @@ -580,42 +619,42 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc }}); } - private Bundle installBundle(Framework framework, File bundle) throws Exception { + protected Bundle installBundle(Framework framework, File bundle) throws Exception { try (FileInputStream stream = new FileInputStream(bundle)) { return framework.getBundleContext().installBundle(bundle.toURI().toString(), stream); } } - private ReferenceWithError<OsgiBundleInstallationResult> installBrooklynBundle(BrooklynLauncher launcher, File bundleFile, boolean force) throws Exception { + protected ReferenceWithError<OsgiBundleInstallationResult> installBrooklynBundle(BrooklynLauncher launcher, File bundleFile, boolean force) throws Exception { OsgiManager osgiManager = ((ManagementContextInternal)launcher.getManagementContext()).getOsgiManager().get(); try (FileInputStream bundleStream = new FileInputStream(bundleFile)) { return osgiManager.install(null, bundleStream, true, true, force); } } - private void assertOnlyBundle(BrooklynLauncher launcher, VersionedName bundleName, Bundle expectedBundle) { + protected void assertOnlyBundle(BrooklynLauncher launcher, VersionedName bundleName, Bundle expectedBundle) { Framework framework = ((ManagementContextInternal)launcher.getManagementContext()).getOsgiManager().get().getFramework(); assertOnlyBundle(framework, bundleName, expectedBundle); } - private void assertOnlyBundleReplaced(BrooklynLauncher launcher, VersionedName bundleName, Bundle expectedBundle) { + protected void assertOnlyBundleReplaced(BrooklynLauncher launcher, VersionedName bundleName, Bundle expectedBundle) { Framework framework = ((ManagementContextInternal)launcher.getManagementContext()).getOsgiManager().get().getFramework(); assertOnlyBundleReplaced(framework, bundleName, expectedBundle); } - private void assertOnlyBundle(Framework framework, VersionedName bundleName, Bundle expectedBundle) { + protected void assertOnlyBundle(Framework framework, VersionedName bundleName, Bundle expectedBundle) { List<Bundle> matchingBundles = Osgis.bundleFinder(framework).symbolicName(bundleName.getSymbolicName()).version(bundleName.getOsgiVersionString()).findAll(); assertTrue(matchingBundles.contains(expectedBundle), "Bundle missing; matching="+matchingBundles); assertEquals(matchingBundles.size(), 1, "Extra bundles; matching="+matchingBundles); } - private void assertOnlyBundleReplaced(Framework framework, VersionedName bundleName, Bundle expectedBundle) { + protected void assertOnlyBundleReplaced(Framework framework, VersionedName bundleName, Bundle expectedBundle) { List<Bundle> matchingBundles = Osgis.bundleFinder(framework).symbolicName(bundleName.getSymbolicName()).version(bundleName.getOsgiVersionString()).findAll(); assertFalse(matchingBundles.contains(expectedBundle), "Bundle still present; matching="+matchingBundles); assertEquals(matchingBundles.size(), 1, "Extra bundles; matching="+matchingBundles); } - private Framework initReusableOsgiFramework() { + protected Framework initReusableOsgiFramework() { if (!reuseOsgi) throw new IllegalStateException("Must first set reuseOsgi"); if (OsgiManager.tryPeekFrameworkForReuse().isAbsent()) { @@ -627,11 +666,11 @@ public class BrooklynLauncherRebindCatalogOsgiTest extends AbstractBrooklynLaunc return OsgiManager.tryPeekFrameworkForReuse().get(); } - private File newTmpBundle(Set<VersionedName> catalogItems, VersionedName bundleName) { + protected File newTmpBundle(Set<VersionedName> catalogItems, VersionedName bundleName) { return newTmpBundle(catalogItems, bundleName, null); } - private File newTmpBundle(Set<VersionedName> catalogItems, VersionedName bundleName, String randomNoise) { + protected File newTmpBundle(Set<VersionedName> catalogItems, VersionedName bundleName, String randomNoise) { String bundleBom = createCatalogYaml(ImmutableList.of(), ImmutableList.of(), catalogItems, randomNoise); return newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName); }
