blob: e915702c02f9167c9165597ff3796576bab656fe [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.util.core.internal;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.api.objs.Configurable;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
import org.apache.brooklyn.core.config.BasicConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
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.config.ConfigBag;
import org.apache.brooklyn.util.core.flags.FlagUtils;
import org.apache.brooklyn.util.core.flags.FlagUtils.FlagConfigKeyAndValueRecord;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.util.guava.Maybe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
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 FlagUtilsTest {
public static final Logger log = LoggerFactory.getLogger(FlagUtilsTest.class);
@Test
public void testGetAllFields() {
log.info("types {}", FlagUtils.getAllAssignableTypes(Baz.class));
assertEquals(FlagUtils.getAllAssignableTypes(Baz.class), ImmutableList.of(Baz.class, Foo.class, Bar.class));
List<Field> fs = FlagUtils.getAllFields(Baz.class);
for (Field f : fs) {
log.info("field {} {}", f.getName(), f);
}
List<String> fsn = ImmutableList.copyOf(Iterables.transform(fs, new Function<Field, String>() {
@Override public String apply(Field f) {
return f.getName();
}}));
assertTrue(fsn.indexOf("A") >= 0);
assertTrue(fsn.indexOf("w") > fsn.indexOf("A"));
assertTrue(fsn.indexOf("x") > fsn.indexOf("A") );
assertTrue(fsn.indexOf("yNotY") > fsn.indexOf("A"));
assertTrue(fsn.indexOf("Z") > fsn.indexOf("yNotY") );
}
@Test
public void testSetFieldsFromFlags() {
Foo f = new Foo();
Map<?,?> m = MutableMap.of("w", 3, "x", 1, "y", 7, "z", 9);
Map<?, ?> unused = FlagUtils.setFieldsFromFlags(m, f);
assertEquals(f.w, 3);
assertEquals(f.x, 1);
assertEquals(f.yNotY, 7);
assertEquals(unused, ImmutableMap.of("z", 9));
Map<?,?> m2 = FlagUtils.getFieldsWithValues(f);
m.remove("z");
assertEquals(m2, m);
}
@Test
public void testCollectionCoercionOnSetFromFlags() {
WithSpecialFieldTypes s = new WithSpecialFieldTypes();
Map<?,?> m = ImmutableMap.of("set", ImmutableSet.of(1));
FlagUtils.setFieldsFromFlags(m, s);
assertEquals(s.set, ImmutableSet.of(1));
}
@Test
public void testInetAddressCoercionOnSetFromFlags() {
WithSpecialFieldTypes s = new WithSpecialFieldTypes();
Map<?,?> m = ImmutableMap.of("inet", "127.0.0.1");
FlagUtils.setFieldsFromFlags(m, s);
assertEquals(s.inet.getHostAddress(), "127.0.0.1");
}
@Test
public void testNonImmutableField() {
Foo f = new Foo();
FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 8), f);
assertEquals(f.w, 8);
FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 9), f);
assertEquals(f.w, 9);
}
@Test
public void testImmutableIntField() {
Foo f = new Foo();
FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 8), f);
assertEquals(f.x, 8);
boolean succeededWhenShouldntHave = false;
try {
FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 9), f);
succeededWhenShouldntHave = true;
} catch (IllegalStateException e) {
//expected
}
assertFalse(succeededWhenShouldntHave);
assertEquals(f.x, 8);
}
@Test
public void testImmutableObjectField() {
WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a", "b", "b"), o);
assertEquals(o.a, "a");
assertEquals(o.b, "b");
FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a2"), o);
assertEquals(o.a, "a2");
boolean succeededWhenShouldntHave = false;
try {
FlagUtils.setFieldsFromFlags(ImmutableMap.of("b", "b2"), o);
succeededWhenShouldntHave = true;
} catch (IllegalStateException e) {
//expected
}
assertFalse(succeededWhenShouldntHave);
assertEquals(o.b, "b");
}
@Test
public void testNonNullable() {
WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
//allowed
FlagUtils.setFieldsFromFlags(MutableMap.of("a", null), o);
assertEquals(o.a, null);
assertEquals(o.b, null);
//not allowed
boolean succeededWhenShouldntHave = false;
try {
FlagUtils.setFieldsFromFlags(MutableMap.of("b", null), o);
succeededWhenShouldntHave = true;
} catch (IllegalArgumentException e) {
//expected
}
assertFalse(succeededWhenShouldntHave);
assertEquals(o.b, null);
}
@Test
public void testGetAnnotatedFields() throws Exception {
Map<Field, SetFromFlag> fm = FlagUtils.getAnnotatedFields(WithImmutableNonNullableObject.class);
assertEquals(fm.keySet().size(), 2);
assertTrue(fm.get(WithImmutableNonNullableObject.class.getDeclaredField("b")).immutable());
}
@Test
public void testCheckRequired() {
WithImmutableNonNullableObject f = new WithImmutableNonNullableObject();
FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a is a"), f);
assertEquals(f.a, "a is a");
assertEquals(f.b, null);
int exceptions = 0;
try {
FlagUtils.checkRequiredFields(f);
} catch (IllegalStateException e) {
exceptions++;
}
assertEquals(exceptions, 1);
}
@Test
public void testSetConfigKeys() {
FooCK f = new FooCK();
Map<?,?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "dont-set", "c3", "do-set"), f);
assertEquals(f.bag.get(FooCK.CK1), "do-set");
assertEquals(f.bag.get(FooCK.CK3), "do-set");
assertEquals(f.f1, 9);
assertEquals(f.bag.containsKey(FooCK.CK2), false);
assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
}
@Test
public void testSetAllConfigKeys() {
FooCK f = new FooCK();
Map<?,?> unused = FlagUtils.setAllConfigKeys(
ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "do-set-2", "c3", "do-set"), f, true, false);
assertEquals(f.bag.get(FooCK.CK1), "do-set");
assertEquals(f.bag.get(FooCK.CK3), "do-set");
assertEquals(f.bag.containsKey(FooCK.CK2), true);
assertEquals(f.bag.get(FooCK.CK2), "do-set-2");
assertEquals(unused, ImmutableMap.of("f1", 9));
}
@Test
public void testSetFromConfigKeys() {
FooCK f = new FooCK();
Map<?, ?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of(new BasicConfigKey<Integer>(Integer.class, "f1"), 9, "ck1", "do-set", "ck2", "dont-set"), f);
assertEquals(f.bag.get(FooCK.CK1), "do-set");
assertEquals(f.f1, 9);
assertEquals(f.bag.containsKey(FooCK.CK2), false);
assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
}
@Test
public void testFindAllConfigKeys() {
Map<String, ConfigKey<?>> keys = FlagUtils.findAllConfigKeys(null, ImmutableList.of(SubFooCK.class));
assertEquals(keys, ImmutableMap.of(
FooCK.CK1.getName(), FooCK.CK1,
FooCK.CK2.getName(), FooCK.CK2,
FooCK.CK3.getName(), FooCK.CK3,
SubFooCK.CK4.getName(), SubFooCK.CK4));
}
@Test
public void testFindAllFlagsAndConfigKeysWithEmptyBag() {
ConfigBag bag = ConfigBag.newInstance(ImmutableMap.of());
List<FlagConfigKeyAndValueRecord> vals = FlagUtils.<SubFooCK>findAllFlagsAndConfigKeys(null, SubFooCK.class, bag);
assertRecordsEqual(vals, ImmutableList.<ExpectedFlagConfigKeyAndValueRecord>of());
}
@Test
public void testFindAllFlagsAndConfigKeysWithConfigVals() {
ConfigBag bag = ConfigBag.newInstance(ImmutableMap.of(FooCK.CK1, "ck1.myval"));
List<FlagConfigKeyAndValueRecord> vals = FlagUtils.<SubFooCK>findAllFlagsAndConfigKeys(null, SubFooCK.class, bag);
assertRecordsEqual(vals, ImmutableList.of(new ExpectedFlagConfigKeyAndValueRecord(FooCK.CK1, "CK1", "ck1.myval")));
}
@Test
public void testFindAllFlagsAndConfigKeysWithFlagVals() {
ConfigBag bag = ConfigBag.newInstance(ImmutableMap.of("f1", 123));
List<FlagConfigKeyAndValueRecord> vals = FlagUtils.<SubFooCK>findAllFlagsAndConfigKeys(null, SubFooCK.class, bag);
assertRecordsEqual(vals, ImmutableList.of(new ExpectedFlagConfigKeyAndValueRecord("f1", 123)));
}
protected void assertRecordsEqual(List<FlagConfigKeyAndValueRecord> actual, List<ExpectedFlagConfigKeyAndValueRecord> expected) {
List<FlagConfigKeyAndValueRecord> actualCopy = MutableList.copyOf(actual);
for (ExpectedFlagConfigKeyAndValueRecord record : expected) {
boolean found = false;
for (FlagConfigKeyAndValueRecord contender : actualCopy) {
if (isRecordEqual(contender, record)) {
actualCopy.remove(contender);
found = true;
break;
}
}
if (!found) {
fail(record+" expected, but not found");
}
}
if (!actualCopy.isEmpty()) {
fail(actualCopy+" additional records found");
}
}
protected boolean isRecordEqual(FlagConfigKeyAndValueRecord val1, ExpectedFlagConfigKeyAndValueRecord val2) {
return Objects.equal(val1.getConfigKey(), val2.configKey)
&& Objects.equal(val1.getFlagName(), val2.flagName)
&& Objects.equal(val1.getConfigKeyMaybeValue(), val2.configKeyValue)
&& Objects.equal(val1.getFlagMaybeValue(), val2.flagValue);
}
// The fields of FlagConfigKeyAndValueRecord are private; hence having this class to make assertions easier
static class ExpectedFlagConfigKeyAndValueRecord {
String flagName = "";
ConfigKey<?> configKey = null;
Maybe<Object> flagValue = Maybe.absent();
Maybe<Object> configKeyValue = Maybe.absent();
ExpectedFlagConfigKeyAndValueRecord(String flagName, Object val) {
this.flagName = flagName;
this.flagValue = Maybe.of(val);
}
ExpectedFlagConfigKeyAndValueRecord(ConfigKey<?> key, String flagName, Object val) {
this.configKey = key;
this.flagName = flagName;
this.configKeyValue = Maybe.of(val);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).omitNullValues()
.add("flag", flagName)
.add("configKey", configKey)
.add("flagValue", flagValue.orNull())
.add("configKeyValue", configKeyValue.orNull())
.toString();
}
}
public static class Foo {
@SetFromFlag
int w;
@SetFromFlag(immutable=true)
private int x;
@SetFromFlag("y")
public int yNotY;
}
public static interface Bar {
static final String Z = "myzval";
}
public static class Baz extends Foo implements Bar {
@SuppressWarnings("unused") //inspected by reflection
private static int A;
}
public static class WithImmutableNonNullableObject {
@SetFromFlag
Object a;
@SetFromFlag(immutable=true, nullable=false)
public Object b;
}
public static class WithSpecialFieldTypes {
@SetFromFlag Set<?> set;
@SetFromFlag InetAddress inet;
}
public static class FooCK implements Configurable {
@SetFromFlag
public static ConfigKey<String> CK1 = ConfigKeys.newStringConfigKey("ck1");
public static ConfigKey<String> CK2 = ConfigKeys.newStringConfigKey("ck2");
@SetFromFlag("c3")
public static ConfigKey<String> CK3 = ConfigKeys.newStringConfigKey("ck3");
@SetFromFlag
int f1;
ConfigBag bag = new ConfigBag();
BasicConfigurationSupport configSupport = new BasicConfigurationSupport();
@Override
public ConfigurationSupport config() {
return configSupport;
}
@Override
public <T> T getConfig(ConfigKey<T> key) {
return config().get(key);
}
private class BasicConfigurationSupport implements ConfigurationSupport {
@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) {
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);
}
}
}
public static class SubFooCK extends FooCK {
public static ConfigKey<String> CK4 = ConfigKeys.newStringConfigKey("ck4");
}
}