/*
* 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.assertFalse;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.location.LocationSpec;
import org.apache.brooklyn.api.mgmt.rebind.RebindContext;
import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.location.AbstractLocation;
import org.apache.brooklyn.core.mgmt.rebind.BasicLocationRebindSupport;
import org.apache.brooklyn.core.mgmt.rebind.RebindEntityTest.MyEntity;
import org.apache.brooklyn.core.test.entity.TestApplication;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.google.common.base.Predicates;
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 class RebindLocationTest extends RebindTestFixtureWithApp {
@SuppressWarnings("unused")
private MyEntity origE;
@BeforeMethod(alwaysRun=true)
public void setUp() throws Exception {
super.setUp();
origE = origApp.createAndManageChild(EntitySpec.create(MyEntity.class));
}
@Test
public void testSetsLocationOnEntities() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of("name", "mylocname"));
origApp.start(ImmutableList.of(origLoc));
newApp = (TestApplication) rebind();
MyEntity newE = (MyEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(MyEntity.class));
assertEquals(newApp.getLocations().size(), 1, "locs="+newE.getLocations());
assertTrue(Iterables.get(newApp.getLocations(), 0) instanceof MyLocation);
assertEquals(newE.getLocations().size(), 1, "locs="+newE.getLocations());
assertTrue(Iterables.get(newE.getLocations(), 0) instanceof MyLocation);
}
@Test
public void testRestoresLocationIdAndDisplayName() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of("name", "mylocname"));
origApp.start(ImmutableList.of(origLoc));
newApp = (TestApplication) rebind();
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
assertEquals(newLoc.getId(), origLoc.getId());
assertEquals(newLoc.getDisplayName(), origLoc.getDisplayName());
}
@Test
public void testCanCustomizeLocationRebind() throws Exception {
MyLocationCustomProps origLoc = new MyLocationCustomProps(MutableMap.of("name", "mylocname", "myfield", "myval"));
origApp.start(ImmutableList.of(origLoc));
newApp = (TestApplication) rebind();
MyLocationCustomProps newLoc2 = (MyLocationCustomProps) Iterables.get(newApp.getLocations(), 0);
assertEquals(newLoc2.getId(), origLoc.getId());
assertEquals(newLoc2.getDisplayName(), origLoc.getDisplayName());
assertEquals(newLoc2.rebound, true);
assertEquals(newLoc2.myfield, "myval");
}
@Test
public void testRestoresFieldsWithSetFromFlag() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of("myfield", "myval"));
origApp.start(ImmutableList.of(origLoc));
newApp = (TestApplication) rebind();
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
assertEquals(newLoc.myfield, "myval");
}
@Test
public void testRestoresAtomicLongWithSetFromFlag() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of("myAtomicLong", "123"));
origApp.start(ImmutableList.of(origLoc));
origLoc.myAtomicLong.incrementAndGet();
assertEquals(origLoc.myAtomicLong.get(), 124L);
origApp.getManagementContext().getRebindManager().getChangeListener().onChanged(origLoc);
newApp = (TestApplication) rebind();
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
// should get _modified_ value, not the one in the config map
assertEquals(newLoc.myAtomicLong.get(), 124L);
}
@Test
public void testRestoresConfig() throws Exception {
MyLocation origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(MyLocation.class)
.configure(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
.configure(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
.configure(MyLocation.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
origApp.start(ImmutableList.of(origLoc));
newApp = (TestApplication) rebind();
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
assertEquals(newLoc.getConfig(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
assertEquals(newLoc.getConfig(MyLocation.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
assertEquals(newLoc.getConfig(MyLocation.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");
}
@Test
public void testIgnoresTransientFieldsNotSetFromFlag() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of());
origLoc.myTransientFieldNotSetFromFlag = "myval";
origApp.start(ImmutableList.of(origLoc));
newApp = (TestApplication) rebind();
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
// transient fields normally not persisted
assertEquals(newLoc.myTransientFieldNotSetFromFlag, null);
}
@Test
public void testIgnoresTransientFieldsSetFromFlag() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of("myTransientFieldSetFromFlag", "myval"));
origApp.start(ImmutableList.of(origLoc));
newApp = (TestApplication) rebind();
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
assertEquals(newLoc.myTransientFieldSetFromFlag, null);
}
@Test
public void testIgnoresStaticFieldsNotSetFromFlag() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of());
MyLocation.myStaticFieldNotSetFromFlag = "myval";
origApp.start(ImmutableList.of(origLoc));
RebindTestUtils.waitForPersisted(origApp);
MyLocation.myStaticFieldNotSetFromFlag = "mynewval";
newApp = (TestApplication) RebindTestUtils.rebind(mementoDir, getClass().getClassLoader());
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
Assert.assertEquals(newLoc, origLoc);
// static fields normally not persisted (we see new value)
assertEquals(MyLocation.myStaticFieldNotSetFromFlag, "mynewval");
}
@Test
public void testIgnoresStaticFieldsSetFromFlag() throws Exception {
MyLocation origLoc = new MyLocation(MutableMap.of("myStaticFieldSetFromFlag", "myval"));
origApp.start(ImmutableList.of(origLoc));
RebindTestUtils.waitForPersisted(origApp);
MyLocation.myStaticFieldSetFromFlag = "mynewval"; // not auto-checkpointed
newApp = (TestApplication) RebindTestUtils.rebind(mementoDir, getClass().getClassLoader());
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
Assert.assertEquals(newLoc, origLoc);
assertEquals(MyLocation.myStaticFieldSetFromFlag, "mynewval");
}
@Test
public void testHandlesFieldReferencingOtherLocations() throws Exception {
MyLocation origOtherLoc = new MyLocation();
MyLocationReffingOthers origLoc = new MyLocationReffingOthers(MutableMap.of("otherLocs", ImmutableList.of(origOtherLoc), "myfield", "myval"));
origOtherLoc.setParent(origLoc);
origApp.start(ImmutableList.of(origLoc));
newApp = rebind();
MyLocationReffingOthers newLoc = (MyLocationReffingOthers) Iterables.get(newApp.getLocations(), 0);
assertEquals(newLoc.getChildren().size(), 1);
assertTrue(Iterables.get(newLoc.getChildren(), 0) instanceof MyLocation, "children="+newLoc.getChildren());
assertEquals(newLoc.otherLocs, ImmutableList.copyOf(newLoc.getChildren()));
// Confirm this didn't override other values (e.g. setting other fields back to their defaults, as was once the case!)
assertEquals(newLoc.myfield, "myval");
}
/**
* @deprecated since 0.7; support for rebinding old-style locations is deprecated
*/
@Test
public void testHandlesOldStyleLocation() throws Exception {
MyOldStyleLocation origLoc = new MyOldStyleLocation(ImmutableMap.of("myfield", "myval"));
origApp.start(ImmutableList.of(origLoc));
newApp = rebind();
MyOldStyleLocation newLoc = (MyOldStyleLocation) Iterables.get(newApp.getLocations(), 0);
assertEquals(newLoc.myfield, "myval");
}
@Test
public void testReboundConfigDoesNotContainId() throws Exception {
MyLocation origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(MyLocation.class));
origApp.start(ImmutableList.of(origLoc));
newApp = rebind();
MyLocation newLoc = (MyLocation) Iterables.get(newApp.getLocations(), 0);
assertNull(newLoc.config().getBag().getStringKey("id"));
assertEquals(newLoc.getId(), origLoc.getId());
}
@Test
public void testIsRebinding() throws Exception {
LocationChecksIsRebinding origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(LocationChecksIsRebinding.class));
rebind();
LocationChecksIsRebinding newLoc = (LocationChecksIsRebinding) newManagementContext.getLocationManager().getLocation(origLoc.getId());
assertTrue(newLoc.isRebindingValWhenRebinding());
assertFalse(newLoc.isRebinding());
}
@Test
public void testLocationTags() throws Exception {
Location origLoc = origManagementContext.getLocationManager().createLocation(LocationSpec.create(MyLocation.class));
origLoc.tags().addTag("foo");
origLoc.tags().addTag(origApp);
origApp.start(ImmutableList.of(origLoc));
newApp = rebind();
Location newLoc = (Location) newManagementContext.getLocationManager().getLocation(origLoc.getId());
Asserts.assertEqualsIgnoringOrder(newLoc.tags().getTags(), ImmutableSet.of("foo", newApp));
}
public static class LocationChecksIsRebinding extends AbstractLocation {
boolean isRebindingValWhenRebinding;
public boolean isRebindingValWhenRebinding() {
return isRebindingValWhenRebinding;
}
@Override public boolean isRebinding() {
return super.isRebinding();
}
@Override public void rebind() {
super.rebind();
isRebindingValWhenRebinding = isRebinding();
}
}
public static class MyOldStyleLocation extends AbstractLocation {
@SetFromFlag
String myfield;
public MyOldStyleLocation(Map<?,?> flags) {
super(flags);
}
}
public static class MyLocation extends AbstractLocation {
@SetFromFlag
public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.noShortName");
@SetFromFlag("myConfigWithSetFromFlagWithShortName")
public static final ConfigKey<String> MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME = ConfigKeys.newStringConfigKey("myconfig.withSetfromflag.withShortName");
public static final ConfigKey<String> MY_CONFIG_WITHOUT_SETFROMFLAG = ConfigKeys.newStringConfigKey("myconfig.withoutSetfromflag");
@SetFromFlag
String myfield;
@SetFromFlag(defaultVal="1")
AtomicLong myAtomicLong;
@SuppressWarnings("unused")
private final Object dummy = new Object(); // so not serializable
@SetFromFlag
transient String myTransientFieldSetFromFlag;
transient String myTransientFieldNotSetFromFlag;
@SetFromFlag
static String myStaticFieldSetFromFlag;
static String myStaticFieldNotSetFromFlag;
public MyLocation() {
}
public MyLocation(Map<?,?> flags) {
super(flags);
}
}
public static class MyLocationReffingOthers extends AbstractLocation {
@SetFromFlag(defaultVal="a")
String myfield;
@SetFromFlag
List<Location> otherLocs;
@SuppressWarnings("unused")
private final Object dummy = new Object(); // so not serializable
public MyLocationReffingOthers() {
}
public MyLocationReffingOthers(Map<?,?> flags) {
super(flags);
}
}
public static class MyLocationCustomProps extends AbstractLocation {
String myfield;
boolean rebound;
@SuppressWarnings("unused")
private final Object dummy = new Object(); // so not serializable
public MyLocationCustomProps() {
}
public MyLocationCustomProps(Map<?,?> flags) {
super(flags);
myfield = (String) flags.get("myfield");
}
@Override
public RebindSupport<LocationMemento> getRebindSupport() {
return new BasicLocationRebindSupport(this) {
@Override public LocationMemento getMemento() {
return getMementoWithProperties(MutableMap.<String,Object>of("myfield", myfield));
}
@Override
protected void doReconstruct(RebindContext rebindContext, LocationMemento memento) {
super.doReconstruct(rebindContext, memento);
myfield = (String) memento.getCustomField("myfield");
rebound = true;
}
};
}
}
}