blob: 31cf646aba26a5aac0bd34d0ef47422f2449de98 [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.camp.brooklyn;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.api.objs.Configurable;
import org.apache.brooklyn.api.sensor.AttributeSensor;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.entity.Dumper;
import org.apache.brooklyn.core.entity.EntityAsserts;
import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.core.test.entity.TestEntity;
import org.apache.brooklyn.entity.stock.BasicApplication;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.time.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
@Test
public class ObjectsYamlTest extends AbstractYamlTest {
private static final Logger log = LoggerFactory.getLogger(ObjectsYamlTest.class);
private static final AtomicBoolean managementContextInjected = new AtomicBoolean(false);
private static final List<String> configKeys = Lists.newLinkedList();
public static class TestObject implements ManagementContextInjectable {
private String string;
private Integer number;
private Object object;
private List<String> list;
// Factory method.
public static TestObject newTestObjectWithNoArgs() {
return new TestObject("myDefaultFirst", 1, "myDefaultThird");
}
// Factory method.
public static TestObject newTestObject(String string, Integer number, Object object) {
return new TestObject(string + "-suffix", number + 1, object);
}
// No-arg constructor.
public TestObject() { }
// Parameterised constructor.
public TestObject(String string, Integer number, Object object) {
this.string = string;
this.number = number;
this.object = object;
}
public String getString() { return string; }
public void setString(String string) { this.string = string; }
public Integer getNumber() { return number; }
public void setNumber(Integer number) { this.number = number; }
public Object getObject() { return object; }
public void setObject(Object object) { this.object = object; }
public List<String> getList() { return list; }
public void setList(List<String> list) { this.list = list; }
@Override
public void setManagementContext(ManagementContext managementContext) {
log.info("Detected injection of {}", managementContext);
managementContextInjected.set(true);
}
}
// TODO Copy of org.apache.brooklyn.rest.security.PasswordHasher; but this module does not
// have access to brooklyn-rest-resources (and would create a circular reference to do so)
public static class PasswordHasher {
public static String sha256(String salt, String password) {
if (salt == null) salt = "";
byte[] bytes = (salt + password).getBytes(Charsets.UTF_8);
HashCode hash = Hashing.sha256().hashBytes(bytes);
return hash.toString();
}
}
public static class ConfigurableObject implements Configurable {
public static final ConfigKey<Integer> INTEGER = ConfigKeys.newIntegerConfigKey("config.number");
@SetFromFlag("object")
public static final ConfigKey<Object> OBJECT = ConfigKeys.newConfigKey(Object.class, "config.object");
@SetFromFlag("flag")
private String string;
private Integer number;
private Object object;
private Double value;
BasicConfigurationSupport configSupport = new BasicConfigurationSupport();
public ConfigurableObject() { }
public String getString() { return string; }
public Integer getNumber() { return number; }
public Object getObject() { return object; }
public Double getDouble() { return value; }
public void setDouble(Double value) { this.value = value; }
@Override
public <T> T getConfig(ConfigKey<T> key) {
return config().get(key);
}
@Override
public ConfigurationSupport config() {
return configSupport;
}
private class BasicConfigurationSupport implements ConfigurationSupport {
private final ConfigBag bag = new ConfigBag();
@Override
public <T> T get(ConfigKey<T> key) {
return bag.get(key);
}
@Override
public <T> T get(HasConfigKey<T> key) {
return get(key.getConfigKey());
}
@Override
public <T> T set(ConfigKey<T> key, T val) {
log.info("Detected configuration injection for {}: {}", key.getName(), val);
configKeys.add(key.getName());
if ("config.number".equals(key.getName())) number = TypeCoercions.coerce(val, Integer.class);
if ("config.object".equals(key.getName())) object = val;
T old = bag.get(key);
bag.configure(key, val);
return old;
}
@Override
public <T> T set(HasConfigKey<T> key, T val) {
return set(key.getConfigKey(), val);
}
@Override
public <T> T set(ConfigKey<T> key, Task<T> val) {
throw new UnsupportedOperationException();
}
@Override
public <T> T set(HasConfigKey<T> key, Task<T> val) {
return set(key.getConfigKey(), val);
}
@Override
public Set<ConfigKey<?>> findKeysDeclared(Predicate<? super ConfigKey<?>> filter) {
return MutableSet.copyOf(Iterables.filter(bag.getAllConfigAsConfigKeyMap().keySet(), filter));
}
@Override
public Set<ConfigKey<?>> findKeysPresent(Predicate<? super ConfigKey<?>> filter) {
return findKeysDeclared(filter);
}
}
}
protected Entity setupAndCheckTestEntityInBasicYamlWith(String ...extras) throws Exception {
managementContextInjected.set(false);
configKeys.clear();
Entity app = createAndStartApplication(loadYaml("test-entity-basic-template.yaml", extras));
waitForApplicationTasks(app);
Assert.assertEquals(app.getDisplayName(), "test-entity-basic-template");
log.info("App started:");
Dumper.dumpInfo(app);
Assert.assertTrue(app.getChildren().iterator().hasNext(), "Expected app to have child entity");
Entity entity = app.getChildren().iterator().next();
Assert.assertTrue(entity instanceof TestEntity, "Expected TestEntity, found " + entity.getClass());
return entity;
}
@Test
public void testSingleEntity() throws Exception {
setupAndCheckTestEntityInBasicYamlWith();
}
@Test
public void testBrooklynObject() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" object.fields:",
" number: 7",
" object:",
" $brooklyn:object:",
" type: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo",
" string: \"frog\"");
Object testObject = testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertTrue(testObject instanceof TestObject, "Expected a TestObject: "+testObject);
Assert.assertTrue(managementContextInjected.get());
Assert.assertEquals(((TestObject) testObject).getNumber(), Integer.valueOf(7));
Assert.assertEquals(((TestObject) testObject).getString(), "frog");
Object testObjectObject = ((TestObject) testObject).getObject();
Assert.assertTrue(testObjectObject instanceof SimpleTestPojo, "Expected a SimpleTestPojo: "+testObjectObject);
}
@Test
public void testBrooklynConfigurableObject() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$ConfigurableObject",
" object.fields:",
" double: 1.4",
" brooklyn.config:",
" flag: frog",
" config.number: 7",
" object:",
" $brooklyn:object:",
" type: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo");
Object testObject = testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertTrue(testObject instanceof ConfigurableObject, "Expected a ConfigurableObject: "+testObject);
Assert.assertEquals(((ConfigurableObject) testObject).getDouble(), Double.valueOf(1.4));
Assert.assertEquals(((ConfigurableObject) testObject).getString(), "frog");
Assert.assertEquals(((ConfigurableObject) testObject).getNumber(), Integer.valueOf(7));
Object testObjectObject = ((ConfigurableObject) testObject).getObject();
Assert.assertTrue(testObjectObject instanceof SimpleTestPojo, "Expected a SimpleTestPojo: "+testObjectObject);
Assert.assertTrue(configKeys.contains(ConfigurableObject.INTEGER.getName()), "Expected INTEGER key: "+configKeys);
Assert.assertTrue(configKeys.contains(ConfigurableObject.OBJECT.getName()), "Expected OBJECT key: "+configKeys);
}
@Test
public void testBrooklynObjectPrefix() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confListPlain:",
" - $brooklyn:object:",
" objectType: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo",
" - $brooklyn:object:",
" object_type: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo",
" - $brooklyn:object:",
" type: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo");
List<?> testList = testEntity.getConfig(TestEntity.CONF_LIST_PLAIN);
Assert.assertEquals(testList.size(), 3);
for (Object entry : testList) {
Assert.assertTrue(entry instanceof SimpleTestPojo, "Expected a SimpleTestPojo: "+entry);
}
}
@Test
public void testBrooklynObjectWithFunction() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" object.fields:",
" number: 7",
" object:",
" $brooklyn:object:",
" type: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo",
" string:",
" $brooklyn:formatString(\"%s\", \"frog\")");
Object testObject = testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertTrue(testObject instanceof TestObject, "Expected a TestObject: "+testObject);
Assert.assertTrue(managementContextInjected.get());
Assert.assertEquals(((TestObject) testObject).getNumber(), Integer.valueOf(7));
Assert.assertEquals(((TestObject) testObject).getString(), "frog");
Object testObjectObject = ((TestObject) testObject).getObject();
Assert.assertTrue(testObjectObject instanceof SimpleTestPojo, "Expected a SimpleTestPojo: "+testObjectObject);
}
@Test
public void testBrooklynObjectWithParameterisedConstructor() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" constructor.args:",
" - frog",
" - 7",
" - $brooklyn:object:",
" type: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo"
);
Object testObject = testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertTrue(testObject instanceof TestObject, "Expected a TestObject: "+testObject);
Assert.assertTrue(managementContextInjected.get());
Assert.assertEquals(((TestObject) testObject).getNumber(), Integer.valueOf(7));
Assert.assertEquals(((TestObject) testObject).getString(), "frog");
Object testObjectObject = ((TestObject) testObject).getObject();
Assert.assertTrue(testObjectObject instanceof SimpleTestPojo, "Expected a SimpleTestPojo: "+testObjectObject);
}
@Test
public void testBrooklynObjectWithFactoryMethod() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" factoryMethod.name: newTestObject",
" factoryMethod.args:",
" - frog",
" - 7",
" - $brooklyn:object:",
" type: org.apache.brooklyn.camp.brooklyn.SimpleTestPojo"
);
Object testObject = testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertTrue(testObject instanceof TestObject, "Expected a TestObject: "+testObject);
Assert.assertTrue(managementContextInjected.get());
Assert.assertEquals(((TestObject) testObject).getNumber(), Integer.valueOf(8));
Assert.assertEquals(((TestObject) testObject).getString(), "frog-suffix");
Object testObjectObject = ((TestObject) testObject).getObject();
Assert.assertTrue(testObjectObject instanceof SimpleTestPojo, "Expected a SimpleTestPojo: "+testObjectObject);
}
@Test
public void testBrooklynObjectWithFactoryMethodNoArgs() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" factoryMethod.name: newTestObjectWithNoArgs");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
assertEquals(testObject.getString(), "myDefaultFirst");
assertEquals(testObject.getNumber(), Integer.valueOf(1));
assertEquals(testObject.getObject(), "myDefaultThird");
}
@Test
public void testBrooklynObjectWithFactoryMethodWithArgCoercion() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: " + Time.class.getName(),
" factoryMethod.name: makeDateString",
" factoryMethod.args:",
" - 1000",
" - yyyy-MM-dd'T'HH:mm:ss",
" - UTC");
String val = (String) testEntity.getConfig(TestEntity.CONF_OBJECT);
assertEquals(val, "1970-01-01T00:00:01");
}
@Test
public void testFieldsAsDeferredSuppliers() throws Exception {
// all fields as deferred suppliers
{
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" object.fields:",
" number: $brooklyn:config(\"myint\")",
" string: $brooklyn:config(\"mystring\")",
" list: ",
" - $brooklyn:config(\"mystring\")");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertEquals(testObject.getNumber(), Integer.valueOf(123));
Assert.assertEquals(testObject.getString(), "myval");
Assert.assertEquals(testObject.getList(), ImmutableList.of("myval"));
}
// Only first field as deferred supplier
{
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" object.fields:",
" number: $brooklyn:config(\"myint\")",
" string: myval");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertEquals(testObject.getNumber(), Integer.valueOf(123));
Assert.assertEquals(testObject.getString(), "myval");
}
// Only second field as deferred supplier
{
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" object.fields:",
" number: 7",
" string: $brooklyn:config(\"mystring\")");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertEquals(testObject.getNumber(), Integer.valueOf(7));
Assert.assertEquals(testObject.getString(), "myval");
}
}
@Test
public void testFieldOfTypeListAsDeferredSuppliersExplicitlyDeferred() throws Exception {
{
// Using explicit `deferred: true`
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" deferred: true",
" object.fields:",
" list: ",
" - $brooklyn:config(\"mystring\")");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertEquals(testObject.getList(), ImmutableList.of("myval"));
}
}
// TODO See https://issues.apache.org/jira/browse/BROOKLYN-565
@Test(groups="Broken")
public void testFieldOfTypeListAsDeferredSuppliers() throws Exception {
{
// See https://issues.apache.org/jira/browse/BROOKLYN-565
// should defer evaluation automatically, and resolve config in `getConfig()`
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" object.fields:",
" list: ",
" - $brooklyn:config(\"mystring\")");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
Assert.assertEquals(testObject.getList(), ImmutableList.of("myval"));
}
}
@Test
public void testConfigAsDeferredSuppliers() throws Exception {
// all fields as deferred suppliers
{
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" mydouble: 1.4",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$ConfigurableObject",
" object.fields:",
" double: $brooklyn:config(\"mydouble\")",
" brooklyn.config:",
" flag: $brooklyn:config(\"mystring\")",
" config.number: $brooklyn:config(\"myint\")");
ConfigurableObject testObject = (ConfigurableObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
assertEquals(testObject.getDouble(), Double.valueOf(1.4));
assertEquals(testObject.getString(), "myval");
assertEquals(testObject.getNumber(), Integer.valueOf(123));
}
// Only only fields (and not config) as deferred supplier
{
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" mydouble: 1.4",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$ConfigurableObject",
" object.fields:",
" double: $brooklyn:config(\"mydouble\")",
" brooklyn.config:",
" flag: myval",
" config.number: 123");
ConfigurableObject testObject = (ConfigurableObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
assertEquals(testObject.getDouble(), Double.valueOf(1.4));
assertEquals(testObject.getString(), "myval");
assertEquals(testObject.getNumber(), Integer.valueOf(123));
}
// Only config (and not fields) as deferred supplier
{
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" mydouble: 1.4",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$ConfigurableObject",
" object.fields:",
" double: 1.4",
" brooklyn.config:",
" flag: $brooklyn:config(\"mystring\")",
" config.number: $brooklyn:config(\"myint\")");
ConfigurableObject testObject = (ConfigurableObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
assertEquals(testObject.getDouble(), Double.valueOf(1.4));
assertEquals(testObject.getString(), "myval");
assertEquals(testObject.getNumber(), Integer.valueOf(123));
}
}
@Test
public void testConstructorArgsAsDeferredSuppliers() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" mydouble: 1.4",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" constructor.args:",
" - $brooklyn:config(\"mystring\")",
" - $brooklyn:config(\"myint\")",
" - myThirdParam");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
assertEquals(testObject.getNumber(), Integer.valueOf(123));
assertEquals(testObject.getString(), "myval");
assertEquals(testObject.getObject(), "myThirdParam");
}
@Test
public void testFactorArgsAsDeferredSuppliers() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" mystring: myval",
" myint: 123",
" mydouble: 1.4",
" test.confObject:",
" $brooklyn:object:",
" type: "+ObjectsYamlTest.class.getName()+"$TestObject",
" factoryMethod.name: newTestObject",
" factoryMethod.args:",
" - $brooklyn:config(\"mystring\")",
" - $brooklyn:config(\"myint\")",
" - myThirdParam");
TestObject testObject = (TestObject) testEntity.getConfig(TestEntity.CONF_OBJECT);
assertEquals(testObject.getNumber(), Integer.valueOf(124)); // factory method adds one
assertEquals(testObject.getString(), "myval-suffix");
assertEquals(testObject.getObject(), "myThirdParam");
}
@Test
public void testCallingPasswordHasher() throws Exception {
Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" brooklyn.password: mypassword",
" brooklyn.password.sha256:",
" brooklyn.password.salt: $brooklyn:entityId()",
" brooklyn.password.sha256:",
" $brooklyn:object:",
" type: "+PasswordHasher.class.getName(),
" factoryMethod.name: sha256",
" factoryMethod.args:",
" - $brooklyn:config(\"brooklyn.password.salt\")",
" - $brooklyn:config(\"brooklyn.password\")");
String salt = (String) testEntity.config().get(ConfigKeys.newConfigKey(Object.class, "brooklyn.password.salt"));
String sha256 = (String) testEntity.config().get(ConfigKeys.newConfigKey(Object.class, "brooklyn.password.sha256"));
assertEquals(salt, testEntity.getId());
assertEquals(sha256, PasswordHasher.sha256(salt, "mypassword"));
}
@Test
public void testBrooklynObjectEvaluatedImmediatelyOnlyOnce() throws Exception {
CallRecorder.clear();
Entity entity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" type: "+CallRecorder.class.getName(),
" factoryMethod.name: call",
" factoryMethod.args:",
" - myval");
// Nothing has called config().get() yet; but expect it to have been evaluated immediate, on entity construction
assertEquals(CallRecorder.getCalls(), ImmutableList.of("myval"));
// The config value is set to the result of that single call; getting the config will not invoke it again
Object val = entity.config().get(TestEntity.CONF_OBJECT);
assertEquals(val, "myval");
assertEquals(CallRecorder.getCalls(), ImmutableList.of("myval"));
}
@Test
public void testBrooklynObjectEvaluationDeferredIfRequired() throws Exception {
CallRecorder.clear();
Entity entity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" anotherConfig: myval",
" test.confObject:",
" $brooklyn:object:",
" type: "+CallRecorder.class.getName(),
" factoryMethod.name: call",
" factoryMethod.args:",
" - $brooklyn:config(\"anotherConfig\")");
// The value is a DeferredSupplier; nothing in the blueprint will have called config().get() yet.
// However, verification will have called it! Therefore not doing:
// assertEquals(CallRecorder.getCalls(), ImmutableList.of());
CallRecorder.clear();
// Retrieving the config value causes it to be resolved
Object val = entity.config().get(TestEntity.CONF_OBJECT);
assertEquals(val, "myval");
assertEquals(CallRecorder.getCalls(), ImmutableList.of("myval"));
// Retrieving the config value a second time will resolve it again
Object val2 = entity.config().get(TestEntity.CONF_OBJECT);
assertEquals(val2, "myval");
assertEquals(CallRecorder.getCalls(), ImmutableList.of("myval", "myval"));
}
@Test
public void testBrooklynObjectEvaluationExplicitlyDeferred() throws Exception {
CallRecorder.clear();
Entity entity = setupAndCheckTestEntityInBasicYamlWith(
" brooklyn.config:",
" test.confObject:",
" $brooklyn:object:",
" deferred: true",
" type: "+CallRecorder.class.getName(),
" factoryMethod.name: call",
" factoryMethod.args:",
" - myval");
// The value is a DeferredSupplier; nothing in the blueprint will have called config().get() yet.
// However, verification will have called it! Therefore not doing:
// assertEquals(CallRecorder.getCalls(), ImmutableList.of());
CallRecorder.clear();
// Retrieving the config value causes it to be resolved
Object val = entity.config().get(TestEntity.CONF_OBJECT);
assertEquals(val, "myval");
assertEquals(CallRecorder.getCalls(), ImmutableList.of("myval"));
// Retrieving the config value a second time will resolve it again
Object val2 = entity.config().get(TestEntity.CONF_OBJECT);
assertEquals(val2, "myval");
assertEquals(CallRecorder.getCalls(), ImmutableList.of("myval", "myval"));
}
@Test
public void testBrooklynObjectGuavaCompose() throws Exception {
AttributeSensor<String> originalSensor = Sensors.newStringSensor("staticSensor");
AttributeSensor<String> transformedSensorFormatString = Sensors.newStringSensor("staticSensor.transformed.format");
AttributeSensor<String> transformedSensorComposeMethod = Sensors.newStringSensor("staticSensor.transformed.compose");
CallRecorder.clear();
final Entity entity = createAndStartApplication(
"services:",
"- type: " + BasicApplication.class.getName(),
" brooklyn.initializers:",
" - type: org.apache.brooklyn.core.sensor.StaticSensor",
" brooklyn.config:",
" name: staticSensor",
" static.value: \"{parent:{child:myValue}}\"",
" brooklyn.enrichers:",
" - type: org.apache.brooklyn.enricher.stock.Transformer",
" brooklyn.config:",
" enricher.sourceSensor: " + originalSensor.getName(),
" enricher.targetSensor: " + transformedSensorComposeMethod.getName(),
" enricher.transformation:",
" $brooklyn:object:",
" type: \"com.google.guava:com.google.common.base.Functions\"",
" factoryMethod.name: \"compose\"",
" factoryMethod.args:",
" - $brooklyn:object:",
" type: \"org.apache.brooklyn.feed.http.JsonFunctions\"",
" factoryMethod.name: \"getPath\"",
" factoryMethod.args:",
" - \"$.parent.child\"",
" - $brooklyn:object:",
" type: \"org.apache.brooklyn.feed.http.JsonFunctions\"",
" factoryMethod.name: \"asJson\"",
" - type: org.apache.brooklyn.enricher.stock.Transformer",
" brooklyn.config:",
" enricher.sourceSensor: "+ originalSensor.getName(),
" enricher.targetSensor: " + transformedSensorFormatString.getName(),
" enricher.targetValue:",
" $brooklyn:formatString:",
" - \"JSON: %s\"",
" - $brooklyn:attributeWhenReady(\"staticSensor\")"
);
EntityAsserts.assertAttributeEqualsEventually(entity, originalSensor, "{parent:{child:myValue}}");
EntityAsserts.assertAttributeEqualsEventually(entity, transformedSensorFormatString, "JSON: {parent:{child:myValue}}");
EntityAsserts.assertAttributeEqualsEventually(entity, transformedSensorComposeMethod, "myValue");
}
public static class CallRecorder {
private static final List<String> calls = Collections.synchronizedList(Lists.<String>newArrayList());
public static String call(String val) {
calls.add(val);
return val;
}
public static void clear() {
calls.clear();
}
public static List<String> getCalls() {
synchronized (calls) {
return MutableList.copyOf(calls);
}
}
}
@Override
protected Logger getLogger() {
return log;
}
}