/* * 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.core.mgmt.rebind; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.io.File; import org.apache.brooklyn.api.catalog.CatalogItem; import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.mgmt.ManagementContext; 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.CatalogDto; import org.apache.brooklyn.core.catalog.internal.CatalogEntityItemDto; import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder; import org.apache.brooklyn.core.catalog.internal.CatalogLocationItemDto; import org.apache.brooklyn.core.catalog.internal.CatalogPolicyItemDto; import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; import org.apache.brooklyn.core.policy.AbstractPolicy; import org.apache.brooklyn.core.server.BrooklynServerConfig; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; public class RebindCatalogItemTest extends RebindTestFixtureWithApp { private static final String TEST_VERSION = "0.0.1"; private static final Logger LOG = LoggerFactory.getLogger(RebindCatalogItemTest.class); public static class MyPolicy extends AbstractPolicy {} private boolean catalogPersistenceWasEnabled; @BeforeMethod(alwaysRun = true) @Override public void setUp() throws Exception { catalogPersistenceWasEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_CATALOG_PERSISTENCE_PROPERTY); BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_CATALOG_PERSISTENCE_PROPERTY); super.setUp(); origApp.createAndManageChild(EntitySpec.create(TestEntity.class)); } @AfterMethod(alwaysRun = true) @Override public void tearDown() throws Exception { super.tearDown(); BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_CATALOG_PERSISTENCE_PROPERTY, catalogPersistenceWasEnabled); } @Override protected LocalManagementContext createOrigManagementContext() { BrooklynProperties properties = BrooklynProperties.Factory.newDefault(); properties.put(BrooklynServerConfig.BROOKLYN_CATALOG_URL, "classpath://brooklyn/entity/rebind/rebind-catalog-item-test-catalog.xml"); properties.put(BrooklynServerConfig.CATALOG_LOAD_MODE, org.apache.brooklyn.core.catalog.CatalogLoadMode.LOAD_BROOKLYN_CATALOG_URL); return RebindTestUtils.managementContextBuilder(mementoDir, classLoader) .properties(properties) .persistPeriodMillis(getPersistPeriodMillis()) .forLive(useLiveManagementContext()) .buildStarted(); } @Override protected LocalManagementContext createNewManagementContext(File mementoDir) { BrooklynProperties properties = BrooklynProperties.Factory.newDefault(); properties.put(BrooklynServerConfig.BROOKLYN_CATALOG_URL, "classpath://brooklyn/entity/rebind/rebind-catalog-item-test-catalog.xml"); return RebindTestUtils.managementContextBuilder(mementoDir, classLoader) .properties(properties) .forLive(useLiveManagementContext()) .emptyCatalog(useEmptyCatalog()) .buildUnstarted(); } @Test public void testPersistsEntityFromCatalogXml() { assertEquals(Iterables.size(origManagementContext.getCatalog().getCatalogItems()), 1); rebindAndAssertCatalogsAreEqual(); } @Test public void testAddAndRebindEntity() throws Exception { String symbolicName = "rebind-yaml-catalog-item-test"; String yaml = "name: " + symbolicName + "\n" + "brooklyn.catalog:\n" + " version: " + TEST_VERSION + "\n" + "services:\n" + "- type: io.camp.mock:AppServer"; CatalogEntityItemDto item = CatalogItemBuilder.newEntity(symbolicName, TEST_VERSION) .displayName(symbolicName) .plan(yaml) .build(); origManagementContext.getCatalog().addItem(item); LOG.info("Added item to catalog: {}, id={}", item, item.getId()); rebindAndAssertCatalogsAreEqual(); } @Test(enabled = false) public void testAddAndRebindTemplate() { // todo: could use (deprecated, perhaps wrongly) BBC.addItem(Class/CatalogItem) fail("Unimplemented because the catalogue does not currently distinguish between application templates and entities"); } @Test public void testAddAndRebindPolicy() { // Doesn't matter that SamplePolicy doesn't exist String symbolicName = "Test Policy"; String yaml = "name: " + symbolicName + "\n" + "brooklyn.catalog:\n" + " id: sample_policy\n" + " version: " + TEST_VERSION + "\n" + "brooklyn.policies: \n" + "- type: org.apache.brooklyn.core.mgmt.rebind.RebindCatalogItemTest$MyPolicy\n" + " brooklyn.config:\n" + " cfg1: 111\n" + " cfg2: 222"; CatalogPolicyItemDto item = CatalogItemBuilder.newPolicy(symbolicName, TEST_VERSION) .displayName(symbolicName) .plan(yaml) .build(); origManagementContext.getCatalog().addItem(item); LOG.info("Added item to catalog: {}, id={}", item, item.getId()); rebindAndAssertCatalogsAreEqual(); } @Test public void testAddAndRebindAndDeleteLocation() { String symbolicName = "sample_location"; String yaml = Joiner.on("\n").join(ImmutableList.of( "name: Test Location", "brooklyn.catalog:", " id: " + symbolicName, " version: " + TEST_VERSION, "brooklyn.locations:", "- type: "+LocalhostMachineProvisioningLocation.class.getName(), " brooklyn.config:", " cfg1: 111", " cfg2: 222")); CatalogLocationItemDto item = CatalogItemBuilder.newLocation(symbolicName, TEST_VERSION) .displayName(symbolicName) .plan(yaml) .build(); origManagementContext.getCatalog().addItem(item); assertEquals(item.getCatalogItemType(), CatalogItemType.LOCATION); rebindAndAssertCatalogsAreEqual(); deleteItem(newManagementContext, item.getSymbolicName(), item.getVersion()); switchOriginalToNewManagementContext(); rebindAndAssertCatalogsAreEqual(); } @Test(enabled = false) public void testAddAndRebindEnricher() { fail("unimplemented"); } @Test(invocationCount = 3) public void testDeletedCatalogItemIsNotPersisted() { assertEquals(Iterables.size(origManagementContext.getCatalog().getCatalogItems()), 1); CatalogItem<Object, Object> toRemove = Iterables.getOnlyElement(origManagementContext.getCatalog().getCatalogItems()); // Must make sure that the original catalogue item is not managed and unmanaged in the same // persistence window. Because BrooklynMementoPersisterToObjectStore applies writes/deletes // asynchronously the winner is down to a race and the test might pass or fail. origManagementContext.getRebindManager().forcePersistNow(false, null); origManagementContext.getCatalog().deleteCatalogItem(toRemove.getSymbolicName(), toRemove.getVersion()); assertEquals(Iterables.size(origManagementContext.getCatalog().getCatalogItems()), 0); rebindAndAssertCatalogsAreEqual(); assertEquals(Iterables.size(newManagementContext.getCatalog().getCatalogItems()), 0); } @Test(invocationCount = 3) public void testCanTagCatalogItemAfterRebind() { assertEquals(Iterables.size(origManagementContext.getCatalog().getCatalogItems()), 1); CatalogItem<Object, Object> toTag = Iterables.getOnlyElement(origManagementContext.getCatalog().getCatalogItems()); final String tag = "tag1"; toTag.tags().addTag(tag); assertTrue(toTag.tags().containsTag(tag)); rebindAndAssertCatalogsAreEqual(); toTag = Iterables.getOnlyElement(newManagementContext.getCatalog().getCatalogItems()); assertTrue(toTag.tags().containsTag(tag)); toTag.tags().removeTag(tag); } @Test public void testSameCatalogItemIdRemovalAndAdditionRebinds() throws Exception { //The test is not reliable on Windows (doesn't catch the pre-fix problem) - //the store is unable to delete still locked files so the bug doesn't manifest. //TODO investigate if locked files not caused by unclosed streams! String symbolicName = "rebind-yaml-catalog-item-test"; String yaml = "name: " + symbolicName + "\n" + "brooklyn.catalog:\n" + " version: " + TEST_VERSION + "\n" + "services:\n" + "- type: io.camp.mock:AppServer"; BasicBrooklynCatalog catalog = (BasicBrooklynCatalog) origManagementContext.getCatalog(); CatalogEntityItemDto item = CatalogItemBuilder.newEntity(symbolicName, TEST_VERSION) .displayName(symbolicName) .plan(yaml) .build(); catalog.addItem(item); String catalogXml = catalog.toXmlString(); catalog.reset(CatalogDto.newDtoFromXmlContents(catalogXml, "Test reset")); rebindAndAssertCatalogsAreEqual(); } @Test public void testRebindAfterItemDeprecated() { String symbolicName = "rebind-yaml-catalog-item-test"; String yaml = "name: " + symbolicName + "\n" + "brooklyn.catalog:\n" + " version: " + TEST_VERSION + "\n" + "services:\n" + "- type: io.camp.mock:AppServer"; CatalogEntityItemDto item = CatalogItemBuilder.newEntity(symbolicName, TEST_VERSION) .displayName(symbolicName) .plan(yaml) .build(); origManagementContext.getCatalog().addItem(item); assertNotNull(item, "catalogItem"); BasicBrooklynCatalog catalog = (BasicBrooklynCatalog) origManagementContext.getCatalog(); item.setDeprecated(true); catalog.persist(item); rebindAndAssertCatalogsAreEqual(); RegisteredType catalogItemAfterRebind = newManagementContext.getTypeRegistry().get("rebind-yaml-catalog-item-test", TEST_VERSION); assertTrue(catalogItemAfterRebind.isDeprecated(), "Expected item to be deprecated"); } protected void deleteItem(ManagementContext mgmt, String symbolicName, String version) { mgmt.getCatalog().deleteCatalogItem(symbolicName, version); LOG.info("Deleted item from catalog: {}:{}", symbolicName, version); Assert.assertNull( mgmt.getTypeRegistry().get(symbolicName, version) ); } private void rebindAndAssertCatalogsAreEqual() { try { rebind(); } catch (Exception e) { throw Throwables.propagate(e); } assertCatalogsEqual(newManagementContext.getCatalog(), origManagementContext.getCatalog()); } }