Skip to content

Commit 98d9b0a

Browse files
committed
tests for deletion of empty wrapper bundles
1 parent c39eb71 commit 98d9b0a

File tree

5 files changed

+131
-11
lines changed

5 files changed

+131
-11
lines changed

camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogScanOsgiTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@
2525
import java.io.FileInputStream;
2626
import java.io.FileNotFoundException;
2727
import java.io.FileOutputStream;
28+
import java.util.Map;
2829
import java.util.zip.ZipEntry;
2930

3031
import org.apache.brooklyn.api.mgmt.ManagementContext;
32+
import org.apache.brooklyn.api.typereg.ManagedBundle;
3133
import org.apache.brooklyn.api.typereg.RegisteredType;
3234
import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
3335
import org.apache.brooklyn.camp.brooklyn.test.lite.CampYamlLiteTest;
3436
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
37+
import org.apache.brooklyn.entity.stock.BasicEntity;
3538
import org.apache.brooklyn.test.Asserts;
3639
import org.apache.brooklyn.test.support.TestResourceUnavailableException;
3740
import org.apache.brooklyn.util.collections.MutableMap;
@@ -117,4 +120,35 @@ static String bomForLegacySiblingLibraries() {
117120
" - classpath://" + OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V2_PATH);
118121
}
119122

