blob: d16aa61a4a1315b8c1ab70dfee96a92fd53dbcfc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.brooklyn.launcher;
import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
import org.apache.brooklyn.core.server.BrooklynServerConfig;
import org.apache.brooklyn.util.stream.InputStreamSource;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.api.entity.Application;
import org.apache.brooklyn.api.entity.Entity;
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.RegisteredType;
import org.apache.brooklyn.core.BrooklynFeatureEnablement;
import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
import org.apache.brooklyn.core.typereg.BundleUpgradeParser;
import org.apache.brooklyn.core.typereg.BundleUpgradeParser.CatalogUpgrades;
import org.apache.brooklyn.entity.group.DynamicCluster;
import org.apache.brooklyn.entity.stock.BasicEntity;
import org.apache.brooklyn.entity.stock.BasicEntityImpl;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.test.support.TestResourceUnavailableException;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.core.osgi.Osgis;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.exceptions.ReferenceWithError;
import org.apache.brooklyn.util.os.Os;
import org.apache.brooklyn.util.osgi.OsgiTestResources;
import org.apache.brooklyn.util.osgi.VersionedName;
import org.apache.brooklyn.util.text.Identifiers;
import org.apache.brooklyn.util.text.Strings;
import org.osgi.framework.Bundle;
import org.osgi.framework.launch.Framework;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
public abstract 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);
private static final Set<VersionedName> COM_EXAMPLE_BUNDLE_CATALOG_IDS = ImmutableSet.of(
new VersionedName("com.example.simpleTest", "0.1.0"),
new VersionedName("com.example.includedCatalogTest", "0.1.0"),
new VersionedName("com.example.includedItemTest", "0.1.0"));
/**
* Whether we reuse OSGi Framework depends if we want it to feel like rebinding on a new machine
* (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).
*
* Default true because this speeds things up, but some fixtures run with it false.
*/
protected boolean reuseOsgi = true;
protected List<Bundle> manuallyInsertedBundles = 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 = true;
// OSGi reuse system will clear cache on framework no longer being used,
// but we've installed out of band so need to clean it up ourselves if the test doesn't actually use it!
for (Bundle bundle : manuallyInsertedBundles) {
if (bundle != null && bundle.getState() != Bundle.UNINSTALLED) {
bundle.uninstall();
}
}
manuallyInsertedBundles.clear();
} finally {
super.tearDown();
}
}
@Override
protected boolean useOsgi() {
return true;
}
@Override
protected boolean reuseOsgi() {
return reuseOsgi;
}
protected BrooklynLauncher newLauncherForTests(String catalogInitial) {
CatalogInitialization catalogInitialization = new CatalogInitialization(catalogInitial);
return super.newLauncherForTests()
.catalogInitialization(catalogInitialization);
}
protected void startT1(BrooklynLauncher l) {
if (launcherT1!=null) throw new IllegalStateException("Already started T1 launcher");
if (isT1KeptRunningWhenT2Starts()) {
l.highAvailabilityMode(HighAvailabilityMode.MASTER);
}
l.start();
launcherLast = launcherT1 = l;
assertMasterEventually(launcherT1);
if (startupAssertions!=null) startupAssertions.run();
}
protected void startT2(BrooklynLauncher l) {
startT2(l, true);
}
protected void startT2(BrooklynLauncher l, boolean expectSuccess) {
if (launcherT2!=null) throw new IllegalStateException("Already started T2 launcher");
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 (expectSuccess) {
if (isT1KeptRunningWhenT2Starts()) {
assertHotStandbyNow(launcherT2);
} else {
assertMasterEventually(launcherT2);
}
} else {
assertFailsEventually(launcherLast);
}
if (startupAssertions!=null) startupAssertions.run();
}
protected void promoteT2IfStandby() {
promoteT2IfStandby(true);
}
protected void promoteT2IfStandby(boolean expectHealthy) {
if (isT1KeptRunningWhenT2Starts()) {
launcherT1.terminate();
if (expectHealthy) {
assertMasterEventually(launcherT2);
} else {
assertFailsEventually(launcherT2);
}
if (startupAssertions!=null) startupAssertions.run();
}
}
@Test
public static class LauncherRebindSubTests extends BrooklynLauncherRebindCatalogOsgiTest {
@Override protected boolean isT1KeptRunningWhenT2Starts() { return false; }
// tests here should run only for straight rebind as they assume a reused framework
/**
* 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()));
// Add our bundle, so it feels for all intents and purposes like a "system bundle"
Framework reusedFramework = initReusableOsgiFramework();
Bundle pseudoSystemBundle = installBundle(reusedFramework, bundleFileCopy);
manuallyInsertedBundles.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();
}
@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);
// Add our bundle, so it feels for all intents and purposes like a "system bundle"
Framework reusedFramework = initReusableOsgiFramework();
Bundle pseudoSystemBundle = installBundle(reusedFramework, bundleFileCopy);
manuallyInsertedBundles.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);
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()));
Preconditions.checkArgument(reuseOsgi, "Should be reusing OSGi; test did not correctly reset it.");
// Add our bundle, so it feels for all intents and purposes like a "system bundle"
Framework reusedFramework = initReusableOsgiFramework();
Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile);
manuallyInsertedBundles.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()));
alsoPersistBundlesInstalledToCatalog();
// Launch brooklyn again (because with the above, it will have persisted both those bundles)
startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL));
launcherT2.terminate();
}
@Test
public void testInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference() throws Exception {
runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(false);
}
// // Aled thought we supported version ranges in 'brooklyn.libraries', but doesn't work here.
// // Alex confirms nope, not supported there yet (2017-10).
// @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);
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()));
// Add our bundle, so it feels for all intents and purposes like a "system bundle"
Framework reusedFramework = initReusableOsgiFramework();
Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile);
manuallyInsertedBundles.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()));
alsoPersistBundlesInstalledToCatalog();
// Launch brooklyn again (because will have persisted both those bundles)
startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL));
launcherT2.terminate();
}
@Test
public void testInstallReplacesPreexistingBundleWithoutForce() throws Exception {
runInstallReplacesPreexistingBundle(false);
}
@Test
public void testInstallReplacesPreexistingBundleWithForce() throws Exception {
runInstallReplacesPreexistingBundle(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));
// Add our bundle, so it feels for all intents and purposes like a "system bundle"
Framework reusedFramework = initReusableOsgiFramework();
Bundle pseudoSystemBundle = installBundle(reusedFramework, systemBundleFile);
manuallyInsertedBundles.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 static class HotStandbyRebindSubTests extends BrooklynLauncherRebindCatalogOsgiTest {
@Override protected boolean isT1KeptRunningWhenT2Starts() { return true; }
}
public abstract static class AbstractNonReuseRebindSubTests extends BrooklynLauncherRebindCatalogOsgiTest {
@BeforeMethod(alwaysRun=true)
@Override
public void setUp() throws Exception {
super.setUp();
//reuseOsgi = false;
}
}
@Test(groups="Integration")
public static class NonReuseRebindSubTests extends AbstractNonReuseRebindSubTests {
@Override protected boolean isT1KeptRunningWhenT2Starts() { return false; }
}
@Test(groups="Integration")
public static class HotStandbyNonReuseRebindSubTests extends AbstractNonReuseRebindSubTests {
@Override protected boolean isT1KeptRunningWhenT2Starts() { return false; }
}
@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()));
startupAssertions = () -> {
assertCatalogConsistsOfIds(launcherLast, bundleItems);
assertManagedBundle(launcherLast, bundleName, bundleItems);
};
startT1( newLauncherForTests(initialBomFile.getAbsolutePath()) );
startT2(newLauncherForTests(initialBomFile.getAbsolutePath()));
promoteT2IfStandby();
}
@Test
public void testRestartWithNewBundleWithSameItemsReplacesItems() throws Exception {
Set<VersionedName> bundleItems = ImmutableSet.of(VersionedName.fromString("one:1.0.0"));
String bundleBom = createCatalogYaml(ImmutableList.of(), bundleItems);
VersionedName bundleNameV1 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "1.0.0");
File bundleFileV1 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleNameV1);
File initialBomFileV1 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV1.toURI()), ImmutableList.of()));
VersionedName bundleNameV2 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "2.0.0");
File bundleFileV2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleNameV2);
File initialBomFileV2 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV2.toURI()), ImmutableList.of()));
startupAssertions = () -> {
assertCatalogConsistsOfIds(launcherLast, bundleItems);
assertManagedBundle(launcherLast, bundleNameV1, bundleItems);
String bundleVersionSupplyingType = getBundleSupplyingFirstType(bundleItems);
if (launcherT2==null) {
Assert.assertEquals(bundleVersionSupplyingType, "1.0.0");
} else {
assertManagedBundle(launcherLast, bundleNameV2, bundleItems);
getBundleSupplyingFirstType(bundleItems);
Assert.assertEquals(bundleVersionSupplyingType, "2.0.0");
}
};
startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath()));
alsoPersistBundlesInstalledToCatalog();
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
assertManagedBundle(launcherLast, bundleNameV2, bundleItems);
promoteT2IfStandby();
}
protected String getBundleSupplyingFirstType(Set<VersionedName> bundleItems) {
RegisteredType type = launcherLast.getManagementContext().getTypeRegistry().get(
bundleItems.iterator().next().toString() );
if (type==null) return null;
return VersionedName.fromString( type.getContainingBundle() ).getVersionString();
}
@Test
public void testRestartWithNewBundleWithNewItemsAddsItems() throws Exception {
Set<VersionedName> bundleItemsV1 = ImmutableSet.of(VersionedName.fromString("one:1.0.0"));
String bundleBomV1 = createCatalogYaml(ImmutableList.of(), bundleItemsV1);
VersionedName bundleNameV1 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "1.0.0");
File bundleFileV1 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBomV1.getBytes(StandardCharsets.UTF_8)), bundleNameV1);
File initialBomFileV1 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV1.toURI()), ImmutableList.of()));
Set<VersionedName> bundleItemsV2 = ImmutableSet.of(VersionedName.fromString("one:2.0.0"));
String bundleBomV2 = createCatalogYaml(ImmutableList.of(), bundleItemsV2);
VersionedName bundleNameV2 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "2.0.0");
File bundleFileV2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBomV2.getBytes(StandardCharsets.UTF_8)), bundleNameV2);
File initialBomFileV2 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV2.toURI()), ImmutableList.of()));
startupAssertions = () -> {
assertManagedBundle(launcherLast, bundleNameV1, bundleItemsV1);
Assert.assertEquals(getBundleSupplyingFirstType(bundleItemsV1), "1.0.0");
if (launcherT2==null) {
assertCatalogConsistsOfIds(launcherLast, bundleItemsV1);
} else {
assertCatalogConsistsOfIds(launcherLast, Iterables.concat(bundleItemsV1, bundleItemsV2));
assertManagedBundle(launcherLast, bundleNameV2, bundleItemsV2);
Assert.assertEquals(getBundleSupplyingFirstType(bundleItemsV2), "2.0.0");
}
};
startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath()));
alsoPersistBundlesInstalledToCatalog();
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
promoteT2IfStandby();
}
// if fails with wiring error you might need to rebuild items in utils/common/dependencies/osgi/
@Test
public void testRebindGetsInitialOsgiCatalogWithJava() throws Exception {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_PATH);
String initialBom = Joiner.on("\n").join(
"brooklyn.catalog:",
" brooklyn.libraries:",
" - " + OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_URL);
File initialBomFile = newTmpFile(initialBom);
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();
}
/**
* 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>
* <li> We become hot-standby; we call RebindManager.startReaOnly (so PeriodicDeltaChangeListener
* discards changes).
* <li>We repeatedly call rebindManager.rebind():
* <ol>
* <li>Each time, we populate the catalog from the initial and persisted state
* <li>The OsgiManager.ManagedBundleRecords is populated the first time; subsequent times we see it is
* already a managed bundle so do nothing.
* <li>The first time, it calls to the PeriodicDeltaChangeListener about the managed bundle, but the
* change is discarded (because we are read-only, and PeriodicDeltaChangeListener is 'STOPPED').
* </ol>
* <li>On HighAvailabilityManagerImpl promoting us from HOT_STANDBY to MASTER:
* <ol>
* <li>Calls rebindManager.stopReadOnly; this resets the PeriodicDeltaChangeListener
* (so that it's in the INIT state, ready for recording whatever happens while we're promoting to MASTER)
* <li>Clears our cache of brooklyn-managed-bundles. This is important so that we record
* (and thus update persistence) for the "initial catalog" bundles being managed.
* <li>Calls rebindManager.rebind(); we are in a good state to do this, having cleared out whatever
* was done previously while we were hot-standby.
* <ol>
* <li>The new ManagedBundle instances from the "initial catalog" are recorded in the
* PeriodicDeltaChangeListener.
* <li>For persisted bundles, if they were duplicates of existing brooklyn-managed-bundles then they
* are recorded as deleted (in PeriodicDeltaChangeListener).
* </ol>
* <li>HighAvailabilityManagerImpl.promoteToMaster() then calls rebindManager.start(), which switches us
* into writable mode. The changes recorded in PeriodicDeltaChangeListener are applied to the
* persisted state.
* </ol>
* </ol>
*
* In contrast, when we start as MASTER:
* <ol>
* <li>We call rebindManager.setPersister(); the PeriodicDeltaChangeListener is in 'INIT' state
* so will record any changes.
* <li>We call rebindManager.rebind(); it populates the catalog from the initial and persisted state;
* <ol>
* <li>The new ManagedBundle instances from the "initial catalog" are recorded in the PeriodicDeltaChangeListener.
* <li>For persisted bundles, if they were duplicates of existing brooklyn-managed-bundles then they
* are recorded as deleted (in PeriodicDeltaChangeListener).
* </ol>
* <li>We call rebindManager.startPersistence(); this enables write-access to the persistence store,
* and starts the PeriodicDeltaChangeListener (so all recorded changes are applied).
* </ol>
*/
@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
startT1(newLauncherForTests(initialBomFile.getAbsolutePath()));
String bundlePersistenceId1 = findManagedBundle(launcherT1, bundleName).getId();
alsoPersistBundlesInstalledToCatalog();
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()) {
// now we keep these the same!
Assert.assertEquals(bundlePersistenceId1, bundlePersistenceId2);
}
}
@Test
public void testRebindRemovedItemAlsoRemovesLibrary() throws Exception {
File initialBomFileV2 = prepForRebindRemovedItemTestReturningBomV2(false, false);
createAndStartApplication(launcherLast.getManagementContext(),
"services: [ { type: 'simple-entity:1' } ]");
// failover here fails, because we depend on the java library which is removed
startupAssertions = null;
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()), false);
}
@Test
public void testRebindRemovedKeepsLibraryIfInstalledExplicitly() throws Exception {
File initialBomFileV2 = prepForRebindRemovedItemTestReturningBomV2(false, false);
createAndStartApplication(launcherLast.getManagementContext(),
"services: [ { type: 'simple-entity:1' } ]");
// as before, but if we install the java library explicitly (directly or as a dependendency), then it _is_ persisted
// (we mark it v2 so that it replaces what startT2 installs, as the bom file on its own otherwise has no version, and the tests assert 1.0 or 2.0)
launcherLast.getManagementContext().getCatalog().addItems(initialBomV1+"\n id: org.example.testRebindGetsInitialOsgiCatalog:2.0.0\n");
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
promoteT2IfStandby();
Entity entity = Iterables.getOnlyElement( Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren() );
Assert.assertEquals(entity.getCatalogItemId(), "simple-entity:1.0.0");
}
@Test
public void testRebindRemovedKeepsLibraryIfPersistFromInitialCatalogEnabled() throws Exception {
File initialBomFileV2 = prepForRebindRemovedItemTestReturningBomV2(false, false);
alsoPersistBundlesInstalledToCatalog();
createAndStartApplication(launcherLast.getManagementContext(),
"services: [ { type: 'simple-entity:1' } ]");
// here rebind/failover should start and promote fine, and it should be able to load the entity from the java type
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
promoteT2IfStandby();
Entity entity = Iterables.getOnlyElement( Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren() );
Assert.assertEquals(entity.getCatalogItemId(), "simple-entity:1.0.0");
}
protected void alsoPersistBundlesInstalledToCatalog() {
((ManagementContextInternal)launcherLast.getManagementContext()).getBrooklynProperties().put(
BrooklynServerConfig.PERSIST_MANAGED_BUNDLES_FROM_INITIAL_CATALOG, true);
launcherLast.getManagementContext().getRebindManager().forcePersistNow(true, null);
}
@Test
public void testRebindRemovedItemAndRemovingJavaDependencyCausesFailure() throws Exception {
File initialBomFileV2 = prepForRebindRemovedItemTestReturningBomV2(true, false);
createAndStartApplication(launcherLast.getManagementContext(),
"services: [ { type: 'simple-entity:1.0' } ]");
// errors on promotion because the SimpleEntity.class isn't available
if (isT1KeptRunningWhenT2Starts()) {
// if starting hot-standby, HA manager will clear all state and set it to FAILED state;
// for master/standalone/single it treats it as a startup subsystem error and does not
// so for hot-standby we should assert everything is cleared
startupAssertions = () -> {
Asserts.assertSize(launcherLast.getManagementContext().getTypeRegistry().getAll(), 0);
Asserts.assertSize(launcherLast.getManagementContext().getEntityManager().getEntities(), 0);
};
}
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()), false);
Assert.assertFalse( ((ManagementContextInternal)launcherLast.getManagementContext()).errors().isEmpty() );
promoteT2IfStandby(false);
Assert.assertFalse( ((ManagementContextInternal)launcherLast.getManagementContext()).errors().isEmpty() );
if (!isT1KeptRunningWhenT2Starts()) {
// if t2 not running as standby then it should start, but with errors,
// including entity shouldn't be loaded (but app is)
Asserts.assertSize( launcherLast.getManagementContext().getApplications(), 1 );
Asserts.assertSize( Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren(), 0 );
}
}
private final String initialBomV1 = Joiner.on("\n").join(
"brooklyn.catalog:",
" brooklyn.libraries:",
" - " + OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_URL,
" items:",
" - id: simple-entity",
" item:",
" type: com.example.brooklyn.test.osgi.entities.SimpleEntity");
private File prepForRebindRemovedItemTestReturningBomV2(boolean removeSourceJavaBundle, boolean upgradeEntity) throws Exception {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_PATH);
VersionedName bundleNameV1 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "1.0.0");
File bundleFileV1 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, initialBomV1.getBytes()), bundleNameV1);
File initialBomFileV1 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV1.toURI()), ImmutableList.of()));
String initialBomV2 = Joiner.on("\n").join(
"brooklyn.catalog:",
" items:",
" - id: simple-entity",
" item:",
" type: "+BasicEntity.class.getName());
VersionedName bundleNameV2 = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "2.0.0");
Map<String,String> headers = MutableMap.of(
BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "*"
+ (removeSourceJavaBundle ? ","+"'"+OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_SYMBOLIC_NAME_FULL+":"+OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_VERSION+"'"
: ""));
if (upgradeEntity) {
headers.put(BundleUpgradeParser.MANIFEST_HEADER_UPGRADE_FOR_BUNDLES, "*");
}
File bundleFileV2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, initialBomV2.getBytes()), bundleNameV2, headers);
File initialBomFileV2 = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV2.toURI()), ImmutableList.of()));
startupAssertions = () -> {
String v = launcherT2==null ? "1.0.0" : "2.0.0";
VersionedName bv = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", v);
VersionedName iv = new VersionedName("simple-entity", v);
assertManagedBundle(launcherLast, bv, MutableSet.of(iv));
if (launcherT2==null || !removeSourceJavaBundle) {
assertCatalogConsistsOfIds(launcherLast, MutableList.copyOf(COM_EXAMPLE_BUNDLE_CATALOG_IDS).append(iv));
} else {
assertCatalogConsistsOfIds(launcherLast, MutableList.of(iv));
}
};
startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath()));
return initialBomFileV2;
}
@Test
public void testRebindUpgradeDeployedEntity() throws Exception {
File initialBomFileV2 = prepForRebindRemovedItemTestReturningBomV2(CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType(), true);
createAndStartApplication(launcherLast.getManagementContext(),
"services: [ { type: 'simple-entity:1' } ]");
alsoPersistBundlesInstalledToCatalog();
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
promoteT2IfStandby();
Entity entity = Iterables.getOnlyElement( Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren() );
// assert it was updated
Assert.assertEquals(entity.getCatalogItemId(), "simple-entity:2.0.0");
if (CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType()) {
Assert.assertEquals(Entities.deproxy(entity).getClass().getName(), BasicEntityImpl.class.getName());
} else {
Assert.assertEquals(Entities.deproxy(entity).getClass().getName(), "com.example.brooklyn.test.osgi.entities.SimpleEntityImpl");
}
}
@Test
public void testRebindUpgradeReferencedEntityFromCatalogAndDeployment() throws Exception {
File initialBomFileV2 = prepForRebindRemovedItemTestReturningBomV2(
CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType(), true);
VersionedName bundleName = new VersionedName("referencer", "1.0");
String bundleBom = Strings.lines("brooklyn.catalog:",
" version: 1", // without this the type gets the osgi version, 1.0.0 (not 1.0)
" items:",
" - id: references-simple-entity",
" item:",
" type: simple-entity:1.0",
" brooklyn.children:",
" - type: simple-entity:1.0");
File zipIn = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName);
((ManagementContextInternal)launcherLast.getManagementContext()).getOsgiManager().get().install(
InputStreamSource.of("testRebindUpgradeReferencedEntityFromCatalogAndDeployment", zipIn)).checkNoError();
startupAssertions = () -> {
String v = launcherT2==null ? "1.0.0" : "2.0.0";
VersionedName bv = new VersionedName("org.example.testRebindGetsInitialOsgiCatalog", v);
VersionedName iv = new VersionedName("simple-entity", v);
VersionedName rv = new VersionedName("references-simple-entity", "1");
assertManagedBundle(launcherLast, bv, MutableSet.of(iv));
if (launcherT2==null || !CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType()) {
assertCatalogConsistsOfIds(launcherLast, MutableList.copyOf(COM_EXAMPLE_BUNDLE_CATALOG_IDS).append(iv).append(rv));
} else {
assertCatalogConsistsOfIds(launcherLast, MutableList.of(iv, rv));
}
};
startupAssertions.run();
createAndStartApplication(launcherLast.getManagementContext(),
"services: [ { type: references-simple-entity } ]");
alsoPersistBundlesInstalledToCatalog();
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
promoteT2IfStandby();
Entity entity = Iterables.getOnlyElement( Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren() );
Assert.assertEquals(entity.getCatalogItemId(), "references-simple-entity:1");
// assert it was updated
if (CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType()) {
Assert.assertEquals(Entities.deproxy(entity).getClass().getName(), BasicEntityImpl.class.getName());
} else {
Assert.assertEquals(Entities.deproxy(entity).getClass().getName(), "com.example.brooklyn.test.osgi.entities.SimpleEntityImpl");
}
Entity child = Iterables.getOnlyElement( entity.getChildren() );
Assert.assertEquals(child.getCatalogItemId(), "simple-entity:2.0.0");
if (CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType()) {
Assert.assertEquals(Entities.deproxy(child).getClass().getName(), BasicEntityImpl.class.getName());
} else {
Assert.assertEquals(Entities.deproxy(child).getClass().getName(), "com.example.brooklyn.test.osgi.entities.SimpleEntityImpl");
}
// new deployment makes the correct java item
Application app2 = createAndStartApplication(launcherLast.getManagementContext(),
"services: [ { type: references-simple-entity } ]");
entity = Iterables.getOnlyElement( app2.getChildren() );
Assert.assertEquals(entity.getCatalogItemId(), "references-simple-entity:1");
Assert.assertEquals(Entities.deproxy(entity).getClass().getName(), BasicEntityImpl.class.getName());
child = Iterables.getOnlyElement( entity.getChildren() );
Assert.assertEquals(child.getCatalogItemId(), "simple-entity:2.0.0");
Assert.assertEquals(Entities.deproxy(child).getClass().getName(), BasicEntityImpl.class.getName());
}
@Test
public void testRebindUpgradeSpecUsedInDeployedApp() throws Exception {
File initialBomFileV2 = prepForRebindRemovedItemTestReturningBomV2(CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType(), true);
Application app = createAndStartApplication(launcherLast.getManagementContext(),
Joiner.on("\n").join(
"services:",
"- type: org.apache.brooklyn.entity.group.DynamicCluster",
" cluster.initial.size: 1",
" dynamiccluster.memberspec:",
" $brooklyn:entitySpec:",
" type: simple-entity:1") );
Entity cluster = Iterables.getOnlyElement( app.getChildren() );
((DynamicCluster)cluster).resize(0);
// at size 0 it should always persist and rebind, even with the dependent java removed (args to prep method above)
alsoPersistBundlesInstalledToCatalog();
startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
promoteT2IfStandby();
cluster = Iterables.getOnlyElement( Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren() );
((DynamicCluster)cluster).resize(1);
Entity entity = Iterables.getOnlyElement( ((DynamicCluster)cluster).getMembers() );
if (CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType() ||
BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_PERSIST_ENTITY_SPEC_AS_SUPPLIER)) {
Assert.assertEquals(entity.getCatalogItemId(), "simple-entity:2.0.0");
Assert.assertEquals(Entities.deproxy(entity).getClass().getName(), BasicEntityImpl.class.getName());
} else {
// old behaviour was to persist $brooklyn:entitySpec as an _unpacking_ of the provided definition,
// which keeps the java class and so isn't upgraded.
// catalog item ID is intercepted and updated, but not the java type.
Assert.assertEquals(entity.getCatalogItemId(), "simple-entity:2.0.0");
Assert.assertEquals(Entities.deproxy(entity).getClass().getName(), "com.example.brooklyn.test.osgi.entities.SimpleEntityImpl");
}
}
protected void assertPersistedBundleListingEqualsEventually(BrooklynLauncher launcher, Set<VersionedName> bundles) {
Asserts.succeedsEventually(new Runnable() {
@Override public void run() {
try {
Set<String> expected = new LinkedHashSet<>();
for (VersionedName bundle : bundles) {
String bundleUid = findManagedBundle(launcher, bundle).getId();
expected.add(bundleUid);
}
Set<String> persisted = getPersistenceListing(BrooklynObjectType.MANAGED_BUNDLE);
assertEquals(persisted, expected);
} catch (Exception e) {
throw Exceptions.propagate(e);
}
}});
}
protected void assertHotStandbyNow(BrooklynLauncher launcher) {
ManagementContext mgmt = launcher.getManagementContext();
assertTrue(mgmt.isStartupComplete());
assertTrue(mgmt.isRunning());
assertEquals(mgmt.getNodeState(), ManagementNodeState.HOT_STANDBY);
Asserts.assertSize(((ManagementContextInternal)mgmt).errors(), 0);
}
protected void assertMasterEventually(BrooklynLauncher launcher) {
ManagementContext mgmt = launcher.getManagementContext();
Asserts.succeedsEventually(new Runnable() {
public void run() {
assertTrue(mgmt.isStartupComplete());
assertTrue(mgmt.isRunning());
assertEquals(mgmt.getNodeState(), ManagementNodeState.MASTER);
Asserts.assertSize(((ManagementContextInternal)mgmt).errors(), 0);
}});
}
protected void assertFailsEventually(BrooklynLauncher launcher) {
Asserts.succeedsEventually(() -> assertEquals(launcher.getManagementContext().getNodeState(), ManagementNodeState.FAILED));
}
protected Bundle installBundle(Framework framework, File bundle) throws Exception {
try (FileInputStream stream = new FileInputStream(bundle)) {
return framework.getBundleContext().installBundle(bundle.toURI().toString(), stream);
}
}
protected ReferenceWithError<OsgiBundleInstallationResult> installBrooklynBundle(BrooklynLauncher launcher, File bundleFile, boolean force) throws Exception {
OsgiManager osgiManager = ((ManagementContextInternal)launcher.getManagementContext()).getOsgiManager().get();
InputStreamSource bundleStream = InputStreamSource.of("test:" + bundleFile, bundleFile);
return osgiManager.install(bundleStream, null, force);
}
protected void assertOnlyBundle(BrooklynLauncher launcher, VersionedName bundleName, Bundle expectedBundle) {
Framework framework = ((ManagementContextInternal)launcher.getManagementContext()).getOsgiManager().get().getFramework();
assertOnlyBundle(framework, bundleName, expectedBundle);
}
protected void assertOnlyBundleReplaced(BrooklynLauncher launcher, VersionedName bundleName, Bundle expectedBundle) {
Framework framework = ((ManagementContextInternal)launcher.getManagementContext()).getOsgiManager().get().getFramework();
assertOnlyBundleReplaced(framework, bundleName, 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);
}
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);
}
protected Framework initReusableOsgiFramework() {
if (!reuseOsgi) throw new IllegalStateException("Must first set reuseOsgi");
if (OsgiManager.tryPeekFrameworkForReuse().isAbsent()) {
BrooklynLauncher launcher = newLauncherForTests(CATALOG_EMPTY_INITIAL);
launcher.start();
launcher.terminate();
Os.deleteRecursively(persistenceDir);
}
return OsgiManager.tryPeekFrameworkForReuse().get();
}
protected File newTmpBundle(Set<VersionedName> catalogItems, VersionedName bundleName) {
return newTmpBundle(catalogItems, bundleName, null);
}
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);
}
// // convenience for testing just a single test (TestNG plugin otherwise runs lots of them)
// public static void main(String[] args) throws Exception {
// try {
// BrooklynLauncherRebindCatalogOsgiTest fixture = new LauncherRebindSubTests();
// fixture.setUp();
// fixture.testRebindUpgradeSpecUsedInDeployedApp();
// fixture.tearDown();
// } catch (Throwable e) {
// e.printStackTrace();
// System.exit(1);
// }
// System.exit(0);
// }
}