123+
@Test
124+
public void testAddAnonymousBomTwiceDeletesOldEmptyOne() {
125+
Map<String, ManagedBundle> b1 = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles();
126+
addCatalogItems(bomAnonymous());
127+
Map<String, ManagedBundle> b2_new = MutableMap.copyOf(
128+
((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles() );
129+
for (String old: b1.keySet()) b2_new.remove(old);
130+
131+
RegisteredType sample = mgmt().getTypeRegistry().get("sample");
132+
Asserts.assertNotNull(sample);
133+
Asserts.assertSize(b2_new.values(), 1);
134+
135+
addCatalogItems(bomAnonymous());
136+
Map<String, ManagedBundle> b3 = MutableMap.copyOf(
137+
((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles() );
138+
Map<String, ManagedBundle> b3_new = MutableMap.copyOf(b3);
139+
for (String old: b1.keySet()) b3_new.remove(old);
140+
for (String old: b2_new.keySet()) b3_new.remove(old);
141+
Asserts.assertSize(b3_new.values(), 1);
142+
143+
Asserts.assertFalse(b3_new.keySet().contains( Iterables.getOnlyElement(b2_new.keySet()) ));
144+
}
145+
146+
static String bomAnonymous() {
147+
return Strings.lines("brooklyn.catalog:",
148+
" items:",
149+
" - item:",
150+
" id: sample",
151+
" type: "+BasicEntity.class.getName());
152+
}
153+
120154
}

camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlRebindTest.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import static org.testng.Assert.assertNull;
2626
import static org.testng.Assert.assertTrue;
2727

28+
import java.io.File;
29+
import java.util.Arrays;
2830
import java.util.List;
2931

3032
import org.apache.brooklyn.api.catalog.CatalogItem;
@@ -38,6 +40,7 @@
3840
import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
3941
import org.apache.brooklyn.core.entity.Entities;
4042
import org.apache.brooklyn.core.entity.StartableApplication;
43+
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
4144
import org.apache.brooklyn.core.mgmt.osgi.OsgiStandaloneTest;
4245
import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
4346
import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
@@ -84,8 +87,14 @@ enum RebindWithCatalogTestMode {
8487

8588
enum OsgiMode {
8689
NONE,
90+
// we don't test OSGi with this because CAMP isn't available
91+
// (and the library bundles assume CAMP in their catalog.bom)
92+
// OSGi rebind isn't the focus of the tests which use this parameter
93+
// so it's okay, though a bit ugly
94+
// NORMAL,
8795
}
8896

97+
boolean useOsgi = false;
8998
private Boolean defaultEnablementOfFeatureAutoFixatalogRefOnRebind;
9099

91100
@BeforeMethod(alwaysRun=true)
@@ -106,7 +115,7 @@ public void tearDown() throws Exception {
106115

107116
@Override
108117
protected boolean useOsgi() {
109-
return false;
118+
return useOsgi || (origManagementContext!=null && ((ManagementContextInternal)origManagementContext).getOsgiManager().isPresent());
110119
}
111120

112121
@DataProvider
@@ -192,6 +201,8 @@ private String idFromPath(BrooklynObjectType type, String path) {
192201
public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mode, OsgiMode osgiMode, RebindOptions options) throws Exception {
193202
if (osgiMode != OsgiMode.NONE) {
194203
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
204+
205+
recreateOrigManagementContextWithOsgi();
195206
}
196207

197208
if (mode == RebindWithCatalogTestMode.REPLACE_CATALOG_WITH_NEWER_VERSION) {
@@ -351,9 +362,33 @@ public void testRebindWithCatalogAndAppUsingOptions(RebindWithCatalogTestMode mo
351362
}
352363
}
353364
}
365+
366+
protected void recreateOrigManagementContextWithOsgi() {
367+
// replace with OSGi context
368+
Entities.destroyAll(origManagementContext);
369+
try {
370+
useOsgi = true;
371+
origManagementContext = createOrigManagementContext();
372+
origApp = createApp();
373+
} finally {
374+
useOsgi = false;
375+
}
376+
}
354377

355378
@Test
356-
public void testLongReferenceSequence() throws Exception {
379+
public void testLongReferenceSequenceWithoutOsgi() throws Exception {
380+
doTestLongReferenceSequence();
381+
}
382+
383+
@Test(groups="Broken")
384+
public void testLongReferenceSequenceWithOsgi() throws Exception {
385+
// won't work in OSGi mode because we need CAMP to resolve type "a0"
386+
// (poor man's resolver only resolves Java classes)
387+
recreateOrigManagementContextWithOsgi();
388+
doTestLongReferenceSequence();
389+
}
390+
391+
private void doTestLongReferenceSequence() throws Exception {
357392
// adds a0, a1 extending a0, a2 extending a1, ... a9 extending a8
358393
// osgi rebind of types can fail because bundles are restored in any order
359394
// and dependencies might not yet be installed;
@@ -373,5 +408,23 @@ public void testLongReferenceSequence() throws Exception {
373408
Asserts.assertTrue(child instanceof BasicEntity);
374409
Asserts.assertEquals(child.getCatalogItemId(), "a9:1");
375410
}
376-
411+
412+
@Test
413+
public void testDeleteEmptyBundleRemovedFromPersistence() throws Exception {
414+
recreateOrigManagementContextWithOsgi();
415+
416+
String bom = Strings.lines(
417+
"brooklyn.catalog:",
418+
" itemType: entity",
419+
" items:",
420+
" - id: sample",
421+
" item:",
422+
" type: " + BasicEntity.class.getName());
423+
addCatalogItems(bom);
424+
addCatalogItems(bom);
425+
rebind();
426+
// should only contain one bundle / bundle.jar pair
427+
Asserts.assertSize(Arrays.asList( new File(mementoDir, "bundles").list() ), 2);
428+
}
429+
377430
}

core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1858,7 +1858,7 @@ public void uninstallEmptyWrapperBundles() {
18581858
if (isNoBundleOrSimpleWrappingBundle(mgmt, b)) {
18591859
Iterable<RegisteredType> typesInBundle = osgi.get().getTypesFromBundle(b.getVersionedName());
18601860
if (Iterables.isEmpty(typesInBundle)) {
1861-
log.debug("uninstalling empty wrapper bundle "+b);
1861+
log.info("Uninstalling now-empty BOM wrapper bundle "+b.getVersionedName()+" ("+b.getOsgiUniqueUrl()+")");
18621862
osgi.get().uninstallUploadedBundle(b);
18631863
}
18641864
}

core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.apache.brooklyn.core.catalog.internal;
2020

21+
import java.util.Map;
2122
import java.util.Set;
2223

2324
import org.apache.brooklyn.api.catalog.CatalogItem;
@@ -32,13 +33,18 @@
3233
import org.apache.brooklyn.api.sensor.EnricherSpec;
3334
import org.apache.brooklyn.api.typereg.RegisteredType;
3435
import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
36+
import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
3537
import org.apache.brooklyn.core.objs.BasicSpecParameter;
3638
import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
3739
import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
3840
import org.apache.brooklyn.util.exceptions.Exceptions;
41+
import org.apache.brooklyn.util.text.Strings;
42+
import org.apache.brooklyn.util.yaml.Yamls;
3943
import org.slf4j.Logger;
4044
import org.slf4j.LoggerFactory;
4145

46+
import com.google.common.collect.Iterables;
47+
4248
/**
4349
* Instantiates classes from a registered type which simply
4450
* defines the java class name and OSGi bundles to use.
@@ -76,12 +82,26 @@ public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT c
7682
CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws UnsupportedTypePlanException {
7783
@SuppressWarnings("deprecation")
7884
String javaType = item.getJavaType();
85+
boolean poorMansCamp = false;
86+
if (javaType == null) {
87+
if (Strings.isNonBlank( item.getPlanYaml() )) {
88+
try {
89+
Map<?,?> parsed = (Map<?,?>) Iterables.getOnlyElement( Yamls.parseAll(item.getPlanYaml()) );
90+
if ("type".equals(Iterables.getOnlyElement(parsed.keySet()))) {
91+
javaType = (String) Iterables.getOnlyElement(parsed.values());
92+
poorMansCamp = true;
93+
}
94+
} catch (Exception e) {
95+
throw new UnsupportedTypePlanException(getClass().getName() + " parses only old-style catalog items containing only 'type: JavaClass' in YAML (or javaType in DTO)", e);
96+
}
97+
}
98+
}
7999
if (javaType != null) {
80-
// TODO This log.warn previously said "Using old-style xml catalog items with java type attribute".
81-
// However, nothing in this code is specific to catalog.xml. Perhaps that is the only way this code
82-
// can be reached? We should investigate further when we have time - if we can confirm it was only
83-
// used for catalog.xml, then this can be deleted.
84-
log.warn("Deprecated functionality (since 0.9.0). Using old-style java type attribute for " + item);
100+
// TODO "JavaType" should never be used any more; but we do want to support a poor-man's camp
101+
// for tests that expect CAMP in core where CAMP module isn't available
102+
if (poorMansCamp) {
103+
log.warn("Deprecated functionality (since 0.9.0). Using old-style java type attribute for " + item);
104+
}
85105
Class<?> type;
86106
try {
87107
// java types were deprecated before we added osgi support so this isn't necessary,
@@ -90,6 +110,7 @@ public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT c
90110
final BrooklynClassLoadingContextSequential ctx = new BrooklynClassLoadingContextSequential(mgmt);
91111
ctx.add(CatalogUtils.newClassLoadingContextForCatalogItems(mgmt, item.getCatalogItemId(),
92112
item.getCatalogItemIdSearchPath()));
113+
ctx.addSecondary(JavaBrooklynClassLoadingContext.create(mgmt));
93114
type = ctx.loadClass(javaType);
94115
} catch (Exception e) {
95116
Exceptions.propagateIfFatal(e);
@@ -117,7 +138,7 @@ public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT c
117138
SpecT untypedSpc = (SpecT) spec;
118139
return untypedSpc;
119140
} else {
120-
throw new UnsupportedTypePlanException(getClass().getName() + " parses only old-style catalog items containing javaType");
141+
throw new UnsupportedTypePlanException(getClass().getName() + " parses only old-style catalog items containing only 'type: JavaClass' or javaType in DTO");
121142
}
122143
}
123144

core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,20 @@ public static Application rebind(ManagementContext newManagementContext, File me
379379
}
380380

381381
public static Application rebind(RebindOptions options) throws Exception {
382+
boolean hadApps = true;
383+
if (options!=null && options.origManagementContext!=null && options.origManagementContext.getApplications().isEmpty()) {
384+
// clearly had no apps before, so don't treat as an error
385+
hadApps = false;
386+
}
382387
Collection<Application> newApps = rebindAll(options);
383-
if (newApps.isEmpty()) throw new IllegalStateException("Application could not be found after rebind; serialization probably failed");
388+
if (newApps.isEmpty()) {
389+
if (hadApps) {
390+
throw new IllegalStateException("Application could not be found after rebind; serialization probably failed");
391+
} else {
392+
// no apps before; probably testing catalog
393+
return null;
394+
}
395+
}
384396
Function<Collection<Application>, Application> chooser = options.applicationChooserOnRebind;
385397
if (chooser != null) {
386398
return chooser.apply(newApps);

0 commit comments

Comments
 (0)